From e136a9db0210d626d9b0b2314aa11ef70f51a2ce Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Mon, 13 Mar 2017 22:48:12 +0900 Subject: [PATCH 001/293] Create README --- src/USER-EES/README | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/USER-EES/README diff --git a/src/USER-EES/README b/src/USER-EES/README new file mode 100644 index 0000000000..220c7fa203 --- /dev/null +++ b/src/USER-EES/README @@ -0,0 +1,10 @@ +This package implements the EES potential between ellipsoidal particles and a semi finite LJ wall introduced by Babadi and Ejtehadi. + +This potential has fixes in both "fix wall" style and "fix wall/region" style so can be used as a boundary of simulation box or on the sides of a region inside the simulation box. + +The ASPHERE package is required for using this fixes. + +For more details please refer to documentation of LAMMPS under "fix wall/ees" entry. +There are also some example of using this code in /examples/usr/EES. + +This implementation is done by Abdoreza Ershadinia at Sharif University of Technology--Tehran (a.ershdinia@physics.sahrif.edu). From 6311d33a5d5665513482d2cd20855ba517154f85 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Mon, 13 Mar 2017 22:49:04 +0900 Subject: [PATCH 002/293] UPLOAD source files source files and install.sh added --- src/USER-EES/fix_wall_ees.cpp | 207 ++++++++++++++ src/USER-EES/fix_wall_ees.h | 51 ++++ src/USER-EES/fix_wall_region_ees.cpp | 405 +++++++++++++++++++++++++++ src/USER-EES/fix_wall_region_ees.h | 94 +++++++ src/USER-EES/install.sh | 34 +++ 5 files changed, 791 insertions(+) create mode 100644 src/USER-EES/fix_wall_ees.cpp create mode 100644 src/USER-EES/fix_wall_ees.h create mode 100644 src/USER-EES/fix_wall_region_ees.cpp create mode 100644 src/USER-EES/fix_wall_region_ees.h create mode 100644 src/USER-EES/install.sh diff --git a/src/USER-EES/fix_wall_ees.cpp b/src/USER-EES/fix_wall_ees.cpp new file mode 100644 index 0000000000..8ccadf274a --- /dev/null +++ b/src/USER-EES/fix_wall_ees.cpp @@ -0,0 +1,207 @@ +/* ---------------------------------------------------------------------- + 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 "math.h" +#include "math_extra.h" +#include "fix_wall_ees.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixWallEES::FixWallEES(LAMMPS *lmp, int narg, char **arg) : + FixWall(lmp, narg, arg) {} + +/* ---------------------------------------------------------------------- */ + +void FixWallEES::precompute(int m) +{ + coeff1[m] = ( 2. / 4725. ) * epsilon[m] * pow(sigma[m],12.0); + coeff2[m] = ( 1. / 24. ) * epsilon[m] * pow(sigma[m],6.0); + + coeff3[m] = ( 2. / 315. ) * epsilon[m] * pow(sigma[m],12.0); + coeff4[m] = ( 1. / 3. ) * epsilon[m] * pow(sigma[m],6.0); + + coeff5[m] = ( 4. / 315. ) * epsilon[m] * pow(sigma[m],12.0); + coeff6[m] = ( 1. / 12. ) * epsilon[m] * pow(sigma[m],6.0); +} + +/* ---------------------------------------------------------------------- */ +void FixWallEES::init() +{ + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + if (!avec) + error->all(FLERR,"Fix wall/ees requires atom style ellipsoid"); + + // check that all particles are finite-size ellipsoids + // no point particles allowed, spherical is OK + + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + if (ellipsoid[i] < 0) + error->one(FLERR,"Fix wall/ees requires extended particles"); + + FixWall::init(); +} + + +/* ---------------------------------------------------------------------- + interaction of all particles in group with a wall + m = index of wall coeffs + which = xlo,xhi,ylo,yhi,zlo,zhi + error if any particle is on or behind wall +------------------------------------------------------------------------- */ + +void FixWallEES::wall_particle(int m, int which, double coord) +{ + double delta; + + double **x = atom->x; + double **f = atom->f; + double **tor = atom->torque; + + + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + + int dim = which / 2; + int side = which % 2; + if (side == 0) side = -1; + + int onflag = 0; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + + if (side < 0) + delta = x[i][dim] - coord; + else + delta = coord - x[i][dim]; + + if (delta >= cutoff[m]) + continue; + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double sigman = 0.0, sigman2 = 0.0; + double nhat[3] = {0,0,0}; + + nhat[dim]=-1*side; + nhat[(dim+1)%3] = 0 ; + nhat[(dim+2)%3] = 0 ; + + + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; + sigman = sqrt(sigman2); + + if (delta <= sigman) { + onflag = 1; + continue; + } + + + double fwall = 0.0, twall = 0.0; + double delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; + double sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; + double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; + double hps = 0.0; + double hms = 0.0; + + double tempvec2[3]= {0,0,0}; + + double SAn[3] = {0,0,0}; + double that[3] = {0,0,0}; + + double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; + double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; + double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; + + + for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + + sigman3 = sigman2 * sigman; + sigman4 = sigman2 * sigman2; + sigman5 = sigman4 * sigman; + sigman6 = sigman3 * sigman3; + + + delta2 = delta * delta; + delta3 = delta2 * delta; + delta4 = delta2 * delta2; + delta5 = delta3 * delta2; + delta6 = delta3 * delta3; + + hhss = delta2 - sigman2; + hhss2 = hhss * hhss; + hhss4 = hhss2 * hhss2; + hhss8 = hhss4 * hhss4; + hhss7 = hhss4 * hhss2 * hhss; + + hps = delta + sigman; + hms = delta - sigman; + + fwall = side*( + -1*coeff4[m]/hhss2 + + coeff3[m] * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 + ); + f[i][dim] -= fwall; + + ewall[0] += -1*coeff2[m] * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + + coeff1[m] * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + + ewall[m+1] += fwall; + + twall = coeff6[m] * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + + coeff5[m] * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + + + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); + + + for(int j = 0; j<3 ; j++) + tor[i][j] += twall * that[j]; + + } + + if (onflag) error->one(FLERR,"Particle on or inside fix wall surface"); +} diff --git a/src/USER-EES/fix_wall_ees.h b/src/USER-EES/fix_wall_ees.h new file mode 100644 index 0000000000..17246c094f --- /dev/null +++ b/src/USER-EES/fix_wall_ees.h @@ -0,0 +1,51 @@ +/* -*- 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(wall/ees,FixWallEES) + +#else + +#ifndef LMP_FIX_WALL_EES_H +#define LMP_FIX_WALL_EES_H + +#include "fix_wall.h" + +namespace LAMMPS_NS { + +class FixWallEES : public FixWall { + public: + FixWallEES(class LAMMPS *, int, char **); + void precompute(int); + void init(); + void wall_particle(int, int, double); + + private: + double coeff1[6],coeff2[6],coeff3[6],coeff4[6],coeff5[6],coeff6[6]; + class AtomVecEllipsoid *avec; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Particle on or inside fix wall surface + +Particles must be "exterior" to the wall in order for energy/force to +be calculated. + +*/ diff --git a/src/USER-EES/fix_wall_region_ees.cpp b/src/USER-EES/fix_wall_region_ees.cpp new file mode 100644 index 0000000000..20a5f74c15 --- /dev/null +++ b/src/USER-EES/fix_wall_region_ees.cpp @@ -0,0 +1,405 @@ +/* -*- 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. +------------------------------------------------------------------------- */ +#include +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "fix_wall_region_ees.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "domain.h" +#include "region.h" +#include "force.h" +#include "lattice.h" +#include "update.h" +#include "output.h" +#include "respa.h" +#include "error.h" +#include "math_extra.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +enum{LJ93,LJ126,COLLOID,HARMONIC,EES};//me + +/* ---------------------------------------------------------------------- */ +/// USAGE: +/// fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff +/// +FixWallRegionEES::FixWallRegionEES(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg != 7) error->all(FLERR,"Illegal fix wall/region/ees command"); + scalar_flag = 1; + vector_flag = 1; + size_vector = 3; + global_freq = 1; + extscalar = 1; + extvector = 1; + + // parse args + + iregion = domain->find_region(arg[3]); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + int n = strlen(arg[3]) + 1; + idregion = new char[n]; + strcpy(idregion,arg[3]); + + + + epsilon = force->numeric(FLERR,arg[4]); + sigma = force->numeric(FLERR,arg[5]); + cutoff = force->numeric(FLERR,arg[6]); + + if (cutoff <= 0.0) error->all(FLERR,"Fix wall/region/ees cutoff <= 0.0"); + + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +FixWallRegionEES::~FixWallRegionEES() +{ + delete [] idregion; +} + +/* ---------------------------------------------------------------------- */ + +int FixWallRegionEES::setmask() +{ + int mask = 0; + mask |= POST_FORCE; + mask |= THERMO_ENERGY; + mask |= POST_FORCE_RESPA; + mask |= MIN_POST_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::init() +{ + // set index and check validity of region + + iregion = domain->find_region(idregion); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + + + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + if (!avec) + error->all(FLERR,"Fix wall/region/ees requires atom style ellipsoid"); + + // check that all particles are finite-size ellipsoids + // no point particles allowed, spherical is OK + + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + if (ellipsoid[i] < 0) + error->one(FLERR,"Fix wall/region/ees requires extended particles"); + + + // setup coefficients for each style + + coeff1 = ( 2. / 4725. ) * epsilon * pow(sigma,12.0); + coeff2 = ( 1. / 24. ) * epsilon * pow(sigma,6.0); + coeff3 = ( 2. / 315. ) * epsilon * pow(sigma,12.0); + coeff4 = ( 1. / 3. ) * epsilon * pow(sigma,6.0); + coeff5 = ( 4. / 315. ) * epsilon * pow(sigma,12.0); + coeff6 = ( 1. / 12. ) * epsilon * pow(sigma,6.0); + offset = 0; + + + if (strstr(update->integrate_style,"respa")) + nlevels_respa = ((Respa *) update->integrate)->nlevels; +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::setup(int vflag) +{ + if (strstr(update->integrate_style,"verlet")) + post_force(vflag); + else { + ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); + post_force_respa(vflag,nlevels_respa-1,0); + ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::min_setup(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::post_force(int vflag) +{ + //me + //sth is needed here, but I dont know what + //that is calculation of sn + + int i,m,n; + double rinv,fx,fy,fz,tooclose[3];//me + double sn;//me + + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; + + double **x = atom->x; + double **f = atom->f; + double *radius = atom->radius; + + double **tor = atom->torque; //me + + //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");//me + AtomVecEllipsoid::Bonus *bonus = avec->bonus;//me + int *ellipsoid = atom->ellipsoid;//me + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + Region *region = domain->regions[iregion]; + region->prematch(); + + int onflag = 0; + + // region->match() insures particle is in region or on surface, else error + // if returned contact dist r = 0, is on surface, also an error + // in COLLOID case, r <= radius is an error + + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + if (!region->match(x[i][0],x[i][1],x[i][2])) { + onflag = 1; + continue; + } + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double sn2 = 0.0; + double nhat[3] = {0,0,0}; + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + + for(int which = 0 ; which < 3; which ++){//me + nhat[which]=1; + nhat[(which+1)%3] = 0 ; + nhat[(which+2)%3] = 0 ; + sn2 = 0 ; + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sn2 += tempvec[k]*tempvec[k]; + sn = sqrt(sn2); + tooclose[which] = sn; + } + + + + n = region->surface(x[i][0],x[i][1],x[i][2],cutoff); + + for (m = 0; m < n; m++) { + + if(region->contact[m].delx != 0 && region->contact[m].r <= tooclose[0] ){ + onflag = 1; + continue; + + }else if (region->contact[m].dely != 0 && region->contact[m].r <= tooclose[1]){ + onflag = 1; + continue; + }else if (region->contact[m].delz !=0 && region->contact[m].r <= tooclose[2]){ + onflag = 1; + continue; + } + else rinv = 1.0/region->contact[m].r; + + ees(m,i);//me + + ewall[0] += eng; + fx = fwall * region->contact[m].delx * rinv; + fy = fwall * region->contact[m].dely * rinv; + fz = fwall * region->contact[m].delz * rinv; + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + ewall[1] -= fx; + ewall[2] -= fy; + ewall[3] -= fz; + + tor[i][0] += torque[0]; + tor[i][1] += torque[1]; + tor[i][2] += torque[2]; + + } + } + + if (onflag) error->one(FLERR,"Particle on or inside surface of region " + "used in fix wall/region/ees"); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::post_force_respa(int vflag, int ilevel, int iloop) +{ + if (ilevel == nlevels_respa-1) post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::min_post_force(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- + energy of wall interaction +------------------------------------------------------------------------- */ + +double FixWallRegionEES::compute_scalar() +{ + // only sum across procs one time + + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[0]; +} + +/* ---------------------------------------------------------------------- + components of force on wall +------------------------------------------------------------------------- */ + +double FixWallRegionEES::compute_vector(int n) +{ + // only sum across procs one time + + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[n+1]; +} + + + +//me +/* ---------------------------------------------------------------------- + EES interaction for ellipsoid particle with wall + compute eng and fwall and twall = magnitude of wall force and torque +------------------------------------------------------------------------- */ + +void FixWallRegionEES::ees(int m, int i) +{ + Region *region = domain->regions[iregion]; + region->prematch(); + + double delta = 0.0, delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; + double sigman = 0.0, sigman2 = 0.0 , sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; + double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; //h^2 - s_n^2 + double hps = 0.0; //h+s_n + double hms = 0.0; //h-s_n + double twall = 0.0; + double tempvec[3]={0,0,0}; + double tempvec2[3]= {0,0,0}; + + double SAn[3] = {0,0,0}; + double that[3] = {0,0,0}; + + double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; + double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; + double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double nhat[3] = {0,0,0}; + + nhat[0] = region->contact[m].delx / region->contact[m].r; + nhat[1] = region->contact[m].dely / region->contact[m].r; + nhat[2] = region->contact[m].delz / region->contact[m].r; + + //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid;//me + + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; + for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + + + sigman = sqrt(sigman2); + delta = fabs(region->contact[m].r); + + sigman3 = sigman2 * sigman; + sigman4 = sigman2 * sigman2; + sigman5 = sigman4 * sigman; + sigman6 = sigman3 * sigman3; + + delta2 = delta * delta; + delta3 = delta2 * delta; + delta4 = delta2 * delta2; + delta5 = delta3 * delta2; + delta6 = delta3 * delta3; + + hhss = delta2 - sigman2; + hhss2 = hhss * hhss; + hhss4 = hhss2 * hhss2; + hhss8 = hhss4 * hhss4; + hhss7 = hhss4 * hhss2 * hhss; + + hps = delta + sigman; + hms = delta - sigman; + + fwall = -1*coeff4/hhss2 + + coeff3 * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 + ; + + eng = -1*coeff2 * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + + coeff1 * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + + twall = coeff6 * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + + coeff5 * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); + + for(int j = 0; j<3 ; j++) + torque[j] = twall * that[j]; + +} diff --git a/src/USER-EES/fix_wall_region_ees.h b/src/USER-EES/fix_wall_region_ees.h new file mode 100644 index 0000000000..59679a0b41 --- /dev/null +++ b/src/USER-EES/fix_wall_region_ees.h @@ -0,0 +1,94 @@ +/* -*- 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(wall/region/ees,FixWallRegionEES) + +#else + +#ifndef LMP_FIX_WALL_REGION_EES_H +#define LMP_FIX_WALL_REGION_EES_H + +#include "fix.h" + + +namespace LAMMPS_NS { + +class FixWallRegionEES : public Fix { + public: + FixWallRegionEES(class LAMMPS *, int, char **); + ~FixWallRegionEES(); + int setmask(); + void init(); + void setup(int); + void min_setup(int); + void post_force(int); + void post_force_respa(int, int, int); + void min_post_force(int); + double compute_scalar(); + double compute_vector(int); + + private: + class AtomVecEllipsoid *avec;//me + + int iregion; + double epsilon,sigma,cutoff; + int eflag; + double ewall[4],ewall_all[4]; + int nlevels_respa; + char *idregion; + + double coeff1,coeff2,coeff3,coeff4,offset; + double coeff5, coeff6;//me + double eng,fwall; + double torque[3];//me + + void ees(int, int);//me +}; + +} + +#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. + +E: Region ID for fix wall/region/ees does not exist + +Self-explanatory. + +E: Fix wall/region/ees cutoff <= 0.0 + +Self-explanatory. + +E: Fix wall/region/ees colloid requires atom style sphere + +Self-explanatory. + +E: Fix wall/region/ees colloid requires extended particles + +One of the particles has radius 0.0. + +E: Particle on or inside surface of region used in fix wall/region + +Particles must be "exterior" to the region surface in order for +energy/force to be calculated. + +*/ diff --git a/src/USER-EES/install.sh b/src/USER-EES/install.sh new file mode 100644 index 0000000000..6163d56ad4 --- /dev/null +++ b/src/USER-EES/install.sh @@ -0,0 +1,34 @@ +# Install/unInstall package files in LAMMPS +# mode = 0/1/2 for uninstall/install/update + +mode=$1 + +# enforce using portable C locale +LC_ALL=C +export LC_ALL + +# arg1 = file, arg2 = file it depends on + +action () { + if (test $mode = 0) then + rm -f ../$1 + elif (! cmp -s $1 ../$1) then + if (test -z "$2" || test -e ../$2) then + cp $1 .. + if (test $mode = 2) then + echo " updating src/$1" + fi + fi + elif (test -n "$2") then + if (test ! -e ../$2) then + rm -f ../$1 + fi + fi +} + +# all package files with dependencies + +action fix_wall_ees.cpp +action fix_wall_ees.h +action fix_wall_region_ees.cpp +action fix_wall_region_ees.h From 23c3f5622af6ec70c4905710589c78c3e364c96d Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Mon, 13 Mar 2017 22:51:15 +0900 Subject: [PATCH 003/293] DOC files for USER-EES txt doc files for fix_wall_ees and fix_wall_region_ees added. --- doc/src/fix_wall_ees.txt | 102 ++++++++++++++++++++++++++++++++ doc/src/fix_wall_region_ees.txt | 41 +++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 doc/src/fix_wall_ees.txt create mode 100644 doc/src/fix_wall_region_ees.txt diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt new file mode 100644 index 0000000000..54511ffba7 --- /dev/null +++ b/doc/src/fix_wall_ees.txt @@ -0,0 +1,102 @@ +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Section_commands.html#comm) + +:line + +fix wall/ees command :h3 + + +[Syntax:] + +fix ID group-ID wall/ees face args ... keyword value ... :pre + +ID, group-ID are documented in "fix"_fix.html command :ulb,l +one or more face/arg pairs may be appended :l +face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} :l + args = coord epsilon sigma cutoff + coord = position of wall = EDGE or constant or variable + EDGE = current lo or hi edge of simulation box + constant = number like 0.0 or -30.0 (distance units) + variable = "equal-style variable"_variable.html like v_x or v_wiggle + epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) + epsilon can be a variable (see below) + sigma = size factor for wall-particle interaction (distance units) + sigma can be a variable (see below) + cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :pre +zero or more keyword/value pairs may be appended :l +keyword = {units} or {fld} :l + {units} value = {lattice} or {box} + {lattice} = the wall position is defined in lattice units + {box} = the wall position is defined in simulation box units + {fld} value = {yes} or {no} + {yes} = invoke the wall constraint to be compatible with implicit FLD + {no} = invoke the wall constraint in the normal way + {pbc} value = {yes} or {no} + {yes} = allow periodic boundary in a wall dimension + {no} = require non-perioidic boundaries in any wall dimension :pre +:ule + +[Examples:] + +fix wallhi all wall/ees xlo -1.0 1.0 1.0 2.5 units box +fix wallhi all wall/ees xhi EDGE 1.0 1.0 2.5 +fix wallhi all wall/ees v_wiggle 23.2 1.0 1.0 2.5 +fix zwalls all wall/ees zlo 0.0 1.0 1.0 0.858 zhi 40.0 1.0 1.0 0.858 :pre + +[Description:] +  +Bound the simulation domain on one or more of its faces with a flat +wall that interacts with the ellipsoidal atoms in the 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: + + + + +:c,image(Eqs/fix_wall_ees.jpg) +  +  +Introduced by Babadi and Ejtehadi in "(Babadi)"_#BabadiEjtehadi. 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 (see the image below). + +:c,image(JPG/fix_wall_ees_image.jpg) + +  +Details of using this command and specifications are the same as fix/wall command.  +  +The prefactor {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. +  +NOTE: You must insure that r is always bigger than 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). +  +[Restrictions:] none + +[Related commands:] + +"fix wall"_fix_wall.html, +"pair resquared"_pair_resquared.html + +[Default:] + +The option defaults units = lattice, fld = no, and pbc = no. + +:line + +:link(BabadiEjtehadi) +[(Babadi)] Babadi and Ejtehadi, EPL, 77 (2007) 23002. +:link(Babadi) +[(Berardi)] Babadi, Ejtehadi, Everaers, J Comp Phys, 219, 770-779 (2006). diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt new file mode 100644 index 0000000000..efb417add1 --- /dev/null +++ b/doc/src/fix_wall_region_ees.txt @@ -0,0 +1,41 @@ +"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c + +:link(lws,http://lammps.sandia.gov) +:link(ld,Manual.html) +:link(lc,Section_commands.html#comm) + +:line + +fix wall/region/ees command :h3 + +[Syntax:] + +fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff :pre + +ID, group-ID are documented in "fix"_fix.html command +wall/region = style name of this fix command +region-ID = region whose boundary will act as wall +epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) +sigma = size factor for wall-particle interaction (distance units) +cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul + +[Examples:]o +o +fix wall all wall/region/ees mySphere 1.0 1.0 2.5 :pre + +[Description:] + +Treat the surface of the geometric region defined by the {region-ID} +as a bounding wall which interacts with nearby ellipsoidal particles according to +the EES potential introduced "fix wall/ees"_fix_wall_ees.html. + +Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. + +[Restrictions:] none + +[Related commands:] + +"fix wall/lj93"_fix_wall.html, +"fix wall/ees"_fix_wall_ees.html + +[Default:] none From 68b2a454b5c178a74ac09b1f4ab32488bf006efc Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Mon, 13 Mar 2017 22:53:10 +0900 Subject: [PATCH 004/293] UPLOAD fix_wall_ees_image --- doc/src/JPG/fix_wall_ees_image.jpg | Bin 0 -> 6013 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/src/JPG/fix_wall_ees_image.jpg diff --git a/doc/src/JPG/fix_wall_ees_image.jpg b/doc/src/JPG/fix_wall_ees_image.jpg new file mode 100644 index 0000000000000000000000000000000000000000..00f958b760916f6fc608edad27142db743d49367 GIT binary patch literal 6013 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 Q3X+5_R8Zx^qrK7p0tm@2tN;K2 literal 0 HcmV?d00001 From d17d99b9dd22fec61a6e63eb656ae11fdf2f6c74 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Mon, 13 Mar 2017 22:54:09 +0900 Subject: [PATCH 005/293] UPLOAD Formulas for EES --- doc/src/Eqs/fix_wall_ees.jpg | Bin 0 -> 106786 bytes doc/src/Eqs/fix_wall_ees.tex | 10 ++++++++++ 2 files changed, 10 insertions(+) create mode 100644 doc/src/Eqs/fix_wall_ees.jpg create mode 100644 doc/src/Eqs/fix_wall_ees.tex diff --git a/doc/src/Eqs/fix_wall_ees.jpg b/doc/src/Eqs/fix_wall_ees.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0f99dae8f717cdf5456b943a3ffb7e246a1078e5 GIT binary patch literal 106786 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≠xCmX8xgA6 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 literal 0 HcmV?d00001 diff --git a/doc/src/Eqs/fix_wall_ees.tex b/doc/src/Eqs/fix_wall_ees.tex new file mode 100644 index 0000000000..c8b62067a8 --- /dev/null +++ b/doc/src/Eqs/fix_wall_ees.tex @@ -0,0 +1,10 @@ +\documentclass[12pt]{article} + +\begin{document} + +$$ +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 +$$ + + +\end{document} From ef72145540a54bc9ce6bcc090ca9609f9ffddc18 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Thu, 16 Mar 2017 21:10:41 +0900 Subject: [PATCH 006/293] Readme for examples --- examples/USER/ees/README | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 examples/USER/ees/README diff --git a/examples/USER/ees/README b/examples/USER/ees/README new file mode 100644 index 0000000000..4eb40665a3 --- /dev/null +++ b/examples/USER/ees/README @@ -0,0 +1,13 @@ +Here one may find simple examples that show how to use "fix wall/ess" and "fix wall/region/ess" commands. + + +--in.fix_wall_region: + + This input file uses Data_region file to setup a system of three particles colliding with a + cubic region which its walls interact with particle with EES potential. To find out details + of how to set parameters of "fix wall/region/ees" see documentaion. + +--in.fix_wall + + This input file uses Data_wall to confine a ellipsoidal particle between two EES walls to + show how to use "fix wall/ees" command. For more details lookup LAMMPS's documentation. From 8f37285b056a5b200564dfabd8e8d2f767f82ec9 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Thu, 16 Mar 2017 21:12:10 +0900 Subject: [PATCH 007/293] UPLOAD examples --- examples/USER/ees/Data_region | 28 ++++++++++++++++++++++++++++ examples/USER/ees/Data_wall | 22 ++++++++++++++++++++++ examples/USER/ees/in.fix_wall | 25 +++++++++++++++++++++++++ examples/USER/ees/in.fix_wall_region | 27 +++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 examples/USER/ees/Data_region create mode 100644 examples/USER/ees/Data_wall create mode 100644 examples/USER/ees/in.fix_wall create mode 100644 examples/USER/ees/in.fix_wall_region diff --git a/examples/USER/ees/Data_region b/examples/USER/ees/Data_region new file mode 100644 index 0000000000..80eefeafe6 --- /dev/null +++ b/examples/USER/ees/Data_region @@ -0,0 +1,28 @@ + +3 atoms +1 atom types +3 ellipsoids +0 60 xlo xhi +0 60 zlo zhi +0 60 ylo yhi + +Atoms +atom-ID atom-type ellipsoidflag density x y z +1 1 1 1 5 30 30 +2 1 1 1 30 5 30 +3 1 1 1 30 30 5 + + +Ellipsoids +atom-ID shapex shapey shapez quatw quati quatj quatk +1 14 6 8 0.89453 0.44700 0 0 +2 14 6 8 0.25755 0 0.96626 0 +3 14 6 8 0.95009 0 0 0.31197 + + +Velocities + +1 1.3 0 0 1 0 5 +2 0 .2 0 .1 3 0 +3 0 0 .9 .5 5 1 + diff --git a/examples/USER/ees/Data_wall b/examples/USER/ees/Data_wall new file mode 100644 index 0000000000..27fa6c5990 --- /dev/null +++ b/examples/USER/ees/Data_wall @@ -0,0 +1,22 @@ + +1 atoms +1 atom types +1 ellipsoids +0 60 xlo xhi +0 60 zlo zhi +0 60 ylo yhi + +Atoms +atom-ID atom-type ellipsoidflag density x y z +1 1 1 1 30 30 30 + + +Ellipsoids +atom-ID shapex shapey shapez quatw quati quatj quatk +1 14 6 8 0.44700 0 0.89453 0 + + +Velocities + +1 0 0 1 1 3 5 + diff --git a/examples/USER/ees/in.fix_wall b/examples/USER/ees/in.fix_wall new file mode 100644 index 0000000000..94db4c3b15 --- /dev/null +++ b/examples/USER/ees/in.fix_wall @@ -0,0 +1,25 @@ + +units lj +atom_style ellipsoid +boundary p p f +read_data Data_wall +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0001 +#------------------------------------# + +fix EES_substrate all wall/ees zhi EDGE 10 1 10 zlo EDGE 10 1 10 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +fix NVT all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +dump 1 all custom 5000 dump1 id type x y z c_qw c_qi c_qj c_qk +run 2000000 + diff --git a/examples/USER/ees/in.fix_wall_region b/examples/USER/ees/in.fix_wall_region new file mode 100644 index 0000000000..d457deae44 --- /dev/null +++ b/examples/USER/ees/in.fix_wall_region @@ -0,0 +1,27 @@ + +units lj +atom_style ellipsoid +boundary p p p +read_data Data_region +#------------------------------------# +region the_wall block 20. 40. 20. 40. 20. 40. side out +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0001 +#------------------------------------# + +fix EES_block all wall/region/ees the_wall 10. 1. 20 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +fix NVT all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +dump 1 all custom 5000 dump1 id type x y z c_qw c_qi c_qj c_qk +run 2000000 + From 67d474df2a5d97e4905bcd61355229af33bd0e76 Mon Sep 17 00:00:00 2001 From: Abdo Date: Wed, 5 Jul 2017 14:39:37 +0900 Subject: [PATCH 008/293] deleteing USER-EES --- src/USER-EES/README | 10 - src/USER-EES/fix_wall_ees.cpp | 207 -------------- src/USER-EES/fix_wall_ees.h | 51 ---- src/USER-EES/fix_wall_region_ees.cpp | 405 --------------------------- src/USER-EES/fix_wall_region_ees.h | 94 ------- src/USER-EES/install.sh | 34 --- 6 files changed, 801 deletions(-) delete mode 100644 src/USER-EES/README delete mode 100644 src/USER-EES/fix_wall_ees.cpp delete mode 100644 src/USER-EES/fix_wall_ees.h delete mode 100644 src/USER-EES/fix_wall_region_ees.cpp delete mode 100644 src/USER-EES/fix_wall_region_ees.h delete mode 100644 src/USER-EES/install.sh diff --git a/src/USER-EES/README b/src/USER-EES/README deleted file mode 100644 index 220c7fa203..0000000000 --- a/src/USER-EES/README +++ /dev/null @@ -1,10 +0,0 @@ -This package implements the EES potential between ellipsoidal particles and a semi finite LJ wall introduced by Babadi and Ejtehadi. - -This potential has fixes in both "fix wall" style and "fix wall/region" style so can be used as a boundary of simulation box or on the sides of a region inside the simulation box. - -The ASPHERE package is required for using this fixes. - -For more details please refer to documentation of LAMMPS under "fix wall/ees" entry. -There are also some example of using this code in /examples/usr/EES. - -This implementation is done by Abdoreza Ershadinia at Sharif University of Technology--Tehran (a.ershdinia@physics.sahrif.edu). diff --git a/src/USER-EES/fix_wall_ees.cpp b/src/USER-EES/fix_wall_ees.cpp deleted file mode 100644 index 8ccadf274a..0000000000 --- a/src/USER-EES/fix_wall_ees.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/* ---------------------------------------------------------------------- - 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 "math.h" -#include "math_extra.h" -#include "fix_wall_ees.h" -#include "atom.h" -#include "atom_vec.h" -#include "atom_vec_ellipsoid.h" -#include "error.h" - -using namespace LAMMPS_NS; -using namespace FixConst; - -/* ---------------------------------------------------------------------- */ - -FixWallEES::FixWallEES(LAMMPS *lmp, int narg, char **arg) : - FixWall(lmp, narg, arg) {} - -/* ---------------------------------------------------------------------- */ - -void FixWallEES::precompute(int m) -{ - coeff1[m] = ( 2. / 4725. ) * epsilon[m] * pow(sigma[m],12.0); - coeff2[m] = ( 1. / 24. ) * epsilon[m] * pow(sigma[m],6.0); - - coeff3[m] = ( 2. / 315. ) * epsilon[m] * pow(sigma[m],12.0); - coeff4[m] = ( 1. / 3. ) * epsilon[m] * pow(sigma[m],6.0); - - coeff5[m] = ( 4. / 315. ) * epsilon[m] * pow(sigma[m],12.0); - coeff6[m] = ( 1. / 12. ) * epsilon[m] * pow(sigma[m],6.0); -} - -/* ---------------------------------------------------------------------- */ -void FixWallEES::init() -{ - avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - if (!avec) - error->all(FLERR,"Fix wall/ees requires atom style ellipsoid"); - - // check that all particles are finite-size ellipsoids - // no point particles allowed, spherical is OK - - int *ellipsoid = atom->ellipsoid; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) - if (mask[i] & groupbit) - if (ellipsoid[i] < 0) - error->one(FLERR,"Fix wall/ees requires extended particles"); - - FixWall::init(); -} - - -/* ---------------------------------------------------------------------- - interaction of all particles in group with a wall - m = index of wall coeffs - which = xlo,xhi,ylo,yhi,zlo,zhi - error if any particle is on or behind wall -------------------------------------------------------------------------- */ - -void FixWallEES::wall_particle(int m, int which, double coord) -{ - double delta; - - double **x = atom->x; - double **f = atom->f; - double **tor = atom->torque; - - - avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - AtomVecEllipsoid::Bonus *bonus = avec->bonus; - int *ellipsoid = atom->ellipsoid; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - - int dim = which / 2; - int side = which % 2; - if (side == 0) side = -1; - - int onflag = 0; - - for (int i = 0; i < nlocal; i++) - if (mask[i] & groupbit) { - - if (side < 0) - delta = x[i][dim] - coord; - else - delta = coord - x[i][dim]; - - if (delta >= cutoff[m]) - continue; - - double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; - double tempvec[3]= {0,0,0}; - double sigman = 0.0, sigman2 = 0.0; - double nhat[3] = {0,0,0}; - - nhat[dim]=-1*side; - nhat[(dim+1)%3] = 0 ; - nhat[(dim+2)%3] = 0 ; - - - double* shape = bonus[ellipsoid[i]].shape;; - MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); - MathExtra::transpose_matvec(A,nhat,tempvec); - for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; - for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; - sigman = sqrt(sigman2); - - if (delta <= sigman) { - onflag = 1; - continue; - } - - - double fwall = 0.0, twall = 0.0; - double delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; - double sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; - double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; - double hps = 0.0; - double hms = 0.0; - - double tempvec2[3]= {0,0,0}; - - double SAn[3] = {0,0,0}; - double that[3] = {0,0,0}; - - double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; - double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; - double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; - - - for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; - - sigman3 = sigman2 * sigman; - sigman4 = sigman2 * sigman2; - sigman5 = sigman4 * sigman; - sigman6 = sigman3 * sigman3; - - - delta2 = delta * delta; - delta3 = delta2 * delta; - delta4 = delta2 * delta2; - delta5 = delta3 * delta2; - delta6 = delta3 * delta3; - - hhss = delta2 - sigman2; - hhss2 = hhss * hhss; - hhss4 = hhss2 * hhss2; - hhss8 = hhss4 * hhss4; - hhss7 = hhss4 * hhss2 * hhss; - - hps = delta + sigman; - hms = delta - sigman; - - fwall = side*( - -1*coeff4[m]/hhss2 + - coeff3[m] * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 - ); - f[i][dim] -= fwall; - - ewall[0] += -1*coeff2[m] * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + - coeff1[m] * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; - - ewall[m+1] += fwall; - - twall = coeff6[m] * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + - coeff5[m] * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; - - - MathExtra::matvec(Lx,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[0] = MathExtra::dot3(SAn,tempvec2); - - MathExtra::matvec(Ly,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[1] = MathExtra::dot3(SAn,tempvec2); - - MathExtra::matvec(Lz,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; - that[2] = MathExtra::dot3(SAn,tempvec2); - - - for(int j = 0; j<3 ; j++) - tor[i][j] += twall * that[j]; - - } - - if (onflag) error->one(FLERR,"Particle on or inside fix wall surface"); -} diff --git a/src/USER-EES/fix_wall_ees.h b/src/USER-EES/fix_wall_ees.h deleted file mode 100644 index 17246c094f..0000000000 --- a/src/USER-EES/fix_wall_ees.h +++ /dev/null @@ -1,51 +0,0 @@ -/* -*- 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(wall/ees,FixWallEES) - -#else - -#ifndef LMP_FIX_WALL_EES_H -#define LMP_FIX_WALL_EES_H - -#include "fix_wall.h" - -namespace LAMMPS_NS { - -class FixWallEES : public FixWall { - public: - FixWallEES(class LAMMPS *, int, char **); - void precompute(int); - void init(); - void wall_particle(int, int, double); - - private: - double coeff1[6],coeff2[6],coeff3[6],coeff4[6],coeff5[6],coeff6[6]; - class AtomVecEllipsoid *avec; -}; - -} - -#endif -#endif - -/* ERROR/WARNING messages: - -E: Particle on or inside fix wall surface - -Particles must be "exterior" to the wall in order for energy/force to -be calculated. - -*/ diff --git a/src/USER-EES/fix_wall_region_ees.cpp b/src/USER-EES/fix_wall_region_ees.cpp deleted file mode 100644 index 20a5f74c15..0000000000 --- a/src/USER-EES/fix_wall_region_ees.cpp +++ /dev/null @@ -1,405 +0,0 @@ -/* -*- 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. -------------------------------------------------------------------------- */ -#include -#include "math.h" -#include "stdlib.h" -#include "string.h" -#include "fix_wall_region_ees.h" -#include "atom.h" -#include "atom_vec.h" -#include "atom_vec_ellipsoid.h" -#include "domain.h" -#include "region.h" -#include "force.h" -#include "lattice.h" -#include "update.h" -#include "output.h" -#include "respa.h" -#include "error.h" -#include "math_extra.h" - -using namespace LAMMPS_NS; -using namespace FixConst; - -enum{LJ93,LJ126,COLLOID,HARMONIC,EES};//me - -/* ---------------------------------------------------------------------- */ -/// USAGE: -/// fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff -/// -FixWallRegionEES::FixWallRegionEES(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) -{ - if (narg != 7) error->all(FLERR,"Illegal fix wall/region/ees command"); - scalar_flag = 1; - vector_flag = 1; - size_vector = 3; - global_freq = 1; - extscalar = 1; - extvector = 1; - - // parse args - - iregion = domain->find_region(arg[3]); - if (iregion == -1) - error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); - int n = strlen(arg[3]) + 1; - idregion = new char[n]; - strcpy(idregion,arg[3]); - - - - epsilon = force->numeric(FLERR,arg[4]); - sigma = force->numeric(FLERR,arg[5]); - cutoff = force->numeric(FLERR,arg[6]); - - if (cutoff <= 0.0) error->all(FLERR,"Fix wall/region/ees cutoff <= 0.0"); - - eflag = 0; - ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; -} - -/* ---------------------------------------------------------------------- */ - -FixWallRegionEES::~FixWallRegionEES() -{ - delete [] idregion; -} - -/* ---------------------------------------------------------------------- */ - -int FixWallRegionEES::setmask() -{ - int mask = 0; - mask |= POST_FORCE; - mask |= THERMO_ENERGY; - mask |= POST_FORCE_RESPA; - mask |= MIN_POST_FORCE; - return mask; -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::init() -{ - // set index and check validity of region - - iregion = domain->find_region(idregion); - if (iregion == -1) - error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); - - - avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - if (!avec) - error->all(FLERR,"Fix wall/region/ees requires atom style ellipsoid"); - - // check that all particles are finite-size ellipsoids - // no point particles allowed, spherical is OK - - int *ellipsoid = atom->ellipsoid; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) - if (mask[i] & groupbit) - if (ellipsoid[i] < 0) - error->one(FLERR,"Fix wall/region/ees requires extended particles"); - - - // setup coefficients for each style - - coeff1 = ( 2. / 4725. ) * epsilon * pow(sigma,12.0); - coeff2 = ( 1. / 24. ) * epsilon * pow(sigma,6.0); - coeff3 = ( 2. / 315. ) * epsilon * pow(sigma,12.0); - coeff4 = ( 1. / 3. ) * epsilon * pow(sigma,6.0); - coeff5 = ( 4. / 315. ) * epsilon * pow(sigma,12.0); - coeff6 = ( 1. / 12. ) * epsilon * pow(sigma,6.0); - offset = 0; - - - if (strstr(update->integrate_style,"respa")) - nlevels_respa = ((Respa *) update->integrate)->nlevels; -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::setup(int vflag) -{ - if (strstr(update->integrate_style,"verlet")) - post_force(vflag); - else { - ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); - post_force_respa(vflag,nlevels_respa-1,0); - ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); - } -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::min_setup(int vflag) -{ - post_force(vflag); -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::post_force(int vflag) -{ - //me - //sth is needed here, but I dont know what - //that is calculation of sn - - int i,m,n; - double rinv,fx,fy,fz,tooclose[3];//me - double sn;//me - - eflag = 0; - ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; - - double **x = atom->x; - double **f = atom->f; - double *radius = atom->radius; - - double **tor = atom->torque; //me - - //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");//me - AtomVecEllipsoid::Bonus *bonus = avec->bonus;//me - int *ellipsoid = atom->ellipsoid;//me - - int *mask = atom->mask; - int nlocal = atom->nlocal; - - Region *region = domain->regions[iregion]; - region->prematch(); - - int onflag = 0; - - // region->match() insures particle is in region or on surface, else error - // if returned contact dist r = 0, is on surface, also an error - // in COLLOID case, r <= radius is an error - - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) { - if (!region->match(x[i][0],x[i][1],x[i][2])) { - onflag = 1; - continue; - } - - double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; - double tempvec[3]= {0,0,0}; - double sn2 = 0.0; - double nhat[3] = {0,0,0}; - double* shape = bonus[ellipsoid[i]].shape;; - MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); - - for(int which = 0 ; which < 3; which ++){//me - nhat[which]=1; - nhat[(which+1)%3] = 0 ; - nhat[(which+2)%3] = 0 ; - sn2 = 0 ; - MathExtra::transpose_matvec(A,nhat,tempvec); - for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; - for(int k = 0; k<3 ; k++) sn2 += tempvec[k]*tempvec[k]; - sn = sqrt(sn2); - tooclose[which] = sn; - } - - - - n = region->surface(x[i][0],x[i][1],x[i][2],cutoff); - - for (m = 0; m < n; m++) { - - if(region->contact[m].delx != 0 && region->contact[m].r <= tooclose[0] ){ - onflag = 1; - continue; - - }else if (region->contact[m].dely != 0 && region->contact[m].r <= tooclose[1]){ - onflag = 1; - continue; - }else if (region->contact[m].delz !=0 && region->contact[m].r <= tooclose[2]){ - onflag = 1; - continue; - } - else rinv = 1.0/region->contact[m].r; - - ees(m,i);//me - - ewall[0] += eng; - fx = fwall * region->contact[m].delx * rinv; - fy = fwall * region->contact[m].dely * rinv; - fz = fwall * region->contact[m].delz * rinv; - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - ewall[1] -= fx; - ewall[2] -= fy; - ewall[3] -= fz; - - tor[i][0] += torque[0]; - tor[i][1] += torque[1]; - tor[i][2] += torque[2]; - - } - } - - if (onflag) error->one(FLERR,"Particle on or inside surface of region " - "used in fix wall/region/ees"); -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::post_force_respa(int vflag, int ilevel, int iloop) -{ - if (ilevel == nlevels_respa-1) post_force(vflag); -} - -/* ---------------------------------------------------------------------- */ - -void FixWallRegionEES::min_post_force(int vflag) -{ - post_force(vflag); -} - -/* ---------------------------------------------------------------------- - energy of wall interaction -------------------------------------------------------------------------- */ - -double FixWallRegionEES::compute_scalar() -{ - // only sum across procs one time - - if (eflag == 0) { - MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); - eflag = 1; - } - return ewall_all[0]; -} - -/* ---------------------------------------------------------------------- - components of force on wall -------------------------------------------------------------------------- */ - -double FixWallRegionEES::compute_vector(int n) -{ - // only sum across procs one time - - if (eflag == 0) { - MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); - eflag = 1; - } - return ewall_all[n+1]; -} - - - -//me -/* ---------------------------------------------------------------------- - EES interaction for ellipsoid particle with wall - compute eng and fwall and twall = magnitude of wall force and torque -------------------------------------------------------------------------- */ - -void FixWallRegionEES::ees(int m, int i) -{ - Region *region = domain->regions[iregion]; - region->prematch(); - - double delta = 0.0, delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; - double sigman = 0.0, sigman2 = 0.0 , sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; - double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; //h^2 - s_n^2 - double hps = 0.0; //h+s_n - double hms = 0.0; //h-s_n - double twall = 0.0; - double tempvec[3]={0,0,0}; - double tempvec2[3]= {0,0,0}; - - double SAn[3] = {0,0,0}; - double that[3] = {0,0,0}; - - double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; - double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; - double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; - - double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; - double nhat[3] = {0,0,0}; - - nhat[0] = region->contact[m].delx / region->contact[m].r; - nhat[1] = region->contact[m].dely / region->contact[m].r; - nhat[2] = region->contact[m].delz / region->contact[m].r; - - //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - AtomVecEllipsoid::Bonus *bonus = avec->bonus; - int *ellipsoid = atom->ellipsoid;//me - - double* shape = bonus[ellipsoid[i]].shape;; - MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); - - MathExtra::transpose_matvec(A,nhat,tempvec); - for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; - for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; - for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; - - - sigman = sqrt(sigman2); - delta = fabs(region->contact[m].r); - - sigman3 = sigman2 * sigman; - sigman4 = sigman2 * sigman2; - sigman5 = sigman4 * sigman; - sigman6 = sigman3 * sigman3; - - delta2 = delta * delta; - delta3 = delta2 * delta; - delta4 = delta2 * delta2; - delta5 = delta3 * delta2; - delta6 = delta3 * delta3; - - hhss = delta2 - sigman2; - hhss2 = hhss * hhss; - hhss4 = hhss2 * hhss2; - hhss8 = hhss4 * hhss4; - hhss7 = hhss4 * hhss2 * hhss; - - hps = delta + sigman; - hms = delta - sigman; - - fwall = -1*coeff4/hhss2 + - coeff3 * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 - ; - - eng = -1*coeff2 * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + - coeff1 * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; - - twall = coeff6 * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + - coeff5 * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; - - MathExtra::matvec(Lx,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[0] = MathExtra::dot3(SAn,tempvec2); - - MathExtra::matvec(Ly,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[1] = MathExtra::dot3(SAn,tempvec2); - - MathExtra::matvec(Lz,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; - that[2] = MathExtra::dot3(SAn,tempvec2); - - for(int j = 0; j<3 ; j++) - torque[j] = twall * that[j]; - -} diff --git a/src/USER-EES/fix_wall_region_ees.h b/src/USER-EES/fix_wall_region_ees.h deleted file mode 100644 index 59679a0b41..0000000000 --- a/src/USER-EES/fix_wall_region_ees.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- 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(wall/region/ees,FixWallRegionEES) - -#else - -#ifndef LMP_FIX_WALL_REGION_EES_H -#define LMP_FIX_WALL_REGION_EES_H - -#include "fix.h" - - -namespace LAMMPS_NS { - -class FixWallRegionEES : public Fix { - public: - FixWallRegionEES(class LAMMPS *, int, char **); - ~FixWallRegionEES(); - int setmask(); - void init(); - void setup(int); - void min_setup(int); - void post_force(int); - void post_force_respa(int, int, int); - void min_post_force(int); - double compute_scalar(); - double compute_vector(int); - - private: - class AtomVecEllipsoid *avec;//me - - int iregion; - double epsilon,sigma,cutoff; - int eflag; - double ewall[4],ewall_all[4]; - int nlevels_respa; - char *idregion; - - double coeff1,coeff2,coeff3,coeff4,offset; - double coeff5, coeff6;//me - double eng,fwall; - double torque[3];//me - - void ees(int, int);//me -}; - -} - -#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. - -E: Region ID for fix wall/region/ees does not exist - -Self-explanatory. - -E: Fix wall/region/ees cutoff <= 0.0 - -Self-explanatory. - -E: Fix wall/region/ees colloid requires atom style sphere - -Self-explanatory. - -E: Fix wall/region/ees colloid requires extended particles - -One of the particles has radius 0.0. - -E: Particle on or inside surface of region used in fix wall/region - -Particles must be "exterior" to the region surface in order for -energy/force to be calculated. - -*/ diff --git a/src/USER-EES/install.sh b/src/USER-EES/install.sh deleted file mode 100644 index 6163d56ad4..0000000000 --- a/src/USER-EES/install.sh +++ /dev/null @@ -1,34 +0,0 @@ -# Install/unInstall package files in LAMMPS -# mode = 0/1/2 for uninstall/install/update - -mode=$1 - -# enforce using portable C locale -LC_ALL=C -export LC_ALL - -# arg1 = file, arg2 = file it depends on - -action () { - if (test $mode = 0) then - rm -f ../$1 - elif (! cmp -s $1 ../$1) then - if (test -z "$2" || test -e ../$2) then - cp $1 .. - if (test $mode = 2) then - echo " updating src/$1" - fi - fi - elif (test -n "$2") then - if (test ! -e ../$2) then - rm -f ../$1 - fi - fi -} - -# all package files with dependencies - -action fix_wall_ees.cpp -action fix_wall_ees.h -action fix_wall_region_ees.cpp -action fix_wall_region_ees.h From d3b8e688c97257aa929a60e2e2c64e9f66bc4684 Mon Sep 17 00:00:00 2001 From: Abdo Date: Wed, 5 Jul 2017 14:57:43 +0900 Subject: [PATCH 009/293] Files Added to MISC --- src/MISC/fix_wall_ees.cpp | 207 ++++++++++++++++ src/MISC/fix_wall_ees.h | 51 ++++ src/MISC/fix_wall_region_ees.cpp | 405 +++++++++++++++++++++++++++++++ src/MISC/fix_wall_region_ees.h | 94 +++++++ 4 files changed, 757 insertions(+) create mode 100644 src/MISC/fix_wall_ees.cpp create mode 100644 src/MISC/fix_wall_ees.h create mode 100644 src/MISC/fix_wall_region_ees.cpp create mode 100644 src/MISC/fix_wall_region_ees.h diff --git a/src/MISC/fix_wall_ees.cpp b/src/MISC/fix_wall_ees.cpp new file mode 100644 index 0000000000..8ccadf274a --- /dev/null +++ b/src/MISC/fix_wall_ees.cpp @@ -0,0 +1,207 @@ +/* ---------------------------------------------------------------------- + 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 "math.h" +#include "math_extra.h" +#include "fix_wall_ees.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixWallEES::FixWallEES(LAMMPS *lmp, int narg, char **arg) : + FixWall(lmp, narg, arg) {} + +/* ---------------------------------------------------------------------- */ + +void FixWallEES::precompute(int m) +{ + coeff1[m] = ( 2. / 4725. ) * epsilon[m] * pow(sigma[m],12.0); + coeff2[m] = ( 1. / 24. ) * epsilon[m] * pow(sigma[m],6.0); + + coeff3[m] = ( 2. / 315. ) * epsilon[m] * pow(sigma[m],12.0); + coeff4[m] = ( 1. / 3. ) * epsilon[m] * pow(sigma[m],6.0); + + coeff5[m] = ( 4. / 315. ) * epsilon[m] * pow(sigma[m],12.0); + coeff6[m] = ( 1. / 12. ) * epsilon[m] * pow(sigma[m],6.0); +} + +/* ---------------------------------------------------------------------- */ +void FixWallEES::init() +{ + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + if (!avec) + error->all(FLERR,"Fix wall/ees requires atom style ellipsoid"); + + // check that all particles are finite-size ellipsoids + // no point particles allowed, spherical is OK + + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + if (ellipsoid[i] < 0) + error->one(FLERR,"Fix wall/ees requires extended particles"); + + FixWall::init(); +} + + +/* ---------------------------------------------------------------------- + interaction of all particles in group with a wall + m = index of wall coeffs + which = xlo,xhi,ylo,yhi,zlo,zhi + error if any particle is on or behind wall +------------------------------------------------------------------------- */ + +void FixWallEES::wall_particle(int m, int which, double coord) +{ + double delta; + + double **x = atom->x; + double **f = atom->f; + double **tor = atom->torque; + + + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + + int dim = which / 2; + int side = which % 2; + if (side == 0) side = -1; + + int onflag = 0; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + + if (side < 0) + delta = x[i][dim] - coord; + else + delta = coord - x[i][dim]; + + if (delta >= cutoff[m]) + continue; + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double sigman = 0.0, sigman2 = 0.0; + double nhat[3] = {0,0,0}; + + nhat[dim]=-1*side; + nhat[(dim+1)%3] = 0 ; + nhat[(dim+2)%3] = 0 ; + + + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; + sigman = sqrt(sigman2); + + if (delta <= sigman) { + onflag = 1; + continue; + } + + + double fwall = 0.0, twall = 0.0; + double delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; + double sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; + double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; + double hps = 0.0; + double hms = 0.0; + + double tempvec2[3]= {0,0,0}; + + double SAn[3] = {0,0,0}; + double that[3] = {0,0,0}; + + double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; + double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; + double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; + + + for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + + sigman3 = sigman2 * sigman; + sigman4 = sigman2 * sigman2; + sigman5 = sigman4 * sigman; + sigman6 = sigman3 * sigman3; + + + delta2 = delta * delta; + delta3 = delta2 * delta; + delta4 = delta2 * delta2; + delta5 = delta3 * delta2; + delta6 = delta3 * delta3; + + hhss = delta2 - sigman2; + hhss2 = hhss * hhss; + hhss4 = hhss2 * hhss2; + hhss8 = hhss4 * hhss4; + hhss7 = hhss4 * hhss2 * hhss; + + hps = delta + sigman; + hms = delta - sigman; + + fwall = side*( + -1*coeff4[m]/hhss2 + + coeff3[m] * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 + ); + f[i][dim] -= fwall; + + ewall[0] += -1*coeff2[m] * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + + coeff1[m] * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + + ewall[m+1] += fwall; + + twall = coeff6[m] * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + + coeff5[m] * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + + + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); + + + for(int j = 0; j<3 ; j++) + tor[i][j] += twall * that[j]; + + } + + if (onflag) error->one(FLERR,"Particle on or inside fix wall surface"); +} diff --git a/src/MISC/fix_wall_ees.h b/src/MISC/fix_wall_ees.h new file mode 100644 index 0000000000..17246c094f --- /dev/null +++ b/src/MISC/fix_wall_ees.h @@ -0,0 +1,51 @@ +/* -*- 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(wall/ees,FixWallEES) + +#else + +#ifndef LMP_FIX_WALL_EES_H +#define LMP_FIX_WALL_EES_H + +#include "fix_wall.h" + +namespace LAMMPS_NS { + +class FixWallEES : public FixWall { + public: + FixWallEES(class LAMMPS *, int, char **); + void precompute(int); + void init(); + void wall_particle(int, int, double); + + private: + double coeff1[6],coeff2[6],coeff3[6],coeff4[6],coeff5[6],coeff6[6]; + class AtomVecEllipsoid *avec; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +E: Particle on or inside fix wall surface + +Particles must be "exterior" to the wall in order for energy/force to +be calculated. + +*/ diff --git a/src/MISC/fix_wall_region_ees.cpp b/src/MISC/fix_wall_region_ees.cpp new file mode 100644 index 0000000000..20a5f74c15 --- /dev/null +++ b/src/MISC/fix_wall_region_ees.cpp @@ -0,0 +1,405 @@ +/* -*- 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. +------------------------------------------------------------------------- */ +#include +#include "math.h" +#include "stdlib.h" +#include "string.h" +#include "fix_wall_region_ees.h" +#include "atom.h" +#include "atom_vec.h" +#include "atom_vec_ellipsoid.h" +#include "domain.h" +#include "region.h" +#include "force.h" +#include "lattice.h" +#include "update.h" +#include "output.h" +#include "respa.h" +#include "error.h" +#include "math_extra.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +enum{LJ93,LJ126,COLLOID,HARMONIC,EES};//me + +/* ---------------------------------------------------------------------- */ +/// USAGE: +/// fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff +/// +FixWallRegionEES::FixWallRegionEES(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + if (narg != 7) error->all(FLERR,"Illegal fix wall/region/ees command"); + scalar_flag = 1; + vector_flag = 1; + size_vector = 3; + global_freq = 1; + extscalar = 1; + extvector = 1; + + // parse args + + iregion = domain->find_region(arg[3]); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + int n = strlen(arg[3]) + 1; + idregion = new char[n]; + strcpy(idregion,arg[3]); + + + + epsilon = force->numeric(FLERR,arg[4]); + sigma = force->numeric(FLERR,arg[5]); + cutoff = force->numeric(FLERR,arg[6]); + + if (cutoff <= 0.0) error->all(FLERR,"Fix wall/region/ees cutoff <= 0.0"); + + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; +} + +/* ---------------------------------------------------------------------- */ + +FixWallRegionEES::~FixWallRegionEES() +{ + delete [] idregion; +} + +/* ---------------------------------------------------------------------- */ + +int FixWallRegionEES::setmask() +{ + int mask = 0; + mask |= POST_FORCE; + mask |= THERMO_ENERGY; + mask |= POST_FORCE_RESPA; + mask |= MIN_POST_FORCE; + return mask; +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::init() +{ + // set index and check validity of region + + iregion = domain->find_region(idregion); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + + + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + if (!avec) + error->all(FLERR,"Fix wall/region/ees requires atom style ellipsoid"); + + // check that all particles are finite-size ellipsoids + // no point particles allowed, spherical is OK + + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + if (ellipsoid[i] < 0) + error->one(FLERR,"Fix wall/region/ees requires extended particles"); + + + // setup coefficients for each style + + coeff1 = ( 2. / 4725. ) * epsilon * pow(sigma,12.0); + coeff2 = ( 1. / 24. ) * epsilon * pow(sigma,6.0); + coeff3 = ( 2. / 315. ) * epsilon * pow(sigma,12.0); + coeff4 = ( 1. / 3. ) * epsilon * pow(sigma,6.0); + coeff5 = ( 4. / 315. ) * epsilon * pow(sigma,12.0); + coeff6 = ( 1. / 12. ) * epsilon * pow(sigma,6.0); + offset = 0; + + + if (strstr(update->integrate_style,"respa")) + nlevels_respa = ((Respa *) update->integrate)->nlevels; +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::setup(int vflag) +{ + if (strstr(update->integrate_style,"verlet")) + post_force(vflag); + else { + ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); + post_force_respa(vflag,nlevels_respa-1,0); + ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); + } +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::min_setup(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::post_force(int vflag) +{ + //me + //sth is needed here, but I dont know what + //that is calculation of sn + + int i,m,n; + double rinv,fx,fy,fz,tooclose[3];//me + double sn;//me + + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; + + double **x = atom->x; + double **f = atom->f; + double *radius = atom->radius; + + double **tor = atom->torque; //me + + //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");//me + AtomVecEllipsoid::Bonus *bonus = avec->bonus;//me + int *ellipsoid = atom->ellipsoid;//me + + int *mask = atom->mask; + int nlocal = atom->nlocal; + + Region *region = domain->regions[iregion]; + region->prematch(); + + int onflag = 0; + + // region->match() insures particle is in region or on surface, else error + // if returned contact dist r = 0, is on surface, also an error + // in COLLOID case, r <= radius is an error + + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + if (!region->match(x[i][0],x[i][1],x[i][2])) { + onflag = 1; + continue; + } + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double sn2 = 0.0; + double nhat[3] = {0,0,0}; + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + + for(int which = 0 ; which < 3; which ++){//me + nhat[which]=1; + nhat[(which+1)%3] = 0 ; + nhat[(which+2)%3] = 0 ; + sn2 = 0 ; + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sn2 += tempvec[k]*tempvec[k]; + sn = sqrt(sn2); + tooclose[which] = sn; + } + + + + n = region->surface(x[i][0],x[i][1],x[i][2],cutoff); + + for (m = 0; m < n; m++) { + + if(region->contact[m].delx != 0 && region->contact[m].r <= tooclose[0] ){ + onflag = 1; + continue; + + }else if (region->contact[m].dely != 0 && region->contact[m].r <= tooclose[1]){ + onflag = 1; + continue; + }else if (region->contact[m].delz !=0 && region->contact[m].r <= tooclose[2]){ + onflag = 1; + continue; + } + else rinv = 1.0/region->contact[m].r; + + ees(m,i);//me + + ewall[0] += eng; + fx = fwall * region->contact[m].delx * rinv; + fy = fwall * region->contact[m].dely * rinv; + fz = fwall * region->contact[m].delz * rinv; + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; + + ewall[1] -= fx; + ewall[2] -= fy; + ewall[3] -= fz; + + tor[i][0] += torque[0]; + tor[i][1] += torque[1]; + tor[i][2] += torque[2]; + + } + } + + if (onflag) error->one(FLERR,"Particle on or inside surface of region " + "used in fix wall/region/ees"); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::post_force_respa(int vflag, int ilevel, int iloop) +{ + if (ilevel == nlevels_respa-1) post_force(vflag); +} + +/* ---------------------------------------------------------------------- */ + +void FixWallRegionEES::min_post_force(int vflag) +{ + post_force(vflag); +} + +/* ---------------------------------------------------------------------- + energy of wall interaction +------------------------------------------------------------------------- */ + +double FixWallRegionEES::compute_scalar() +{ + // only sum across procs one time + + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[0]; +} + +/* ---------------------------------------------------------------------- + components of force on wall +------------------------------------------------------------------------- */ + +double FixWallRegionEES::compute_vector(int n) +{ + // only sum across procs one time + + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[n+1]; +} + + + +//me +/* ---------------------------------------------------------------------- + EES interaction for ellipsoid particle with wall + compute eng and fwall and twall = magnitude of wall force and torque +------------------------------------------------------------------------- */ + +void FixWallRegionEES::ees(int m, int i) +{ + Region *region = domain->regions[iregion]; + region->prematch(); + + double delta = 0.0, delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; + double sigman = 0.0, sigman2 = 0.0 , sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; + double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; //h^2 - s_n^2 + double hps = 0.0; //h+s_n + double hms = 0.0; //h-s_n + double twall = 0.0; + double tempvec[3]={0,0,0}; + double tempvec2[3]= {0,0,0}; + + double SAn[3] = {0,0,0}; + double that[3] = {0,0,0}; + + double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; + double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; + double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; + + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double nhat[3] = {0,0,0}; + + nhat[0] = region->contact[m].delx / region->contact[m].r; + nhat[1] = region->contact[m].dely / region->contact[m].r; + nhat[2] = region->contact[m].delz / region->contact[m].r; + + //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid;//me + + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; + for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + + + sigman = sqrt(sigman2); + delta = fabs(region->contact[m].r); + + sigman3 = sigman2 * sigman; + sigman4 = sigman2 * sigman2; + sigman5 = sigman4 * sigman; + sigman6 = sigman3 * sigman3; + + delta2 = delta * delta; + delta3 = delta2 * delta; + delta4 = delta2 * delta2; + delta5 = delta3 * delta2; + delta6 = delta3 * delta3; + + hhss = delta2 - sigman2; + hhss2 = hhss * hhss; + hhss4 = hhss2 * hhss2; + hhss8 = hhss4 * hhss4; + hhss7 = hhss4 * hhss2 * hhss; + + hps = delta + sigman; + hms = delta - sigman; + + fwall = -1*coeff4/hhss2 + + coeff3 * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 + ; + + eng = -1*coeff2 * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + + coeff1 * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + + twall = coeff6 * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + + coeff5 * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); + + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); + + for(int j = 0; j<3 ; j++) + torque[j] = twall * that[j]; + +} diff --git a/src/MISC/fix_wall_region_ees.h b/src/MISC/fix_wall_region_ees.h new file mode 100644 index 0000000000..59679a0b41 --- /dev/null +++ b/src/MISC/fix_wall_region_ees.h @@ -0,0 +1,94 @@ +/* -*- 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(wall/region/ees,FixWallRegionEES) + +#else + +#ifndef LMP_FIX_WALL_REGION_EES_H +#define LMP_FIX_WALL_REGION_EES_H + +#include "fix.h" + + +namespace LAMMPS_NS { + +class FixWallRegionEES : public Fix { + public: + FixWallRegionEES(class LAMMPS *, int, char **); + ~FixWallRegionEES(); + int setmask(); + void init(); + void setup(int); + void min_setup(int); + void post_force(int); + void post_force_respa(int, int, int); + void min_post_force(int); + double compute_scalar(); + double compute_vector(int); + + private: + class AtomVecEllipsoid *avec;//me + + int iregion; + double epsilon,sigma,cutoff; + int eflag; + double ewall[4],ewall_all[4]; + int nlevels_respa; + char *idregion; + + double coeff1,coeff2,coeff3,coeff4,offset; + double coeff5, coeff6;//me + double eng,fwall; + double torque[3];//me + + void ees(int, int);//me +}; + +} + +#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. + +E: Region ID for fix wall/region/ees does not exist + +Self-explanatory. + +E: Fix wall/region/ees cutoff <= 0.0 + +Self-explanatory. + +E: Fix wall/region/ees colloid requires atom style sphere + +Self-explanatory. + +E: Fix wall/region/ees colloid requires extended particles + +One of the particles has radius 0.0. + +E: Particle on or inside surface of region used in fix wall/region + +Particles must be "exterior" to the region surface in order for +energy/force to be calculated. + +*/ From 5eb5391b20c79b3bf8dcdd9e061bd4f827c22d38 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Wed, 5 Jul 2017 15:06:34 +0900 Subject: [PATCH 010/293] Add reference to example --- doc/src/fix_wall_ees.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt index 54511ffba7..075f62efaf 100644 --- a/doc/src/fix_wall_ees.txt +++ b/doc/src/fix_wall_ees.txt @@ -66,7 +66,7 @@ particle and wall no longer interact. Also,  sigma_n is the distance between c :c,image(JPG/fix_wall_ees_image.jpg)   -Details of using this command and specifications are the same as fix/wall command.  +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 effective Hamaker constant with energy units for the strength of the From e0521f27b42de12bcde38d0e339b9a5a2d983346 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Wed, 5 Jul 2017 15:08:07 +0900 Subject: [PATCH 011/293] Added reference to example directory. --- doc/src/fix_wall_region_ees.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt index efb417add1..aafde5eb69 100644 --- a/doc/src/fix_wall_region_ees.txt +++ b/doc/src/fix_wall_region_ees.txt @@ -30,6 +30,7 @@ as a bounding wall which interacts with nearby ellipsoidal particles according t the EES potential introduced "fix wall/ees"_fix_wall_ees.html. Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. +One may also find and exapmle of using this code in USER/ees/ under examples/ directory. [Restrictions:] none From 769870cfc9579d4946d8836077b93d54d69f499b Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Thu, 29 Jun 2017 15:50:54 +0200 Subject: [PATCH 012/293] Proper spline coefficient calculation for AIREBO --- src/MANYBODY/pair_airebo.cpp | 326 +++++++++++++++++++++++++++++++++++ src/MANYBODY/pair_airebo.h | 6 + 2 files changed, 332 insertions(+) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 0ca80c6b76..b8ef4db48c 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -4066,6 +4066,276 @@ double PairAIREBO::Sptricubic(double x, double y, double z, return f; } +/* ---------------------------------------------------------------------- + spline coefficient matrix python script +------------------------------------------------------------------------- + +import numpy as np +import numpy.linalg as lin + +# Generate all the derivatives that are spline conditions +# Ordered such that df / dx_i / d_xj i < j. +# Gives the derivatives at which the spline's values are prescribed. +def generate_derivs(n): + def generate_derivs_order(n, m): + if m == 0: + return [tuple()] + if m == 1: + return [tuple([i]) for i in range(n)] + rec = generate_derivs_order(n, m - 1) + return [tuple([i]+list(j)) for i in range(n) for j in rec if j[0] > i] + ret = [] + m = 0 + while m <= n: + ret += generate_derivs_order(n, m) + m += 1 + return ret + +# Generate all the points in an n-dimensional unit cube. +# Gives the points at which the spline's values are prescribed. +def generate_points(n): + if n == 1: + return [(0,), (1,)] + rec = generate_points(n - 1) + return [tuple([j]+list(i)) for j in range(2) for i in rec] + +# Generate all the coefficients in the order later expected. +def generate_coeffs(n): + if n == 1: + return [tuple([i]) for i in range(4)] # cubic + rec = generate_coeffs(n-1) + return [tuple([i]+list(j)) for i in range(4) for j in rec] + +# Evaluate the `deriv`'s derivative at `point` symbolically +# with respect to the coefficients `coeffs`. +def eval_at(n, coeffs, deriv, point): + def eval_single(order, value, the_deriv): + if the_deriv: + if order == 0: + return 0 + if order == 1: + return 1 + return order * value + else: + if order == 0: + return 1 + else: + return value + result = {} + for c in coeffs: + result[c] = 1 + for i in range(n): + result[c] *= eval_single(c[i], point[i], i in deriv) + return result + +# Build the matrix transforming prescribed values to coefficients. +def get_matrix(n): + coeffs = generate_coeffs(n) + points = generate_points(n) + derivs = generate_derivs(n) + assert(len(coeffs) == len(points)*len(derivs)) + i = 0 + A = np.zeros((len(coeffs), len(points)*len(derivs))) + for d in derivs: + for p in points: + coeff = eval_at(n, coeffs, d, p) + for j, c in enumerate(coeffs): + A[i, j] = coeff[c] + i += 1 + return lin.inv(A) + +# Output the first k values with padding n from A. +def output_matrix(n, k, A): + print('\n'.join([''.join([("%{}d,".format(n+1)) % i for i in j[:k]]) for j in A])) + +*/ + +/* ---------------------------------------------------------------------- + tricubic spline coefficient calculation +------------------------------------------------------------------------- */ + +void PairAIREBO::Sptricubic_patch_adjust(double * dl, double wid, double lo, + char dir) { + int rowOuterL = 16, rowInnerL = 1, colL; + if (dir == 'R') { + rowOuterL = 4; + colL = 16; + } else if (dir == 'M') { + colL = 4; + } else if (dir == 'L') { + rowInnerL = 4; + colL = 1; + } + double binomial[5] = {1, 1, 2, 6}; + for (int rowOuter = 0; rowOuter < 4; rowOuter++) { + for (int rowInner = 0; rowInner < 4; rowInner++) { + for (int col = 0; col < 4; col++) { + double acc = 0; + for (int k = col; k < 4; k++) { + acc += dl[rowOuterL * rowOuter + rowInnerL * rowInner + colL * k] + * pow(wid, -k) * pow(-lo, k - col) * binomial[k] / binomial[col] + / binomial[k - col]; + } + dl[rowOuterL * rowOuter + rowInnerL * rowInner + colL * col] = acc; + } + } + } +} + +void PairAIREBO::Sptricubic_patch_coeffs( + double xmin, double xmax, double ymin, double ymax, double zmin, double zmax, + double * y, double * y1, double * y2, double * y3, double * dl +) { + const double C_inv[64][32] = { + // output_matrix(2, 8*4, get_matrix(3)) + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, -1, 0, 0, 0, 0, 0, 0, + 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, + 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, -6, 3, -3, 0, 0, 0, 0, 6, 3, -6, -3, 0, 0, 0, 0, + -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, 4, -2, 2, 0, 0, 0, 0, -3, -3, 3, 3, 0, 0, 0, 0, + 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, + -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, -3, 3, 0, 0, 0, 0, -4, -2, 4, 2, 0, 0, 0, 0, + 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 2, -2, 0, 0, 0, 0, 2, 2, -2, -2, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -3, 0, 0, 0, 3, 0, 0, 0, -2, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, + 9, -9, 0, 0, -9, 9, 0, 0, 6, -6, 0, 0, 3, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 3, 0, 0, -6, -3, 0, 0, + -6, 6, 0, 0, 6, -6, 0, 0, -4, 4, 0, 0, -2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, -3, 0, 0, 3, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, -9, 0, 0, -9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 9, 0, -9, 0, -9, 0, 9, 0, 6, 0, -6, 0, 3, 0, -3, 0, 6, 0, 3, 0, -6, 0, -3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, -9, 0, -9, 0, 9, 0, + -27, 27, 27,-27, 27,-27,-27, 27,-18, 18, 18,-18, -9, 9, 9, -9,-18, 18, -9, 9, 18,-18, 9, -9,-18, -9, 18, 9, 18, 9,-18, -9, + 18,-18,-18, 18,-18, 18, 18,-18, 12,-12,-12, 12, 6, -6, -6, 6, 12,-12, 6, -6,-12, 12, -6, 6, 9, 9, -9, -9, -9, -9, 9, 9, + -6, 0, 6, 0, 6, 0, -6, 0, -4, 0, 4, 0, -2, 0, 2, 0, -3, 0, -3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, + 18,-18,-18, 18,-18, 18, 18,-18, 12,-12,-12, 12, 6, -6, -6, 6, 9, -9, 9, -9, -9, 9, -9, 9, 12, 6,-12, -6,-12, -6, 12, 6, + -12, 12, 12,-12, 12,-12,-12, 12, -8, 8, 8, -8, -4, 4, 4, -4, -6, 6, -6, 6, 6, -6, 6, -6, -6, -6, 6, 6, 6, 6, -6, -6, + 2, 0, 0, 0, -2, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, + -6, 6, 0, 0, 6, -6, 0, 0, -3, 3, 0, 0, -3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -2, 0, 0, 4, 2, 0, 0, + 4, -4, 0, 0, -4, 4, 0, 0, 2, -2, 0, 0, 2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, -2, -2, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 6, 0, 0, 6, -6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4, 0, 0, -4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + -6, 0, 6, 0, 6, 0, -6, 0, -3, 0, 3, 0, -3, 0, 3, 0, -4, 0, -2, 0, 4, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -6, 0, 6, 0, 6, 0, -6, 0, + 18,-18,-18, 18,-18, 18, 18,-18, 9, -9, -9, 9, 9, -9, -9, 9, 12,-12, 6, -6,-12, 12, -6, 6, 12, 6,-12, -6,-12, -6, 12, 6, + -12, 12, 12,-12, 12,-12,-12, 12, -6, 6, 6, -6, -6, 6, 6, -6, -8, 8, -4, 4, 8, -8, 4, -4, -6, -6, 6, 6, 6, 6, -6, -6, + 4, 0, -4, 0, -4, 0, 4, 0, 2, 0, -2, 0, 2, 0, -2, 0, 2, 0, 2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, -4, 0, -4, 0, 4, 0, + -12, 12, 12,-12, 12,-12,-12, 12, -6, 6, 6, -6, -6, 6, 6, -6, -6, 6, -6, 6, 6, -6, 6, -6, -8, -4, 8, 4, 8, 4, -8, -4, + 8, -8, -8, 8, -8, 8, 8, -8, 4, -4, -4, 4, 4, -4, -4, 4, 4, -4, 4, -4, -4, 4, -4, 4, 4, 4, -4, -4, -4, -4, 4, 4, + }; + double dx = xmax - xmin; + double dy = ymax - ymin; + double dz = zmax - zmin; + double x[32]; + for (int i = 0; i < 8; i++) { + x[i+0*8] = y[i]; + x[i+1*8] = y1[i] * dx; + x[i+2*8] = y2[i] * dy; + x[i+3*8] = y3[i] * dz; + } + for (int i = 0; i < 64; i++) { + dl[i] = 0; + for (int k = 0; k < 32; k++) { + dl[i] += x[k] * C_inv[i][k]; + } + } + Sptricubic_patch_adjust(dl, dx, xmin, 'R'); + Sptricubic_patch_adjust(dl, dy, ymin, 'M'); + Sptricubic_patch_adjust(dl, dz, zmin, 'L'); +} + +/* ---------------------------------------------------------------------- + bicubic spline coefficient calculation +------------------------------------------------------------------------- */ + +void PairAIREBO::Spbicubic_patch_adjust(double * dl, double wid, double lo, + char dir) { + int rowL = dir == 'R' ? 1 : 4; + int colL = dir == 'L' ? 1 : 4; + double binomial[5] = {1, 1, 2, 6}; + for (int row = 0; row < 4; row++) { + for (int col = 0; col < 4; col++) { + double acc = 0; + for (int k = col; k < 4; k++) { + acc += dl[rowL * row + colL * k] * pow(wid, -k) * pow(-lo, k - col) + * binomial[k] / binomial[col] / binomial[k - col]; + } + dl[rowL * row + colL * col] = acc; + } + } +} + +void PairAIREBO::Spbicubic_patch_coeffs( + double xmin, double xmax, double ymin, double ymax, double * y, + double * y1, double * y2, double * dl +) { + const double C_inv[16][12] = { + // output_matrix(1, 4*3, get_matrix(2)) + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, + -3, 3, 0, 0, 0, 0, 0, 0,-2,-1, 0, 0, + 2,-2, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, + 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0,-3, 3, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 2,-2, 0, 0, 0, 0, 0, 0, + -3, 0, 3, 0,-2, 0,-1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0,-3, 0, 3, 0, + 9,-9,-9, 9, 6,-6, 3,-3, 6, 3,-6,-3, + -6, 6, 6,-6,-4, 4,-2, 2,-3,-3, 3, 3, + 2, 0,-2, 0, 1, 0, 1, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,-2, 0, + -6, 6, 6,-6,-3, 3,-3, 3,-4,-2, 4, 2, + 4,-4,-4, 4, 2,-2, 2,-2, 2, 2,-2,-2, + }; + double dx = xmax - xmin; + double dy = ymax - ymin; + double x[12]; + for (int i = 0; i < 4; i++) { + x[i+0*4] = y[i]; + x[i+1*4] = y1[i] * dx; + x[i+2*4] = y2[i] * dy; + } + for (int i = 0; i < 16; i++) { + dl[i] = 0; + for (int k = 0; k < 12; k++) { + dl[i] += x[k] * C_inv[i][k]; + } + } + Spbicubic_patch_adjust(dl, dx, xmin, 'R'); + Spbicubic_patch_adjust(dl, dy, ymin, 'L'); +} + /* ---------------------------------------------------------------------- initialize spline knot values ------------------------------------------------------------------------- */ @@ -4107,6 +4377,22 @@ void PairAIREBO::spline_init() PCHf[2][1] = -0.300529172; PCHf[3][0] = -0.307584705; + for (int nH = 0; nH < 4; nH++) { + for (int nC = 0; nC < 4; nC++) { + double y[4] = {0}, y1[4] = {0}, y2[4] = {0}; + y[0] = PCCf[nC][nH]; + y[1] = PCCf[nC][nH+1]; + y[2] = PCCf[nC+1][nH]; + y[3] = PCCf[nC+1][nH+1]; + Spbicubic_patch_coeffs(nC, nC+1, nH, nH+1, y, y1, y2, &pCC[nC][nH][0]); + y[0] = PCHf[nC][nH]; + y[1] = PCHf[nC][nH+1]; + y[2] = PCHf[nC+1][nH]; + y[3] = PCHf[nC+1][nH+1]; + Spbicubic_patch_coeffs(nC, nC+1, nH, nH+1, y, y1, y2, &pCH[nC][nH][0]); + } + } + for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { for (k = 0; k < 10; k++) { @@ -4271,6 +4557,46 @@ void PairAIREBO::spline_init() Tf[2][2][1] = -0.035140; for (i = 2; i < 10; i++) Tf[2][2][i] = -0.0040480; + + for (int nH = 0; nH < 4; nH++) { + for (int nC = 0; nC < 4; nC++) { + // Note: Spline knot values exist up to "10", but are never used because + // they are clamped down to 9. + for (int nConj = 0; nConj < 9; nConj++) { + double y[8] = {0}, y1[8] = {0}, y2[8] = {0}, y3[8] = {0}; + #define FILL_KNOTS_TRI(dest, src) \ + dest[0] = src[nC+0][nH+0][nConj+0]; \ + dest[1] = src[nC+0][nH+0][nConj+1]; \ + dest[2] = src[nC+0][nH+1][nConj+0]; \ + dest[3] = src[nC+0][nH+1][nConj+1]; \ + dest[4] = src[nC+1][nH+0][nConj+0]; \ + dest[5] = src[nC+1][nH+0][nConj+1]; \ + dest[6] = src[nC+1][nH+1][nConj+0]; \ + dest[7] = src[nC+1][nH+1][nConj+1]; + FILL_KNOTS_TRI(y, piCCf) + FILL_KNOTS_TRI(y1, piCCdfdx) + FILL_KNOTS_TRI(y2, piCCdfdy) + FILL_KNOTS_TRI(y3, piCCdfdz) + Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piCC[nC][nH][nConj][0]); + FILL_KNOTS_TRI(y, piCHf) + FILL_KNOTS_TRI(y1, piCHdfdx) + FILL_KNOTS_TRI(y2, piCHdfdy) + FILL_KNOTS_TRI(y3, piCHdfdz) + Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piCH[nC][nH][nConj][0]); + FILL_KNOTS_TRI(y, piHHf) + FILL_KNOTS_TRI(y1, piHHdfdx) + FILL_KNOTS_TRI(y2, piHHdfdy) + FILL_KNOTS_TRI(y3, piHHdfdz) + Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &piHH[nC][nH][nConj][0]); + FILL_KNOTS_TRI(y, Tf) + FILL_KNOTS_TRI(y1, Tdfdx) + FILL_KNOTS_TRI(y2, Tdfdy) + FILL_KNOTS_TRI(y3, Tdfdz) + Sptricubic_patch_coeffs(nC, nC+1, nH, nH+1, nConj, nConj+1, y, y1, y2, y3, &Tijc[nC][nH][nConj][0]); + #undef FILL_KNOTS_TRI + } + } + } } /* ---------------------------------------------------------------------- diff --git a/src/MANYBODY/pair_airebo.h b/src/MANYBODY/pair_airebo.h index e927794ec0..aabc3fe17a 100644 --- a/src/MANYBODY/pair_airebo.h +++ b/src/MANYBODY/pair_airebo.h @@ -113,6 +113,12 @@ class PairAIREBO : public Pair { double Sp5th(double, double *, double *); double Spbicubic(double, double, double *, double *); double Sptricubic(double, double, double, double *, double *); + void Sptricubic_patch_adjust(double *, double, double, char); + void Sptricubic_patch_coeffs(double, double, double, double, double, double, + double*, double*, double*, double*, double*); + void Spbicubic_patch_adjust(double *, double, double, char); + void Spbicubic_patch_coeffs(double, double, double, double, double *, + double *, double *, double *); void spline_init(); void allocate(); From 74d63c24fd349c06594b94b6e51415677b1e98b2 Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 14:51:34 +0200 Subject: [PATCH 013/293] Fix AIREBO missing derivative in bondorderLJ This change replaces the bondorderLJ() function with code provided by Github user CF17, which is based on the bondorder() code. It could be fixed with a shorter patch [1], but layering fix upon fix seems to be unwise in this case. While the code at this point departs from following the Fortran code closely, the reason is that the bug is present in the Fortran code as well. Instead, the new code follows closely the bondorder() code that already exists, which should be easier to maintain in the future. This patch makes the two functions consistent with each other, and makes outside contributions easier. Since it uses a different approach to compute its value, some explanation of that reasoning has been added on top. 1: https://github.com/v0i0/lammps/commit/e8c5c662b28914de6b77e0ca49010eddfe1423e9 --- src/MANYBODY/pair_airebo.cpp | 401 +++++++++++++++++------------------ 1 file changed, 200 insertions(+), 201 deletions(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index b8ef4db48c..bc3af2d332 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -2081,44 +2081,63 @@ double PairAIREBO::bondorder(int i, int j, double rij[3], /* ---------------------------------------------------------------------- Bij* function -------------------------------------------------------------------------- */ +------------------------------------------------------------------------- -double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, - double VA, double rij0[3], double rij0mag, +This function calculates S(t_b(b_ij*)) as specified in the AIREBO paper. +To do so, it needs to compute b_ij*, i.e. the bondorder given that the +atoms i and j are placed a ficticious distance rijmag_mod apart. +Now there are two approaches to calculate the resulting forces: +1. Carry through the ficticious distance and corresponding vector + rij_mod, correcting afterwards using the derivative of r/|r|. +2. Perform all the calculations using the real distance, and do not + use a correction, only using rijmag_mod where necessary. +This code opts for (2). Mathematically, the approaches are equivalent +if implemented correctly, since in terms where only the normalized +vector is used, both calculations necessarily lead to the same result +since if f(x) = g(x/|x|) then for x = y/|y| f(x) = g(y/|y|/1). +The actual modified distance is only used in the lamda terms. +Note that these do not contribute to the forces between i and j, since +rijmag_mod is a constant and the corresponding derivatives are +accordingly zero. +This function should be kept in sync with bondorder(), i.e. changes +there probably also need to be performed here. + +*/ + +double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mod, + double VA, double rij[3], double rijmag, double **f, int vflag_atom) { - int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; - int atomi,atomj,itype,jtype,ktype,ltype,ntype; - double rik[3], rjl[3], rkn[3],rknmag,dNki; + int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; + int itype,jtype,ktype,ltype,ntype; + double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij; double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl; double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3; - double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ; - double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; - double dN2[2],dN3[3],dwjl; - double Tij,crosskij[3],crosskijmag; - double crossijl[3],crossijlmag,omkijl; - double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; - double bij,tmp3pij,tmp3pji,Stb,dStb; - double r32[3],r32mag,cos321; + double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS; + double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; + double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3]; + double dN2[2],dN3[3]; + double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3]; + double Tij; + double r32[3],r32mag,cos321,r43[3],r13[3]; + double dNlj; double om1234,rln[3]; double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag; double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; - double fcikpc,fcjlpc,fcjkpc,fcilpc; - double dt2dik[3],dt2djl[3],aa,aaa2,at2,cw,cwnum,cwnom; + double fcikpc,fcjlpc,fcjkpc,fcilpc,fcijpc; + double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; - double dctik,dctjk,dctjl,dctil,rik2i,rjl2i,sink2i,sinl2i; - double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil; - double dNlj; - double PijS,PjiS; + double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; + double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; + double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3]; + double f1[3],f2[3],f3[3],f4[4]; + double dcut321,PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; - double F12[3],F34[3],F31[3],F24[3]; - double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4]; - double rji[3],rki[3],rlj[3],r13[3],r43[3]; - double realrij[3], realrijmag; - double rjkmag, rilmag, dctdjk, dctdik, dctdil, dctdjl; - double fjk[3], fil[3], rijmbr; + double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; + double tmp3pij,tmp3pji,Stb,dStb; + double **x = atom->x; int *type = atom->type; @@ -2127,12 +2146,11 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, atomj = j; itype = map[type[atomi]]; jtype = map[type[atomj]]; - wij = Sp(rij0mag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); + wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); NijC = nC[atomi]-(wij*kronecker(jtype,0)); NijH = nH[atomi]-(wij*kronecker(jtype,1)); NjiC = nC[atomj]-(wij*kronecker(itype,0)); NjiH = nH[atomj]-(wij*kronecker(itype,1)); - bij = 0.0; tmp = 0.0; tmp2 = 0.0; @@ -2145,12 +2163,6 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, Stb = 0.0; dStb = 0.0; - realrij[0] = x[atomi][0] - x[atomj][0]; - realrij[1] = x[atomi][1] - x[atomj][1]; - realrij[2] = x[atomi][2] - x[atomj][2]; - realrijmag = sqrt(realrij[0] * realrij[0] + realrij[1] * realrij[1] - + realrij[2] * realrij[2]); - REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; @@ -2161,9 +2173,9 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); lamdajik = 4.0*kronecker(itype,1) * - ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); + ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS); - Nki = nC[atomk]-(wik*kronecker(itype,0)) + + Nki = nC[atomk]-(wik*kronecker(itype,0))+ nH[atomk]-(wik*kronecker(itype,1)); cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); @@ -2186,6 +2198,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, pij = 1.0/sqrt(1.0+Etmp+PijS); tmppij = -.5*cube(pij); tmp3pij = tmp3; + tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; @@ -2201,7 +2214,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * - ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); + ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); @@ -2231,82 +2244,80 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ); piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC); + Tij = 0.0; dN3Tij[0] = 0.0; dN3Tij[1] = 0.0; dN3Tij[2] = 0.0; if (itype == 0 && jtype == 0) Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij); - Etmp = 0.0; + if (fabs(Tij) > TOL) { + atom2 = atomi; + atom3 = atomj; + r32[0] = x[atom3][0]-x[atom2][0]; + r32[1] = x[atom3][1]-x[atom2][1]; + r32[2] = x[atom3][2]-x[atom2][2]; + r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); + r23[0] = -r32[0]; + r23[1] = -r32[1]; + r23[2] = -r32[2]; + r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; + atom1 = atomk; ktype = map[type[atomk]]; if (atomk != atomj) { - rik[0] = x[atomi][0]-x[atomk][0]; - rik[1] = x[atomi][1]-x[atomk][1]; - rik[2] = x[atomi][2]-x[atomk][2]; - rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); - cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / - (rijmag*rikmag); + r21[0] = x[atom2][0]-x[atom1][0]; + r21[1] = x[atom2][1]-x[atom1][1]; + r21[2] = x[atom2][2]-x[atom1][2]; + r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]); + cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) / + (r21mag*r32mag); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); + sin321 = sqrt(1.0 - cos321*cos321); + if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0 + w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); + tspjik = Sp2(cos321,thmin,thmax,dtsjik); - rjk[0] = rik[0]-rij[0]; - rjk[1] = rik[1]-rij[1]; - rjk[2] = rik[2]-rij[2]; - rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); - rij2 = rijmag*rijmag; - rik2 = rikmag*rikmag; - costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag; - tspjik = Sp2(costmp,thmin,thmax,dtsjik); - - if (sqrt(1.0 - cos321*cos321) > sqrt(TOL)) { - wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik); REBO_neighs_j = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs_j[l]; + atom4 = atoml; ltype = map[type[atoml]]; if (!(atoml == atomi || atoml == atomk)) { - rjl[0] = x[atomj][0]-x[atoml][0]; - rjl[1] = x[atomj][1]-x[atoml][1]; - rjl[2] = x[atomj][2]-x[atoml][2]; - rjlmag = sqrt(rjl[0]*rjl[0] + rjl[1]*rjl[1] + rjl[2]*rjl[2]); - cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) / - (rijmag*rjlmag); + r34[0] = x[atom3][0]-x[atom4][0]; + r34[1] = x[atom3][1]-x[atom4][1]; + r34[2] = x[atom3][2]-x[atom4][2]; + r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2])); + cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) / + (r32mag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); + sin234 = sqrt(1.0 - cos234*cos234); - ril[0] = rij[0]+rjl[0]; - ril[1] = rij[1]+rjl[1]; - ril[2] = rij[2]+rjl[2]; - ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]); - rjl2 = rjlmag*rjlmag; - costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag; - tspijl = Sp2(costmp,thmin,thmax,dtsijl); + if ((sin234 > TOL) && (r34mag > TOL)) { // XXX was sin234 != 0.0 + w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34); + tspijl = Sp2(cos234,thmin,thmax,dtsijl); - if (sqrt(1.0 - cos234*cos234) > sqrt(TOL)) { - wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS); - crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]); - crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]); - crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]); - crosskijmag = sqrt(crosskij[0]*crosskij[0] + - crosskij[1]*crosskij[1] + - crosskij[2]*crosskij[2]); - crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]); - crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]); - crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]); - crossijlmag = sqrt(crossijl[0]*crossijl[0] + - crossijl[1]*crossijl[1] + - crossijl[2]*crossijl[2]); - omkijl = -1.0*(((crosskij[0]*crossijl[0]) + - (crosskij[1]*crossijl[1]) + - (crosskij[2]*crossijl[2])) / - (crosskijmag*crossijlmag)); - Etmp += ((1.0-square(omkijl))*wik*wjl) * + cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]); + cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]); + cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]); + cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]); + cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]); + cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]); + + cwnum = (cross321[0]*cross234[0]) + + (cross321[1]*cross234[1]) + (cross321[2]*cross234[2]); + cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234; + om1234 = cwnum/cwnom; + cw = om1234; + Etmp += ((1.0-square(om1234))*w21*w34) * (1.0-tspjik)*(1.0-tspijl); + } } } @@ -2338,50 +2349,43 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]); lamdajik = 4.0*kronecker(itype,1) * - ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); + ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); - rjk[0] = rik[0] - rij[0]; - rjk[1] = rik[1] - rij[1]; - rjk[2] = rik[2] - rij[2]; - rjkmag = sqrt(rjk[0] * rjk[0] + rjk[1] * rjk[1] + rjk[2] * rjk[2]); - rijrik = 2 * rijmag * rikmag; - rr = rijmag * rijmag - rikmag * rikmag; - cosjik = (rijmag * rijmag + rikmag * rikmag - rjkmag * rjkmag) / rijrik; + cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) / + (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); - dctdjk = -2 / rijrik; - dctdik = (-rr + rjkmag * rjkmag) / (rijrik * rikmag * rikmag); - // evaluate splines g and derivatives dg + + dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) - + (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag)))); + dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) - + (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag)))); + dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) - + (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag)))); + dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) + + (cosjik*(rik[0]/(rikmag*rikmag))); + dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) + + (cosjik*(rik[1]/(rikmag*rikmag))); + dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) + + (cosjik*(rik[2]/(rikmag*rikmag))); + dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) + + (cosjik*(rij[0]/(rijmag*rijmag))); + dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) + + (cosjik*(rij[1]/(rijmag*rijmag))); + dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) + + (cosjik*(rij[2]/(rijmag*rijmag))); g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); - tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik)); - - fi[0] = -tmp2 * dctdik * rik[0]; - fi[1] = -tmp2 * dctdik * rik[1]; - fi[2] = -tmp2 * dctdik * rik[2]; - fk[0] = tmp2 * dctdik * rik[0]; - fk[1] = tmp2 * dctdik * rik[1]; - fk[2] = tmp2 * dctdik * rik[2]; - fj[0] = 0; - fj[1] = 0; - fj[2] = 0; - fjk[0] = -tmp2 * dctdjk * rjk[0]; - fjk[1] = -tmp2 * dctdjk * rjk[1]; - fjk[2] = -tmp2 * dctdjk * rjk[2]; - fi[0] += fjk[0]; - fi[1] += fjk[1]; - fi[2] += fjk[2]; - fk[0] -= fjk[0]; - fk[1] -= fjk[1]; - fk[2] -= fjk[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - fj[0] += rijmbr * (fjk[0] - (realrij[0] * realrij[0] * fjk[0] + realrij[0] * realrij[1] * fjk[1] + realrij[0] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fj[1] += rijmbr * (fjk[1] - (realrij[1] * realrij[0] * fjk[0] + realrij[1] * realrij[1] * fjk[1] + realrij[1] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fj[2] += rijmbr * (fjk[2] - (realrij[2] * realrij[0] * fjk[0] + realrij[2] * realrij[1] * fjk[1] + realrij[2] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[0] -= rijmbr * (fjk[0] - (realrij[0] * realrij[0] * fjk[0] + realrij[0] * realrij[1] * fjk[1] + realrij[0] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[1] -= rijmbr * (fjk[1] - (realrij[1] * realrij[0] * fjk[0] + realrij[1] * realrij[1] * fjk[1] + realrij[1] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[2] -= rijmbr * (fjk[2] - (realrij[2] * realrij[0] * fjk[0] + realrij[2] * realrij[1] * fjk[1] + realrij[2] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); + fj[0] = -tmp2*dcosjikdrj[0]; + fj[1] = -tmp2*dcosjikdrj[1]; + fj[2] = -tmp2*dcosjikdrj[2]; + fi[0] = -tmp2*dcosjikdri[0]; + fi[1] = -tmp2*dcosjikdri[1]; + fi[2] = -tmp2*dcosjikdri[2]; + fk[0] = -tmp2*dcosjikdrk[0]; + fk[1] = -tmp2*dcosjikdrk[1]; + fk[2] = -tmp2*dcosjikdrk[2]; tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1)); fi[0] += tmp2*(rik[0]/rikmag); @@ -2439,6 +2443,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, tmp3 = tmp3pji; dN2[0] = dN2PJI[0]; dN2[1] = dN2PJI[1]; + REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; @@ -2449,51 +2454,43 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * - ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); + ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); - ril[0] = rij[0] + rjl[0]; - ril[1] = rij[1] + rjl[1]; - ril[2] = rij[2] + rjl[2]; - rilmag = sqrt(ril[0] * ril[0] + ril[1] * ril[1] + ril[2] * ril[2]); - rijrjl = 2 * rijmag * rjlmag; - rr = rijmag * rijmag - rjlmag * rjlmag; - cosijl = (rijmag * rijmag + rjlmag * rjlmag - rilmag * rilmag) / rijrjl; + cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) / + (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); - dctdil = -2 / rijrjl; - dctdjl = (-rr + rilmag * rilmag) / (rijrjl * rjlmag * rjlmag); + + dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) - + (cosijl*rij[0]/(rijmag*rijmag)); + dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) - + (cosijl*rij[1]/(rijmag*rijmag)); + dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) - + (cosijl*rij[2]/(rijmag*rijmag)); + dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) + + (cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag)))); + dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + + (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag)))); + dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + + (cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag)))); + dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag)); + dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag)); + dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag)); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl)); - fj[0] = -tmp2 * dctdjl * rjl[0]; - fj[1] = -tmp2 * dctdjl * rjl[1]; - fj[2] = -tmp2 * dctdjl * rjl[2]; - fl[0] = tmp2 * dctdjl * rjl[0]; - fl[1] = tmp2 * dctdjl * rjl[1]; - fl[2] = tmp2 * dctdjl * rjl[2]; - fi[0] = 0; - fi[1] = 0; - fi[2] = 0; - fil[0] = -tmp2 * dctdil * ril[0]; - fil[1] = -tmp2 * dctdil * ril[1]; - fil[2] = -tmp2 * dctdil * ril[2]; - fj[0] += fil[0]; - fj[1] += fil[1]; - fj[2] += fil[2]; - fl[0] -= fil[0]; - fl[1] -= fil[1]; - fl[2] -= fil[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - fi[0] += rijmbr * (fil[0] - (realrij[0] * realrij[0] * fil[0] + realrij[0] * realrij[1] * fil[1] + realrij[0] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fi[1] += rijmbr * (fil[1] - (realrij[1] * realrij[0] * fil[0] + realrij[1] * realrij[1] * fil[1] + realrij[1] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fi[2] += rijmbr * (fil[2] - (realrij[2] * realrij[0] * fil[0] + realrij[2] * realrij[1] * fil[1] + realrij[2] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[0] -= rijmbr * (fil[0] - (realrij[0] * realrij[0] * fil[0] + realrij[0] * realrij[1] * fil[1] + realrij[0] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[1] -= rijmbr * (fil[1] - (realrij[1] * realrij[0] * fil[0] + realrij[1] * realrij[1] * fil[1] + realrij[1] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[2] -= rijmbr * (fil[2] - (realrij[2] * realrij[0] * fil[0] + realrij[2] * realrij[1] * fil[1] + realrij[2] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - - + fi[0] = -tmp2*dcosijldri[0]; + fi[1] = -tmp2*dcosijldri[1]; + fi[2] = -tmp2*dcosijldri[2]; + fj[0] = -tmp2*dcosijldrj[0]; + fj[1] = -tmp2*dcosijldrj[1]; + fj[2] = -tmp2*dcosijldrj[2]; + fl[0] = -tmp2*dcosijldrl[0]; + fl[1] = -tmp2*dcosijldrl[1]; + fl[2] = -tmp2*dcosijldrl[2]; + tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1)); fj[0] += tmp2*(rjl[0]/rjlmag); fj[1] += tmp2*(rjl[1]/rjlmag); @@ -2503,6 +2500,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, fl[2] -= tmp2*(rjl[2]/rjlmag); // coordination forces + // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag; @@ -2617,8 +2615,8 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, // piRC forces to J side - REBO_neighs = REBO_firstneigh[j]; - for (l = 0; l < REBO_numneigh[j]; l++) { + REBO_neighs = REBO_firstneigh[atomj]; + for (l = 0; l < REBO_numneigh[atomj]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; @@ -2688,15 +2686,14 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, dN3[2] = dN3Tij[2]; atom2 = atomi; atom3 = atomj; - r32[0] = -rij[0]; - r32[1] = -rij[1]; - r32[2] = -rij[2]; - r23[0] = rij[0]; - r23[1] = rij[1]; - r23[2] = rij[2]; - r32mag = rijmag; - r23mag = rijmag; - + r32[0] = x[atom3][0]-x[atom2][0]; + r32[1] = x[atom3][1]-x[atom2][1]; + r32[2] = x[atom3][2]-x[atom2][2]; + r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); + r23[0] = -r32[0]; + r23[1] = -r32[1]; + r23[2] = -r32[2]; + r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; @@ -2712,20 +2709,21 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); sin321 = sqrt(1.0 - cos321*cos321); - if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0 sink2i = 1.0/(sin321*sin321); rik2i = 1.0/(r21mag*r21mag); rr = (rijmag*rijmag)-(r21mag*r21mag); - rjk[0] = r21[0]-rij[0]; - rjk[1] = r21[1]-rij[1]; - rjk[2] = r21[2]-rij[2]; + rjk[0] = r21[0]-r23[0]; + rjk[1] = r21[1]-r23[1]; + rjk[2] = r21[2]-r23[2]; rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); - rijrik = 2.0*rijmag*r21mag; + rijrik = 2.0*r23mag*r21mag; rik2 = r21mag*r21mag; dctik = (-rr+rjk2)/(rijrik*rik2); + dctij = (rr+rjk2)/(rijrik*r23mag*r23mag); dctjk = -2.0/rijrik; w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); + rijmag = r32mag; rikmag = r21mag; rij2 = r32mag*r32mag; rik2 = r21mag*r21mag; @@ -2743,8 +2741,8 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, r34[1] = x[atom3][1]-x[atom4][1]; r34[2] = x[atom3][2]-x[atom4][2]; r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]); - cos234 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) + - (rij[2]*r34[2]))/(rijmag*r34mag); + cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) / + (r32mag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); sin234 = sqrt(1.0 - cos234*cos234); @@ -2762,6 +2760,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, rijrjl = 2.0*r23mag*r34mag; rjl2 = r34mag*r34mag; dctjl = (-rr+ril2)/(rijrjl*rjl2); + dctji = (rr+ril2)/(rijrjl*r23mag*r23mag); dctil = -2.0/rijrjl; rjlmag = r34mag; rjl2 = r34mag*r34mag; @@ -2787,6 +2786,8 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, dt1djk = (-dctjk*sink2i*cos321); dt1djl = (rjl2i)-(dctjl*sinl2i*cos234); dt1dil = (-dctil*sinl2i*cos234); + dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) - + (dctji*sinl2i*cos234); dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]); dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]); @@ -2796,16 +2797,29 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]); dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]); + dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) - + (r21[1]*cross234[2])+(r34[1]*cross321[2]); + dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) - + (r21[2]*cross234[0])+(r34[2]*cross321[0]); + dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) - + (r21[0]*cross234[1])+(r34[0]*cross321[1]); + aa = (prefactor*2.0*cw/cwnom)*w21*w34 * (1.0-tspjik)*(1.0-tspijl); aaa2 = -prefactor*(1.0-square(om1234)) * w21*w34; at2 = aa*cwnum; + fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) + + (aaa2*dtsijl*dctji*(1.0-tspjik)); fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl)); fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik)); fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl)); fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik)); + F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]); + F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]); + F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]); + F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]); F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]); F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]); @@ -2825,31 +2839,16 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij[3], double rijmag, f1[0] = -F12[0]-F31[0]; f1[1] = -F12[1]-F31[1]; f1[2] = -F12[2]-F31[2]; - f2[0] = F12[0]+F31[0]; - f2[1] = F12[1]+F31[1]; - f2[2] = F12[2]+F31[2]; - f3[0] = F34[0]+F24[0]; - f3[1] = F34[1]+F24[1]; - f3[2] = F34[2]+F24[2]; + f2[0] = F23[0]+F12[0]+F24[0]; + f2[1] = F23[1]+F12[1]+F24[1]; + f2[2] = F23[2]+F12[2]+F24[2]; + f3[0] = -F23[0]+F34[0]+F31[0]; + f3[1] = -F23[1]+F34[1]+F31[1]; + f3[2] = -F23[2]+F34[2]+F31[2]; f4[0] = -F34[0]-F24[0]; f4[1] = -F34[1]-F24[1]; f4[2] = -F34[2]-F24[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - f2[0] += rijmbr * (F24[0] - (realrij[0] * realrij[0] * F24[0] + realrij[0] * realrij[1] * F24[1] + realrij[0] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f2[1] += rijmbr * (F24[1] - (realrij[1] * realrij[0] * F24[0] + realrij[1] * realrij[1] * F24[1] + realrij[1] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f2[2] += rijmbr * (F24[2] - (realrij[2] * realrij[0] * F24[0] + realrij[2] * realrij[1] * F24[1] + realrij[2] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[0] -= rijmbr * (F24[0] - (realrij[0] * realrij[0] * F24[0] + realrij[0] * realrij[1] * F24[1] + realrij[0] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[1] -= rijmbr * (F24[1] - (realrij[1] * realrij[0] * F24[0] + realrij[1] * realrij[1] * F24[1] + realrij[1] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[2] -= rijmbr * (F24[2] - (realrij[2] * realrij[0] * F24[0] + realrij[2] * realrij[1] * F24[1] + realrij[2] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - - f2[0] -= rijmbr * (F31[0] - (realrij[0] * realrij[0] * F31[0] + realrij[0] * realrij[1] * F31[1] + realrij[0] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f2[1] -= rijmbr * (F31[1] - (realrij[1] * realrij[0] * F31[0] + realrij[1] * realrij[1] * F31[1] + realrij[1] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f2[2] -= rijmbr * (F31[2] - (realrij[2] * realrij[0] * F31[0] + realrij[2] * realrij[1] * F31[1] + realrij[2] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[0] += rijmbr * (F31[0] - (realrij[0] * realrij[0] * F31[0] + realrij[0] * realrij[1] * F31[1] + realrij[0] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[1] += rijmbr * (F31[1] - (realrij[1] * realrij[0] * F31[0] + realrij[1] * realrij[1] * F31[1] + realrij[1] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[2] += rijmbr * (F31[2] - (realrij[2] * realrij[0] * F31[0] + realrij[2] * realrij[1] * F31[1] + realrij[2] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - // coordination forces tmp2 = VA*Tij*((1.0-(om1234*om1234))) * From 7e42af18bc6870b4d8769528228842b27388c97e Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 15:11:58 +0200 Subject: [PATCH 014/293] Feature: AIREBO parametrize cutoff switching In #514 it has been raised that the switching function that ensures a smooth transition to the cutoff is only correct if cutlj = 3.0. This patch gives users an opportunity to configure the switching function together with the cutoff by specifying the start of the transition region. Behaviour in the default case remaing unchanged. This allows users to specify larger cutoffs than 3 (which used to have no effect) and get correct cutoff behaviour for values less then 3. --- doc/src/pair_airebo.txt | 13 ++++++++++--- src/MANYBODY/pair_airebo.cpp | 18 +++++++++++++----- src/MANYBODY/pair_airebo.h | 1 + 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/doc/src/pair_airebo.txt b/doc/src/pair_airebo.txt index 2e3083c34b..0c03eb3267 100644 --- a/doc/src/pair_airebo.txt +++ b/doc/src/pair_airebo.txt @@ -15,12 +15,13 @@ pair_style rebo/omp command :h3 [Syntax:] -pair_style style cutoff LJ_flag TORSION_flag :pre +pair_style style cutoff LJ_flag TORSION_flag cutoff_min :pre style = {airebo} or {airebo/morse} or {rebo} cutoff = LJ or Morse cutoff (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) :ul +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) :ul [Examples:] @@ -60,7 +61,7 @@ The AIREBO potential consists of three terms: :c,image(Eqs/pair_airebo.jpg) By default, all three terms are included. For the {airebo} style, if -the two optional flag arguments to the pair_style command are +the first two optional flag arguments to the pair_style command are 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 @@ -97,6 +98,12 @@ 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 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 +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 various dihedral angle preferences in hydrocarbon configurations. diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index bc3af2d332..e0cc15fae1 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -68,6 +68,10 @@ PairAIREBO::PairAIREBO(LAMMPS *lmp) : Pair(lmp) nC = nH = NULL; map = NULL; manybody_flag = 1; + + sigwid = 0.84; + sigcut = 3.0; + sigmin = sigcut - sigwid; } /* ---------------------------------------------------------------------- @@ -147,7 +151,8 @@ void PairAIREBO::allocate() void PairAIREBO::settings(int narg, char **arg) { - if (narg != 1 && narg != 3) error->all(FLERR,"Illegal pair_style command"); + if (narg != 1 && narg != 3 && narg != 4) + error->all(FLERR,"Illegal pair_style command"); cutlj = force->numeric(FLERR,arg[0]); @@ -155,6 +160,13 @@ void PairAIREBO::settings(int narg, char **arg) ljflag = force->inumeric(FLERR,arg[1]); torflag = force->inumeric(FLERR,arg[2]); } + if (narg == 4) { + ljflag = force->inumeric(FLERR,arg[1]); + torflag = force->inumeric(FLERR,arg[2]); + sigcut = cutlj; + sigmin = force->numeric(FLERR,arg[3]); + sigwid = sigcut - sigmin; + } // this one parameter for C-C interactions is different in AIREBO vs REBO // see Favata, Micheletti, Ryu, Pugno, Comp Phys Comm (2016) @@ -736,10 +748,6 @@ void PairAIREBO::FLJ(int eflag, int vflag) // compute LJ forces and energy - sigwid = 0.84; - sigcut = 3.0; - sigmin = sigcut - sigwid; - rljmin = sigma[itype][jtype]; rljmax = sigcut * rljmin; rljmin = sigmin * rljmin; diff --git a/src/MANYBODY/pair_airebo.h b/src/MANYBODY/pair_airebo.h index aabc3fe17a..d9628f3bb3 100644 --- a/src/MANYBODY/pair_airebo.h +++ b/src/MANYBODY/pair_airebo.h @@ -46,6 +46,7 @@ class PairAIREBO : public Pair { int morseflag; // 1 if Morse instead of LJ for non-bonded double cutlj; // user-specified LJ cutoff + double sigcut,sigwid,sigmin; // corresponding cutoff function double cutljrebosq; // cut for when to compute // REBO neighs of ghost atoms From d2f7f4843a7cc64cb0468f64507d40f203ea0dab Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 15:16:45 +0200 Subject: [PATCH 015/293] AIREBO Fix Credits --- src/MANYBODY/pair_airebo.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index e0cc15fae1..27a5aad21c 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -14,7 +14,8 @@ /* ---------------------------------------------------------------------- Contributing author: Ase Henry (MIT) Bugfixes and optimizations: - Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U) + Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U), + Markus Hoehnerbach (RWTH Aachen), Github user CF17 AIREBO-M modification to optionally replace LJ with Morse potentials. Thomas C. O'Connor (JHU) 2014 ------------------------------------------------------------------------- */ From ff761d639a78bf40627a26de52724e06fdc375df Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 15:29:40 +0200 Subject: [PATCH 016/293] Sync AIREBO USER-OMP implementation. --- src/MANYBODY/pair_airebo.cpp | 3 +- src/USER-OMP/pair_airebo_omp.cpp | 403 +++++++++++++++---------------- 2 files changed, 200 insertions(+), 206 deletions(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 27a5aad21c..a33abfcb63 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -2147,7 +2147,6 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mo double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; double tmp3pij,tmp3pji,Stb,dStb; - double **x = atom->x; int *type = atom->type; @@ -2261,7 +2260,7 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mo if (itype == 0 && jtype == 0) Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij); Etmp = 0.0; - + if (fabs(Tij) > TOL) { atom2 = atomi; atom3 = atomj; diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index 13df133585..2fd6c93f03 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -504,10 +504,6 @@ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, // compute LJ forces and energy - sigwid = 0.84; - sigcut = 3.0; - sigmin = sigcut - sigwid; - rljmin = sigma[itype][jtype]; rljmax = sigcut * rljmin; rljmin = sigmin * rljmin; @@ -1853,44 +1849,62 @@ double PairAIREBOOMP::bondorder_thr(int i, int j, double rij[3], double rijmag, /* ---------------------------------------------------------------------- Bij* function -------------------------------------------------------------------------- */ +------------------------------------------------------------------------- -double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag, - double VA, double rij0[3], double rij0mag, +This function calculates S(t_b(b_ij*)) as specified in the AIREBO paper. +To do so, it needs to compute b_ij*, i.e. the bondorder given that the +atoms i and j are placed a ficticious distance rijmag_mod apart. +Now there are two approaches to calculate the resulting forces: +1. Carry through the ficticious distance and corresponding vector + rij_mod, correcting afterwards using the derivative of r/|r|. +2. Perform all the calculations using the real distance, and do not + use a correction, only using rijmag_mod where necessary. +This code opts for (2). Mathematically, the approaches are equivalent +if implemented correctly, since in terms where only the normalized +vector is used, both calculations necessarily lead to the same result +since if f(x) = g(x/|x|) then for x = y/|y| f(x) = g(y/|y|/1). +The actual modified distance is only used in the lamda terms. +Note that these do not contribute to the forces between i and j, since +rijmag_mod is a constant and the corresponding derivatives are +accordingly zero. +This function should be kept in sync with bondorder(), i.e. changes +there probably also need to be performed here. + +*/ + +double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij_mod[3], double rijmag_mod, + double VA, double rij[3], double rijmag, int vflag_atom, ThrData * const thr) { - int k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; - int atomi,atomj,itype,jtype,ktype,ltype,ntype; - double rik[3], rjl[3], rkn[3],rknmag,dNki; + int atomi,atomj,k,n,l,atomk,atoml,atomn,atom1,atom2,atom3,atom4; + int itype,jtype,ktype,ltype,ntype; + double rik[3],rjl[3],rkn[3],rji[3],rki[3],rlj[3],rknmag,dNki,dwjl,bij; double NijC,NijH,NjiC,NjiH,wik,dwik,dwkn,wjl; double rikmag,rjlmag,cosjik,cosijl,g,tmp2,tmp3; - double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ; - double Nki,Nlj,dS,lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; - double dN2[2],dN3[3],dwjl; - double Tij,crosskij[3],crosskijmag; - double crossijl[3],crossijlmag,omkijl; - double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; - double bij,tmp3pij,tmp3pji,Stb,dStb; - double r32[3],r32mag,cos321; + double Etmp,pij,tmp,wij,dwij,NconjtmpI,NconjtmpJ,Nki,Nlj,dS; + double lamdajik,lamdaijl,dgdc,dgdN,pji,Nijconj,piRC; + double dcosjikdri[3],dcosijldri[3],dcosjikdrk[3]; + double dN2[2],dN3[3]; + double dcosjikdrj[3],dcosijldrj[3],dcosijldrl[3]; + double Tij; + double r32[3],r32mag,cos321,r43[3],r13[3]; + double dNlj; double om1234,rln[3]; double rlnmag,dwln,r23[3],r23mag,r21[3],r21mag; double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; - double fcikpc,fcjlpc,fcjkpc,fcilpc; - double dt2dik[3],dt2djl[3],aa,aaa2,at2,cw,cwnum,cwnom; + double fcikpc,fcjlpc,fcjkpc,fcilpc,fcijpc; + double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; - double dctik,dctjk,dctjl,dctil,rik2i,rjl2i,sink2i,sinl2i; - double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil; - double dNlj; - double PijS,PjiS; + double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; + double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; + double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3]; + double f1[3],f2[3],f3[3],f4[4]; + double dcut321,PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; - double F12[3],F34[3],F31[3],F24[3]; - double fi[3],fj[3],fk[3],fl[3],f1[3],f2[3],f3[3],f4[4]; - double rji[3],rki[3],rlj[3],r13[3],r43[3]; - double realrij[3], realrijmag; - double rjkmag, rilmag, dctdjk, dctdik, dctdil, dctdjl; - double fjk[3], fil[3], rijmbr; + double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; + double tmp3pij,tmp3pji,Stb,dStb; const double * const * const x = atom->x; double * const * const f = thr->get_f(); @@ -1900,12 +1914,11 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag atomj = j; itype = map[type[atomi]]; jtype = map[type[atomj]]; - wij = Sp(rij0mag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); + wij = Sp(rijmag,rcmin[itype][jtype],rcmax[itype][jtype],dwij); NijC = nC[atomi]-(wij*kronecker(jtype,0)); NijH = nH[atomi]-(wij*kronecker(jtype,1)); NjiC = nC[atomj]-(wij*kronecker(itype,0)); NjiH = nH[atomj]-(wij*kronecker(itype,1)); - bij = 0.0; tmp = 0.0; tmp2 = 0.0; @@ -1918,12 +1931,6 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag Stb = 0.0; dStb = 0.0; - realrij[0] = x[atomi][0] - x[atomj][0]; - realrij[1] = x[atomi][1] - x[atomj][1]; - realrij[2] = x[atomi][2] - x[atomj][2]; - realrijmag = sqrt(realrij[0] * realrij[0] + realrij[1] * realrij[1] - + realrij[2] * realrij[2]); - REBO_neighs = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs[k]; @@ -1934,9 +1941,9 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); lamdajik = 4.0*kronecker(itype,1) * - ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); + ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dS); - Nki = nC[atomk]-(wik*kronecker(itype,0)) + + Nki = nC[atomk]-(wik*kronecker(itype,0))+ nH[atomk]-(wik*kronecker(itype,1)); cosjik = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / (rijmag*rikmag); @@ -1959,6 +1966,7 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag pij = 1.0/sqrt(1.0+Etmp+PijS); tmppij = -.5*pij*pij*pij; tmp3pij = tmp3; + tmp = 0.0; tmp2 = 0.0; tmp3 = 0.0; @@ -1974,7 +1982,7 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * - ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); + ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dS); Nlj = nC[atoml]-(wjl*kronecker(jtype,0))+nH[atoml] - (wjl*kronecker(jtype,1)); @@ -2004,82 +2012,80 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag Nijconj = 1.0+(NconjtmpI*NconjtmpI)+(NconjtmpJ*NconjtmpJ); piRC = piRCSpline(NijC+NijH,NjiC+NjiH,Nijconj,itype,jtype,dN3piRC); + Tij = 0.0; dN3Tij[0] = 0.0; dN3Tij[1] = 0.0; dN3Tij[2] = 0.0; if (itype == 0 && jtype == 0) Tij=TijSpline((NijC+NijH),(NjiC+NjiH),Nijconj,dN3Tij); - Etmp = 0.0; + if (fabs(Tij) > TOL) { + atom2 = atomi; + atom3 = atomj; + r32[0] = x[atom3][0]-x[atom2][0]; + r32[1] = x[atom3][1]-x[atom2][1]; + r32[2] = x[atom3][2]-x[atom2][2]; + r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); + r23[0] = -r32[0]; + r23[1] = -r32[1]; + r23[2] = -r32[2]; + r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; + atom1 = atomk; ktype = map[type[atomk]]; if (atomk != atomj) { - rik[0] = x[atomi][0]-x[atomk][0]; - rik[1] = x[atomi][1]-x[atomk][1]; - rik[2] = x[atomi][2]-x[atomk][2]; - rikmag = sqrt((rik[0]*rik[0])+(rik[1]*rik[1])+(rik[2]*rik[2])); - cos321 = ((rij[0]*rik[0])+(rij[1]*rik[1])+(rij[2]*rik[2])) / - (rijmag*rikmag); + r21[0] = x[atom2][0]-x[atom1][0]; + r21[1] = x[atom2][1]-x[atom1][1]; + r21[2] = x[atom2][2]-x[atom1][2]; + r21mag = sqrt(r21[0]*r21[0] + r21[1]*r21[1] + r21[2]*r21[2]); + cos321 = -1.0*((r21[0]*r32[0])+(r21[1]*r32[1])+(r21[2]*r32[2])) / + (r21mag*r32mag); cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); + sin321 = sqrt(1.0 - cos321*cos321); + if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0 + w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); + tspjik = Sp2(cos321,thmin,thmax,dtsjik); - rjk[0] = rik[0]-rij[0]; - rjk[1] = rik[1]-rij[1]; - rjk[2] = rik[2]-rij[2]; - rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); - rij2 = rijmag*rijmag; - rik2 = rikmag*rikmag; - costmp = 0.5*(rij2+rik2-rjk2)/rijmag/rikmag; - tspjik = Sp2(costmp,thmin,thmax,dtsjik); - - if (sqrt(1.0 - cos321*cos321) > sqrt(TOL)) { - wik = Sp(rikmag,rcmin[itype][ktype],rcmaxp[itype][ktype],dwik); REBO_neighs_j = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs_j[l]; + atom4 = atoml; ltype = map[type[atoml]]; if (!(atoml == atomi || atoml == atomk)) { - rjl[0] = x[atomj][0]-x[atoml][0]; - rjl[1] = x[atomj][1]-x[atoml][1]; - rjl[2] = x[atomj][2]-x[atoml][2]; - rjlmag = sqrt(rjl[0]*rjl[0] + rjl[1]*rjl[1] + rjl[2]*rjl[2]); - cos234 = -((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2])) / - (rijmag*rjlmag); + r34[0] = x[atom3][0]-x[atom4][0]; + r34[1] = x[atom3][1]-x[atom4][1]; + r34[2] = x[atom3][2]-x[atom4][2]; + r34mag = sqrt((r34[0]*r34[0])+(r34[1]*r34[1])+(r34[2]*r34[2])); + cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) / + (r32mag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); + sin234 = sqrt(1.0 - cos234*cos234); - ril[0] = rij[0]+rjl[0]; - ril[1] = rij[1]+rjl[1]; - ril[2] = rij[2]+rjl[2]; - ril2 = (ril[0]*ril[0])+(ril[1]*ril[1])+(ril[2]*ril[2]); - rjl2 = rjlmag*rjlmag; - costmp = 0.5*(rij2+rjl2-ril2)/rijmag/rjlmag; - tspijl = Sp2(costmp,thmin,thmax,dtsijl); + if ((sin234 > TOL) && (r34mag > TOL)) { // XXX was sin234 != 0.0 + w34 = Sp(r34mag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dw34); + tspijl = Sp2(cos234,thmin,thmax,dtsijl); - if (sqrt(1.0 - cos234*cos234) > sqrt(TOL)) { - wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmaxp[jtype][ltype],dS); - crosskij[0] = (rij[1]*rik[2]-rij[2]*rik[1]); - crosskij[1] = (rij[2]*rik[0]-rij[0]*rik[2]); - crosskij[2] = (rij[0]*rik[1]-rij[1]*rik[0]); - crosskijmag = sqrt(crosskij[0]*crosskij[0] + - crosskij[1]*crosskij[1] + - crosskij[2]*crosskij[2]); - crossijl[0] = (rij[1]*rjl[2]-rij[2]*rjl[1]); - crossijl[1] = (rij[2]*rjl[0]-rij[0]*rjl[2]); - crossijl[2] = (rij[0]*rjl[1]-rij[1]*rjl[0]); - crossijlmag = sqrt(crossijl[0]*crossijl[0] + - crossijl[1]*crossijl[1] + - crossijl[2]*crossijl[2]); - omkijl = -1.0*(((crosskij[0]*crossijl[0]) + - (crosskij[1]*crossijl[1]) + - (crosskij[2]*crossijl[2])) / - (crosskijmag*crossijlmag)); - Etmp += ((1.0-square(omkijl))*wik*wjl) * + cross321[0] = (r32[1]*r21[2])-(r32[2]*r21[1]); + cross321[1] = (r32[2]*r21[0])-(r32[0]*r21[2]); + cross321[2] = (r32[0]*r21[1])-(r32[1]*r21[0]); + cross234[0] = (r23[1]*r34[2])-(r23[2]*r34[1]); + cross234[1] = (r23[2]*r34[0])-(r23[0]*r34[2]); + cross234[2] = (r23[0]*r34[1])-(r23[1]*r34[0]); + + cwnum = (cross321[0]*cross234[0]) + + (cross321[1]*cross234[1]) + (cross321[2]*cross234[2]); + cwnom = r21mag*r34mag*r23mag*r23mag*sin321*sin234; + om1234 = cwnum/cwnom; + cw = om1234; + Etmp += ((1.0-square(om1234))*w21*w34) * (1.0-tspjik)*(1.0-tspijl); + } } } @@ -2111,50 +2117,43 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag rik[2] = x[atomi][2]-x[atomk][2]; rikmag = sqrt(rik[0]*rik[0] + rik[1]*rik[1] + rik[2]*rik[2]); lamdajik = 4.0*kronecker(itype,1) * - ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag)); + ((rho[ktype][1]-rikmag)-(rho[jtype][1]-rijmag_mod)); wik = Sp(rikmag,rcmin[itype][ktype],rcmax[itype][ktype],dwik); - rjk[0] = rik[0] - rij[0]; - rjk[1] = rik[1] - rij[1]; - rjk[2] = rik[2] - rij[2]; - rjkmag = sqrt(rjk[0] * rjk[0] + rjk[1] * rjk[1] + rjk[2] * rjk[2]); - rijrik = 2 * rijmag * rikmag; - rr = rijmag * rijmag - rikmag * rikmag; - cosjik = (rijmag * rijmag + rikmag * rikmag - rjkmag * rjkmag) / rijrik; + cosjik = (rij[0]*rik[0] + rij[1]*rik[1] + rij[2]*rik[2]) / + (rijmag*rikmag); cosjik = MIN(cosjik,1.0); cosjik = MAX(cosjik,-1.0); - dctdjk = -2 / rijrik; - dctdik = (-rr + rjkmag * rjkmag) / (rijrik * rikmag * rikmag); - // evaluate splines g and derivatives dg + + dcosjikdri[0] = ((rij[0]+rik[0])/(rijmag*rikmag)) - + (cosjik*((rij[0]/(rijmag*rijmag))+(rik[0]/(rikmag*rikmag)))); + dcosjikdri[1] = ((rij[1]+rik[1])/(rijmag*rikmag)) - + (cosjik*((rij[1]/(rijmag*rijmag))+(rik[1]/(rikmag*rikmag)))); + dcosjikdri[2] = ((rij[2]+rik[2])/(rijmag*rikmag)) - + (cosjik*((rij[2]/(rijmag*rijmag))+(rik[2]/(rikmag*rikmag)))); + dcosjikdrk[0] = (-rij[0]/(rijmag*rikmag)) + + (cosjik*(rik[0]/(rikmag*rikmag))); + dcosjikdrk[1] = (-rij[1]/(rijmag*rikmag)) + + (cosjik*(rik[1]/(rikmag*rikmag))); + dcosjikdrk[2] = (-rij[2]/(rijmag*rikmag)) + + (cosjik*(rik[2]/(rikmag*rikmag))); + dcosjikdrj[0] = (-rik[0]/(rijmag*rikmag)) + + (cosjik*(rij[0]/(rijmag*rijmag))); + dcosjikdrj[1] = (-rik[1]/(rijmag*rikmag)) + + (cosjik*(rij[1]/(rijmag*rijmag))); + dcosjikdrj[2] = (-rik[2]/(rijmag*rikmag)) + + (cosjik*(rij[2]/(rijmag*rijmag))); g = gSpline(cosjik,(NijC+NijH),itype,&dgdc,&dgdN); - tmp2 = VA*.5*(tmp*wik*dgdc*exp(lamdajik)); - - fi[0] = -tmp2 * dctdik * rik[0]; - fi[1] = -tmp2 * dctdik * rik[1]; - fi[2] = -tmp2 * dctdik * rik[2]; - fk[0] = tmp2 * dctdik * rik[0]; - fk[1] = tmp2 * dctdik * rik[1]; - fk[2] = tmp2 * dctdik * rik[2]; - fj[0] = 0; - fj[1] = 0; - fj[2] = 0; - fjk[0] = -tmp2 * dctdjk * rjk[0]; - fjk[1] = -tmp2 * dctdjk * rjk[1]; - fjk[2] = -tmp2 * dctdjk * rjk[2]; - fi[0] += fjk[0]; - fi[1] += fjk[1]; - fi[2] += fjk[2]; - fk[0] -= fjk[0]; - fk[1] -= fjk[1]; - fk[2] -= fjk[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - fj[0] += rijmbr * (fjk[0] - (realrij[0] * realrij[0] * fjk[0] + realrij[0] * realrij[1] * fjk[1] + realrij[0] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fj[1] += rijmbr * (fjk[1] - (realrij[1] * realrij[0] * fjk[0] + realrij[1] * realrij[1] * fjk[1] + realrij[1] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fj[2] += rijmbr * (fjk[2] - (realrij[2] * realrij[0] * fjk[0] + realrij[2] * realrij[1] * fjk[1] + realrij[2] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[0] -= rijmbr * (fjk[0] - (realrij[0] * realrij[0] * fjk[0] + realrij[0] * realrij[1] * fjk[1] + realrij[0] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[1] -= rijmbr * (fjk[1] - (realrij[1] * realrij[0] * fjk[0] + realrij[1] * realrij[1] * fjk[1] + realrij[1] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); - fi[2] -= rijmbr * (fjk[2] - (realrij[2] * realrij[0] * fjk[0] + realrij[2] * realrij[1] * fjk[1] + realrij[2] * realrij[2] * fjk[2]) / (realrijmag * realrijmag)); + fj[0] = -tmp2*dcosjikdrj[0]; + fj[1] = -tmp2*dcosjikdrj[1]; + fj[2] = -tmp2*dcosjikdrj[2]; + fi[0] = -tmp2*dcosjikdri[0]; + fi[1] = -tmp2*dcosjikdri[1]; + fi[2] = -tmp2*dcosjikdri[2]; + fk[0] = -tmp2*dcosjikdrk[0]; + fk[1] = -tmp2*dcosjikdrk[1]; + fk[2] = -tmp2*dcosjikdrk[2]; tmp2 = VA*.5*(tmp*wik*g*exp(lamdajik)*4.0*kronecker(itype,1)); fi[0] += tmp2*(rik[0]/rikmag); @@ -2212,6 +2211,7 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag tmp3 = tmp3pji; dN2[0] = dN2PJI[0]; dN2[1] = dN2PJI[1]; + REBO_neighs = REBO_firstneigh[j]; for (l = 0; l < REBO_numneigh[j]; l++) { atoml = REBO_neighs[l]; @@ -2222,50 +2222,43 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag rjl[2] = x[atomj][2]-x[atoml][2]; rjlmag = sqrt((rjl[0]*rjl[0])+(rjl[1]*rjl[1])+(rjl[2]*rjl[2])); lamdaijl = 4.0*kronecker(jtype,1) * - ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag)); + ((rho[ltype][1]-rjlmag)-(rho[itype][1]-rijmag_mod)); wjl = Sp(rjlmag,rcmin[jtype][ltype],rcmax[jtype][ltype],dwjl); - ril[0] = rij[0] + rjl[0]; - ril[1] = rij[1] + rjl[1]; - ril[2] = rij[2] + rjl[2]; - rilmag = sqrt(ril[0] * ril[0] + ril[1] * ril[1] + ril[2] * ril[2]); - rijrjl = 2 * rijmag * rjlmag; - rr = rijmag * rijmag - rjlmag * rjlmag; - cosijl = (rijmag * rijmag + rjlmag * rjlmag - rilmag * rilmag) / rijrjl; + cosijl = (-1.0*((rij[0]*rjl[0])+(rij[1]*rjl[1])+(rij[2]*rjl[2]))) / + (rijmag*rjlmag); cosijl = MIN(cosijl,1.0); cosijl = MAX(cosijl,-1.0); - dctdil = -2 / rijrjl; - dctdjl = (-rr + rilmag * rilmag) / (rijrjl * rjlmag * rjlmag); + + dcosijldri[0] = (-rjl[0]/(rijmag*rjlmag)) - + (cosijl*rij[0]/(rijmag*rijmag)); + dcosijldri[1] = (-rjl[1]/(rijmag*rjlmag)) - + (cosijl*rij[1]/(rijmag*rijmag)); + dcosijldri[2] = (-rjl[2]/(rijmag*rjlmag)) - + (cosijl*rij[2]/(rijmag*rijmag)); + dcosijldrj[0] = ((-rij[0]+rjl[0])/(rijmag*rjlmag)) + + (cosijl*((rij[0]/square(rijmag))-(rjl[0]/(rjlmag*rjlmag)))); + dcosijldrj[1] = ((-rij[1]+rjl[1])/(rijmag*rjlmag)) + + (cosijl*((rij[1]/square(rijmag))-(rjl[1]/(rjlmag*rjlmag)))); + dcosijldrj[2] = ((-rij[2]+rjl[2])/(rijmag*rjlmag)) + + (cosijl*((rij[2]/square(rijmag))-(rjl[2]/(rjlmag*rjlmag)))); + dcosijldrl[0] = (rij[0]/(rijmag*rjlmag))+(cosijl*rjl[0]/(rjlmag*rjlmag)); + dcosijldrl[1] = (rij[1]/(rijmag*rjlmag))+(cosijl*rjl[1]/(rjlmag*rjlmag)); + dcosijldrl[2] = (rij[2]/(rijmag*rjlmag))+(cosijl*rjl[2]/(rjlmag*rjlmag)); // evaluate splines g and derivatives dg g = gSpline(cosijl,NjiC+NjiH,jtype,&dgdc,&dgdN); tmp2 = VA*.5*(tmp*wjl*dgdc*exp(lamdaijl)); - fj[0] = -tmp2 * dctdjl * rjl[0]; - fj[1] = -tmp2 * dctdjl * rjl[1]; - fj[2] = -tmp2 * dctdjl * rjl[2]; - fl[0] = tmp2 * dctdjl * rjl[0]; - fl[1] = tmp2 * dctdjl * rjl[1]; - fl[2] = tmp2 * dctdjl * rjl[2]; - fi[0] = 0; - fi[1] = 0; - fi[2] = 0; - fil[0] = -tmp2 * dctdil * ril[0]; - fil[1] = -tmp2 * dctdil * ril[1]; - fil[2] = -tmp2 * dctdil * ril[2]; - fj[0] += fil[0]; - fj[1] += fil[1]; - fj[2] += fil[2]; - fl[0] -= fil[0]; - fl[1] -= fil[1]; - fl[2] -= fil[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - fi[0] += rijmbr * (fil[0] - (realrij[0] * realrij[0] * fil[0] + realrij[0] * realrij[1] * fil[1] + realrij[0] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fi[1] += rijmbr * (fil[1] - (realrij[1] * realrij[0] * fil[0] + realrij[1] * realrij[1] * fil[1] + realrij[1] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fi[2] += rijmbr * (fil[2] - (realrij[2] * realrij[0] * fil[0] + realrij[2] * realrij[1] * fil[1] + realrij[2] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[0] -= rijmbr * (fil[0] - (realrij[0] * realrij[0] * fil[0] + realrij[0] * realrij[1] * fil[1] + realrij[0] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[1] -= rijmbr * (fil[1] - (realrij[1] * realrij[0] * fil[0] + realrij[1] * realrij[1] * fil[1] + realrij[1] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - fj[2] -= rijmbr * (fil[2] - (realrij[2] * realrij[0] * fil[0] + realrij[2] * realrij[1] * fil[1] + realrij[2] * realrij[2] * fil[2]) / (realrijmag * realrijmag)); - + fi[0] = -tmp2*dcosijldri[0]; + fi[1] = -tmp2*dcosijldri[1]; + fi[2] = -tmp2*dcosijldri[2]; + fj[0] = -tmp2*dcosijldrj[0]; + fj[1] = -tmp2*dcosijldrj[1]; + fj[2] = -tmp2*dcosijldrj[2]; + fl[0] = -tmp2*dcosijldrl[0]; + fl[1] = -tmp2*dcosijldrl[1]; + fl[2] = -tmp2*dcosijldrl[2]; + tmp2 = VA*.5*(tmp*wjl*g*exp(lamdaijl)*4.0*kronecker(jtype,1)); fj[0] += tmp2*(rjl[0]/rjlmag); fj[1] += tmp2*(rjl[1]/rjlmag); @@ -2275,6 +2268,7 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag fl[2] -= tmp2*(rjl[2]/rjlmag); // coordination forces + // dwik forces tmp2 = VA*.5*(tmp*dwjl*g*exp(lamdaijl))/rjlmag; @@ -2389,8 +2383,8 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag // piRC forces to J side - REBO_neighs = REBO_firstneigh[j]; - for (l = 0; l < REBO_numneigh[j]; l++) { + REBO_neighs = REBO_firstneigh[atomj]; + for (l = 0; l < REBO_numneigh[atomj]; l++) { atoml = REBO_neighs[l]; if (atoml != atomi) { ltype = map[type[atoml]]; @@ -2460,15 +2454,14 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag dN3[2] = dN3Tij[2]; atom2 = atomi; atom3 = atomj; - r32[0] = -rij[0]; - r32[1] = -rij[1]; - r32[2] = -rij[2]; - r23[0] = rij[0]; - r23[1] = rij[1]; - r23[2] = rij[2]; - r32mag = rijmag; - r23mag = rijmag; - + r32[0] = x[atom3][0]-x[atom2][0]; + r32[1] = x[atom3][1]-x[atom2][1]; + r32[2] = x[atom3][2]-x[atom2][2]; + r32mag = sqrt((r32[0]*r32[0])+(r32[1]*r32[1])+(r32[2]*r32[2])); + r23[0] = -r32[0]; + r23[1] = -r32[1]; + r23[2] = -r32[2]; + r23mag = r32mag; REBO_neighs_i = REBO_firstneigh[i]; for (k = 0; k < REBO_numneigh[i]; k++) { atomk = REBO_neighs_i[k]; @@ -2484,20 +2477,21 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag cos321 = MIN(cos321,1.0); cos321 = MAX(cos321,-1.0); sin321 = sqrt(1.0 - cos321*cos321); - if ((sin321 > TOL) && (r21mag > TOL)) { // XXX was sin321 != 0.0 sink2i = 1.0/(sin321*sin321); rik2i = 1.0/(r21mag*r21mag); rr = (rijmag*rijmag)-(r21mag*r21mag); - rjk[0] = r21[0]-rij[0]; - rjk[1] = r21[1]-rij[1]; - rjk[2] = r21[2]-rij[2]; + rjk[0] = r21[0]-r23[0]; + rjk[1] = r21[1]-r23[1]; + rjk[2] = r21[2]-r23[2]; rjk2 = (rjk[0]*rjk[0])+(rjk[1]*rjk[1])+(rjk[2]*rjk[2]); - rijrik = 2.0*rijmag*r21mag; + rijrik = 2.0*r23mag*r21mag; rik2 = r21mag*r21mag; dctik = (-rr+rjk2)/(rijrik*rik2); + dctij = (rr+rjk2)/(rijrik*r23mag*r23mag); dctjk = -2.0/rijrik; w21 = Sp(r21mag,rcmin[itype][ktype],rcmaxp[itype][ktype],dw21); + rijmag = r32mag; rikmag = r21mag; rij2 = r32mag*r32mag; rik2 = r21mag*r21mag; @@ -2515,8 +2509,8 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag r34[1] = x[atom3][1]-x[atom4][1]; r34[2] = x[atom3][2]-x[atom4][2]; r34mag = sqrt(r34[0]*r34[0] + r34[1]*r34[1] + r34[2]*r34[2]); - cos234 = -1.0*((rij[0]*r34[0])+(rij[1]*r34[1]) + - (rij[2]*r34[2]))/(rijmag*r34mag); + cos234 = (r32[0]*r34[0] + r32[1]*r34[1] + r32[2]*r34[2]) / + (r32mag*r34mag); cos234 = MIN(cos234,1.0); cos234 = MAX(cos234,-1.0); sin234 = sqrt(1.0 - cos234*cos234); @@ -2534,6 +2528,7 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag rijrjl = 2.0*r23mag*r34mag; rjl2 = r34mag*r34mag; dctjl = (-rr+ril2)/(rijrjl*rjl2); + dctji = (rr+ril2)/(rijrjl*r23mag*r23mag); dctil = -2.0/rijrjl; rjlmag = r34mag; rjl2 = r34mag*r34mag; @@ -2559,6 +2554,8 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag dt1djk = (-dctjk*sink2i*cos321); dt1djl = (rjl2i)-(dctjl*sinl2i*cos234); dt1dil = (-dctil*sinl2i*cos234); + dt1dij = (2.0/(r23mag*r23mag))-(dctij*sink2i*cos321) - + (dctji*sinl2i*cos234); dt2dik[0] = (-r23[2]*cross234[1])+(r23[1]*cross234[2]); dt2dik[1] = (-r23[0]*cross234[2])+(r23[2]*cross234[0]); @@ -2568,16 +2565,29 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag dt2djl[1] = (-r23[2]*cross321[0])+(r23[0]*cross321[2]); dt2djl[2] = (-r23[0]*cross321[1])+(r23[1]*cross321[0]); + dt2dij[0] = (r21[2]*cross234[1])-(r34[2]*cross321[1]) - + (r21[1]*cross234[2])+(r34[1]*cross321[2]); + dt2dij[1] = (r21[0]*cross234[2])-(r34[0]*cross321[2]) - + (r21[2]*cross234[0])+(r34[2]*cross321[0]); + dt2dij[2] = (r21[1]*cross234[0])-(r34[1]*cross321[0]) - + (r21[0]*cross234[1])+(r34[0]*cross321[1]); + aa = (prefactor*2.0*cw/cwnom)*w21*w34 * (1.0-tspjik)*(1.0-tspijl); aaa2 = -prefactor*(1.0-square(om1234)) * w21*w34; at2 = aa*cwnum; + fcijpc = (-dt1dij*at2)+(aaa2*dtsjik*dctij*(1.0-tspijl)) + + (aaa2*dtsijl*dctji*(1.0-tspjik)); fcikpc = (-dt1dik*at2)+(aaa2*dtsjik*dctik*(1.0-tspijl)); fcjlpc = (-dt1djl*at2)+(aaa2*dtsijl*dctjl*(1.0-tspjik)); fcjkpc = (-dt1djk*at2)+(aaa2*dtsjik*dctjk*(1.0-tspijl)); fcilpc = (-dt1dil*at2)+(aaa2*dtsijl*dctil*(1.0-tspjik)); + F23[0] = (fcijpc*r23[0])+(aa*dt2dij[0]); + F23[1] = (fcijpc*r23[1])+(aa*dt2dij[1]); + F23[2] = (fcijpc*r23[2])+(aa*dt2dij[2]); + F12[0] = (fcikpc*r21[0])+(aa*dt2dik[0]); F12[1] = (fcikpc*r21[1])+(aa*dt2dik[1]); F12[2] = (fcikpc*r21[2])+(aa*dt2dik[2]); @@ -2597,31 +2607,16 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij[3], double rijmag f1[0] = -F12[0]-F31[0]; f1[1] = -F12[1]-F31[1]; f1[2] = -F12[2]-F31[2]; - f2[0] = F12[0]+F31[0]; - f2[1] = F12[1]+F31[1]; - f2[2] = F12[2]+F31[2]; - f3[0] = F34[0]+F24[0]; - f3[1] = F34[1]+F24[1]; - f3[2] = F34[2]+F24[2]; + f2[0] = F23[0]+F12[0]+F24[0]; + f2[1] = F23[1]+F12[1]+F24[1]; + f2[2] = F23[2]+F12[2]+F24[2]; + f3[0] = -F23[0]+F34[0]+F31[0]; + f3[1] = -F23[1]+F34[1]+F31[1]; + f3[2] = -F23[2]+F34[2]+F31[2]; f4[0] = -F34[0]-F24[0]; f4[1] = -F34[1]-F24[1]; f4[2] = -F34[2]-F24[2]; - rijmbr = rcmin[itype][jtype] / realrijmag; - f2[0] += rijmbr * (F24[0] - (realrij[0] * realrij[0] * F24[0] + realrij[0] * realrij[1] * F24[1] + realrij[0] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f2[1] += rijmbr * (F24[1] - (realrij[1] * realrij[0] * F24[0] + realrij[1] * realrij[1] * F24[1] + realrij[1] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f2[2] += rijmbr * (F24[2] - (realrij[2] * realrij[0] * F24[0] + realrij[2] * realrij[1] * F24[1] + realrij[2] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[0] -= rijmbr * (F24[0] - (realrij[0] * realrij[0] * F24[0] + realrij[0] * realrij[1] * F24[1] + realrij[0] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[1] -= rijmbr * (F24[1] - (realrij[1] * realrij[0] * F24[0] + realrij[1] * realrij[1] * F24[1] + realrij[1] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - f3[2] -= rijmbr * (F24[2] - (realrij[2] * realrij[0] * F24[0] + realrij[2] * realrij[1] * F24[1] + realrij[2] * realrij[2] * F24[2]) / (realrijmag * realrijmag)); - - f2[0] -= rijmbr * (F31[0] - (realrij[0] * realrij[0] * F31[0] + realrij[0] * realrij[1] * F31[1] + realrij[0] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f2[1] -= rijmbr * (F31[1] - (realrij[1] * realrij[0] * F31[0] + realrij[1] * realrij[1] * F31[1] + realrij[1] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f2[2] -= rijmbr * (F31[2] - (realrij[2] * realrij[0] * F31[0] + realrij[2] * realrij[1] * F31[1] + realrij[2] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[0] += rijmbr * (F31[0] - (realrij[0] * realrij[0] * F31[0] + realrij[0] * realrij[1] * F31[1] + realrij[0] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[1] += rijmbr * (F31[1] - (realrij[1] * realrij[0] * F31[0] + realrij[1] * realrij[1] * F31[1] + realrij[1] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - f3[2] += rijmbr * (F31[2] - (realrij[2] * realrij[0] * F31[0] + realrij[2] * realrij[1] * F31[1] + realrij[2] * realrij[2] * F31[2]) / (realrijmag * realrijmag)); - // coordination forces tmp2 = VA*Tij*((1.0-(om1234*om1234))) * From b720f391637b4a668e7d4b7447b7bbb82c43cd17 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Wed, 5 Jul 2017 23:15:23 +0900 Subject: [PATCH 017/293] Restrictions Added --- doc/src/fix_wall_ees.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt index 075f62efaf..5b08a22935 100644 --- a/doc/src/fix_wall_ees.txt +++ b/doc/src/fix_wall_ees.txt @@ -83,7 +83,14 @@ 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).   -[Restrictions:] none +[Restrictions:] + +This fix is part of the USER-MISC package. It is only enabled if LAMMPS +was built with that package. See the "Making +LAMMPS"_Section_start.html#start_3 section for more info. + +This fix requires that atoms be ellipsoids as defined by the +"atom_style ellipsoid"_atom_style.html command. [Related commands:] From cbd8f997548f3114bf9fb18eeb24570e12b50539 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Wed, 5 Jul 2017 23:15:27 +0900 Subject: [PATCH 018/293] Restrictions Added --- doc/src/fix_wall_region_ees.txt | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt index aafde5eb69..6171291bc0 100644 --- a/doc/src/fix_wall_region_ees.txt +++ b/doc/src/fix_wall_region_ees.txt @@ -19,8 +19,8 @@ epsilon = strength factor for wall-particle interaction (energy or energy/distan sigma = size factor for wall-particle interaction (distance units) cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul -[Examples:]o -o +[Examples:] + fix wall all wall/region/ees mySphere 1.0 1.0 2.5 :pre [Description:] @@ -32,7 +32,14 @@ the EES potential introduced "fix wall/ees"_fix_wall_ees.html. Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. One may also find and exapmle of using this code in USER/ees/ under examples/ directory. -[Restrictions:] none +[Restrictions:] + +This fix is part of the USER-MISC package. It is only enabled if LAMMPS +was built with that package. See the "Making +LAMMPS"_Section_start.html#start_3 section for more info. + +This fix requires that atoms be ellipsoids as defined by the +"atom_style ellipsoid"_atom_style.html command. [Related commands:] From 8e279d4ec84e6ace7879ef6f23b911c0b2f667bc Mon Sep 17 00:00:00 2001 From: Abdo Date: Wed, 5 Jul 2017 23:16:42 +0900 Subject: [PATCH 019/293] Examples moved --- examples/USER/{ => misc}/ees/Data_region | 0 examples/USER/{ => misc}/ees/Data_wall | 0 examples/USER/{ => misc}/ees/README | 0 examples/USER/{ => misc}/ees/in.fix_wall | 0 examples/USER/{ => misc}/ees/in.fix_wall_region | 0 src/USER-MISC/README | 2 ++ src/{MISC => USER-MISC}/fix_wall_ees.cpp | 0 src/{MISC => USER-MISC}/fix_wall_ees.h | 0 src/{MISC => USER-MISC}/fix_wall_region_ees.cpp | 0 src/{MISC => USER-MISC}/fix_wall_region_ees.h | 0 10 files changed, 2 insertions(+) rename examples/USER/{ => misc}/ees/Data_region (100%) rename examples/USER/{ => misc}/ees/Data_wall (100%) rename examples/USER/{ => misc}/ees/README (100%) rename examples/USER/{ => misc}/ees/in.fix_wall (100%) rename examples/USER/{ => misc}/ees/in.fix_wall_region (100%) rename src/{MISC => USER-MISC}/fix_wall_ees.cpp (100%) rename src/{MISC => USER-MISC}/fix_wall_ees.h (100%) rename src/{MISC => USER-MISC}/fix_wall_region_ees.cpp (100%) rename src/{MISC => USER-MISC}/fix_wall_region_ees.h (100%) diff --git a/examples/USER/ees/Data_region b/examples/USER/misc/ees/Data_region similarity index 100% rename from examples/USER/ees/Data_region rename to examples/USER/misc/ees/Data_region diff --git a/examples/USER/ees/Data_wall b/examples/USER/misc/ees/Data_wall similarity index 100% rename from examples/USER/ees/Data_wall rename to examples/USER/misc/ees/Data_wall diff --git a/examples/USER/ees/README b/examples/USER/misc/ees/README similarity index 100% rename from examples/USER/ees/README rename to examples/USER/misc/ees/README diff --git a/examples/USER/ees/in.fix_wall b/examples/USER/misc/ees/in.fix_wall similarity index 100% rename from examples/USER/ees/in.fix_wall rename to examples/USER/misc/ees/in.fix_wall diff --git a/examples/USER/ees/in.fix_wall_region b/examples/USER/misc/ees/in.fix_wall_region similarity index 100% rename from examples/USER/ees/in.fix_wall_region rename to examples/USER/misc/ees/in.fix_wall_region diff --git a/src/USER-MISC/README b/src/USER-MISC/README index 52ee6cad94..37f472af1c 100644 --- a/src/USER-MISC/README +++ b/src/USER-MISC/README @@ -48,6 +48,8 @@ fix pimd, Yuxing Peng (U Chicago), yuxing at uchicago.edu, 24 Nov 2014 fix smd, Axel Kohlmeyer, akohlmey at gmail.com, 19 May 2008 fix ti/spring, Rodrigo Freitas (Unicamp/Brazil), rodrigohb at gmail.com, 7 Nov 2013 fix ttm/mod, Sergey Starikov and Vasily Pisarev (JIHT), pisarevvv at gmail.com, 2 Feb 2015 +fix wall/ees, Abdoreza Ershadinia, a.ershadinia at gmail.com, Jul 2017 +wall/region/ees, Abdoreza Ershadinia, a.ershadinia at gmail.com, Jul 2017 improper_style cossq, Georgios Vogiatzis, gvog at chemeng.ntua.gr, 25 May 12 improper_style fourier, Loukas Peristeras, loukas.peristeras at scienomics.com, 27 Oct 12 improper_style ring, Georgios Vogiatzis, gvog at chemeng.ntua.gr, 25 May 12 diff --git a/src/MISC/fix_wall_ees.cpp b/src/USER-MISC/fix_wall_ees.cpp similarity index 100% rename from src/MISC/fix_wall_ees.cpp rename to src/USER-MISC/fix_wall_ees.cpp diff --git a/src/MISC/fix_wall_ees.h b/src/USER-MISC/fix_wall_ees.h similarity index 100% rename from src/MISC/fix_wall_ees.h rename to src/USER-MISC/fix_wall_ees.h diff --git a/src/MISC/fix_wall_region_ees.cpp b/src/USER-MISC/fix_wall_region_ees.cpp similarity index 100% rename from src/MISC/fix_wall_region_ees.cpp rename to src/USER-MISC/fix_wall_region_ees.cpp diff --git a/src/MISC/fix_wall_region_ees.h b/src/USER-MISC/fix_wall_region_ees.h similarity index 100% rename from src/MISC/fix_wall_region_ees.h rename to src/USER-MISC/fix_wall_region_ees.h From 92831f185b3f2a34001c55ac5f226a153f384188 Mon Sep 17 00:00:00 2001 From: Abdo Date: Wed, 5 Jul 2017 23:23:09 +0900 Subject: [PATCH 020/293] Merge branch 'master' of https://github.com/aershadinia/lammps --- doc/src/fix_wall_ees.txt | 11 +++++++++-- doc/src/fix_wall_region_ees.txt | 14 +++++++++++--- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt index 54511ffba7..5b08a22935 100644 --- a/doc/src/fix_wall_ees.txt +++ b/doc/src/fix_wall_ees.txt @@ -66,7 +66,7 @@ particle and wall no longer interact. Also,  sigma_n is the distance between c :c,image(JPG/fix_wall_ees_image.jpg)   -Details of using this command and specifications are the same as fix/wall command.  +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 effective Hamaker constant with energy units for the strength of the @@ -83,7 +83,14 @@ 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).   -[Restrictions:] none +[Restrictions:] + +This fix is part of the USER-MISC package. It is only enabled if LAMMPS +was built with that package. See the "Making +LAMMPS"_Section_start.html#start_3 section for more info. + +This fix requires that atoms be ellipsoids as defined by the +"atom_style ellipsoid"_atom_style.html command. [Related commands:] diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt index efb417add1..6171291bc0 100644 --- a/doc/src/fix_wall_region_ees.txt +++ b/doc/src/fix_wall_region_ees.txt @@ -19,8 +19,8 @@ epsilon = strength factor for wall-particle interaction (energy or energy/distan sigma = size factor for wall-particle interaction (distance units) cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul -[Examples:]o -o +[Examples:] + fix wall all wall/region/ees mySphere 1.0 1.0 2.5 :pre [Description:] @@ -30,8 +30,16 @@ as a bounding wall which interacts with nearby ellipsoidal particles according t the EES potential introduced "fix wall/ees"_fix_wall_ees.html. Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. +One may also find and exapmle of using this code in USER/ees/ under examples/ directory. -[Restrictions:] none +[Restrictions:] + +This fix is part of the USER-MISC package. It is only enabled if LAMMPS +was built with that package. See the "Making +LAMMPS"_Section_start.html#start_3 section for more info. + +This fix requires that atoms be ellipsoids as defined by the +"atom_style ellipsoid"_atom_style.html command. [Related commands:] From 9fa4588eb72096f35d6a9fac311a280625861929 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Wed, 5 Jul 2017 23:46:48 +0900 Subject: [PATCH 021/293] fixed a typo --- src/USER-MISC/README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/USER-MISC/README b/src/USER-MISC/README index 37f472af1c..901338c562 100644 --- a/src/USER-MISC/README +++ b/src/USER-MISC/README @@ -49,7 +49,7 @@ fix smd, Axel Kohlmeyer, akohlmey at gmail.com, 19 May 2008 fix ti/spring, Rodrigo Freitas (Unicamp/Brazil), rodrigohb at gmail.com, 7 Nov 2013 fix ttm/mod, Sergey Starikov and Vasily Pisarev (JIHT), pisarevvv at gmail.com, 2 Feb 2015 fix wall/ees, Abdoreza Ershadinia, a.ershadinia at gmail.com, Jul 2017 -wall/region/ees, Abdoreza Ershadinia, a.ershadinia at gmail.com, Jul 2017 +fix wall/region/ees, Abdoreza Ershadinia, a.ershadinia at gmail.com, Jul 2017 improper_style cossq, Georgios Vogiatzis, gvog at chemeng.ntua.gr, 25 May 12 improper_style fourier, Loukas Peristeras, loukas.peristeras at scienomics.com, 27 Oct 12 improper_style ring, Georgios Vogiatzis, gvog at chemeng.ntua.gr, 25 May 12 From 1bf1cb150faefd84910a89be70b6823ff3a34e5c Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 18:26:32 +0200 Subject: [PATCH 022/293] Updated credits --- src/MANYBODY/pair_airebo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index a33abfcb63..5c022cedb2 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -15,7 +15,7 @@ Contributing author: Ase Henry (MIT) Bugfixes and optimizations: Marcel Fallet & Steve Stuart (Clemson), Axel Kohlmeyer (Temple U), - Markus Hoehnerbach (RWTH Aachen), Github user CF17 + Markus Hoehnerbach (RWTH Aachen), Cyril Falvo (Universite Paris Sud) AIREBO-M modification to optionally replace LJ with Morse potentials. Thomas C. O'Connor (JHU) 2014 ------------------------------------------------------------------------- */ From 6eddc1a2ee772ec7c2aa0dcdbd68402f2c0702c9 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 12:33:41 -0400 Subject: [PATCH 023/293] coding style and whitespace cleanup to match LAMMPS style --- src/USER-MISC/fix_wall_ees.cpp | 66 ++-- src/USER-MISC/fix_wall_region_ees.cpp | 478 ++++++++++++-------------- src/USER-MISC/fix_wall_region_ees.h | 8 +- 3 files changed, 271 insertions(+), 281 deletions(-) diff --git a/src/USER-MISC/fix_wall_ees.cpp b/src/USER-MISC/fix_wall_ees.cpp index 8ccadf274a..9b65d1e30f 100644 --- a/src/USER-MISC/fix_wall_ees.cpp +++ b/src/USER-MISC/fix_wall_ees.cpp @@ -11,13 +11,25 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include "math.h" +/* ---------------------------------------------------------------------- + Contributing author: Abdoreza Ershadinia, a.ershadinia at gmail.com +------------------------------------------------------------------------- */ + +#include #include "math_extra.h" #include "fix_wall_ees.h" #include "atom.h" #include "atom_vec.h" #include "atom_vec_ellipsoid.h" +#include "domain.h" +#include "region.h" +#include "force.h" +#include "lattice.h" +#include "update.h" +#include "output.h" +#include "respa.h" #include "error.h" +#include "math_extra.h" using namespace LAMMPS_NS; using namespace FixConst; @@ -96,13 +108,13 @@ void FixWallEES::wall_particle(int m, int which, double coord) for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { - if (side < 0) - delta = x[i][dim] - coord; + if (side < 0) + delta = x[i][dim] - coord; else - delta = coord - x[i][dim]; + delta = coord - x[i][dim]; if (delta >= cutoff[m]) - continue; + continue; double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; double tempvec[3]= {0,0,0}; @@ -168,37 +180,37 @@ void FixWallEES::wall_particle(int m, int which, double coord) hms = delta - sigman; fwall = side*( - -1*coeff4[m]/hhss2 + - coeff3[m] * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 - ); - f[i][dim] -= fwall; + -1*coeff4[m]/hhss2 + + coeff3[m] * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 + ); + f[i][dim] -= fwall; - ewall[0] += -1*coeff2[m] * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + - coeff1[m] * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + ewall[0] += -1*coeff2[m] * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + + coeff1[m] * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; - ewall[m+1] += fwall; + ewall[m+1] += fwall; - twall = coeff6[m] * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + - coeff5[m] * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + twall = coeff6[m] * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + + coeff5[m] * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; - MathExtra::matvec(Lx,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[0] = MathExtra::dot3(SAn,tempvec2); + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); - MathExtra::matvec(Ly,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[1] = MathExtra::dot3(SAn,tempvec2); + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); - MathExtra::matvec(Lz,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; - that[2] = MathExtra::dot3(SAn,tempvec2); + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); - for(int j = 0; j<3 ; j++) + for(int j = 0; j<3 ; j++) tor[i][j] += twall * that[j]; } diff --git a/src/USER-MISC/fix_wall_region_ees.cpp b/src/USER-MISC/fix_wall_region_ees.cpp index 20a5f74c15..e070e2a221 100644 --- a/src/USER-MISC/fix_wall_region_ees.cpp +++ b/src/USER-MISC/fix_wall_region_ees.cpp @@ -1,4 +1,4 @@ -/* -*- c++ -*- ---------------------------------------------------------- +/* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories Steve Plimpton, sjplimp@sandia.gov @@ -10,10 +10,14 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -#include -#include "math.h" -#include "stdlib.h" -#include "string.h" + +/* ---------------------------------------------------------------------- + Contributing author: Abdoreza Ershadinia, a.ershadinia at gmail.com +------------------------------------------------------------------------- */ + +#include +#include +#include #include "fix_wall_region_ees.h" #include "atom.h" #include "atom_vec.h" @@ -31,117 +35,109 @@ using namespace LAMMPS_NS; using namespace FixConst; -enum{LJ93,LJ126,COLLOID,HARMONIC,EES};//me - /* ---------------------------------------------------------------------- */ -/// USAGE: -/// fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff -/// + FixWallRegionEES::FixWallRegionEES(LAMMPS *lmp, int narg, char **arg) : - Fix(lmp, narg, arg) + Fix(lmp, narg, arg) { - if (narg != 7) error->all(FLERR,"Illegal fix wall/region/ees command"); - scalar_flag = 1; - vector_flag = 1; - size_vector = 3; - global_freq = 1; - extscalar = 1; - extvector = 1; + if (narg != 7) error->all(FLERR,"Illegal fix wall/region/ees command"); + scalar_flag = 1; + vector_flag = 1; + size_vector = 3; + global_freq = 1; + extscalar = 1; + extvector = 1; - // parse args + // parse args - iregion = domain->find_region(arg[3]); - if (iregion == -1) - error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); - int n = strlen(arg[3]) + 1; - idregion = new char[n]; - strcpy(idregion,arg[3]); + iregion = domain->find_region(arg[3]); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + int n = strlen(arg[3]) + 1; + idregion = new char[n]; + strcpy(idregion,arg[3]); + epsilon = force->numeric(FLERR,arg[4]); + sigma = force->numeric(FLERR,arg[5]); + cutoff = force->numeric(FLERR,arg[6]); + if (cutoff <= 0.0) error->all(FLERR,"Fix wall/region/ees cutoff <= 0.0"); - epsilon = force->numeric(FLERR,arg[4]); - sigma = force->numeric(FLERR,arg[5]); - cutoff = force->numeric(FLERR,arg[6]); - - if (cutoff <= 0.0) error->all(FLERR,"Fix wall/region/ees cutoff <= 0.0"); - - eflag = 0; - ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; } /* ---------------------------------------------------------------------- */ FixWallRegionEES::~FixWallRegionEES() { - delete [] idregion; + delete [] idregion; } /* ---------------------------------------------------------------------- */ int FixWallRegionEES::setmask() { - int mask = 0; - mask |= POST_FORCE; - mask |= THERMO_ENERGY; - mask |= POST_FORCE_RESPA; - mask |= MIN_POST_FORCE; - return mask; + int mask = 0; + mask |= POST_FORCE; + mask |= THERMO_ENERGY; + mask |= POST_FORCE_RESPA; + mask |= MIN_POST_FORCE; + return mask; } /* ---------------------------------------------------------------------- */ void FixWallRegionEES::init() { - // set index and check validity of region + // set index and check validity of region - iregion = domain->find_region(idregion); - if (iregion == -1) - error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + iregion = domain->find_region(idregion); + if (iregion == -1) + error->all(FLERR,"Region ID for fix wall/region/ees does not exist"); + + avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); + if (!avec) + error->all(FLERR,"Fix wall/region/ees requires atom style ellipsoid"); + + // check that all particles are finite-size ellipsoids + // no point particles allowed, spherical is OK + + int *ellipsoid = atom->ellipsoid; + int *mask = atom->mask; + int nlocal = atom->nlocal; + + for (int i = 0; i < nlocal; i++) + if (mask[i] & groupbit) + if (ellipsoid[i] < 0) + error->one(FLERR,"Fix wall/region/ees requires extended particles"); + + // setup coefficients + + coeff1 = ( 2. / 4725. ) * epsilon * pow(sigma,12.0); + coeff2 = ( 1. / 24. ) * epsilon * pow(sigma,6.0); + coeff3 = ( 2. / 315. ) * epsilon * pow(sigma,12.0); + coeff4 = ( 1. / 3. ) * epsilon * pow(sigma,6.0); + coeff5 = ( 4. / 315. ) * epsilon * pow(sigma,12.0); + coeff6 = ( 1. / 12. ) * epsilon * pow(sigma,6.0); + offset = 0; - avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - if (!avec) - error->all(FLERR,"Fix wall/region/ees requires atom style ellipsoid"); - - // check that all particles are finite-size ellipsoids - // no point particles allowed, spherical is OK - - int *ellipsoid = atom->ellipsoid; - int *mask = atom->mask; - int nlocal = atom->nlocal; - - for (int i = 0; i < nlocal; i++) - if (mask[i] & groupbit) - if (ellipsoid[i] < 0) - error->one(FLERR,"Fix wall/region/ees requires extended particles"); - - - // setup coefficients for each style - - coeff1 = ( 2. / 4725. ) * epsilon * pow(sigma,12.0); - coeff2 = ( 1. / 24. ) * epsilon * pow(sigma,6.0); - coeff3 = ( 2. / 315. ) * epsilon * pow(sigma,12.0); - coeff4 = ( 1. / 3. ) * epsilon * pow(sigma,6.0); - coeff5 = ( 4. / 315. ) * epsilon * pow(sigma,12.0); - coeff6 = ( 1. / 12. ) * epsilon * pow(sigma,6.0); - offset = 0; - - - if (strstr(update->integrate_style,"respa")) - nlevels_respa = ((Respa *) update->integrate)->nlevels; + if (strstr(update->integrate_style,"respa")) + nlevels_respa = ((Respa *) update->integrate)->nlevels; } /* ---------------------------------------------------------------------- */ void FixWallRegionEES::setup(int vflag) { - if (strstr(update->integrate_style,"verlet")) - post_force(vflag); - else { - ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); - post_force_respa(vflag,nlevels_respa-1,0); - ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); - } + if (strstr(update->integrate_style,"verlet")) + post_force(vflag); + else { + ((Respa *) update->integrate)->copy_flevel_f(nlevels_respa-1); + post_force_respa(vflag,nlevels_respa-1,0); + ((Respa *) update->integrate)->copy_f_flevel(nlevels_respa-1); + } } /* ---------------------------------------------------------------------- */ @@ -155,121 +151,111 @@ void FixWallRegionEES::min_setup(int vflag) void FixWallRegionEES::post_force(int vflag) { - //me - //sth is needed here, but I dont know what - //that is calculation of sn + //sth is needed here, but I dont know what + //that is calculation of sn - int i,m,n; - double rinv,fx,fy,fz,tooclose[3];//me - double sn;//me + int i,m,n; + double rinv,fx,fy,fz,sn,tooclose[3]; - eflag = 0; - ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; + eflag = 0; + ewall[0] = ewall[1] = ewall[2] = ewall[3] = 0.0; - double **x = atom->x; - double **f = atom->f; - double *radius = atom->radius; + double **x = atom->x; + double **f = atom->f; + double **tor = atom->torque; - double **tor = atom->torque; //me + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid; - //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid");//me - AtomVecEllipsoid::Bonus *bonus = avec->bonus;//me - int *ellipsoid = atom->ellipsoid;//me + int *mask = atom->mask; + int nlocal = atom->nlocal; - int *mask = atom->mask; - int nlocal = atom->nlocal; + Region *region = domain->regions[iregion]; + region->prematch(); - Region *region = domain->regions[iregion]; - region->prematch(); + int onflag = 0; - int onflag = 0; + // region->match() insures particle is in region or on surface, else error + // if returned contact dist r = 0, is on surface, also an error + // in COLLOID case, r <= radius is an error - // region->match() insures particle is in region or on surface, else error - // if returned contact dist r = 0, is on surface, also an error - // in COLLOID case, r <= radius is an error + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) { + if (!region->match(x[i][0],x[i][1],x[i][2])) { + onflag = 1; + continue; + } - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) { - if (!region->match(x[i][0],x[i][1],x[i][2])) { - onflag = 1; - continue; - } + double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double sn2 = 0.0; + double nhat[3] = {0,0,0}; + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); - double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; - double tempvec[3]= {0,0,0}; - double sn2 = 0.0; - double nhat[3] = {0,0,0}; - double* shape = bonus[ellipsoid[i]].shape;; - MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + for(int which = 0 ; which < 3; which ++){//me + nhat[which]=1; + nhat[(which+1)%3] = 0 ; + nhat[(which+2)%3] = 0 ; + sn2 = 0 ; + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3 ; k++) sn2 += tempvec[k]*tempvec[k]; + sn = sqrt(sn2); + tooclose[which] = sn; + } - for(int which = 0 ; which < 3; which ++){//me - nhat[which]=1; - nhat[(which+1)%3] = 0 ; - nhat[(which+2)%3] = 0 ; - sn2 = 0 ; - MathExtra::transpose_matvec(A,nhat,tempvec); - for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; - for(int k = 0; k<3 ; k++) sn2 += tempvec[k]*tempvec[k]; - sn = sqrt(sn2); - tooclose[which] = sn; - } + n = region->surface(x[i][0],x[i][1],x[i][2],cutoff); + for (m = 0; m < n; m++) { + if (region->contact[m].delx != 0 && region->contact[m].r <= tooclose[0]){ + onflag = 1; + continue; + } else if (region->contact[m].dely != 0 && region->contact[m].r <= tooclose[1]){ + onflag = 1; + continue; + } else if (region->contact[m].delz !=0 && region->contact[m].r <= tooclose[2]){ + onflag = 1; + continue; + } else rinv = 1.0/region->contact[m].r; - n = region->surface(x[i][0],x[i][1],x[i][2],cutoff); + ees(m,i); - for (m = 0; m < n; m++) { + ewall[0] += eng; + fx = fwall * region->contact[m].delx * rinv; + fy = fwall * region->contact[m].dely * rinv; + fz = fwall * region->contact[m].delz * rinv; + f[i][0] += fx; + f[i][1] += fy; + f[i][2] += fz; - if(region->contact[m].delx != 0 && region->contact[m].r <= tooclose[0] ){ - onflag = 1; - continue; + ewall[1] -= fx; + ewall[2] -= fy; + ewall[3] -= fz; - }else if (region->contact[m].dely != 0 && region->contact[m].r <= tooclose[1]){ - onflag = 1; - continue; - }else if (region->contact[m].delz !=0 && region->contact[m].r <= tooclose[2]){ - onflag = 1; - continue; - } - else rinv = 1.0/region->contact[m].r; + tor[i][0] += torque[0]; + tor[i][1] += torque[1]; + tor[i][2] += torque[2]; + } + } - ees(m,i);//me - - ewall[0] += eng; - fx = fwall * region->contact[m].delx * rinv; - fy = fwall * region->contact[m].dely * rinv; - fz = fwall * region->contact[m].delz * rinv; - f[i][0] += fx; - f[i][1] += fy; - f[i][2] += fz; - - ewall[1] -= fx; - ewall[2] -= fy; - ewall[3] -= fz; - - tor[i][0] += torque[0]; - tor[i][1] += torque[1]; - tor[i][2] += torque[2]; - - } - } - - if (onflag) error->one(FLERR,"Particle on or inside surface of region " - "used in fix wall/region/ees"); + if (onflag) error->one(FLERR,"Particle on or inside surface of region " + "used in fix wall/region/ees"); } /* ---------------------------------------------------------------------- */ void FixWallRegionEES::post_force_respa(int vflag, int ilevel, int iloop) { - if (ilevel == nlevels_respa-1) post_force(vflag); + if (ilevel == nlevels_respa-1) post_force(vflag); } /* ---------------------------------------------------------------------- */ void FixWallRegionEES::min_post_force(int vflag) { - post_force(vflag); + post_force(vflag); } /* ---------------------------------------------------------------------- @@ -278,13 +264,13 @@ void FixWallRegionEES::min_post_force(int vflag) double FixWallRegionEES::compute_scalar() { - // only sum across procs one time + // only sum across procs one time - if (eflag == 0) { - MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); - eflag = 1; - } - return ewall_all[0]; + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[0]; } /* ---------------------------------------------------------------------- @@ -293,18 +279,15 @@ double FixWallRegionEES::compute_scalar() double FixWallRegionEES::compute_vector(int n) { - // only sum across procs one time + // only sum across procs one time - if (eflag == 0) { - MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); - eflag = 1; - } - return ewall_all[n+1]; + if (eflag == 0) { + MPI_Allreduce(ewall,ewall_all,4,MPI_DOUBLE,MPI_SUM,world); + eflag = 1; + } + return ewall_all[n+1]; } - - -//me /* ---------------------------------------------------------------------- EES interaction for ellipsoid particle with wall compute eng and fwall and twall = magnitude of wall force and torque @@ -312,94 +295,89 @@ double FixWallRegionEES::compute_vector(int n) void FixWallRegionEES::ees(int m, int i) { - Region *region = domain->regions[iregion]; - region->prematch(); + Region *region = domain->regions[iregion]; + region->prematch(); - double delta = 0.0, delta2 = 0.0, delta3 = 0.0, delta4 = 0.0, delta5 = 0.0, delta6 = 0.0; - double sigman = 0.0, sigman2 = 0.0 , sigman3 = 0.0, sigman4 = 0.0, sigman5 = 0.0, sigman6 = 0.0; - double hhss = 0.0, hhss2 = 0.0, hhss4 = 0.0, hhss7 = 0.0, hhss8 = 0.0; //h^2 - s_n^2 - double hps = 0.0; //h+s_n - double hms = 0.0; //h-s_n - double twall = 0.0; - double tempvec[3]={0,0,0}; - double tempvec2[3]= {0,0,0}; + double delta, delta2, delta3, delta4, delta5, delta6; + double sigman, sigman2 , sigman3, sigman4, sigman5, sigman6; + double hhss, hhss2, hhss4, hhss7, hhss8; //h^2 - s_n^2 + double hps; //h+s_n + double hms; //h-s_n + double twall; - double SAn[3] = {0,0,0}; - double that[3] = {0,0,0}; + double A[3][3], nhat[3], SAn[3], that[3]; - double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; - double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; - double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; + double tempvec[3]= {0,0,0}; + double tempvec2[3]= {0,0,0}; - double A[3][3] = {{0,0,0},{0,0,0},{0,0,0}}; - double nhat[3] = {0,0,0}; + double Lx[3][3] = {{0,0,0},{0,0,-1},{0,1,0}}; + double Ly[3][3] = {{0,0,1},{0,0,0},{-1,0,0}}; + double Lz[3][3] = {{0,-1,0},{1,0,0},{0,0,0}}; - nhat[0] = region->contact[m].delx / region->contact[m].r; - nhat[1] = region->contact[m].dely / region->contact[m].r; - nhat[2] = region->contact[m].delz / region->contact[m].r; + nhat[0] = region->contact[m].delx / region->contact[m].r; + nhat[1] = region->contact[m].dely / region->contact[m].r; + nhat[2] = region->contact[m].delz / region->contact[m].r; - //avec = (AtomVecEllipsoid *) atom->style_match("ellipsoid"); - AtomVecEllipsoid::Bonus *bonus = avec->bonus; - int *ellipsoid = atom->ellipsoid;//me + AtomVecEllipsoid::Bonus *bonus = avec->bonus; + int *ellipsoid = atom->ellipsoid; - double* shape = bonus[ellipsoid[i]].shape;; - MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); + double* shape = bonus[ellipsoid[i]].shape;; + MathExtra::quat_to_mat(bonus[ellipsoid[i]].quat,A); - MathExtra::transpose_matvec(A,nhat,tempvec); - for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; - for(int k = 0; k<3 ; k++) sigman2 += tempvec[k]*tempvec[k]; - for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + sigman2 = 0.0; + MathExtra::transpose_matvec(A,nhat,tempvec); + for(int k = 0; k<3; k++) tempvec[k] *= shape[k]; + for(int k = 0; k<3; k++) sigman2 += tempvec[k]*tempvec[k]; + for(int k = 0; k<3; k++) SAn[k] = tempvec[k]; + sigman = sqrt(sigman2); + delta = fabs(region->contact[m].r); - sigman = sqrt(sigman2); - delta = fabs(region->contact[m].r); + sigman3 = sigman2 * sigman; + sigman4 = sigman2 * sigman2; + sigman5 = sigman4 * sigman; + sigman6 = sigman3 * sigman3; - sigman3 = sigman2 * sigman; - sigman4 = sigman2 * sigman2; - sigman5 = sigman4 * sigman; - sigman6 = sigman3 * sigman3; + delta2 = delta * delta; + delta3 = delta2 * delta; + delta4 = delta2 * delta2; + delta5 = delta3 * delta2; + delta6 = delta3 * delta3; - delta2 = delta * delta; - delta3 = delta2 * delta; - delta4 = delta2 * delta2; - delta5 = delta3 * delta2; - delta6 = delta3 * delta3; + hhss = delta2 - sigman2; + hhss2 = hhss * hhss; + hhss4 = hhss2 * hhss2; + hhss8 = hhss4 * hhss4; + hhss7 = hhss4 * hhss2 * hhss; - hhss = delta2 - sigman2; - hhss2 = hhss * hhss; - hhss4 = hhss2 * hhss2; - hhss8 = hhss4 * hhss4; - hhss7 = hhss4 * hhss2 * hhss; + hps = delta + sigman; + hms = delta - sigman; - hps = delta + sigman; - hms = delta - sigman; + fwall = -1*coeff4/hhss2 + coeff3 + * (21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6) / hhss8; - fwall = -1*coeff4/hhss2 + - coeff3 * ( 21*delta6 + 63*delta4*sigman2 + 27*delta2*sigman4 + sigman6 ) / hhss8 - ; + eng = -1*coeff2 * (4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3) + + coeff1 * (35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4) / hhss7; - eng = -1*coeff2 * ( 4*delta/sigman2/hhss + 2*log(hms/hps)/sigman3 ) + - coeff1 * ( 35*delta5 + 70*delta3*sigman2 + 15*delta*sigman4 ) / hhss7; + twall = coeff6 * (6*delta3/sigman4/hhss2 - 10*delta/sigman2/hhss2 + + 3*log(hms/hps)/sigman5) + + coeff5 * (21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4) / hhss8; - twall = coeff6 * ( 6.*delta3/sigman4/hhss2 - 10.*delta/sigman2/hhss2 + 3.*log(hms/hps)/sigman5 ) + - coeff5 * ( 21.*delta5 + 30.*delta3*sigman2 + 5.*delta*sigman4 ) / hhss8 ; + MathExtra::matvec(Lx,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[0] = MathExtra::dot3(SAn,tempvec2); - MathExtra::matvec(Lx,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[0] = MathExtra::dot3(SAn,tempvec2); + MathExtra::matvec(Ly,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; + that[1] = MathExtra::dot3(SAn,tempvec2); - MathExtra::matvec(Ly,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k<3; k++) tempvec2[k] *= shape[k]; - that[1] = MathExtra::dot3(SAn,tempvec2); - - MathExtra::matvec(Lz,nhat,tempvec); - MathExtra::transpose_matvec(A,tempvec,tempvec2); - for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; - that[2] = MathExtra::dot3(SAn,tempvec2); - - for(int j = 0; j<3 ; j++) - torque[j] = twall * that[j]; + MathExtra::matvec(Lz,nhat,tempvec); + MathExtra::transpose_matvec(A,tempvec,tempvec2); + for(int k = 0; k < 3; k++) tempvec2[k] *= shape[k]; + that[2] = MathExtra::dot3(SAn,tempvec2); + for(int j = 0; j<3 ; j++) + torque[j] = twall * that[j]; } diff --git a/src/USER-MISC/fix_wall_region_ees.h b/src/USER-MISC/fix_wall_region_ees.h index 59679a0b41..9da2cccce6 100644 --- a/src/USER-MISC/fix_wall_region_ees.h +++ b/src/USER-MISC/fix_wall_region_ees.h @@ -40,7 +40,7 @@ class FixWallRegionEES : public Fix { double compute_vector(int); private: - class AtomVecEllipsoid *avec;//me + class AtomVecEllipsoid *avec; int iregion; double epsilon,sigma,cutoff; @@ -50,11 +50,11 @@ class FixWallRegionEES : public Fix { char *idregion; double coeff1,coeff2,coeff3,coeff4,offset; - double coeff5, coeff6;//me + double coeff5, coeff6; double eng,fwall; - double torque[3];//me + double torque[3]; - void ees(int, int);//me + void ees(int, int); }; } From d451dbb1a0791d837bd017965976610ec942ee3d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 13:54:56 -0400 Subject: [PATCH 024/293] adjust EES wall input example to print out some thermodynamic info that can be used for testing --- examples/USER/misc/ees/Data_region | 2 +- examples/USER/misc/ees/Data_wall | 4 ++-- examples/USER/misc/ees/in.fix_wall | 10 ++++++++-- examples/USER/misc/ees/in.fix_wall_region | 7 +++++-- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/examples/USER/misc/ees/Data_region b/examples/USER/misc/ees/Data_region index 80eefeafe6..1b3dc65dde 100644 --- a/examples/USER/misc/ees/Data_region +++ b/examples/USER/misc/ees/Data_region @@ -15,7 +15,7 @@ atom-ID atom-type ellipsoidflag density x y z Ellipsoids atom-ID shapex shapey shapez quatw quati quatj quatk -1 14 6 8 0.89453 0.44700 0 0 +1 14 6 8 0.89453 0.44700 0 0 2 14 6 8 0.25755 0 0.96626 0 3 14 6 8 0.95009 0 0 0.31197 diff --git a/examples/USER/misc/ees/Data_wall b/examples/USER/misc/ees/Data_wall index 27fa6c5990..c4693e33fb 100644 --- a/examples/USER/misc/ees/Data_wall +++ b/examples/USER/misc/ees/Data_wall @@ -8,12 +8,12 @@ Atoms atom-ID atom-type ellipsoidflag density x y z -1 1 1 1 30 30 30 +1 1 1 1 30 30 50 Ellipsoids atom-ID shapex shapey shapez quatw quati quatj quatk -1 14 6 8 0.44700 0 0.89453 0 +1 14 6 8 0.44700 0 0.89453 0 Velocities diff --git a/examples/USER/misc/ees/in.fix_wall b/examples/USER/misc/ees/in.fix_wall index 94db4c3b15..6ea3b67d3b 100644 --- a/examples/USER/misc/ees/in.fix_wall +++ b/examples/USER/misc/ees/in.fix_wall @@ -10,9 +10,14 @@ pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 timestep 0.0001 #------------------------------------# +compute temp all temp/asphere +thermo_modify temp temp + fix EES_substrate all wall/ees zhi EDGE 10 1 10 zlo EDGE 10 1 10 #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# +thermo_style custom step temp press etotal f_EES_substrate f_EES_substrate[1] + fix NVT all nve/asphere #------------------------------------# compute qw all property/atom quatw @@ -20,6 +25,7 @@ compute qi all property/atom quati compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# -dump 1 all custom 5000 dump1 id type x y z c_qw c_qi c_qj c_qk -run 2000000 +thermo 500 +dump 1 all custom 500 dump1 id type x y z c_qw c_qi c_qj c_qk +run 2000 diff --git a/examples/USER/misc/ees/in.fix_wall_region b/examples/USER/misc/ees/in.fix_wall_region index d457deae44..655fb6e724 100644 --- a/examples/USER/misc/ees/in.fix_wall_region +++ b/examples/USER/misc/ees/in.fix_wall_region @@ -15,6 +15,8 @@ timestep 0.0001 fix EES_block all wall/region/ees the_wall 10. 1. 20 #^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# +thermo_style custom step temp press etotal f_EES_block[1] f_EES_block[3] + fix NVT all nve/asphere #------------------------------------# compute qw all property/atom quatw @@ -22,6 +24,7 @@ compute qi all property/atom quati compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# -dump 1 all custom 5000 dump1 id type x y z c_qw c_qi c_qj c_qk -run 2000000 +thermo 500 +#dump 1 all custom 500 dump1 id type x y z c_qw c_qi c_qj c_qk +run 2000 From 894e0c3cf5064ab4f524d6cf0a25e564a65a6c1b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 16:19:24 -0400 Subject: [PATCH 025/293] simplify parsing of optional arguments --- src/MANYBODY/pair_airebo.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 5c022cedb2..26800a75d3 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -157,13 +157,11 @@ void PairAIREBO::settings(int narg, char **arg) cutlj = force->numeric(FLERR,arg[0]); - if (narg == 3) { + if (narg >= 3) { ljflag = force->inumeric(FLERR,arg[1]); torflag = force->inumeric(FLERR,arg[2]); } if (narg == 4) { - ljflag = force->inumeric(FLERR,arg[1]); - torflag = force->inumeric(FLERR,arg[2]); sigcut = cutlj; sigmin = force->numeric(FLERR,arg[3]); sigwid = sigcut - sigmin; From 8c3f6947ad480fd6cf22809331af916b99c76146 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 16:19:59 -0400 Subject: [PATCH 026/293] remove unused variables to silence compiler warnings --- src/MANYBODY/pair_airebo.cpp | 8 +++----- src/USER-OMP/pair_airebo_omp.cpp | 7 +++---- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 26800a75d3..1b248f701c 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -534,7 +534,7 @@ void PairAIREBO::FLJ(int eflag, int vflag) double delij[3],rijsq,delik[3],rik,deljk[3]; double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb; double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2; - double rljmin,rljmax,sigcut,sigmin,sigwid; + double rljmin,rljmax,sigcut,sigmin; double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3]; int *ilist,*jlist,*numneigh,**firstneigh; int *REBO_neighs_i,*REBO_neighs_k; @@ -552,8 +552,6 @@ void PairAIREBO::FLJ(int eflag, int vflag) rljmax = 0.0; sigcut = 0.0; sigmin = 0.0; - sigwid = 0.0; - double **x = atom->x; double **f = atom->f; @@ -2133,13 +2131,13 @@ double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mo double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; double fcikpc,fcjlpc,fcjkpc,fcilpc,fcijpc; - double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; + double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3]; double f1[3],f2[3],f3[3],f4[4]; - double dcut321,PijS,PjiS; + double PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index 2fd6c93f03..bc83ff8e4b 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -294,7 +294,7 @@ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, double delij[3],rijsq,delik[3],rik,deljk[3]; double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb; double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2; - double rljmin,rljmax,sigcut,sigmin,sigwid; + double rljmin,rljmax,sigcut,sigmin; double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3]; int *ilist,*jlist,*numneigh,**firstneigh; int *REBO_neighs_i,*REBO_neighs_k; @@ -312,7 +312,6 @@ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, rljmax = 0.0; sigcut = 0.0; sigmin = 0.0; - sigwid = 0.0; const double * const * const x = atom->x; double * const * const f = thr->get_f(); @@ -1894,13 +1893,13 @@ double PairAIREBOOMP::bondorderLJ_thr(int i, int j, double rij_mod[3], double ri double w21,dw21,r34[3],r34mag,cos234,w34,dw34; double cross321[3],cross234[3],prefactor,SpN; double fcikpc,fcjlpc,fcjkpc,fcilpc,fcijpc; - double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa1,aaa2,at2,cw,cwnum,cwnom; + double dt2dik[3],dt2djl[3],dt2dij[3],aa,aaa2,at2,cw,cwnum,cwnom; double sin321,sin234,rr,rijrik,rijrjl,rjk2,rik2,ril2,rjl2; double dctik,dctjk,dctjl,dctij,dctji,dctil,rik2i,rjl2i,sink2i,sinl2i; double rjk[3],ril[3],dt1dik,dt1djk,dt1djl,dt1dil,dt1dij; double F23[3],F12[3],F34[3],F31[3],F24[3],fi[3],fj[3],fk[3],fl[3]; double f1[3],f2[3],f3[3],f4[4]; - double dcut321,PijS,PjiS; + double PijS,PjiS; double rij2,tspjik,dtsjik,tspijl,dtsijl,costmp; int *REBO_neighs,*REBO_neighs_i,*REBO_neighs_j,*REBO_neighs_k,*REBO_neighs_l; double tmppij,tmppji,dN2PIJ[2],dN2PJI[2],dN3piRC[3],dN3Tij[3]; From e493b6a648b268a86654824d09536bd846e618d1 Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Wed, 5 Jul 2017 22:52:29 +0200 Subject: [PATCH 027/293] Fix sigcut class variable actually used --- src/MANYBODY/pair_airebo.cpp | 4 +--- src/USER-OMP/pair_airebo_omp.cpp | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 1b248f701c..67e1e5262a 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -534,7 +534,7 @@ void PairAIREBO::FLJ(int eflag, int vflag) double delij[3],rijsq,delik[3],rik,deljk[3]; double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb; double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2; - double rljmin,rljmax,sigcut,sigmin; + double rljmin,rljmax; double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3]; int *ilist,*jlist,*numneigh,**firstneigh; int *REBO_neighs_i,*REBO_neighs_k; @@ -550,8 +550,6 @@ void PairAIREBO::FLJ(int eflag, int vflag) evdwl = 0.0; rljmin = 0.0; rljmax = 0.0; - sigcut = 0.0; - sigmin = 0.0; double **x = atom->x; double **f = atom->f; diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index bc83ff8e4b..73529847f2 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -294,7 +294,7 @@ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, double delij[3],rijsq,delik[3],rik,deljk[3]; double rkj,wkj,dC,VLJ,dVLJ,VA,Str,dStr,Stb; double vdw,slw,dvdw,dslw,drij,swidth,tee,tee2; - double rljmin,rljmax,sigcut,sigmin; + double rljmin,rljmax; double delkm[3],rkm,deljm[3],rmj,wmj,r2inv,r6inv,scale,delscale[3]; int *ilist,*jlist,*numneigh,**firstneigh; int *REBO_neighs_i,*REBO_neighs_k; @@ -310,8 +310,6 @@ void PairAIREBOOMP::FLJ_thr(int ifrom, int ito, int evflag, int eflag, evdwl = 0.0; rljmin = 0.0; rljmax = 0.0; - sigcut = 0.0; - sigmin = 0.0; const double * const * const x = atom->x; double * const * const f = thr->get_f(); From fa469ae1d0b2de105594c1015219ba75a67648c1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 17:44:18 -0400 Subject: [PATCH 028/293] add polyethylene airebo example for future reference --- examples/airebo/data.airebo | 78 ++++++++++++++++++++ examples/airebo/in.airebo | 22 ++++++ examples/airebo/in.airebo-m | 22 ++++++ examples/airebo/log.23Jun17.airebo-m.g++.1 | 86 ++++++++++++++++++++++ examples/airebo/log.23Jun17.airebo-m.g++.4 | 86 ++++++++++++++++++++++ examples/airebo/log.23Jun17.airebo.g++.1 | 86 ++++++++++++++++++++++ examples/airebo/log.23Jun17.airebo.g++.4 | 86 ++++++++++++++++++++++ 7 files changed, 466 insertions(+) create mode 100644 examples/airebo/data.airebo create mode 100644 examples/airebo/in.airebo create mode 100644 examples/airebo/in.airebo-m create mode 100644 examples/airebo/log.23Jun17.airebo-m.g++.1 create mode 100644 examples/airebo/log.23Jun17.airebo-m.g++.4 create mode 100644 examples/airebo/log.23Jun17.airebo.g++.1 create mode 100644 examples/airebo/log.23Jun17.airebo.g++.4 diff --git a/examples/airebo/data.airebo b/examples/airebo/data.airebo new file mode 100644 index 0000000000..90e20b2388 --- /dev/null +++ b/examples/airebo/data.airebo @@ -0,0 +1,78 @@ +LAMMPS data file from restart file: timestep = 1, procs = 1 + +60 atoms + +2 atom types + +-2.1 2.1 xlo xhi +-2.1 2.1 ylo yhi +0 25.5790000000 zlo zhi + +Masses + +1 12.01 +2 1.00794 + +Atoms + +1 1 0.0000000000 0.0000000000 0.0000000000 +2 2 0.9010066786 -0.6310205743 0.0000000000 +3 2 -0.9010066786 -0.6310205743 0.0000000000 +4 1 0.0000000000 0.8470061967 1.2789591482 +5 2 0.9010066786 1.4780267710 1.2789591482 +6 2 -0.9010066786 1.4780267710 1.2789591482 +7 1 0.0000000000 0.0000000000 2.5579182965 +8 2 0.9010066786 -0.6310205743 2.5579182965 +9 2 -0.9010066786 -0.6310205743 2.5579182965 +10 1 0.0000000000 0.8470061967 3.8368774447 +11 2 0.9010066786 1.4780267710 3.8368774447 +12 2 -0.9010066786 1.4780267710 3.8368774447 +13 1 0.0000000000 0.0000000000 5.1158365929 +14 2 0.9010066786 -0.6310205743 5.1158365929 +15 2 -0.9010066786 -0.6310205743 5.1158365929 +16 1 0.0000000000 0.8470061967 6.3947957411 +17 2 0.9010066786 1.4780267710 6.3947957411 +18 2 -0.9010066786 1.4780267710 6.3947957411 +19 1 0.0000000000 0.0000000000 7.6737548894 +20 2 0.9010066786 -0.6310205743 7.6737548894 +21 2 -0.9010066786 -0.6310205743 7.6737548894 +22 1 0.0000000000 0.8470061967 8.9527140376 +23 2 0.9010066786 1.4780267710 8.9527140376 +24 2 -0.9010066786 1.4780267710 8.9527140376 +25 1 0.0000000000 0.0000000000 10.2316731858 +26 2 0.9010066786 -0.6310205743 10.2316731858 +27 2 -0.9010066786 -0.6310205743 10.2316731858 +28 1 0.0000000000 0.8470061967 11.5106323340 +29 2 0.9010066786 1.4780267710 11.5106323340 +30 2 -0.9010066786 1.4780267710 11.5106323340 +31 1 0.0000000000 0.0000000000 12.7895914823 +32 2 0.9010066786 -0.6310205743 12.7895914823 +33 2 -0.9010066786 -0.6310205743 12.7895914823 +34 1 0.0000000000 0.8470061967 14.0685506305 +35 2 0.9010066786 1.4780267710 14.0685506305 +36 2 -0.9010066786 1.4780267710 14.0685506305 +37 1 0.0000000000 0.0000000000 15.3475097787 +38 2 0.9010066786 -0.6310205743 15.3475097787 +39 2 -0.9010066786 -0.6310205743 15.3475097787 +40 1 0.0000000000 0.8470061967 16.6264689269 +41 2 0.9010066786 1.4780267710 16.6264689269 +42 2 -0.9010066786 1.4780267710 16.6264689269 +43 1 0.0000000000 0.0000000000 17.9054280752 +44 2 0.9010066786 -0.6310205743 17.9054280752 +45 2 -0.9010066786 -0.6310205743 17.9054280752 +46 1 0.0000000000 0.8470061967 19.1843872234 +47 2 0.9010066786 1.4780267710 19.1843872234 +48 2 -0.9010066786 1.4780267710 19.1843872234 +49 1 0.0000000000 0.0000000000 20.4633463716 +50 2 0.9010066786 -0.6310205743 20.4633463716 +51 2 -0.9010066786 -0.6310205743 20.4633463716 +52 1 0.0000000000 0.8470061967 21.7423055198 +53 2 0.9010066786 1.4780267710 21.7423055198 +54 2 -0.9010066786 1.4780267710 21.7423055198 +55 1 0.0000000000 0.0000000000 23.0212646681 +56 2 0.9010066786 -0.6310205743 23.0212646681 +57 2 -0.9010066786 -0.6310205743 23.0212646681 +58 1 0.0000000000 0.8470061967 24.3002238163 +59 2 0.9010066786 1.4780267710 24.3002238163 +60 2 -0.9010066786 1.4780267710 24.3002238163 + diff --git a/examples/airebo/in.airebo b/examples/airebo/in.airebo new file mode 100644 index 0000000000..5b0e36ff4a --- /dev/null +++ b/examples/airebo/in.airebo @@ -0,0 +1,22 @@ +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + +replicate 17 16 2 + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo C H + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 diff --git a/examples/airebo/in.airebo-m b/examples/airebo/in.airebo-m new file mode 100644 index 0000000000..3ec29482a7 --- /dev/null +++ b/examples/airebo/in.airebo-m @@ -0,0 +1,22 @@ +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + +replicate 17 16 2 + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo/morse 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo-m C H + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 diff --git a/examples/airebo/log.23Jun17.airebo-m.g++.1 b/examples/airebo/log.23Jun17.airebo-m.g++.1 new file mode 100644 index 0000000000..1483fcb4a6 --- /dev/null +++ b/examples/airebo/log.23Jun17.airebo-m.g++.1 @@ -0,0 +1,86 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + orthogonal box = (-2.1 -2.1 0) to (2.1 2.1 25.579) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 60 atoms + +replicate 17 16 2 + orthogonal box = (-2.1 -2.1 0) to (69.3 65.1 51.158) + 1 by 1 by 1 MPI processor grid + 32640 atoms + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo/morse 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo-m C H +Reading potential file ../../potentials/CH.airebo-m with DATE: 2016-03-15 + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 +Neighbor list info ... + update every 1 steps, delay 5 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.7 + ghost atom cutoff = 10.7 + binsize = 5.35, bins = 14 13 10 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair airebo/morse, perpetual + attributes: full, newton on, ghost + pair build: full/bin/ghost + stencil: full/ghost/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 106.4 | 106.4 | 106.4 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 300 -139283.82 0 -138018.14 152.25271 + 10 166.76148 -138718.75 0 -138015.19 17412.343 + 20 207.7293 -138891.79 0 -138015.4 -19395.339 + 30 138.54469 -138596.42 0 -138011.92 -11909.248 + 40 153.95239 -138661.7 0 -138012.19 -2448.7701 + 50 126.22907 -138545.12 0 -138012.57 5206.1374 + 60 181.02757 -138778.28 0 -138014.54 22506.777 + 70 185.72779 -138799.18 0 -138015.61 -10803.744 + 80 164.28396 -138709.5 0 -138016.4 -1524.7353 + 90 180.26403 -138776.42 0 -138015.9 -27143.467 + 100 164.05694 -138706.58 0 -138014.44 5157.5516 +Loop time of 117.672 on 1 procs for 100 steps with 32640 atoms + +Performance: 0.037 ns/day, 653.734 hours/ns, 0.850 timesteps/s +99.3% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 108.31 | 108.31 | 108.31 | 0.0 | 92.04 +Neigh | 9.2199 | 9.2199 | 9.2199 | 0.0 | 7.84 +Comm | 0.052942 | 0.052942 | 0.052942 | 0.0 | 0.04 +Output | 0.0015149 | 0.0015149 | 0.0015149 | 0.0 | 0.00 +Modify | 0.060962 | 0.060962 | 0.060962 | 0.0 | 0.05 +Other | | 0.02656 | | | 0.02 + +Nlocal: 32640 ave 32640 max 32640 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 48094 ave 48094 max 48094 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 2.22109e+07 ave 2.22109e+07 max 2.22109e+07 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 22210922 +Ave neighs/atom = 680.482 +Neighbor list builds = 8 +Dangerous builds = 0 +Total wall time: 0:02:00 diff --git a/examples/airebo/log.23Jun17.airebo-m.g++.4 b/examples/airebo/log.23Jun17.airebo-m.g++.4 new file mode 100644 index 0000000000..3a3d922bcb --- /dev/null +++ b/examples/airebo/log.23Jun17.airebo-m.g++.4 @@ -0,0 +1,86 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + orthogonal box = (-2.1 -2.1 0) to (2.1 2.1 25.579) + 1 by 1 by 4 MPI processor grid + reading atoms ... + 60 atoms + +replicate 17 16 2 + orthogonal box = (-2.1 -2.1 0) to (69.3 65.1 51.158) + 2 by 2 by 1 MPI processor grid + 32640 atoms + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo/morse 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo-m C H +Reading potential file ../../potentials/CH.airebo-m with DATE: 2016-03-15 + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 +Neighbor list info ... + update every 1 steps, delay 5 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.7 + ghost atom cutoff = 10.7 + binsize = 5.35, bins = 14 13 10 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair airebo/morse, perpetual + attributes: full, newton on, ghost + pair build: full/bin/ghost + stencil: full/ghost/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 29.37 | 29.75 | 30.13 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 300 -139283.82 0 -138018.14 152.25271 + 10 166.76148 -138718.75 0 -138015.19 17412.343 + 20 207.7293 -138891.79 0 -138015.4 -19395.339 + 30 138.54469 -138596.42 0 -138011.92 -11909.248 + 40 153.95239 -138661.7 0 -138012.19 -2448.7701 + 50 126.22907 -138545.12 0 -138012.57 5206.1374 + 60 181.02757 -138778.28 0 -138014.54 22506.777 + 70 185.72779 -138799.18 0 -138015.61 -10803.744 + 80 164.28396 -138709.5 0 -138016.4 -1524.7353 + 90 180.26403 -138776.42 0 -138015.9 -27143.467 + 100 164.05694 -138706.58 0 -138014.44 5157.5516 +Loop time of 32.9268 on 4 procs for 100 steps with 32640 atoms + +Performance: 0.131 ns/day, 182.927 hours/ns, 3.037 timesteps/s +99.4% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 28.045 | 28.537 | 29.42 | 10.4 | 86.67 +Neigh | 3.163 | 3.237 | 3.3761 | 4.7 | 9.83 +Comm | 0.09883 | 1.1206 | 1.6862 | 60.4 | 3.40 +Output | 0.00099325 | 0.0011329 | 0.0012462 | 0.3 | 0.00 +Modify | 0.016013 | 0.016726 | 0.017257 | 0.4 | 0.05 +Other | | 0.01459 | | | 0.04 + +Nlocal: 8160 ave 8167 max 8153 min +Histogram: 1 0 1 0 0 0 0 1 0 1 +Nghost: 22581 ave 22594 max 22569 min +Histogram: 1 0 0 0 1 1 0 0 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 5.55273e+06 ave 5.55908e+06 max 5.54496e+06 min +Histogram: 1 0 0 0 0 1 1 0 0 1 + +Total # of neighbors = 22210922 +Ave neighs/atom = 680.482 +Neighbor list builds = 8 +Dangerous builds = 0 +Total wall time: 0:00:33 diff --git a/examples/airebo/log.23Jun17.airebo.g++.1 b/examples/airebo/log.23Jun17.airebo.g++.1 new file mode 100644 index 0000000000..0ef895dc28 --- /dev/null +++ b/examples/airebo/log.23Jun17.airebo.g++.1 @@ -0,0 +1,86 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + orthogonal box = (-2.1 -2.1 0) to (2.1 2.1 25.579) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 60 atoms + +replicate 17 16 2 + orthogonal box = (-2.1 -2.1 0) to (69.3 65.1 51.158) + 1 by 1 by 1 MPI processor grid + 32640 atoms + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo C H +Reading potential file ../../potentials/CH.airebo with DATE: 2011-10-25 + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 +Neighbor list info ... + update every 1 steps, delay 5 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.7 + ghost atom cutoff = 10.7 + binsize = 5.35, bins = 14 13 10 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair airebo, perpetual + attributes: full, newton on, ghost + pair build: full/bin/ghost + stencil: full/ghost/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 106.4 | 106.4 | 106.4 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 300 -139300.72 0 -138035.04 7988.6647 + 10 161.34683 -138712.9 0 -138032.19 33228.921 + 20 208.59504 -138912.79 0 -138032.74 -3211.8806 + 30 139.7513 -138618.85 0 -138029.25 10878.143 + 40 142.14562 -138629.02 0 -138029.32 14601.302 + 50 114.23401 -138510.95 0 -138029 24691.125 + 60 164.92002 -138726 0 -138030.21 35125.541 + 70 162.15256 -138715.9 0 -138031.79 5658.7946 + 80 157.16184 -138695.77 0 -138032.72 19824.698 + 90 196.15907 -138860.65 0 -138033.07 -7950.8462 + 100 178.31875 -138784.89 0 -138032.57 30997.671 +Loop time of 110.107 on 1 procs for 100 steps with 32640 atoms + +Performance: 0.039 ns/day, 611.705 hours/ns, 0.908 timesteps/s +99.5% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 100.76 | 100.76 | 100.76 | 0.0 | 91.51 +Neigh | 9.1909 | 9.1909 | 9.1909 | 0.0 | 8.35 +Comm | 0.058134 | 0.058134 | 0.058134 | 0.0 | 0.05 +Output | 0.0015941 | 0.0015941 | 0.0015941 | 0.0 | 0.00 +Modify | 0.062212 | 0.062212 | 0.062212 | 0.0 | 0.06 +Other | | 0.03123 | | | 0.03 + +Nlocal: 32640 ave 32640 max 32640 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 48190 ave 48190 max 48190 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 2.22178e+07 ave 2.22178e+07 max 2.22178e+07 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 22217840 +Ave neighs/atom = 680.694 +Neighbor list builds = 8 +Dangerous builds = 0 +Total wall time: 0:01:52 diff --git a/examples/airebo/log.23Jun17.airebo.g++.4 b/examples/airebo/log.23Jun17.airebo.g++.4 new file mode 100644 index 0000000000..486b48a004 --- /dev/null +++ b/examples/airebo/log.23Jun17.airebo.g++.4 @@ -0,0 +1,86 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +# AIREBO polyethelene benchmark + +units metal +atom_style atomic + +read_data data.airebo + orthogonal box = (-2.1 -2.1 0) to (2.1 2.1 25.579) + 1 by 1 by 4 MPI processor grid + reading atoms ... + 60 atoms + +replicate 17 16 2 + orthogonal box = (-2.1 -2.1 0) to (69.3 65.1 51.158) + 2 by 2 by 1 MPI processor grid + 32640 atoms + +neighbor 0.5 bin +neigh_modify delay 5 every 1 + +pair_style airebo 3.0 1 1 +pair_coeff * * ../../potentials/CH.airebo C H +Reading potential file ../../potentials/CH.airebo with DATE: 2011-10-25 + +velocity all create 300.0 761341 + +fix 1 all nve +timestep 0.0005 + +thermo 10 +run 100 +Neighbor list info ... + update every 1 steps, delay 5 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10.7 + ghost atom cutoff = 10.7 + binsize = 5.35, bins = 14 13 10 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair airebo, perpetual + attributes: full, newton on, ghost + pair build: full/bin/ghost + stencil: full/ghost/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 29.37 | 29.75 | 30.13 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 300 -139300.72 0 -138035.04 7988.6647 + 10 161.34683 -138712.9 0 -138032.19 33228.921 + 20 208.59504 -138912.79 0 -138032.74 -3211.8806 + 30 139.7513 -138618.85 0 -138029.25 10878.143 + 40 142.14562 -138629.02 0 -138029.32 14601.302 + 50 114.23401 -138510.95 0 -138029 24691.125 + 60 164.92002 -138726 0 -138030.21 35125.541 + 70 162.15256 -138715.9 0 -138031.79 5658.7946 + 80 157.16184 -138695.77 0 -138032.72 19824.698 + 90 196.15907 -138860.65 0 -138033.07 -7950.8462 + 100 178.31875 -138784.89 0 -138032.57 30997.671 +Loop time of 30.1916 on 4 procs for 100 steps with 32640 atoms + +Performance: 0.143 ns/day, 167.731 hours/ns, 3.312 timesteps/s +99.1% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 26.083 | 26.31 | 26.795 | 5.5 | 87.14 +Neigh | 3.1781 | 3.2134 | 3.2775 | 2.2 | 10.64 +Comm | 0.086296 | 0.63643 | 0.88995 | 40.2 | 2.11 +Output | 0.00074124 | 0.0010698 | 0.0013616 | 0.7 | 0.00 +Modify | 0.015335 | 0.016373 | 0.017565 | 0.8 | 0.05 +Other | | 0.01457 | | | 0.05 + +Nlocal: 8160 ave 8174 max 8146 min +Histogram: 1 0 1 0 0 0 0 1 0 1 +Nghost: 22614.5 ave 22629 max 22601 min +Histogram: 1 1 0 0 0 0 0 1 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 5.55446e+06 ave 5.56556e+06 max 5.54192e+06 min +Histogram: 1 0 0 1 0 0 0 1 0 1 + +Total # of neighbors = 22217840 +Ave neighs/atom = 680.694 +Neighbor list builds = 8 +Dangerous builds = 0 +Total wall time: 0:00:30 From 47649ff50f3ab81e702e9866dca45945b5e8dd77 Mon Sep 17 00:00:00 2001 From: Abdo Date: Thu, 6 Jul 2017 15:35:06 +0900 Subject: [PATCH 029/293] some edits to make examples more illustrative. --- examples/USER/misc/ees/Data_region | 12 ++++++------ examples/USER/misc/ees/README | 8 ++++---- examples/USER/misc/ees/in.fix_wall | 10 +++++----- examples/USER/misc/ees/in.fix_wall_region | 10 +++++----- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/examples/USER/misc/ees/Data_region b/examples/USER/misc/ees/Data_region index 1b3dc65dde..e48c5342d0 100644 --- a/examples/USER/misc/ees/Data_region +++ b/examples/USER/misc/ees/Data_region @@ -8,9 +8,9 @@ Atoms atom-ID atom-type ellipsoidflag density x y z -1 1 1 1 5 30 30 -2 1 1 1 30 5 30 -3 1 1 1 30 30 5 +1 1 1 1 10 30 30 +2 1 1 1 30 10 30 +3 1 1 1 30 30 10 Ellipsoids @@ -22,7 +22,7 @@ atom-ID shapex shapey shapez quatw quati quatj quatk Velocities -1 1.3 0 0 1 0 5 -2 0 .2 0 .1 3 0 -3 0 0 .9 .5 5 1 +1 1.3 0 0 0 0 50 +2 0 .5 0 .1 3 10 +3 0 0 .9 .5 61 1 diff --git a/examples/USER/misc/ees/README b/examples/USER/misc/ees/README index 4eb40665a3..9f4cb4f159 100644 --- a/examples/USER/misc/ees/README +++ b/examples/USER/misc/ees/README @@ -1,13 +1,13 @@ -Here one may find simple examples that show how to use "fix wall/ess" and "fix wall/region/ess" commands. +Here one may find simple examples showing how "fix wall/ess" and "fix wall/region/ess" work. --in.fix_wall_region: - This input file uses Data_region file to setup a system of three particles colliding with a + This input uses "Data_region" to setup a system of three particles colliding with a cubic region which its walls interact with particle with EES potential. To find out details of how to set parameters of "fix wall/region/ees" see documentaion. --in.fix_wall - This input file uses Data_wall to confine a ellipsoidal particle between two EES walls to - show how to use "fix wall/ees" command. For more details lookup LAMMPS's documentation. + This input uses "Data_wall" to confine a ellipsoidal particle between two EES walls. + For more details lookup LAMMPS's documentation under "fix wall/ess" command. diff --git a/examples/USER/misc/ees/in.fix_wall b/examples/USER/misc/ees/in.fix_wall index 6ea3b67d3b..d0306bea63 100644 --- a/examples/USER/misc/ees/in.fix_wall +++ b/examples/USER/misc/ees/in.fix_wall @@ -1,4 +1,4 @@ - +log log_substrate units lj atom_style ellipsoid boundary p p f @@ -7,7 +7,7 @@ read_data Data_wall pair_style resquared 1 pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 #------------------------------------# -timestep 0.0001 +timestep 0.0002 #------------------------------------# compute temp all temp/asphere @@ -18,7 +18,7 @@ fix EES_substrate all wall/ees zhi EDGE 10 1 10 zlo EDGE 10 1 10 thermo_style custom step temp press etotal f_EES_substrate f_EES_substrate[1] -fix NVT all nve/asphere +fix NVE all nve/asphere #------------------------------------# compute qw all property/atom quatw compute qi all property/atom quati @@ -26,6 +26,6 @@ compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# thermo 500 -dump 1 all custom 500 dump1 id type x y z c_qw c_qi c_qj c_qk -run 2000 +dump 1 all custom 1000 dump_substrate id type x y z c_qw c_qi c_qj c_qk +run 40000 diff --git a/examples/USER/misc/ees/in.fix_wall_region b/examples/USER/misc/ees/in.fix_wall_region index 655fb6e724..fb16f23481 100644 --- a/examples/USER/misc/ees/in.fix_wall_region +++ b/examples/USER/misc/ees/in.fix_wall_region @@ -1,4 +1,4 @@ - +log log_region units lj atom_style ellipsoid boundary p p p @@ -9,7 +9,7 @@ region the_wall block 20. 40. 20. 40. 20. 40. side out pair_style resquared 1 pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 #------------------------------------# -timestep 0.0001 +timestep 0.0005 #------------------------------------# fix EES_block all wall/region/ees the_wall 10. 1. 20 @@ -17,7 +17,7 @@ fix EES_block all wall/region/ees the_wall 10. 1. 20 thermo_style custom step temp press etotal f_EES_block[1] f_EES_block[3] -fix NVT all nve/asphere +fix NVE all nve/asphere #------------------------------------# compute qw all property/atom quatw compute qi all property/atom quati @@ -25,6 +25,6 @@ compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# thermo 500 -#dump 1 all custom 500 dump1 id type x y z c_qw c_qi c_qj c_qk -run 2000 +dump 1 all custom 1000 dump_region id type x y z c_qw c_qi c_qj c_qk +run 50000 From 33be51af54323bf87c9cb2996d5768818de7f9a8 Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Thu, 6 Jul 2017 20:19:40 +0900 Subject: [PATCH 030/293] Deleted "fix wall/region/ees" doc file --- doc/src/fix_wall_region_ees.txt | 48 --------------------------------- 1 file changed, 48 deletions(-) diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt index 6171291bc0..8b13789179 100644 --- a/doc/src/fix_wall_region_ees.txt +++ b/doc/src/fix_wall_region_ees.txt @@ -1,49 +1 @@ -"LAMMPS WWW Site"_lws - "LAMMPS Documentation"_ld - "LAMMPS Commands"_lc :c -:link(lws,http://lammps.sandia.gov) -:link(ld,Manual.html) -:link(lc,Section_commands.html#comm) - -:line - -fix wall/region/ees command :h3 - -[Syntax:] - -fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff :pre - -ID, group-ID are documented in "fix"_fix.html command -wall/region = style name of this fix command -region-ID = region whose boundary will act as wall -epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) -sigma = size factor for wall-particle interaction (distance units) -cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul - -[Examples:] - -fix wall all wall/region/ees mySphere 1.0 1.0 2.5 :pre - -[Description:] - -Treat the surface of the geometric region defined by the {region-ID} -as a bounding wall which interacts with nearby ellipsoidal particles according to -the EES potential introduced "fix wall/ees"_fix_wall_ees.html. - -Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. -One may also find and exapmle of using this code in USER/ees/ under examples/ directory. - -[Restrictions:] - -This fix is part of the USER-MISC package. It is only enabled if LAMMPS -was built with that package. See the "Making -LAMMPS"_Section_start.html#start_3 section for more info. - -This fix requires that atoms be ellipsoids as defined by the -"atom_style ellipsoid"_atom_style.html command. - -[Related commands:] - -"fix wall/lj93"_fix_wall.html, -"fix wall/ees"_fix_wall_ees.html - -[Default:] none From a62eb43791daccf3a7780090ff2bda50308a4e2a Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Thu, 6 Jul 2017 20:20:12 +0900 Subject: [PATCH 031/293] Delete "fix_wall_region_ees.txt" --- doc/src/fix_wall_region_ees.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 doc/src/fix_wall_region_ees.txt diff --git a/doc/src/fix_wall_region_ees.txt b/doc/src/fix_wall_region_ees.txt deleted file mode 100644 index 8b13789179..0000000000 --- a/doc/src/fix_wall_region_ees.txt +++ /dev/null @@ -1 +0,0 @@ - From 8be6d5bfd841ee1b06e7e7de25b386af80b123ed Mon Sep 17 00:00:00 2001 From: Abdoreza Ershadinia Date: Thu, 6 Jul 2017 20:21:55 +0900 Subject: [PATCH 032/293] Merged two doc files --- doc/src/fix_wall_ees.txt | 41 ++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt index 5b08a22935..450d743372 100644 --- a/doc/src/fix_wall_ees.txt +++ b/doc/src/fix_wall_ees.txt @@ -8,6 +8,7 @@ fix wall/ees command :h3 +fix wall/region/ees command :h3 [Syntax:] @@ -26,29 +27,32 @@ face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} :l sigma = size factor for wall-particle interaction (distance units) sigma can be a variable (see below) cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :pre -zero or more keyword/value pairs may be appended :l -keyword = {units} or {fld} :l - {units} value = {lattice} or {box} - {lattice} = the wall position is defined in lattice units - {box} = the wall position is defined in simulation box units - {fld} value = {yes} or {no} - {yes} = invoke the wall constraint to be compatible with implicit FLD - {no} = invoke the wall constraint in the normal way - {pbc} value = {yes} or {no} - {yes} = allow periodic boundary in a wall dimension - {no} = require non-perioidic boundaries in any wall dimension :pre :ule + + +fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff :pre + +ID, group-ID are documented in "fix"_fix.html command +wall/region = style name of this fix command +region-ID = region whose boundary will act as wall +epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) +sigma = size factor for wall-particle interaction (distance units) +cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul + [Examples:] fix wallhi all wall/ees xlo -1.0 1.0 1.0 2.5 units box fix wallhi all wall/ees xhi EDGE 1.0 1.0 2.5 fix wallhi all wall/ees v_wiggle 23.2 1.0 1.0 2.5 -fix zwalls all wall/ees zlo 0.0 1.0 1.0 0.858 zhi 40.0 1.0 1.0 0.858 :pre +fix zwalls all wall/ees zlo 0.0 1.0 1.0 0.858 zhi 40.0 1.0 1.0 0.858 + +fix ees_cube all wall/region/ees myCube 1.0 1.0 2.5 :pre + [Description:]   -Bound the simulation domain on one or more of its faces with a flat +"Fix wall/ees" bounds the simulation domain on one or more of its faces with a flat wall that interacts with the ellipsoidal atoms in the 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: @@ -82,7 +86,16 @@ 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). -  + + + +"fix wall/region/ees" treat the surface of the geometric region defined by the {region-ID} +as a bounding wall which interacts with nearby ellipsoidal particles according to +the EES potential introduced above. + +Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. +One may also find and exapmle of using this code in USER/ees/ under examples/ directory. + [Restrictions:] This fix is part of the USER-MISC package. It is only enabled if LAMMPS From 423e3b6389dc4584d0194b1697be0eccf29a7447 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 6 Jul 2017 14:45:51 -0400 Subject: [PATCH 033/293] integrate fix wall/ees and wall/region/ees into doc system --- doc/src/Section_commands.txt | 4 +++- doc/src/fixes.txt | 1 + doc/src/lammps.book | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/src/Section_commands.txt b/doc/src/Section_commands.txt index 6e526dcb51..df283f62e2 100644 --- a/doc/src/Section_commands.txt +++ b/doc/src/Section_commands.txt @@ -732,7 +732,9 @@ package"_Section_start.html#start_3. "smd/wall/surface"_fix_smd_wall_surface.html, "temp/rescale/eff"_fix_temp_rescale_eff.html, "ti/spring"_fix_ti_spring.html, -"ttm/mod"_fix_ttm.html :tb(c=6,ea=c) +"ttm/mod"_fix_ttm.html +"wall/ees"_fix_wall_ees.html +"wall/region/ees"_fix_wall_ees.html :tb(c=6,ea=c) :line diff --git a/doc/src/fixes.txt b/doc/src/fixes.txt index 7997f6f1d4..733d402057 100644 --- a/doc/src/fixes.txt +++ b/doc/src/fixes.txt @@ -154,6 +154,7 @@ Fixes :h1 fix_viscosity fix_viscous fix_wall + fix_wall_ees fix_wall_gran fix_wall_gran_region fix_wall_piston diff --git a/doc/src/lammps.book b/doc/src/lammps.book index 3186865fb6..09d9e2906d 100644 --- a/doc/src/lammps.book +++ b/doc/src/lammps.book @@ -280,6 +280,7 @@ fix_vector.html fix_viscosity.html fix_viscous.html fix_wall.html +fix_wall_ees.html fix_wall_gran.html fix_wall_gran_region.html fix_wall_piston.html From 23925b3a57fcd51e862a19756348d46c632f69df Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 6 Jul 2017 14:47:44 -0400 Subject: [PATCH 034/293] update fix wall/ees and wall/region/ees file to conform more to common formatting also fix some typos and formatting issues --- doc/src/fix_wall_ees.txt | 93 +++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 49 deletions(-) diff --git a/doc/src/fix_wall_ees.txt b/doc/src/fix_wall_ees.txt index 450d743372..a8688e8e41 100644 --- a/doc/src/fix_wall_ees.txt +++ b/doc/src/fix_wall_ees.txt @@ -7,17 +7,17 @@ :line fix wall/ees command :h3 - fix wall/region/ees command :h3 [Syntax:] -fix ID group-ID wall/ees face args ... keyword value ... :pre +fix ID group-ID style args :pre ID, group-ID are documented in "fix"_fix.html command :ulb,l -one or more face/arg pairs may be appended :l -face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} :l - args = coord epsilon sigma cutoff +style = {wall/ees} or {wall/region/ees} :l + args for style {wall/ees}: one or more {face parameters} groups may be appended + face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} + parameters = coord epsilon sigma cutoff coord = position of wall = EDGE or constant or variable EDGE = current lo or hi edge of simulation box constant = number like 0.0 or -30.0 (distance units) @@ -27,60 +27,57 @@ face = {xlo} or {xhi} or {ylo} or {yhi} or {zlo} or {zhi} :l sigma = size factor for wall-particle interaction (distance units) sigma can be a variable (see below) cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :pre -:ule - - -fix ID group-ID wall/region/ees region-ID epsilon sigma cutoff :pre - -ID, group-ID are documented in "fix"_fix.html command -wall/region = style name of this fix command -region-ID = region whose boundary will act as wall -epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) -sigma = size factor for wall-particle interaction (distance units) -cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :ul + args for style {wall/region/ees}: {region-ID} {epsilon} {sigma} {cutoff} + region-ID = region whose boundary will act as wall + epsilon = strength factor for wall-particle interaction (energy or energy/distance^2 units) + sigma = size factor for wall-particle interaction (distance units) + cutoff = distance from wall at which wall-particle interaction is cut off (distance units) :pre + :ule [Examples:] fix wallhi all wall/ees xlo -1.0 1.0 1.0 2.5 units box fix wallhi all wall/ees xhi EDGE 1.0 1.0 2.5 fix wallhi all wall/ees v_wiggle 23.2 1.0 1.0 2.5 -fix zwalls all wall/ees zlo 0.0 1.0 1.0 0.858 zhi 40.0 1.0 1.0 0.858 +fix zwalls all wall/ees zlo 0.0 1.0 1.0 0.858 zhi 40.0 1.0 1.0 0.858 :pre fix ees_cube all wall/region/ees myCube 1.0 1.0 2.5 :pre [Description:] -  -"Fix wall/ees" bounds the simulation domain on one or more of its faces with a flat -wall that interacts with the ellipsoidal atoms in the 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 + +Fix {wall/ees} bounds the simulation domain on one or more of its +faces with a flat wall that interacts with the ellipsoidal atoms in the +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: - - - :c,image(Eqs/fix_wall_ees.jpg) -  -  -Introduced by Babadi and Ejtehadi in "(Babadi)"_#BabadiEjtehadi. 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 (see the image below). + +Introduced by Babadi and Ejtehadi in "(Babadi)"_#BabadiEjtehadi. 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 (see the image below). :c,image(JPG/fix_wall_ees_image.jpg) -  -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. -  +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 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. -  += 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. + NOTE: You must insure that r is always bigger than 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 @@ -88,18 +85,18 @@ position {coord} (r = sigma_n) or with particles penetrating the wall (0 =< r < wall (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 +ellipsoidal particles according to the EES potential introduced above. -"fix wall/region/ees" treat the surface of the geometric region defined by the {region-ID} -as a bounding wall which interacts with nearby ellipsoidal particles according to -the EES potential introduced above. - -Other details of this command is the same wiht "fix wall/region"_fix_wall_region.html command. -One may also find and exapmle of using this code in USER/ees/ under examples/ directory. +Other details of this command are the same as for the "fix +wall/region"_fix_wall_region.html command. One may also find an example +of using this fix in the examples/USER/misc/ees/ directory. [Restrictions:] -This fix is part of the USER-MISC package. It is only enabled if LAMMPS -was built with that package. See the "Making +This fix is part of the USER-MISC package. It is only enabled if +LAMMPS was built with that package. See the "Making LAMMPS"_Section_start.html#start_3 section for more info. This fix requires that atoms be ellipsoids as defined by the @@ -112,11 +109,9 @@ This fix requires that atoms be ellipsoids as defined by the [Default:] -The option defaults units = lattice, fld = no, and pbc = no. +none :line :link(BabadiEjtehadi) [(Babadi)] Babadi and Ejtehadi, EPL, 77 (2007) 23002. -:link(Babadi) -[(Berardi)] Babadi, Ejtehadi, Everaers, J Comp Phys, 219, 770-779 (2006). From 7193fffe0d1c465a39c835d87bb0be1a4d4dee0e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 6 Jul 2017 16:08:25 -0400 Subject: [PATCH 035/293] make example input / output conform with LAMMPS conventions (no dump files, no log command) and update reference outputs --- examples/USER/misc/ees/in.fix_wall | 3 +- examples/USER/misc/ees/in.fix_wall_region | 3 +- .../USER/misc/ees/log.23Jun17.fix_wall.g++.1 | 162 ++++++++++++++++ .../USER/misc/ees/log.23Jun17.fix_wall.g++.4 | 162 ++++++++++++++++ .../ees/log.23Jun17.fix_wall_region.g++.1 | 180 ++++++++++++++++++ .../ees/log.23Jun17.fix_wall_region.g++.4 | 180 ++++++++++++++++++ 6 files changed, 686 insertions(+), 4 deletions(-) create mode 100644 examples/USER/misc/ees/log.23Jun17.fix_wall.g++.1 create mode 100644 examples/USER/misc/ees/log.23Jun17.fix_wall.g++.4 create mode 100644 examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.1 create mode 100644 examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.4 diff --git a/examples/USER/misc/ees/in.fix_wall b/examples/USER/misc/ees/in.fix_wall index d0306bea63..42f03fb1a5 100644 --- a/examples/USER/misc/ees/in.fix_wall +++ b/examples/USER/misc/ees/in.fix_wall @@ -1,4 +1,3 @@ -log log_substrate units lj atom_style ellipsoid boundary p p f @@ -26,6 +25,6 @@ compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# thermo 500 -dump 1 all custom 1000 dump_substrate id type x y z c_qw c_qi c_qj c_qk +#dump 1 all custom 1000 dump_substrate id type x y z c_qw c_qi c_qj c_qk run 40000 diff --git a/examples/USER/misc/ees/in.fix_wall_region b/examples/USER/misc/ees/in.fix_wall_region index fb16f23481..c3a2ea2488 100644 --- a/examples/USER/misc/ees/in.fix_wall_region +++ b/examples/USER/misc/ees/in.fix_wall_region @@ -1,4 +1,3 @@ -log log_region units lj atom_style ellipsoid boundary p p p @@ -25,6 +24,6 @@ compute qj all property/atom quatj compute qk all property/atom quatk #------------------------------------# thermo 500 -dump 1 all custom 1000 dump_region id type x y z c_qw c_qi c_qj c_qk +#dump 1 all custom 1000 dump_region id type x y z c_qw c_qi c_qj c_qk run 50000 diff --git a/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.1 b/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.1 new file mode 100644 index 0000000000..91e39687bb --- /dev/null +++ b/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.1 @@ -0,0 +1,162 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +units lj +atom_style ellipsoid +boundary p p f +read_data Data_wall + orthogonal box = (0 0 0) to (60 60 60) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 1 atoms + 1 ellipsoids + reading velocities ... + 1 velocities +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0002 +#------------------------------------# + +compute temp all temp/asphere +thermo_modify temp temp + +fix EES_substrate all wall/ees zhi EDGE 10 1 10 zlo EDGE 10 1 10 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +thermo_style custom step temp press etotal f_EES_substrate f_EES_substrate[1] +WARNING: New thermo_style command, previous thermo_modify settings will be lost (../output.cpp:705) + +fix NVE all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +thermo 500 +#dump 1 all custom 1000 dump_substrate id type x y z c_qw c_qi c_qj c_qk +run 40000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 1.3 + ghost atom cutoff = 1.3 + binsize = 0.65, bins = 93 93 93 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair resquared, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 7.95 | 7.95 | 7.95 Mbytes +Step Temp Press TotEng f_EES_substrate f_EES_substrate[1] + 0 0 0.00054301475 0 0 0 + 500 0 0.00054301501 0 -0.002011167 -0.00089853601 + 1000 0 0.0005430153 0 -0.0021039425 -0.00095953758 + 1500 0 0.00054301561 0 -0.0022030914 -0.0010262478 + 2000 0 0.00054301593 0 -0.002309218 -0.0010993652 + 2500 0 0.00054301628 0 -0.0024230015 -0.0011796956 + 3000 0 0.00054301666 0 -0.0025452078 -0.0012681725 + 3500 0 0.00054301707 0 -0.0026767034 -0.0013658817 + 4000 0 0.00054301751 0 -0.0028184722 -0.0014740918 + 4500 0 0.00054301798 0 -0.0029716352 -0.0015942917 + 5000 0 0.00054301849 0 -0.0031374752 -0.0017282378 + 5500 0 0.00054301905 0 -0.0033174662 -0.0018780129 + 6000 0 0.00054301965 0 -0.0035133093 -0.0020461007 + 6500 0 0.00054302031 0 -0.0037269778 -0.0022354811 + 7000 0 0.00054302103 0 -0.0039607721 -0.0024497521 + 7500 0 0.00054302182 0 -0.0042173892 -0.0026932881 + 8000 0 0.0005430227 0 -0.0045000102 -0.0029714471 + 8500 0 0.00054302366 0 -0.0048124114 -0.003290844 + 9000 0 0.00054302473 0 -0.0051591071 -0.0036597154 + 9500 0 0.00054302592 0 -0.0055455349 -0.0040884113 + 10000 0 0.00054302726 0 -0.0059782985 -0.0045900652 + 10500 0 0.00054302876 0 -0.0064654891 -0.0051815166 + 11000 0 0.00054303046 0 -0.0070171161 -0.0058845936 + 11500 0 0.0005430324 0 -0.0076456899 -0.0067279075 + 12000 0 0.00054303463 0 -0.0083670175 -0.0077493697 + 12500 0 0.00054303721 0 -0.0092012967 -0.0089996821 + 13000 0 0.00054304021 0 -0.010174616 -0.010546991 + 13500 0 0.00054304375 0 -0.011320967 -0.012482357 + 14000 0 0.00054304796 0 -0.012684757 -0.01492338 + 14500 0 0.00054305301 0 -0.014323176 -0.01800425 + 15000 0 0.00054305913 0 -0.016305242 -0.021804766 + 15500 0 0.0005430665 0 -0.018693849 -0.026019991 + 16000 0 0.00054307501 0 -0.021450982 -0.028460977 + 16500 0 0.0005430828 0 -0.023974925 -0.017549988 + 17000 0 0.00054307849 0 -0.022577692 0.07296284 + 17500 0 0.00054298744 0 0.0069237358 0.72962844 + 18000 0 0.00054212125 0 0.28756839 7.5171061 + 18500 0 0.00052809177 0 4.8331004 159.56814 + 19000 0 0.00019717774 0 112.04947 5692.3379 + 19500 0 0.00051978321 0 7.5250598 262.38764 + 20000 0 0.00054179603 0 0.39293697 10.289153 + 20500 0 0.00054296932 0 0.01279406 0.89377639 + 21000 0 0.00054308425 0 -0.02444466 0.081890707 + 21500 0 0.0005430907 0 -0.026532401 -0.021386086 + 22000 0 0.00054308271 0 -0.023944983 -0.032642459 + 22500 0 0.00054307381 0 -0.02106205 -0.029524272 + 23000 0 0.00054306612 0 -0.018569361 -0.024753431 + 23500 0 0.00054305976 0 -0.01650866 -0.020566675 + 24000 0 0.00054305452 0 -0.014811253 -0.017216347 + 24500 0 0.00054305017 0 -0.013402896 -0.014581066 + 25000 0 0.00054304653 0 -0.012222687 -0.01250069 + 25500 0 0.00054304345 0 -0.011223677 -0.0108418 + 26000 0 0.00054304081 0 -0.010370111 -0.0095034766 + 26500 0 0.00054303854 0 -0.0096346546 -0.0084112161 + 27000 0 0.00054303657 0 -0.0089962072 -0.0075100751 + 27500 0 0.00054303485 0 -0.0084382935 -0.0067592209 + 28000 0 0.00054303334 0 -0.0079478992 -0.0061279726 + 28500 0 0.000543032 0 -0.0075146283 -0.0055930001 + 29000 0 0.00054303081 0 -0.0071300893 -0.0051363504 + 29500 0 0.00054302976 0 -0.0067874426 -0.00474405 + 30000 0 0.00054302881 0 -0.0064810641 -0.0044051051 + 30500 0 0.00054302796 0 -0.0062062911 -0.0041107799 + 31000 0 0.0005430272 0 -0.0059592289 -0.0038540677 + 31500 0 0.00054302651 0 -0.0057366023 -0.0036293011 + 32000 0 0.00054302589 0 -0.0055356393 -0.0034318592 + 32500 0 0.00054302533 0 -0.0053539804 -0.0032579475 + 33000 0 0.00054302482 0 -0.0051896066 -0.0031044289 + 33500 0 0.00054302436 0 -0.0050407818 -0.0029686945 + 34000 0 0.00054302395 0 -0.0049060063 -0.002848562 + 34500 0 0.00054302357 0 -0.0047839795 -0.002742197 + 35000 0 0.00054302323 0 -0.0046735688 -0.0026480503 + 35500 0 0.00054302292 0 -0.0045737849 -0.0025648085 + 36000 0 0.00054302264 0 -0.0044837605 -0.0024913535 + 36500 0 0.00054302239 0 -0.0044027327 -0.0024267309 + 37000 0 0.00054302217 0 -0.0043300292 -0.0023701236 + 37500 0 0.00054302197 0 -0.0042650554 -0.0023208304 + 38000 0 0.00054302179 0 -0.0042072838 -0.0022782486 + 38500 0 0.00054302163 0 -0.0041562461 -0.0022418592 + 39000 0 0.0005430215 0 -0.0041115244 -0.0022112152 + 39500 0 0.00054302138 0 -0.0040727453 -0.0021859312 + 40000 0 0.00054302127 0 -0.0040395743 -0.0021656748 +Loop time of 0.111517 on 1 procs for 40000 steps with 1 atoms + +Performance: 6198147.516 tau/day, 358689.092 timesteps/s +98.6% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.0082421 | 0.0082421 | 0.0082421 | 0.0 | 7.39 +Neigh | 0.021163 | 0.021163 | 0.021163 | 0.0 | 18.98 +Comm | 0.045411 | 0.045411 | 0.045411 | 0.0 | 40.72 +Output | 0.0012326 | 0.0012326 | 0.0012326 | 0.0 | 1.11 +Modify | 0.022813 | 0.022813 | 0.022813 | 0.0 | 20.46 +Other | | 0.01265 | | | 11.35 + +Nlocal: 1 ave 1 max 1 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 0 +Ave neighs/atom = 0 +Neighbor list builds = 33 +Dangerous builds = 0 + +Total wall time: 0:00:00 diff --git a/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.4 b/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.4 new file mode 100644 index 0000000000..6c69ce3e72 --- /dev/null +++ b/examples/USER/misc/ees/log.23Jun17.fix_wall.g++.4 @@ -0,0 +1,162 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +units lj +atom_style ellipsoid +boundary p p f +read_data Data_wall + orthogonal box = (0 0 0) to (60 60 60) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 1 atoms + 1 ellipsoids + reading velocities ... + 1 velocities +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0002 +#------------------------------------# + +compute temp all temp/asphere +thermo_modify temp temp + +fix EES_substrate all wall/ees zhi EDGE 10 1 10 zlo EDGE 10 1 10 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +thermo_style custom step temp press etotal f_EES_substrate f_EES_substrate[1] +WARNING: New thermo_style command, previous thermo_modify settings will be lost (../output.cpp:705) + +fix NVE all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +thermo 500 +#dump 1 all custom 1000 dump_substrate id type x y z c_qw c_qi c_qj c_qk +run 40000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 1.3 + ghost atom cutoff = 1.3 + binsize = 0.65, bins = 93 93 93 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair resquared, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 5.128 | 5.41 | 5.753 Mbytes +Step Temp Press TotEng f_EES_substrate f_EES_substrate[1] + 0 0 0.00054301475 0 0 0 + 500 0 0.00054301501 0 -0.002011167 -0.00089853601 + 1000 0 0.0005430153 0 -0.0021039425 -0.00095953758 + 1500 0 0.00054301561 0 -0.0022030914 -0.0010262478 + 2000 0 0.00054301593 0 -0.002309218 -0.0010993652 + 2500 0 0.00054301628 0 -0.0024230015 -0.0011796956 + 3000 0 0.00054301666 0 -0.0025452078 -0.0012681725 + 3500 0 0.00054301707 0 -0.0026767034 -0.0013658817 + 4000 0 0.00054301751 0 -0.0028184722 -0.0014740918 + 4500 0 0.00054301798 0 -0.0029716352 -0.0015942917 + 5000 0 0.00054301849 0 -0.0031374752 -0.0017282378 + 5500 0 0.00054301905 0 -0.0033174662 -0.0018780129 + 6000 0 0.00054301965 0 -0.0035133093 -0.0020461007 + 6500 0 0.00054302031 0 -0.0037269778 -0.0022354811 + 7000 0 0.00054302103 0 -0.0039607721 -0.0024497521 + 7500 0 0.00054302182 0 -0.0042173892 -0.0026932881 + 8000 0 0.0005430227 0 -0.0045000102 -0.0029714471 + 8500 0 0.00054302366 0 -0.0048124114 -0.003290844 + 9000 0 0.00054302473 0 -0.0051591071 -0.0036597154 + 9500 0 0.00054302592 0 -0.0055455349 -0.0040884113 + 10000 0 0.00054302726 0 -0.0059782985 -0.0045900652 + 10500 0 0.00054302876 0 -0.0064654891 -0.0051815166 + 11000 0 0.00054303046 0 -0.0070171161 -0.0058845936 + 11500 0 0.0005430324 0 -0.0076456899 -0.0067279075 + 12000 0 0.00054303463 0 -0.0083670175 -0.0077493697 + 12500 0 0.00054303721 0 -0.0092012967 -0.0089996821 + 13000 0 0.00054304021 0 -0.010174616 -0.010546991 + 13500 0 0.00054304375 0 -0.011320967 -0.012482357 + 14000 0 0.00054304796 0 -0.012684757 -0.01492338 + 14500 0 0.00054305301 0 -0.014323176 -0.01800425 + 15000 0 0.00054305913 0 -0.016305242 -0.021804766 + 15500 0 0.0005430665 0 -0.018693849 -0.026019991 + 16000 0 0.00054307501 0 -0.021450982 -0.028460977 + 16500 0 0.0005430828 0 -0.023974925 -0.017549988 + 17000 0 0.00054307849 0 -0.022577692 0.07296284 + 17500 0 0.00054298744 0 0.0069237358 0.72962844 + 18000 0 0.00054212125 0 0.28756839 7.5171061 + 18500 0 0.00052809177 0 4.8331004 159.56814 + 19000 0 0.00019717774 0 112.04947 5692.3379 + 19500 0 0.00051978321 0 7.5250598 262.38764 + 20000 0 0.00054179603 0 0.39293697 10.289153 + 20500 0 0.00054296932 0 0.01279406 0.89377639 + 21000 0 0.00054308425 0 -0.02444466 0.081890707 + 21500 0 0.0005430907 0 -0.026532401 -0.021386086 + 22000 0 0.00054308271 0 -0.023944983 -0.032642459 + 22500 0 0.00054307381 0 -0.02106205 -0.029524272 + 23000 0 0.00054306612 0 -0.018569361 -0.024753431 + 23500 0 0.00054305976 0 -0.01650866 -0.020566675 + 24000 0 0.00054305452 0 -0.014811253 -0.017216347 + 24500 0 0.00054305017 0 -0.013402896 -0.014581066 + 25000 0 0.00054304653 0 -0.012222687 -0.01250069 + 25500 0 0.00054304345 0 -0.011223677 -0.0108418 + 26000 0 0.00054304081 0 -0.010370111 -0.0095034766 + 26500 0 0.00054303854 0 -0.0096346546 -0.0084112161 + 27000 0 0.00054303657 0 -0.0089962072 -0.0075100751 + 27500 0 0.00054303485 0 -0.0084382935 -0.0067592209 + 28000 0 0.00054303334 0 -0.0079478992 -0.0061279726 + 28500 0 0.000543032 0 -0.0075146283 -0.0055930001 + 29000 0 0.00054303081 0 -0.0071300893 -0.0051363504 + 29500 0 0.00054302976 0 -0.0067874426 -0.00474405 + 30000 0 0.00054302881 0 -0.0064810641 -0.0044051051 + 30500 0 0.00054302796 0 -0.0062062911 -0.0041107799 + 31000 0 0.0005430272 0 -0.0059592289 -0.0038540677 + 31500 0 0.00054302651 0 -0.0057366023 -0.0036293011 + 32000 0 0.00054302589 0 -0.0055356393 -0.0034318592 + 32500 0 0.00054302533 0 -0.0053539804 -0.0032579475 + 33000 0 0.00054302482 0 -0.0051896066 -0.0031044289 + 33500 0 0.00054302436 0 -0.0050407818 -0.0029686945 + 34000 0 0.00054302395 0 -0.0049060063 -0.002848562 + 34500 0 0.00054302357 0 -0.0047839795 -0.002742197 + 35000 0 0.00054302323 0 -0.0046735688 -0.0026480503 + 35500 0 0.00054302292 0 -0.0045737849 -0.0025648085 + 36000 0 0.00054302264 0 -0.0044837605 -0.0024913535 + 36500 0 0.00054302239 0 -0.0044027327 -0.0024267309 + 37000 0 0.00054302217 0 -0.0043300292 -0.0023701236 + 37500 0 0.00054302197 0 -0.0042650554 -0.0023208304 + 38000 0 0.00054302179 0 -0.0042072838 -0.0022782486 + 38500 0 0.00054302163 0 -0.0041562461 -0.0022418592 + 39000 0 0.0005430215 0 -0.0041115244 -0.0022112152 + 39500 0 0.00054302138 0 -0.0040727453 -0.0021859312 + 40000 0 0.00054302127 0 -0.0040395743 -0.0021656748 +Loop time of 0.216115 on 4 procs for 40000 steps with 1 atoms + +Performance: 3198303.409 tau/day, 185087.003 timesteps/s +98.5% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.0020442 | 0.0047204 | 0.012008 | 6.1 | 2.18 +Neigh | 0.0069654 | 0.0072649 | 0.0074701 | 0.2 | 3.36 +Comm | 0.024762 | 0.039833 | 0.056166 | 7.4 | 18.43 +Output | 0.0020285 | 0.0023268 | 0.0026891 | 0.5 | 1.08 +Modify | 0.0081856 | 0.013537 | 0.029052 | 7.7 | 6.26 +Other | | 0.1484 | | | 68.68 + +Nlocal: 0.25 ave 1 max 0 min +Histogram: 3 0 0 0 0 0 0 0 0 1 +Nghost: 0.25 ave 1 max 0 min +Histogram: 3 0 0 0 0 0 0 0 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 0 +Ave neighs/atom = 0 +Neighbor list builds = 33 +Dangerous builds = 0 + +Total wall time: 0:00:00 diff --git a/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.1 b/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.1 new file mode 100644 index 0000000000..f4bd804127 --- /dev/null +++ b/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.1 @@ -0,0 +1,180 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +units lj +atom_style ellipsoid +boundary p p p +read_data Data_region + orthogonal box = (0 0 0) to (60 60 60) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 3 atoms + 3 ellipsoids + reading velocities ... + 3 velocities +#------------------------------------# +region the_wall block 20. 40. 20. 40. 20. 40. side out +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0005 +#------------------------------------# + +fix EES_block all wall/region/ees the_wall 10. 1. 20 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +thermo_style custom step temp press etotal f_EES_block[1] f_EES_block[3] + +fix NVE all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +thermo 500 +#dump 1 all custom 1000 dump_region id type x y z c_qw c_qi c_qj c_qk +run 50000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 1.3 + ghost atom cutoff = 1.3 + binsize = 0.65, bins = 93 93 93 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair resquared, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 7.958 | 7.958 | 7.958 Mbytes +Step Temp Press TotEng f_EES_block[1] f_EES_block[3] + 0 161.26842 0.0014932261 161.26842 -0.00042715909 -0.00015747012 + 500 161.26864 0.0014932281 161.26864 -0.00055836679 -0.00017557792 + 1000 161.26891 0.0014932306 161.26891 -0.00075239934 -0.00019646897 + 1500 161.26926 0.0014932339 161.26926 -0.0010543331 -0.0002206925 + 2000 161.26975 0.0014932385 161.26975 -0.0015566164 -0.00024893301 + 2500 161.27047 0.0014932451 161.27047 -0.0024700842 -0.00028205104 + 3000 161.27163 0.0014932558 161.27163 -0.0043191186 -0.00032113859 + 3500 161.27364 0.0014932745 161.27364 -0.0073109231 -0.00036759584 + 4000 161.26391 0.0014931843 161.26391 0.2453813 -0.00042323837 + 4500 77.783029 0.00072021324 77.783029 4908.2333 -0.00049044991 + 5000 160.23852 0.00148369 160.23852 0.13220034 -0.00057240356 + 5500 160.2431 0.0014837324 160.2431 -0.0072005112 -0.00067338844 + 6000 160.24148 0.0014837174 160.24148 -0.0040896209 -0.0007993028 + 6500 160.24071 0.0014837103 160.24071 -0.0023574992 -0.00095841662 + 7000 160.24038 0.0014837072 160.24038 -0.001495267 -0.001162584 + 7500 160.24031 0.0014837066 160.24031 -0.0010172907 -0.0014292316 + 8000 160.24043 0.0014837077 160.24043 -0.00072823316 -0.0017847384 + 8500 160.24073 0.0014837105 160.24073 -0.00054165121 -0.0022704187 + 9000 160.24121 0.0014837149 160.24121 -0.00041506183 -0.0029536182 + 9500 160.24192 0.0014837215 160.24192 -0.00032574317 -0.0039493769 + 10000 160.24293 0.0014837308 160.24293 -0.00026069929 -0.0054649542 + 10500 160.2444 0.0014837444 160.2444 -0.00021208476 -0.0078936604 + 11000 160.2466 0.0014837648 160.2466 -0.00017494913 -0.011981095 + 11500 160.25001 0.0014837964 160.25001 -0.00014605132 -0.018414768 + 12000 160.25411 0.0014838343 160.25411 -0.00012320207 -0.0069059119 + 12500 160.18929 0.0014832342 160.18929 -0.00010488251 1.4672359 + 13000 127.86814 0.0011839642 127.86814 -9.0014128e-05 1420.4476 + 13500 154.09961 0.0014268483 154.09961 -7.7815401e-05 5.4703004 + 14000 154.31359 0.0014288295 154.31359 -6.7709777e-05 0.025351973 + 14500 154.3112 0.0014288074 154.3112 -5.9265083e-05 -0.020243217 + 15000 154.30773 0.0014287753 154.30773 -5.2152714e-05 -0.013791198 + 15500 154.30551 0.0014287547 154.30551 -4.6119584e-05 -0.0090829354 + 16000 154.30409 0.0014287415 154.30409 -4.0968492e-05 -0.0062748728 + 16500 154.30315 0.0014287329 154.30315 -3.6544144e-05 -0.004532774 + 17000 154.30254 0.0014287272 154.30254 -3.2723062e-05 -0.003394041 + 17500 154.30216 0.0014287237 154.30216 -2.9406189e-05 -0.0026153428 + 18000 154.30195 0.0014287218 154.30195 -2.6513408e-05 -0.0020627306 + 18500 154.30188 0.0014287211 154.30188 -2.397943e-05 -0.0016584214 + 19000 154.30194 0.0014287216 154.30194 -2.1750674e-05 -0.0013550174 + 19500 154.3021 0.0014287232 154.3021 -1.9782885e-05 -0.0011224153 + 20000 154.30239 0.0014287258 154.30239 -1.8039282e-05 -0.00094080826 + 20500 154.30279 0.0014287295 154.30279 -1.6489128e-05 -0.00079676335 + 21000 154.30332 0.0014287345 154.30332 -1.5106598e-05 -0.00068092925 + 21500 154.30401 0.0014287409 154.30401 -1.3869884e-05 -0.000586646 + 22000 154.30489 0.001428749 154.30489 -1.2760487e-05 -0.00050907464 + 22500 154.30601 0.0014287593 154.30601 -1.1762643e-05 -0.00044463657 + 23000 154.30743 0.0014287725 154.30743 -1.0862863e-05 -0.00039064328 + 23500 154.30924 0.0014287893 154.30924 -1.004956e-05 -0.00034504622 + 24000 154.31159 0.001428811 154.31159 -9.3127419e-06 -0.0003062645 + 24500 154.31464 0.0014288393 154.31464 8.7817413e-06 -0.00027306395 + 25000 154.31848 0.0014288748 154.31848 9.4348998e-06 -0.00024447093 + 25500 154.32222 0.0014289094 154.32222 1.0150613e-05 -0.00021970994 + 26000 154.31667 0.0014288581 154.31667 1.0936298e-05 -0.0001981578 + 26500 154.19679 0.0014277481 154.19679 1.1800434e-05 -0.00017930967 + 27000 151.70582 0.0014046835 151.70582 1.2752738e-05 -0.00016275349 + 27500 144.06864 0.0013339689 144.06864 1.3804382e-05 -0.00014815061 + 28000 153.30039 0.0014194481 153.30039 1.4968247e-05 -0.00013522085 + 28500 153.70626 0.0014232061 153.70626 1.6259237e-05 -0.00012373107 + 29000 153.73143 0.0014234392 153.73143 1.7694652e-05 -0.00011348611 + 29500 153.72942 0.0014234205 153.72942 1.9294649e-05 -0.0001043218 + 30000 153.72536 0.001423383 153.72536 2.1082798e-05 -9.6099303e-05 + 30500 153.72189 0.0014233508 153.72189 2.3086777e-05 -8.8700684e-05 + 31000 153.71915 0.0014233255 153.71915 2.533922e-05 -8.2025314e-05 + 31500 153.71701 0.0014233056 153.71701 2.7878775e-05 -7.5986974e-05 + 32000 153.7153 0.0014232898 153.7153 3.0751438e-05 -7.05115e-05 + 32500 153.71392 0.0014232771 153.71392 3.4012214e-05 -6.5534861e-05 + 33000 153.7128 0.0014232667 153.7128 3.7727241e-05 -6.1001578e-05 + 33500 153.71187 0.001423258 153.71187 4.1976497e-05 -5.686342e-05 + 34000 153.71109 0.0014232508 153.71109 4.6857282e-05 -5.3078322e-05 + 34500 153.71043 0.0014232447 153.71043 5.2488748e-05 -4.9609488e-05 + 35000 153.70987 0.0014232395 153.70987 5.9017833e-05 -4.6424634e-05 + 35500 153.70939 0.0014232351 153.70939 6.6627108e-05 -4.3495356e-05 + 36000 153.70898 0.0014232313 153.70898 7.5545279e-05 -4.0796599e-05 + 36500 153.70863 0.001423228 153.70863 8.6061387e-05 -3.8306204e-05 + 37000 153.70832 0.0014232252 153.70832 9.8544264e-05 -3.6004526e-05 + 37500 153.70806 0.0014232227 153.70806 0.00011346953 -3.3874109e-05 + 38000 153.70783 0.0014232207 153.70783 0.00013145761 -3.1899404e-05 + 38500 153.70764 0.0014232189 153.70764 0.00015332826 -3.0066532e-05 + 39000 153.70748 0.0014232174 153.70748 0.00018017988 -2.836308e-05 + 39500 153.70736 0.0014232163 153.70736 0.00021350768 -2.6777922e-05 + 40000 153.70726 0.0014232154 153.70726 0.00025538329 -2.5301066e-05 + 40500 153.70719 0.0014232147 153.70719 0.00030873482 -2.3923522e-05 + 41000 153.70716 0.0014232145 153.70716 0.00037779644 -2.2637186e-05 + 41500 153.70717 0.0014232145 153.70717 0.00046885357 -2.1434741e-05 + 42000 153.70722 0.001423215 153.70722 0.00059152584 -2.0309568e-05 + 42500 153.70733 0.001423216 153.70733 0.00076107465 -1.9255668e-05 + 43000 153.70751 0.0014232177 153.70751 0.0010027741 -1.82676e-05 + 43500 153.7078 0.0014232203 153.7078 0.0013607156 -1.7340414e-05 + 44000 153.70823 0.0014232244 153.70823 0.0019168919 -1.6469607e-05 + 44500 153.70891 0.0014232306 153.70891 0.0028362183 -1.5651071e-05 + 45000 153.70999 0.0014232407 153.70999 0.0044814624 -1.4881056e-05 + 45500 153.71183 0.0014232577 153.71183 0.0076783372 -1.4156133e-05 + 46000 153.71504 0.0014232874 153.71504 0.012021529 -1.347316e-05 + 46500 153.70337 0.0014231794 153.70337 -0.27386631 -1.2829258e-05 + 47000 109.96863 0.0010182281 109.96863 -1552.3264 -1.2221783e-05 + 47500 56.442204 0.000522613 56.442204 -0.62595366 -1.1648303e-05 + 48000 56.439532 0.00052258826 56.439532 0.015282177 -1.1106581e-05 + 48500 56.439907 0.00052259173 56.439907 0.01178542 -1.0594552e-05 + 49000 56.44015 0.00052259399 56.44015 0.0080268131 -1.0110314e-05 + 49500 56.440316 0.00052259552 56.440316 0.0061338692 -9.6521057e-06 + 50000 56.440444 0.0005225967 56.440444 0.005195231 -9.2183009e-06 +Loop time of 0.344104 on 1 procs for 50000 steps with 3 atoms + +Performance: 6277171.077 tau/day, 145304.886 timesteps/s +98.2% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.023412 | 0.023412 | 0.023412 | 0.0 | 6.80 +Neigh | 0.13182 | 0.13182 | 0.13182 | 0.0 | 38.31 +Comm | 0.084006 | 0.084006 | 0.084006 | 0.0 | 24.41 +Output | 0.0023429 | 0.0023429 | 0.0023429 | 0.0 | 0.68 +Modify | 0.083383 | 0.083383 | 0.083383 | 0.0 | 24.23 +Other | | 0.01914 | | | 5.56 + +Nlocal: 3 ave 3 max 3 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1 ave 1 max 1 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 0 +Ave neighs/atom = 0 +Neighbor list builds = 210 +Dangerous builds = 0 + +Total wall time: 0:00:00 diff --git a/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.4 b/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.4 new file mode 100644 index 0000000000..6a5f6fca19 --- /dev/null +++ b/examples/USER/misc/ees/log.23Jun17.fix_wall_region.g++.4 @@ -0,0 +1,180 @@ +LAMMPS (23 Jun 2017) + using 1 OpenMP thread(s) per MPI task +units lj +atom_style ellipsoid +boundary p p p +read_data Data_region + orthogonal box = (0 0 0) to (60 60 60) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 3 atoms + 3 ellipsoids + reading velocities ... + 3 velocities +#------------------------------------# +region the_wall block 20. 40. 20. 40. 20. 40. side out +#------------------------------------# +pair_style resquared 1 +pair_coeff 1 1 10.0 1.0 0.5 0.5 4 0.5 0.5 4 1 +#------------------------------------# +timestep 0.0005 +#------------------------------------# + +fix EES_block all wall/region/ees the_wall 10. 1. 20 +#^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^# + +thermo_style custom step temp press etotal f_EES_block[1] f_EES_block[3] + +fix NVE all nve/asphere +#------------------------------------# +compute qw all property/atom quatw +compute qi all property/atom quati +compute qj all property/atom quatj +compute qk all property/atom quatk +#------------------------------------# +thermo 500 +#dump 1 all custom 1000 dump_region id type x y z c_qw c_qi c_qj c_qk +run 50000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 1.3 + ghost atom cutoff = 1.3 + binsize = 0.65, bins = 93 93 93 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair resquared, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 5.629 | 5.722 | 5.754 Mbytes +Step Temp Press TotEng f_EES_block[1] f_EES_block[3] + 0 161.26842 0.0014932261 161.26842 -0.00042715909 -0.00015747012 + 500 161.26864 0.0014932281 161.26864 -0.00055836679 -0.00017557792 + 1000 161.26891 0.0014932306 161.26891 -0.00075239934 -0.00019646897 + 1500 161.26926 0.0014932339 161.26926 -0.0010543331 -0.0002206925 + 2000 161.26975 0.0014932385 161.26975 -0.0015566164 -0.00024893301 + 2500 161.27047 0.0014932451 161.27047 -0.0024700842 -0.00028205104 + 3000 161.27163 0.0014932558 161.27163 -0.0043191186 -0.00032113859 + 3500 161.27364 0.0014932745 161.27364 -0.0073109231 -0.00036759584 + 4000 161.26391 0.0014931843 161.26391 0.2453813 -0.00042323837 + 4500 77.783029 0.00072021324 77.783029 4908.2333 -0.00049044991 + 5000 160.23852 0.00148369 160.23852 0.13220034 -0.00057240356 + 5500 160.2431 0.0014837324 160.2431 -0.0072005112 -0.00067338844 + 6000 160.24148 0.0014837174 160.24148 -0.0040896209 -0.0007993028 + 6500 160.24071 0.0014837103 160.24071 -0.0023574992 -0.00095841662 + 7000 160.24038 0.0014837072 160.24038 -0.001495267 -0.001162584 + 7500 160.24031 0.0014837066 160.24031 -0.0010172907 -0.0014292316 + 8000 160.24043 0.0014837077 160.24043 -0.00072823316 -0.0017847384 + 8500 160.24073 0.0014837105 160.24073 -0.00054165121 -0.0022704187 + 9000 160.24121 0.0014837149 160.24121 -0.00041506183 -0.0029536182 + 9500 160.24192 0.0014837215 160.24192 -0.00032574317 -0.0039493769 + 10000 160.24293 0.0014837308 160.24293 -0.00026069929 -0.0054649542 + 10500 160.2444 0.0014837444 160.2444 -0.00021208476 -0.0078936604 + 11000 160.2466 0.0014837648 160.2466 -0.00017494913 -0.011981095 + 11500 160.25001 0.0014837964 160.25001 -0.00014605132 -0.018414768 + 12000 160.25411 0.0014838343 160.25411 -0.00012320207 -0.0069059119 + 12500 160.18929 0.0014832342 160.18929 -0.00010488251 1.4672359 + 13000 127.86814 0.0011839642 127.86814 -9.0014128e-05 1420.4476 + 13500 154.09961 0.0014268483 154.09961 -7.7815401e-05 5.4703004 + 14000 154.31359 0.0014288295 154.31359 -6.7709777e-05 0.025351973 + 14500 154.3112 0.0014288074 154.3112 -5.9265083e-05 -0.020243217 + 15000 154.30773 0.0014287753 154.30773 -5.2152714e-05 -0.013791198 + 15500 154.30551 0.0014287547 154.30551 -4.6119584e-05 -0.0090829354 + 16000 154.30409 0.0014287415 154.30409 -4.0968492e-05 -0.0062748728 + 16500 154.30315 0.0014287329 154.30315 -3.6544144e-05 -0.004532774 + 17000 154.30254 0.0014287272 154.30254 -3.2723062e-05 -0.003394041 + 17500 154.30216 0.0014287237 154.30216 -2.9406189e-05 -0.0026153428 + 18000 154.30195 0.0014287218 154.30195 -2.6513408e-05 -0.0020627306 + 18500 154.30188 0.0014287211 154.30188 -2.397943e-05 -0.0016584214 + 19000 154.30194 0.0014287216 154.30194 -2.1750674e-05 -0.0013550174 + 19500 154.3021 0.0014287232 154.3021 -1.9782885e-05 -0.0011224153 + 20000 154.30239 0.0014287258 154.30239 -1.8039282e-05 -0.00094080826 + 20500 154.30279 0.0014287295 154.30279 -1.6489128e-05 -0.00079676335 + 21000 154.30332 0.0014287345 154.30332 -1.5106598e-05 -0.00068092925 + 21500 154.30401 0.0014287409 154.30401 -1.3869884e-05 -0.000586646 + 22000 154.30489 0.001428749 154.30489 -1.2760487e-05 -0.00050907464 + 22500 154.30601 0.0014287593 154.30601 -1.1762643e-05 -0.00044463657 + 23000 154.30743 0.0014287725 154.30743 -1.0862863e-05 -0.00039064328 + 23500 154.30924 0.0014287893 154.30924 -1.004956e-05 -0.00034504622 + 24000 154.31159 0.001428811 154.31159 -9.3127419e-06 -0.0003062645 + 24500 154.31464 0.0014288393 154.31464 8.7817413e-06 -0.00027306395 + 25000 154.31848 0.0014288748 154.31848 9.4348998e-06 -0.00024447093 + 25500 154.32222 0.0014289094 154.32222 1.0150613e-05 -0.00021970994 + 26000 154.31667 0.0014288581 154.31667 1.0936298e-05 -0.0001981578 + 26500 154.19679 0.0014277481 154.19679 1.1800434e-05 -0.00017930967 + 27000 151.70582 0.0014046835 151.70582 1.2752738e-05 -0.00016275349 + 27500 144.06864 0.0013339689 144.06864 1.3804382e-05 -0.00014815061 + 28000 153.30039 0.0014194481 153.30039 1.4968247e-05 -0.00013522085 + 28500 153.70626 0.0014232061 153.70626 1.6259237e-05 -0.00012373107 + 29000 153.73143 0.0014234392 153.73143 1.7694652e-05 -0.00011348611 + 29500 153.72942 0.0014234205 153.72942 1.9294649e-05 -0.0001043218 + 30000 153.72536 0.001423383 153.72536 2.1082798e-05 -9.6099303e-05 + 30500 153.72189 0.0014233508 153.72189 2.3086777e-05 -8.8700684e-05 + 31000 153.71915 0.0014233255 153.71915 2.533922e-05 -8.2025314e-05 + 31500 153.71701 0.0014233056 153.71701 2.7878775e-05 -7.5986974e-05 + 32000 153.7153 0.0014232898 153.7153 3.0751438e-05 -7.05115e-05 + 32500 153.71392 0.0014232771 153.71392 3.4012214e-05 -6.5534861e-05 + 33000 153.7128 0.0014232667 153.7128 3.7727241e-05 -6.1001578e-05 + 33500 153.71187 0.001423258 153.71187 4.1976497e-05 -5.686342e-05 + 34000 153.71109 0.0014232508 153.71109 4.6857282e-05 -5.3078322e-05 + 34500 153.71043 0.0014232447 153.71043 5.2488748e-05 -4.9609488e-05 + 35000 153.70987 0.0014232395 153.70987 5.9017833e-05 -4.6424634e-05 + 35500 153.70939 0.0014232351 153.70939 6.6627108e-05 -4.3495356e-05 + 36000 153.70898 0.0014232313 153.70898 7.5545279e-05 -4.0796599e-05 + 36500 153.70863 0.001423228 153.70863 8.6061387e-05 -3.8306204e-05 + 37000 153.70832 0.0014232252 153.70832 9.8544264e-05 -3.6004526e-05 + 37500 153.70806 0.0014232227 153.70806 0.00011346953 -3.3874109e-05 + 38000 153.70783 0.0014232207 153.70783 0.00013145761 -3.1899404e-05 + 38500 153.70764 0.0014232189 153.70764 0.00015332826 -3.0066532e-05 + 39000 153.70748 0.0014232174 153.70748 0.00018017988 -2.836308e-05 + 39500 153.70736 0.0014232163 153.70736 0.00021350768 -2.6777922e-05 + 40000 153.70726 0.0014232154 153.70726 0.00025538329 -2.5301066e-05 + 40500 153.70719 0.0014232147 153.70719 0.00030873482 -2.3923522e-05 + 41000 153.70716 0.0014232145 153.70716 0.00037779644 -2.2637186e-05 + 41500 153.70717 0.0014232145 153.70717 0.00046885357 -2.1434741e-05 + 42000 153.70722 0.001423215 153.70722 0.00059152584 -2.0309568e-05 + 42500 153.70733 0.001423216 153.70733 0.00076107465 -1.9255668e-05 + 43000 153.70751 0.0014232177 153.70751 0.0010027741 -1.82676e-05 + 43500 153.7078 0.0014232203 153.7078 0.0013607156 -1.7340414e-05 + 44000 153.70823 0.0014232244 153.70823 0.0019168919 -1.6469607e-05 + 44500 153.70891 0.0014232306 153.70891 0.0028362183 -1.5651071e-05 + 45000 153.70999 0.0014232407 153.70999 0.0044814624 -1.4881056e-05 + 45500 153.71183 0.0014232577 153.71183 0.0076783372 -1.4156133e-05 + 46000 153.71504 0.0014232874 153.71504 0.012021529 -1.347316e-05 + 46500 153.70337 0.0014231794 153.70337 -0.27386631 -1.2829258e-05 + 47000 109.96863 0.0010182281 109.96863 -1552.3264 -1.2221783e-05 + 47500 56.442204 0.000522613 56.442204 -0.62595366 -1.1648303e-05 + 48000 56.439532 0.00052258826 56.439532 0.015282177 -1.1106581e-05 + 48500 56.439907 0.00052259173 56.439907 0.01178542 -1.0594552e-05 + 49000 56.44015 0.00052259399 56.44015 0.0080268131 -1.0110314e-05 + 49500 56.440316 0.00052259552 56.440316 0.0061338692 -9.6521057e-06 + 50000 56.440444 0.0005225967 56.440444 0.005195231 -9.2183009e-06 +Loop time of 0.483531 on 4 procs for 50000 steps with 3 atoms + +Performance: 4467138.628 tau/day, 103405.987 timesteps/s +97.4% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.0032809 | 0.010859 | 0.013737 | 4.2 | 2.25 +Neigh | 0.037744 | 0.039156 | 0.042488 | 1.0 | 8.10 +Comm | 0.19775 | 0.2088 | 0.21768 | 1.8 | 43.18 +Output | 0.0028036 | 0.0030343 | 0.0035536 | 0.6 | 0.63 +Modify | 0.011325 | 0.032141 | 0.039636 | 6.7 | 6.65 +Other | | 0.1895 | | | 39.20 + +Nlocal: 0.75 ave 1 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 3 +Nghost: 1.75 ave 3 max 1 min +Histogram: 2 0 0 0 0 1 0 0 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 0 +Ave neighs/atom = 0 +Neighbor list builds = 210 +Dangerous builds = 0 + +Total wall time: 0:00:00 From 16fc2d6fe179d45ac86076b20238bc50086d300b Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Thu, 22 Jun 2017 22:33:09 -0500 Subject: [PATCH 036/293] Add install.py and update config for kim lib --- lib/kim/Makefile.lammps | 7 +++- lib/kim/README | 23 ++++++------- lib/kim/install.py | 72 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 14 deletions(-) create mode 100644 lib/kim/install.py diff --git a/lib/kim/Makefile.lammps b/lib/kim/Makefile.lammps index 427c62b5f3..8384f8d399 100644 --- a/lib/kim/Makefile.lammps +++ b/lib/kim/Makefile.lammps @@ -16,7 +16,12 @@ # Settings that the LAMMPS build will import when this package is installed -KIM_CONFIG_HELPER = kim-api-build-config + +ifeq ($(wildcard ../../lib/kim/bin/kim-api-build-config),) + KIM_CONFIG_HELPER = kim-api-build-config +else + KIM_CONFIG_HELPER = ../../lib/kim/bin/kim-api-build-config +endif ifeq ($(shell $(KIM_CONFIG_HELPER) --version 2> /dev/null),) $(error $(KIM_CONFIG_HELPER) utility is not available. Something is wrong with your KIM API package setup) endif diff --git a/lib/kim/README b/lib/kim/README index fcaf09bd17..086bbce90c 100644 --- a/lib/kim/README +++ b/lib/kim/README @@ -9,13 +9,16 @@ KIM API and he also maintains the code that implements the pair_style kim command. To download, build, and install the KIM API on your system, follow -these steps. We are working on scripts that will automate this -process. +these steps. You can use the install.py script to automate these steps. -The KIM API is available for download from "this -site"_https://openkim.org, namely https://openkim.org. The tarball -you download is "kim-api-vX.Y.Z.tgz", which can be unpacked in this -directory or whereever you wish: +**Note** The process described below will compile the kim-api using absolute +paths names. This means that if you move your lammps directory to a new +location after compilation the kim-api library will not be able to find some of +its components. It is best to recompile after moving the lammps directory. + +The KIM API is available for download from "this site"_https://openkim.org, +namely https://openkim.org. The tarball you download is "kim-api-vX.Y.Z.tgz", +which can be unpacked in this directory or whereever you wish: tar xvfz kim*tgz @@ -41,13 +44,7 @@ $ tar zxvf kim-api-vX.Y.Z.tgz # get OpenKIM models, setup and compile $ cd kim-api-vX.Y.Z -$ cp Makefile.KIM_Config.example Makefile.KIM_Config - -# edit this file as appropriate following the instructions given in -# INSTALL. Here, we'll assume you set the 'prefix' variable as -# follows in order to install the KIM API to your home directory: -# prefix = $(HOME)/local -$ vi Makefile.KIM_Config +$ ./configure --prefix=?????? $ make add-EAM_Dynamo_Angelo_Moody_NiAlH__MO_418978237058_001 $ make diff --git a/lib/kim/install.py b/lib/kim/install.py new file mode 100644 index 0000000000..d075e522c3 --- /dev/null +++ b/lib/kim/install.py @@ -0,0 +1,72 @@ +#!usr/local/python + +# install.py tool to setup the kim-api library +# used to automate the steps described in the README file in this dir + +import sys,os,re,urllib,commands + +help = """ +Syntax: install.py -v version + specify one or more options, order does not matter + -v = version of kim-api to download and work with + default = kim-api-v1.8.2 (current as of June 2017) +""" + +def error(): + print help + sys.exit() + +# parse args + +args = sys.argv + +dir = "." +version = "kim-api-v1.8.2" + +iarg = 1 +while iarg < len(args): + if args[iarg] == "-v": + if iarg+2 > len(args): error() + version = args[iarg+1] + iarg += 2 + else: error() + +dir = os.path.abspath(dir) +url = "https://s3.openkim.org/kim-api/%s.tgz" % version + +# download and unpack tarball + +print "Downloading kim-api tarball ..." +urllib.urlretrieve(url,"%s/%s.tgz" % (dir,version)) +print "Unpacking kim-api tarball ..." +cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (dir,version,version) +txt = commands.getstatusoutput(cmd) +if txt[0] != 0: error() + +# configure kim-api +print "Configuring kim-api ..." +cmd = "cd %s/%s; ./configure --prefix='%s'" % (dir,version,dir) +txt = commands.getstatusoutput(cmd) +print txt[1] +if txt[0] != 0: error() + +# build kim-api + +print "Building kim-api ..." +cmd = "cd %s/%s; make" % (dir,version) +txt = commands.getstatusoutput(cmd) +print txt[1] +if txt[0] != 0: error() + +# install kim-api + +print "Installing kim-api ..." +cmd = "cd %s/%s; make install" % (dir,version) +txt = commands.getstatusoutput(cmd) +print txt[1] +if txt[0] != 0: error() + +cmd = "cd %s/%s; make install-set-default-to-v1" %(dir,version) +txt = commands.getstatusoutput(cmd) +print txt[1] +if txt[0] != 0: error() From b0be8b24eac994ae2f1a7402c66b8ac69a565373 Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Thu, 6 Jul 2017 15:46:36 -0500 Subject: [PATCH 037/293] Further work on lib/kim/install.py --- lib/kim/.gitignore | 1 + lib/kim/Makefile.lammps | 5 +- lib/kim/install.py | 127 ++++++++++++++++++++++++++++++---------- 3 files changed, 101 insertions(+), 32 deletions(-) create mode 100644 lib/kim/.gitignore diff --git a/lib/kim/.gitignore b/lib/kim/.gitignore new file mode 100644 index 0000000000..eb55b3d4b8 --- /dev/null +++ b/lib/kim/.gitignore @@ -0,0 +1 @@ +/Makefile.KIM_DIR diff --git a/lib/kim/Makefile.lammps b/lib/kim/Makefile.lammps index 8384f8d399..3964e662b5 100644 --- a/lib/kim/Makefile.lammps +++ b/lib/kim/Makefile.lammps @@ -16,11 +16,12 @@ # Settings that the LAMMPS build will import when this package is installed +include ./Makefile.KIM_DIR -ifeq ($(wildcard ../../lib/kim/bin/kim-api-build-config),) +ifeq ($(wildcard $(KIM_INSTALL_DIR)/bin/kim-api-build-config),) KIM_CONFIG_HELPER = kim-api-build-config else - KIM_CONFIG_HELPER = ../../lib/kim/bin/kim-api-build-config + KIM_CONFIG_HELPER = $(KIM_INSTALL_DIR)/bin/kim-api-build-config endif ifeq ($(shell $(KIM_CONFIG_HELPER) --version 2> /dev/null),) $(error $(KIM_CONFIG_HELPER) utility is not available. Something is wrong with your KIM API package setup) diff --git a/lib/kim/install.py b/lib/kim/install.py index d075e522c3..bfc97a0983 100644 --- a/lib/kim/install.py +++ b/lib/kim/install.py @@ -6,10 +6,20 @@ import sys,os,re,urllib,commands help = """ -Syntax: install.py -v version +Syntax: install.py -v version -c kim-dir -b kim-model-name -a kim-name specify one or more options, order does not matter -v = version of kim-api to download and work with default = kim-api-v1.8.2 (current as of June 2017) + -c = create Makefile.KIM_DIR within lammps lib/kim to configure lammps + for use with the kim-api library installed at "kim-dir" (absolute + path). default = this dir + -b = build kim-api and kim model where kim-model-name can be a specific + openkim.org model name (such as + "EAM_Dynamo_Ackland_W__MO_141627196590_002") or the keyword + "OpenKIM" to install all compatible models from the openkim.org + site. + -a = add kim-name openkim.org item (model driver or model) to existing + kim-api instalation. """ def error(): @@ -20,53 +30,110 @@ def error(): args = sys.argv -dir = "." +thisdir = os.environ['PWD'] +dir = thisdir version = "kim-api-v1.8.2" +dirflag = 0 +buildflag = 0 +addflag = 0 + iarg = 1 while iarg < len(args): if args[iarg] == "-v": if iarg+2 > len(args): error() version = args[iarg+1] iarg += 2 + elif args[iarg] == "-c": + dirflag = 1 + if iarg+2 > len(args): error() + dir = args[iarg+1] + iarg += 2 + elif args[iarg] == "-b": + buildflag = 1 + if iarg+2 > len(args): error() + modelname = args[iarg+1] + iarg += 2 + elif args[iarg] == "-a": + addflag = 1 + if iarg+2 > len(args): error() + addmodelname = args[iarg+1] + iarg += 2 else: error() +thisdir = os.path.abspath(thisdir) dir = os.path.abspath(dir) url = "https://s3.openkim.org/kim-api/%s.tgz" % version # download and unpack tarball -print "Downloading kim-api tarball ..." -urllib.urlretrieve(url,"%s/%s.tgz" % (dir,version)) -print "Unpacking kim-api tarball ..." -cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (dir,version,version) -txt = commands.getstatusoutput(cmd) -if txt[0] != 0: error() -# configure kim-api -print "Configuring kim-api ..." -cmd = "cd %s/%s; ./configure --prefix='%s'" % (dir,version,dir) -txt = commands.getstatusoutput(cmd) -print txt[1] -if txt[0] != 0: error() +if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): + open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) + print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) +else: + if dirflag == 1: + open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) + print "Updated %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) -# build kim-api -print "Building kim-api ..." -cmd = "cd %s/%s; make" % (dir,version) -txt = commands.getstatusoutput(cmd) -print txt[1] -if txt[0] != 0: error() +if buildflag == 1: + # download kim-api + print "Downloading kim-api tarball ..." + urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) + print "Unpacking kim-api tarball ..." + cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) + txt = commands.getstatusoutput(cmd) + if txt[0] != 0: error() -# install kim-api + # configure kim-api + print "Configuring kim-api ..." + cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() -print "Installing kim-api ..." -cmd = "cd %s/%s; make install" % (dir,version) -txt = commands.getstatusoutput(cmd) -print txt[1] -if txt[0] != 0: error() + # build kim-api + print "Configuring model : %s" % modelname + cmd = "cd %s/%s; make add-%s" % (thisdir,version,modelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + # + print "Building kim-api ..." + cmd = "cd %s/%s; make" % (thisdir,version) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() -cmd = "cd %s/%s; make install-set-default-to-v1" %(dir,version) -txt = commands.getstatusoutput(cmd) -print txt[1] -if txt[0] != 0: error() + # install kim-api + print "Installing kim-api ..." + cmd = "cd %s/%s; make install" % (thisdir,version) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + # + cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + + # remove source files + print "Removing kim-api source and build files" + cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + +if addflag == 1: + # download model + url = "https://openkim.org/download/%s.tgz" % addmodelname + print "Downloading item tarball ..." + urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) + print "Unpacking item tarball ..." + cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + if txt[0] != 0: error() + # + print "Building item ..." + #..... From fe888e46221910931096e959d48943114ef974ee Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 7 Jul 2017 15:39:25 -0400 Subject: [PATCH 038/293] add support for recomputing normalization factors and finite size correction during --- doc/src/compute_rdf.txt | 11 ++++- src/compute_rdf.cpp | 96 ++++++++++++++++++++++++++--------------- src/compute_rdf.h | 2 + 3 files changed, 73 insertions(+), 36 deletions(-) diff --git a/doc/src/compute_rdf.txt b/doc/src/compute_rdf.txt index acbc0e4f0c..e462e85fc0 100644 --- a/doc/src/compute_rdf.txt +++ b/doc/src/compute_rdf.txt @@ -180,9 +180,18 @@ will register an arbitrarily large spike at whatever distance they happen to be at, and zero everywhere else. Coord(r) will show a step change from zero to one at the location of the spike in g(r). +NOTE: compute rdf can handle dynamic groups and systems where atoms +are added or removed, but this causes that certain normalization +parameters need to be recomputed in every step and include collective +communication operations. This will reduce performance and limit +parallel efficiency and scaling. For systems, where only the type +of atoms changes (e.g. when using "fix atom/swap"_fix_atom_swap.html), +you need to explicitly request the dynamic normalization updates +via "compute_modify dynamic yes"_compute_modify.html + [Related commands:] -"fix ave/time"_fix_ave_time.html +"fix ave/time"_fix_ave_time.html, "compute_modify"_compute_modify.html [Default:] diff --git a/src/compute_rdf.cpp b/src/compute_rdf.cpp index fc6ad6d8b6..72eb46f6f5 100644 --- a/src/compute_rdf.cpp +++ b/src/compute_rdf.cpp @@ -48,7 +48,6 @@ ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : array_flag = 1; extarray = 0; - dynamic_group_allow = 0; nbin = force->inumeric(FLERR,arg[3]); if (nbin < 1) error->all(FLERR,"Illegal compute rdf command"); @@ -125,6 +124,9 @@ ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : icount = new int[npairs]; jcount = new int[npairs]; duplicates = new int[npairs]; + + dynamic = 0; + natoms_old = 0; } /* ---------------------------------------------------------------------- */ @@ -150,7 +152,6 @@ ComputeRDF::~ComputeRDF() void ComputeRDF::init() { - int i,j,m; if (!force->pair && !cutflag) error->all(FLERR,"Compute rdf requires a pair style be defined " @@ -184,40 +185,12 @@ void ComputeRDF::init() for (int i = 0; i < nbin; i++) array[i][0] = (i+0.5) * delr; - // count atoms of each type that are also in group + // initialize normalization, finite size correction, and changing atom counts - int *mask = atom->mask; - int *type = atom->type; - int nlocal = atom->nlocal; - int ntypes = atom->ntypes; - - for (i = 1; i <= ntypes; i++) typecount[i] = 0; - for (i = 0; i < nlocal; i++) - if (mask[i] & groupbit) typecount[type[i]]++; - - // icount = # of I atoms participating in I,J pairs for each histogram - // jcount = # of J atoms participating in I,J pairs for each histogram - // duplicates = # of atoms in both groups I and J for each histogram - - for (m = 0; m < npairs; m++) { - icount[m] = 0; - for (i = ilo[m]; i <= ihi[m]; i++) icount[m] += typecount[i]; - jcount[m] = 0; - for (i = jlo[m]; i <= jhi[m]; i++) jcount[m] += typecount[i]; - duplicates[m] = 0; - for (i = ilo[m]; i <= ihi[m]; i++) - for (j = jlo[m]; j <= jhi[m]; j++) - if (i == j) duplicates[m] += typecount[i]; - } - - int *scratch = new int[npairs]; - MPI_Allreduce(icount,scratch,npairs,MPI_INT,MPI_SUM,world); - for (i = 0; i < npairs; i++) icount[i] = scratch[i]; - MPI_Allreduce(jcount,scratch,npairs,MPI_INT,MPI_SUM,world); - for (i = 0; i < npairs; i++) jcount[i] = scratch[i]; - MPI_Allreduce(duplicates,scratch,npairs,MPI_INT,MPI_SUM,world); - for (i = 0; i < npairs; i++) duplicates[i] = scratch[i]; - delete [] scratch; + natoms_old = atom->natoms; + dynamic = group->dynamic[igroup]; + if (dynamic_user) dynamic = 1; + init_norm(); // need an occasional half neighbor list // if user specified, request a cutoff = cutoff_user + skin @@ -246,6 +219,48 @@ void ComputeRDF::init_list(int id, NeighList *ptr) /* ---------------------------------------------------------------------- */ +void ComputeRDF::init_norm() +{ + int i,j,m; + + // count atoms of each type that are also in group + + const int nlocal = atom->nlocal; + const int ntypes = atom->ntypes; + const int * const mask = atom->mask; + const int * const type = atom->type; + + for (i = 1; i <= ntypes; i++) typecount[i] = 0; + for (i = 0; i < nlocal; i++) + if (mask[i] & groupbit) typecount[type[i]]++; + + // icount = # of I atoms participating in I,J pairs for each histogram + // jcount = # of J atoms participating in I,J pairs for each histogram + // duplicates = # of atoms in both groups I and J for each histogram + + for (m = 0; m < npairs; m++) { + icount[m] = 0; + for (i = ilo[m]; i <= ihi[m]; i++) icount[m] += typecount[i]; + jcount[m] = 0; + for (i = jlo[m]; i <= jhi[m]; i++) jcount[m] += typecount[i]; + duplicates[m] = 0; + for (i = ilo[m]; i <= ihi[m]; i++) + for (j = jlo[m]; j <= jhi[m]; j++) + if (i == j) duplicates[m] += typecount[i]; + } + + int *scratch = new int[npairs]; + MPI_Allreduce(icount,scratch,npairs,MPI_INT,MPI_SUM,world); + for (i = 0; i < npairs; i++) icount[i] = scratch[i]; + MPI_Allreduce(jcount,scratch,npairs,MPI_INT,MPI_SUM,world); + for (i = 0; i < npairs; i++) jcount[i] = scratch[i]; + MPI_Allreduce(duplicates,scratch,npairs,MPI_INT,MPI_SUM,world); + for (i = 0; i < npairs; i++) duplicates[i] = scratch[i]; + delete [] scratch; +} + +/* ---------------------------------------------------------------------- */ + void ComputeRDF::compute_array() { int i,j,m,ii,jj,inum,jnum,itype,jtype,ipair,jpair,ibin,ihisto; @@ -253,6 +268,17 @@ void ComputeRDF::compute_array() int *ilist,*jlist,*numneigh,**firstneigh; double factor_lj,factor_coul; + if (natoms_old != atom->natoms) { + dynamic = 1; + natoms_old = atom->natoms; + } + + // if the number of atoms has changed or we have a dynamic group + // or dynamic updates are requested (e.g. when changing atom types) + // we need to recompute some normalization parameters + + if (dynamic) init_norm(); + invoked_array = update->ntimestep; // invoke half neighbor list (will copy or build if necessary) diff --git a/src/compute_rdf.h b/src/compute_rdf.h index 61d99e0881..4188799b74 100644 --- a/src/compute_rdf.h +++ b/src/compute_rdf.h @@ -51,6 +51,8 @@ class ComputeRDF : public Compute { int *duplicates; class NeighList *list; // half neighbor list + void init_norm(); + bigint natoms_old; }; } From 71ddcaf0b607c6518516bb67907eee64d80eeea8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 7 Jul 2017 15:50:19 -0400 Subject: [PATCH 039/293] whitespace cleanup --- src/compute_rdf.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/compute_rdf.cpp b/src/compute_rdf.cpp index 72eb46f6f5..167de4576d 100644 --- a/src/compute_rdf.cpp +++ b/src/compute_rdf.cpp @@ -41,7 +41,7 @@ using namespace MathConst; ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : Compute(lmp, narg, arg), rdfpair(NULL), nrdfpair(NULL), ilo(NULL), ihi(NULL), jlo(NULL), jhi(NULL), - hist(NULL), histall(NULL), typecount(NULL), icount(NULL), jcount(NULL), + hist(NULL), histall(NULL), typecount(NULL), icount(NULL), jcount(NULL), duplicates(NULL) { if (narg < 4 || (narg-4) % 2) error->all(FLERR,"Illegal compute rdf command"); @@ -72,7 +72,7 @@ ComputeRDF::ComputeRDF(LAMMPS *lmp, int narg, char **arg) : iarg += 2; } else error->all(FLERR,"Illegal compute rdf command"); } - + // pairwise args if (nargpair == 0) npairs = 1; @@ -162,12 +162,12 @@ void ComputeRDF::init() mycutneigh = cutoff_user + skin; double cutghost; // as computed by Neighbor and Comm - if (force->pair) + if (force->pair) cutghost = MAX(force->pair->cutforce+skin,comm->cutghostuser); - else + else cutghost = comm->cutghostuser; - if (mycutneigh > cutghost) + if (mycutneigh > cutghost) error->all(FLERR,"Compure rdf cutoff exceeds ghost atom range - " "use comm_modify cutoff command"); if (force->pair && mycutneigh < force->pair->cutforce + skin) From 68206079da39fbef08c37e5c1cef1ae8bd9ad2c6 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Fri, 7 Jul 2017 16:47:24 -0500 Subject: [PATCH 040/293] Supported short neighbor lists for 3-body kernels in sw/gpu and vashishta/gpu --- lib/gpu/lal_aux_fun1.h | 24 +++---- lib/gpu/lal_base_three.cpp | 65 ++++++++++++++---- lib/gpu/lal_base_three.h | 27 ++++---- lib/gpu/lal_sw.cpp | 26 ++++++-- lib/gpu/lal_sw.cu | 117 +++++++++++++++++++++++++++++--- lib/gpu/lal_vashishta.cpp | 34 +++++++--- lib/gpu/lal_vashishta.cu | 133 +++++++++++++++++++++++++++++-------- lib/gpu/lal_vashishta.h | 1 + 8 files changed, 332 insertions(+), 95 deletions(-) diff --git a/lib/gpu/lal_aux_fun1.h b/lib/gpu/lal_aux_fun1.h index b40bb7f943..47a216ff6f 100644 --- a/lib/gpu/lal_aux_fun1.h +++ b/lib/gpu/lal_aux_fun1.h @@ -22,21 +22,21 @@ offset=tid & (t_per_atom-1); \ ii=fast_mul((int)BLOCK_ID_X,(int)(BLOCK_SIZE_X)/t_per_atom)+tid/t_per_atom; -#define nbor_info(nbor_mem, packed_mem, nbor_stride, t_per_atom, ii, offset, \ - i, numj, stride, nbor_end, nbor_begin) \ - i=nbor_mem[ii]; \ - nbor_begin=ii+nbor_stride; \ - numj=nbor_mem[nbor_begin]; \ - if (nbor_mem==packed_mem) { \ - nbor_begin+=nbor_stride+fast_mul(ii,t_per_atom-1); \ - stride=fast_mul(t_per_atom,nbor_stride); \ - nbor_end=nbor_begin+fast_mul(numj/t_per_atom,stride)+(numj & (t_per_atom-1)); \ +#define nbor_info(dev_nbor, dev_packed, nbor_pitch, t_per_atom, ii, offset, \ + i, numj, n_stride, nbor_end, nbor_begin) \ + i=dev_nbor[ii]; \ + nbor_begin=ii+nbor_pitch; \ + numj=dev_nbor[nbor_begin]; \ + if (dev_nbor==dev_packed) { \ + nbor_begin+=nbor_pitch+fast_mul(ii,t_per_atom-1); \ + n_stride=fast_mul(t_per_atom,nbor_pitch); \ + nbor_end=nbor_begin+fast_mul(numj/t_per_atom,n_stride)+(numj & (t_per_atom-1)); \ nbor_begin+=offset; \ } else { \ - nbor_begin+=nbor_stride; \ - nbor_begin=nbor_mem[nbor_begin]; \ + nbor_begin+=nbor_pitch; \ + nbor_begin=dev_nbor[nbor_begin]; \ nbor_end=nbor_begin+numj; \ - stride=t_per_atom; \ + n_stride=t_per_atom; \ nbor_begin+=offset; \ } diff --git a/lib/gpu/lal_base_three.cpp b/lib/gpu/lal_base_three.cpp index f772e36295..fd9fc7f272 100644 --- a/lib/gpu/lal_base_three.cpp +++ b/lib/gpu/lal_base_three.cpp @@ -20,7 +20,7 @@ using namespace LAMMPS_AL; extern Device global_device; template -BaseThreeT::BaseThree() : _compiled(false), _max_bytes(0) { +BaseThreeT::BaseThree() : _compiled(false), _max_bytes(0), _short_nbor(false) { device=&global_device; ans=new Answer(); nbor=new Neighbor(); @@ -53,8 +53,8 @@ int BaseThreeT::init_three(const int nlocal, const int nall, const int max_nbors, const int maxspecial, const double cell_size, const double gpu_split, FILE *_screen, const void *pair_program, - const char *k_two, const char *k_three_center, - const char *k_three_end) { + const char *two, const char *three_center, + const char *three_end, const char *short_nbor) { screen=_screen; int gpu_nbor=0; @@ -70,10 +70,10 @@ int BaseThreeT::init_three(const int nlocal, const int nall, _gpu_host=1; _threads_per_atom=device->threads_per_atom(); - if (_threads_per_atom>1 && gpu_nbor==0) { + if (_threads_per_atom>1 && gpu_nbor==0) { // neigh no and tpa > 1 nbor->packing(true); _nbor_data=&(nbor->dev_packed); - } else + } else // neigh yes or tpa == 1 _nbor_data=&(nbor->dev_nbor); if (_threads_per_atom*_threads_per_atom>device->warp_size()) return -10; @@ -97,7 +97,7 @@ int BaseThreeT::init_three(const int nlocal, const int nall, _block_pair=device->pair_block_size(); _block_size=device->block_ellipse(); - compile_kernels(*ucl_device,pair_program,k_two,k_three_center,k_three_end); + compile_kernels(*ucl_device,pair_program,two,three_center,three_end,short_nbor); // Initialize host-device load balancer hd_balancer.init(device,gpu_nbor,gpu_split); @@ -113,6 +113,15 @@ int BaseThreeT::init_three(const int nlocal, const int nall, _max_an_bytes+=ans2->gpu_bytes(); #endif + // if short neighbor list is supported + if (short_nbor) { + _short_nbor = true; + int ef_nall=nall; + if (ef_nall==0) + ef_nall=2000; + dev_short_nbor.alloc(ef_nall*(2+max_nbors),*(this->ucl_device),UCL_READ_WRITE); + } + return 0; } @@ -136,6 +145,7 @@ void BaseThreeT::clear_atomic() { k_three_end.clear(); k_three_end_vatom.clear(); k_pair.clear(); + k_short_nbor.clear(); delete pair_program; _compiled=false; } @@ -143,6 +153,7 @@ void BaseThreeT::clear_atomic() { time_pair.clear(); hd_balancer.clear(); + dev_short_nbor.clear(); nbor->clear(); ans->clear(); #ifdef THREE_CONCURRENT @@ -247,12 +258,26 @@ void BaseThreeT::compute(const int f_ago, const int inum_full, const int nall, reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); if (!success) return; + _max_nbors = nbor->max_nbor_loop(nlist,numj,ilist); } atom->cast_x_data(host_x,host_type); hd_balancer.start_timer(); atom->add_x_data(host_x,host_type); + // if short neighbor list is supported + if (_short_nbor) { + + // re-allocate dev_short_nbor if necessary + if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + dev_short_nbor.resize((2+_max_nbors)*_nmax); + } + } + + // _ainum to be used in loop() for short neighbor list build + _ainum = nlist; + int evatom=0; if (eatom || vatom) evatom=1; @@ -300,7 +325,7 @@ int ** BaseThreeT::compute(const int ago, const int inum_full, // Build neighbor list on GPU if necessary if (ago==0) { - build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, + _max_nbors = build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, sublo, subhi, tag, nspecial, special, success); if (!success) return NULL; @@ -313,6 +338,19 @@ int ** BaseThreeT::compute(const int ago, const int inum_full, *ilist=nbor->host_ilist.begin(); *jnum=nbor->host_acc.begin(); + // if short neighbor list is supported + if (_short_nbor) { + + // re-allocate dev_short_nbor if necessary + if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + dev_short_nbor.resize((2+_max_nbors)*_nmax); + } + } + + // _ainum to be used in loop() for short neighbor list build + _ainum = nall; + int evatom=0; if (eatom || vatom) evatom=1; @@ -339,19 +377,20 @@ double BaseThreeT::host_memory_usage_atomic() const { template void BaseThreeT::compile_kernels(UCL_Device &dev, const void *pair_str, - const char *ktwo, const char *kthree_center, - const char *kthree_end) { + const char *two, const char *three_center, + const char *three_end, const char* short_nbor) { if (_compiled) return; - std::string vatom_name=std::string(kthree_end)+"_vatom"; + std::string vatom_name=std::string(three_end)+"_vatom"; pair_program=new UCL_Program(dev); pair_program->load_string(pair_str,device->compile_string().c_str()); - k_three_center.set_function(*pair_program,kthree_center); - k_three_end.set_function(*pair_program,kthree_end); + k_three_center.set_function(*pair_program,three_center); + k_three_end.set_function(*pair_program,three_end); k_three_end_vatom.set_function(*pair_program,vatom_name.c_str()); - k_pair.set_function(*pair_program,ktwo); + k_pair.set_function(*pair_program,two); + if (short_nbor) k_short_nbor.set_function(*pair_program,short_nbor); pos_tex.get_texture(*pair_program,"pos_tex"); #ifdef THREE_CONCURRENT diff --git a/lib/gpu/lal_base_three.h b/lib/gpu/lal_base_three.h index 4f27ecdf92..d03a7521cd 100644 --- a/lib/gpu/lal_base_three.h +++ b/lib/gpu/lal_base_three.h @@ -56,7 +56,8 @@ class BaseThree { const int maxspecial, const double cell_size, const double gpu_split, FILE *screen, const void *pair_program, const char *k_two, - const char *k_three_center, const char *k_three_end); + const char *k_three_center, const char *k_three_end, + const char *k_short_nbor=NULL); /// Estimate the overhead for GPU context changes and CPU driver void estimate_gpu_overhead(); @@ -74,8 +75,8 @@ class BaseThree { /// Check if there is enough storage for neighbors and realloc if not /** \param nlocal number of particles whose nbors must be stored on device - * \param host_inum number of particles whose nbors need to copied to host - * \param current maximum number of neighbors + * \param max_nbors maximum number of neighbors + * \param success set to false if insufficient memory * \note olist_size=total number of local particles **/ inline void resize_local(const int inum, const int max_nbors, bool &success) { nbor->resize(inum,max_nbors,success); @@ -84,7 +85,7 @@ class BaseThree { /// Check if there is enough storage for neighbors and realloc if not /** \param nlocal number of particles whose nbors must be stored on device * \param host_inum number of particles whose nbors need to copied to host - * \param current maximum number of neighbors + * \param max_nbors current maximum number of neighbors * \note host_inum is 0 if the host is performing neighboring * \note nlocal+host_inum=total number local particles * \note olist_size=0 **/ @@ -143,14 +144,6 @@ class BaseThree { const bool vflag, const bool eatom, const bool vatom, int &host_start, const double cpu_time, bool &success); - /// Pair loop with device neighboring - int * compute(const int ago, const int inum_full, const int nall, - double **host_x, int *host_type, double *sublo, - double *subhi, tagint *tag, int **nspecial, - tagint **special, const bool eflag, const bool vflag, - const bool eatom, const bool vatom, int &host_start, - const double cpu_time, bool &success); - /// Pair loop with device neighboring int ** compute(const int ago, const int inum_full, const int nall, double **host_x, int *host_type, double *sublo, @@ -193,6 +186,9 @@ class BaseThree { /// Neighbor data Neighbor *nbor; + UCL_D_Vec dev_short_nbor; + UCL_Kernel k_short_nbor; + // ------------------------- DEVICE KERNELS ------------------------- UCL_Program *pair_program; UCL_Kernel k_pair, k_three_center, k_three_end, k_three_end_vatom; @@ -203,16 +199,17 @@ class BaseThree { UCL_Texture pos_tex; protected: - bool _compiled; + bool _compiled,_short_nbor; int _block_pair, _block_size, _threads_per_atom, _end_command_queue; int _gpu_nbor; double _max_bytes, _max_an_bytes; + int _max_nbors, _ainum; double _gpu_overhead, _driver_overhead; UCL_D_Vec *_nbor_data; void compile_kernels(UCL_Device &dev, const void *pair_string, - const char *k_two, const char *k_three_center, - const char *k_three_end); + const char *two, const char *three_center, + const char *three_end, const char* short_nbor); virtual void loop(const bool _eflag, const bool _vflag, const int evatom) = 0; diff --git a/lib/gpu/lal_sw.cpp b/lib/gpu/lal_sw.cpp index 3492d7030e..24984e4878 100644 --- a/lib/gpu/lal_sw.cpp +++ b/lib/gpu/lal_sw.cpp @@ -55,7 +55,7 @@ int SWT::init(const int ntypes, const int nlocal, const int nall, const int max_ int success; success=this->init_three(nlocal,nall,max_nbors,0,cell_size,gpu_split, _screen,sw,"k_sw","k_sw_three_center", - "k_sw_three_end"); + "k_sw_three_end","k_sw_short_nbor"); if (success!=0) return success; @@ -193,19 +193,30 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) { else vflag=0; - int GX=static_cast(ceil(static_cast(this->ans->inum())/ + // build the short neighbor list + int ainum=this->_ainum; + int nbor_pitch=this->nbor->nbor_pitch(); + int GX=static_cast(ceil(static_cast(ainum)/ (BX/this->_threads_per_atom))); + this->k_short_nbor.set_size(GX,BX); + this->k_short_nbor.run(&this->atom->x, &sw3, &map, &elem2param, &_nelements, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &ainum, + &nbor_pitch, &this->_threads_per_atom); // this->_nbor_data == nbor->dev_packed for gpu_nbor == 0 and tpa > 1 // this->_nbor_data == nbor->dev_nbor for gpu_nbor == 1 or tpa == 1 - int ainum=this->ans->inum(); - int nbor_pitch=this->nbor->nbor_pitch(); + ainum=this->ans->inum(); + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->ans->inum())/ + (BX/this->_threads_per_atom))); this->time_pair.start(); - + this->k_pair.set_size(GX,BX); this->k_pair.run(&this->atom->x, &sw1, &sw2, &sw3, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom); @@ -217,6 +228,7 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_center.run(&this->atom->x, &sw1, &sw2, &sw3, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &evatom); @@ -231,7 +243,7 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end_vatom.run(&this->atom->x, &sw1, &sw2, &sw3, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); @@ -240,7 +252,7 @@ void SWT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end.run(&this->atom->x, &sw1, &sw2, &sw3, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); diff --git a/lib/gpu/lal_sw.cu b/lib/gpu/lal_sw.cu index 46330c59e4..7dea52898e 100644 --- a/lib/gpu/lal_sw.cu +++ b/lib/gpu/lal_sw.cu @@ -130,6 +130,64 @@ texture sw3_tex; #endif +__kernel void k_sw_short_nbor(const __global numtyp4 *restrict x_, + const __global numtyp4 *restrict sw3, + const __global int *restrict map, + const __global int *restrict elem2param, + const int nelements, + const __global int * dev_nbor, + const __global int * dev_packed, + __global int * dev_short_nbor, + const int inum, const int nbor_pitch, const int t_per_atom) { + __local int n_stride; + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + if (iiinit_three(nlocal,nall,max_nbors,0,cell_size,gpu_split, _screen,vashishta,"k_vashishta","k_vashishta_three_center", - "k_vashishta_three_end"); + "k_vashishta_three_end","k_vashishta_short_nbor"); if (success!=0) return success; @@ -128,15 +128,18 @@ int VashishtaT::init(const int ntypes, const int nlocal, const int nall, const i param4.alloc(nparams,*(this->ucl_device),UCL_READ_ONLY); + double r0sqmax = 0; for (int i=0; i(r0sq); dview[i].y=static_cast(gamma[i]); dview[i].z=static_cast(cutsq[i]); dview[i].w=static_cast(r0[i]); } + _cutshortsq = static_cast(r0sqmax); + ucl_copy(param4,dview,false); param4_tex.get_texture(*(this->pair_program),"param4_tex"); param4_tex.bind_float(param4,4); @@ -223,15 +226,27 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) { else vflag=0; - int GX=static_cast(ceil(static_cast(this->ans->inum())/ + // build the short neighbor list + int ainum=this->_ainum; + int nbor_pitch=this->nbor->nbor_pitch(); + int GX=static_cast(ceil(static_cast(ainum)/ (BX/this->_threads_per_atom))); + this->k_short_nbor.set_size(GX,BX); + this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &ainum, + &nbor_pitch, &this->_threads_per_atom); + // this->_nbor_data == nbor->dev_packed for gpu_nbor == 0 and tpa > 1 // this->_nbor_data == nbor->dev_nbor for gpu_nbor == 1 or tpa == 1 - int ainum=this->ans->inum(); - int nbor_pitch=this->nbor->nbor_pitch(); + ainum=this->ans->inum(); + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->ans->inum())/ + (BX/this->_threads_per_atom))); this->time_pair.start(); + // note that k_pair does not run with the short neighbor list this->k_pair.set_size(GX,BX); this->k_pair.run(&this->atom->x, ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, &map, &elem2param, &_nelements, @@ -248,6 +263,7 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_center.run(&this->atom->x, ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &evatom); Answer *end_ans; @@ -257,21 +273,19 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) { end_ans=this->ans; #endif if (evatom!=0) { - this->k_three_end_vatom.set_size(GX,BX); this->k_three_end_vatom.run(&this->atom->x, ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); } else { - this->k_three_end.set_size(GX,BX); this->k_three_end.run(&this->atom->x, ¶m1, ¶m2, ¶m3, ¶m4, ¶m5, &map, &elem2param, &_nelements, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); } diff --git a/lib/gpu/lal_vashishta.cu b/lib/gpu/lal_vashishta.cu index caa3c03613..7449b18f6b 100644 --- a/lib/gpu/lal_vashishta.cu +++ b/lib/gpu/lal_vashishta.cu @@ -136,6 +136,56 @@ texture param5_tex; #endif +__kernel void k_vashishta_short_nbor(const __global numtyp4 *restrict x_, + const numtyp cutshortsq, + const __global int * dev_nbor, + const __global int * dev_packed, + __global int * dev_short_nbor, + const int inum, const int nbor_pitch, + const int t_per_atom) { + __local int n_stride; + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + if (ii { UCL_D_Vec elem2param; UCL_D_Vec map; int _nparams,_nelements; + numtyp _cutshortsq; UCL_Texture param1_tex, param2_tex, param3_tex, param4_tex, param5_tex; From 1c6533e53df2e4d69cb40228baf69677b5941405 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Sat, 8 Jul 2017 14:15:26 -0500 Subject: [PATCH 041/293] Working on short neighbor list for tersoff/gpu --- lib/gpu/lal_tersoff.cpp | 81 +++++++++++--------- lib/gpu/lal_tersoff.cu | 165 ++++++++++++++++++++++++++++++++-------- lib/gpu/lal_tersoff.h | 3 +- 3 files changed, 178 insertions(+), 71 deletions(-) diff --git a/lib/gpu/lal_tersoff.cpp b/lib/gpu/lal_tersoff.cpp index 6b0b563d9f..f1e0320b8c 100644 --- a/lib/gpu/lal_tersoff.cpp +++ b/lib/gpu/lal_tersoff.cpp @@ -55,7 +55,8 @@ int TersoffT::init(const int ntypes, const int nlocal, const int nall, const int int success; success=this->init_three(nlocal,nall,max_nbors,0,cell_size,gpu_split, _screen,tersoff,"k_tersoff_repulsive", - "k_tersoff_three_center", "k_tersoff_three_end"); + "k_tersoff_three_center", "k_tersoff_three_end", + "k_tersoff_short_nbor"); if (success!=0) return success; @@ -157,8 +158,12 @@ int TersoffT::init(const int ntypes, const int nlocal, const int nall, const int UCL_H_Vec cutsq_view(nparams,*(this->ucl_device), UCL_WRITE_ONLY); - for (int i=0; i(host_cutsq[i]); + if (cutsqmax < host_cutsq[i]) cutsqmax = host_cutsq[i]; + } + _cutshortsq = static_cast(cutsqmax); cutsq.alloc(nparams,*(this->ucl_device),UCL_READ_ONLY); ucl_copy(cutsq,cutsq_view,false); @@ -250,7 +255,7 @@ void TersoffT::compute(const int f_ago, const int inum_full, const int nall, this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); if (!success) return; - _max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); + this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); } this->atom->cast_x_data(host_x,host_type); @@ -258,29 +263,19 @@ void TersoffT::compute(const int f_ago, const int inum_full, const int nall, this->atom->add_x_data(host_x,host_type); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nlist; + int _eflag; if (eflag) _eflag=1; else _eflag=0; - int ainum=nlist; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - int evatom=0; if (eatom || vatom) evatom=1; @@ -329,7 +324,7 @@ int ** TersoffT::compute(const int ago, const int inum_full, // Build neighbor list on GPU if necessary if (ago==0) { - _max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, + this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, sublo, subhi, tag, nspecial, special, success); if (!success) return NULL; @@ -343,29 +338,19 @@ int ** TersoffT::compute(const int ago, const int inum_full, *jnum=this->nbor->host_acc.begin(); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nall; + int _eflag; if (eflag) _eflag=1; else _eflag=0; - int ainum=nall; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - int evatom=0; if (eatom || vatom) evatom=1; @@ -402,9 +387,32 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { else vflag=0; - int ainum=this->ans->inum(); + // build the short neighbor list + int ainum=this->_ainum; int nbor_pitch=this->nbor->nbor_pitch(); - int GX=static_cast(ceil(static_cast(this->ans->inum())/ + int GX=static_cast(ceil(static_cast(ainum)/ + (BX/this->_threads_per_atom))); + + this->k_short_nbor.set_size(GX,BX); + this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &ainum, + &nbor_pitch, &this->_threads_per_atom); + + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->_ainum)/ + (BX/(JTHREADS*KTHREADS)))); + + this->k_zeta.set_size(GX,BX); + this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, + &map, &elem2param, &_nelements, &_nparams, &_zetaij, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, + &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom); + + ainum=this->ans->inum(); + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->ans->inum())/ (BX/this->_threads_per_atom))); this->time_pair.start(); @@ -423,6 +431,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_center.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &evatom); @@ -437,7 +446,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); @@ -446,7 +455,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); } diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu index b7d48d9e34..d132545984 100644 --- a/lib/gpu/lal_tersoff.cu +++ b/lib/gpu/lal_tersoff.cu @@ -164,6 +164,57 @@ texture ts5_tex; #endif +__kernel void k_tersoff_short_nbor(const __global numtyp4 *restrict x_, + const numtyp cutshortsq, + const __global int * dev_nbor, + const __global int * dev_packed, + __global int * dev_short_nbor, + const int inum, const int nbor_pitch, + const int t_per_atom) { + __local int n_stride; + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + if (ii { UCL_Kernel k_zeta; UCL_Texture ts1_tex, ts2_tex, ts3_tex, ts4_tex, ts5_tex; - - int _max_nbors; + numtyp _cutshortsq; private: bool _allocated; From 77c60189b8cd11d6f1f5329c6e22ff4d105b7c8a Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Sat, 8 Jul 2017 14:43:53 -0500 Subject: [PATCH 042/293] Minor cleanups for tersoff/gpu --- lib/gpu/lal_tersoff.cpp | 3 ++- lib/gpu/lal_tersoff.cu | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/gpu/lal_tersoff.cpp b/lib/gpu/lal_tersoff.cpp index f1e0320b8c..d830499257 100644 --- a/lib/gpu/lal_tersoff.cpp +++ b/lib/gpu/lal_tersoff.cpp @@ -163,10 +163,11 @@ int TersoffT::init(const int ntypes, const int nlocal, const int nall, const int cutsq_view[i]=static_cast(host_cutsq[i]); if (cutsqmax < host_cutsq[i]) cutsqmax = host_cutsq[i]; } - _cutshortsq = static_cast(cutsqmax); cutsq.alloc(nparams,*(this->ucl_device),UCL_READ_ONLY); ucl_copy(cutsq,cutsq_view,false); + _cutshortsq = static_cast(cutsqmax); + UCL_H_Vec dview_elem2param(nelements*nelements*nelements, *(this->ucl_device), UCL_WRITE_ONLY); diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu index d132545984..9faa59c34d 100644 --- a/lib/gpu/lal_tersoff.cu +++ b/lib/gpu/lal_tersoff.cu @@ -106,7 +106,7 @@ texture ts5_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ __local acctyp red_acc[BLOCK_PAIR]; \ red_acc[tid]=z; \ @@ -155,7 +155,7 @@ texture ts5_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ for (unsigned int s=t_per_atom/2; s>0; s>>=1) { \ z += shfl_xor(z, s, t_per_atom); \ @@ -348,7 +348,7 @@ __kernel void k_tersoff_zeta(const __global numtyp4 *restrict x_, int idx = nbor_j - n_stride; // zeta_idx(dev_nbor,dev_packed, nbor_pitch, n_stride, t_per_atom, // i, nbor_j, offset_j, idx); - store_zeta(z, tid, t_per_atom, offset_k); + acc_zeta(z, tid, t_per_atom, offset_k); numtyp4 ts1_ijparam = ts1[ijparam]; //fetch4(ts1_ijparam,ijparam,ts1_tex); numtyp ijparam_lam2 = ts1_ijparam.y; From 34fe2273f64bbee8f96ab91642106471ad77c25b Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Sat, 8 Jul 2017 14:59:48 -0500 Subject: [PATCH 043/293] Added short neighbor list implementation for tersoff/zbl/gpu and tersoff/mod/gpu --- lib/gpu/lal_tersoff_mod.cpp | 58 +++++++++--- lib/gpu/lal_tersoff_mod.cu | 173 ++++++++++++++++++++++++++++-------- lib/gpu/lal_tersoff_mod.h | 3 +- lib/gpu/lal_tersoff_zbl.cpp | 58 +++++++++--- lib/gpu/lal_tersoff_zbl.cu | 171 +++++++++++++++++++++++++++-------- lib/gpu/lal_tersoff_zbl.h | 2 +- 6 files changed, 365 insertions(+), 100 deletions(-) diff --git a/lib/gpu/lal_tersoff_mod.cpp b/lib/gpu/lal_tersoff_mod.cpp index 553dad3583..ba1804c37e 100644 --- a/lib/gpu/lal_tersoff_mod.cpp +++ b/lib/gpu/lal_tersoff_mod.cpp @@ -55,7 +55,8 @@ int TersoffMT::init(const int ntypes, const int nlocal, const int nall, const in int success; success=this->init_three(nlocal,nall,max_nbors,0,cell_size,gpu_split, _screen,tersoff_mod,"k_tersoff_mod_repulsive", - "k_tersoff_mod_three_center", "k_tersoff_mod_three_end"); + "k_tersoff_mod_three_center", "k_tersoff_mod_three_end", + "k_tersoff_mod_short_nbor"); if (success!=0) return success; @@ -157,11 +158,16 @@ int TersoffMT::init(const int ntypes, const int nlocal, const int nall, const in UCL_H_Vec cutsq_view(nparams,*(this->ucl_device), UCL_WRITE_ONLY); - for (int i=0; i(host_cutsq[i]); + if (cutsqmax < host_cutsq[i]) cutsqmax = host_cutsq[i]; + } cutsq.alloc(nparams,*(this->ucl_device),UCL_READ_ONLY); ucl_copy(cutsq,cutsq_view,false); + _cutshortsq = static_cast(cutsqmax); + UCL_H_Vec dview_elem2param(nelements*nelements*nelements, *(this->ucl_device), UCL_WRITE_ONLY); @@ -250,7 +256,7 @@ void TersoffMT::compute(const int f_ago, const int inum_full, const int nall, this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); if (!success) return; - _max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); + this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); } this->atom->cast_x_data(host_x,host_type); @@ -258,11 +264,13 @@ void TersoffMT::compute(const int f_ago, const int inum_full, const int nall, this->atom->add_x_data(host_x,host_type); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nlist; + int _eflag; if (eflag) _eflag=1; @@ -329,7 +337,7 @@ int ** TersoffMT::compute(const int ago, const int inum_full, // Build neighbor list on GPU if necessary if (ago==0) { - _max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, + this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, sublo, subhi, tag, nspecial, special, success); if (!success) return NULL; @@ -343,11 +351,13 @@ int ** TersoffMT::compute(const int ago, const int inum_full, *jnum=this->nbor->host_acc.begin(); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nall; + int _eflag; if (eflag) _eflag=1; @@ -402,9 +412,32 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { else vflag=0; - int ainum=this->ans->inum(); + // build the short neighbor list + int ainum=this->_ainum; int nbor_pitch=this->nbor->nbor_pitch(); - int GX=static_cast(ceil(static_cast(this->ans->inum())/ + int GX=static_cast(ceil(static_cast(ainum)/ + (BX/this->_threads_per_atom))); + + this->k_short_nbor.set_size(GX,BX); + this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &ainum, + &nbor_pitch, &this->_threads_per_atom); + + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->_ainum)/ + (BX/(JTHREADS*KTHREADS)))); + + this->k_zeta.set_size(GX,BX); + this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, + &map, &elem2param, &_nelements, &_nparams, &_zetaij, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, + &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom); + + ainum=this->ans->inum(); + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->ans->inum())/ (BX/this->_threads_per_atom))); this->time_pair.start(); @@ -423,6 +456,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_center.run(&this->atom->x, &ts1, &ts2, &ts4, &ts5, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &evatom); @@ -437,7 +471,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &ts5, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); @@ -446,7 +480,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &ts5, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); } diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu index 3a81b36941..75bacc2179 100644 --- a/lib/gpu/lal_tersoff_mod.cu +++ b/lib/gpu/lal_tersoff_mod.cu @@ -106,7 +106,7 @@ texture ts5_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ __local acctyp red_acc[BLOCK_PAIR]; \ red_acc[tid]=z; \ @@ -155,7 +155,7 @@ texture ts5_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ for (unsigned int s=t_per_atom/2; s>0; s>>=1) { \ z += shfl_xor(z, s, t_per_atom); \ @@ -164,6 +164,57 @@ texture ts5_tex; #endif +__kernel void k_tersoff_mod_short_nbor(const __global numtyp4 *restrict x_, + const numtyp cutshortsq, + const __global int * dev_nbor, + const __global int * dev_packed, + __global int * dev_short_nbor, + const int inum, const int nbor_pitch, + const int t_per_atom) { + __local int n_stride; + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + if (ii cutsq[ijparam]) continue; // compute zeta_ij - z = (numtyp)0; + z = (acctyp)0; int nbor_k = nborj_start-offset_j+offset_k; - for ( ; nbor_k < nbor_end; nbor_k+=n_stride) { - int k=dev_packed[nbor_k]; + int numk = dev_short_nbor[nbor_k-n_stride]; + int k_end = nbor_k+fast_mul(numk,n_stride); + + for ( ; nbor_k < k_end; nbor_k+=n_stride) { + int k=dev_short_nbor[nbor_k]; k &= NEIGHMASK; if (k == j) continue; @@ -287,10 +347,11 @@ __kernel void k_tersoff_mod_zeta(const __global numtyp4 *restrict x_, //int jj = (nbor_j-offset_j-2*nbor_pitch)/n_stride; //int idx = jj*n_stride + i*t_per_atom + offset_j; - int idx; - zeta_idx(dev_nbor,dev_packed, nbor_pitch, n_stride, t_per_atom, - i, nbor_j, offset_j, idx); - store_zeta(z, tid, t_per_atom, offset_k); + //idx to zetaij is shifted by n_stride relative to nbor_j in dev_short_nbor + int idx = nbor_j - n_stride; +// zeta_idx(dev_nbor,dev_packed, nbor_pitch, n_stride, t_per_atom, +// i, nbor_j, offset_j, idx); + acc_zeta(z, tid, t_per_atom, offset_k); numtyp4 ts1_ijparam = ts1[ijparam]; //fetch4(ts1_ijparam,ijparam,ts1_tex); numtyp ijparam_lam2 = ts1_ijparam.y; @@ -430,6 +491,7 @@ __kernel void k_tersoff_mod_three_center(const __global numtyp4 *restrict x_, const __global acctyp4 *restrict zetaij, const __global int * dev_nbor, const __global int * dev_packed, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, @@ -470,15 +532,20 @@ __kernel void k_tersoff_mod_three_center(const __global numtyp4 *restrict x_, nbor_info(dev_nbor,dev_packed,nbor_pitch,t_per_atom,ii,offset_j,i,numj, n_stride,nbor_end,nbor_j); int offset_k=tid & (t_per_atom-1); - int nborj_start = nbor_j; numtyp4 ix; fetch4(ix,i,pos_tex); //x_[i]; int itype=ix.w; itype=map[itype]; + // recalculate numj and nbor_end for use of the short nbor list + numj = dev_short_nbor[nbor_j]; + nbor_j += n_stride; + int nborj_start = nbor_j; + nbor_end = nbor_j+fast_mul(numj,n_stride); + for ( ; nbor_j { UCL_Kernel k_zeta; UCL_Texture ts1_tex, ts2_tex, ts3_tex, ts4_tex, ts5_tex; - - int _max_nbors; + numtyp _cutshortsq; private: bool _allocated; diff --git a/lib/gpu/lal_tersoff_zbl.cpp b/lib/gpu/lal_tersoff_zbl.cpp index 9cce8a802d..6efa8b9487 100644 --- a/lib/gpu/lal_tersoff_zbl.cpp +++ b/lib/gpu/lal_tersoff_zbl.cpp @@ -62,7 +62,8 @@ int TersoffZT::init(const int ntypes, const int nlocal, const int nall, int success; success=this->init_three(nlocal,nall,max_nbors,0,cell_size,gpu_split, _screen,tersoff_zbl,"k_tersoff_zbl_repulsive", - "k_tersoff_zbl_three_center", "k_tersoff_zbl_three_end"); + "k_tersoff_zbl_three_center", "k_tersoff_zbl_three_end", + "k_tersoff_zbl_short_nbor"); if (success!=0) return success; @@ -177,11 +178,16 @@ int TersoffZT::init(const int ntypes, const int nlocal, const int nall, UCL_H_Vec cutsq_view(nparams,*(this->ucl_device), UCL_WRITE_ONLY); - for (int i=0; i(host_cutsq[i]); + if (cutsqmax < host_cutsq[i]) cutsqmax = host_cutsq[i]; + } cutsq.alloc(nparams,*(this->ucl_device),UCL_READ_ONLY); ucl_copy(cutsq,cutsq_view,false); + _cutshortsq = static_cast(cutsqmax); + UCL_H_Vec dview_elem2param(nelements*nelements*nelements, *(this->ucl_device), UCL_WRITE_ONLY); @@ -275,7 +281,7 @@ void TersoffZT::compute(const int f_ago, const int inum_full, const int nall, this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); if (!success) return; - _max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); + this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); } this->atom->cast_x_data(host_x,host_type); @@ -283,11 +289,13 @@ void TersoffZT::compute(const int f_ago, const int inum_full, const int nall, this->atom->add_x_data(host_x,host_type); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nlist; + int _eflag; if (eflag) _eflag=1; @@ -354,7 +362,7 @@ int ** TersoffZT::compute(const int ago, const int inum_full, // Build neighbor list on GPU if necessary if (ago==0) { - _max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, + this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, sublo, subhi, tag, nspecial, special, success); if (!success) return NULL; @@ -368,11 +376,13 @@ int ** TersoffZT::compute(const int ago, const int inum_full, *jnum=this->nbor->host_acc.begin(); // re-allocate zetaij if necessary - if (nall*_max_nbors > _zetaij.cols()) { + if (nall*this->_max_nbors > _zetaij.cols()) { int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(_max_nbors*_nmax); + _zetaij.resize(this->_max_nbors*_nmax); } + this->_ainum=nall; + int _eflag; if (eflag) _eflag=1; @@ -427,9 +437,32 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { else vflag=0; - int ainum=this->ans->inum(); + // build the short neighbor list + int ainum=this->_ainum; int nbor_pitch=this->nbor->nbor_pitch(); - int GX=static_cast(ceil(static_cast(this->ans->inum())/ + int GX=static_cast(ceil(static_cast(ainum)/ + (BX/this->_threads_per_atom))); + + this->k_short_nbor.set_size(GX,BX); + this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &ainum, + &nbor_pitch, &this->_threads_per_atom); + + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->_ainum)/ + (BX/(JTHREADS*KTHREADS)))); + + this->k_zeta.set_size(GX,BX); + this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, + &map, &elem2param, &_nelements, &_nparams, &_zetaij, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, + &_eflag, &this->_ainum, &nbor_pitch, &this->_threads_per_atom); + + ainum=this->ans->inum(); + nbor_pitch=this->nbor->nbor_pitch(); + GX=static_cast(ceil(static_cast(this->ans->inum())/ (BX/this->_threads_per_atom))); this->time_pair.start(); @@ -449,6 +482,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_center.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &evatom); @@ -463,7 +497,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end_vatom.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); @@ -472,7 +506,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_three_end.run(&this->atom->x, &ts1, &ts2, &ts4, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &this->nbor->dev_acc, + &this->nbor->dev_acc, &this->dev_short_nbor, &end_ans->force, &end_ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &this->_gpu_nbor); } diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu index 9509b9802c..439d4028df 100644 --- a/lib/gpu/lal_tersoff_zbl.cu +++ b/lib/gpu/lal_tersoff_zbl.cu @@ -109,7 +109,7 @@ texture ts6_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ __local acctyp red_acc[BLOCK_PAIR]; \ red_acc[tid]=z; \ @@ -158,7 +158,7 @@ texture ts6_tex; ans[ii]=old; \ } -#define store_zeta(z, tid, t_per_atom, offset) \ +#define acc_zeta(z, tid, t_per_atom, offset) \ if (t_per_atom>1) { \ for (unsigned int s=t_per_atom/2; s>0; s>>=1) { \ z += shfl_xor(z, s, t_per_atom); \ @@ -167,6 +167,57 @@ texture ts6_tex; #endif +__kernel void k_tersoff_zbl_short_nbor(const __global numtyp4 *restrict x_, + const numtyp cutshortsq, + const __global int * dev_nbor, + const __global int * dev_packed, + __global int * dev_short_nbor, + const int inum, const int nbor_pitch, + const int t_per_atom) { + __local int n_stride; + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + if (ii { UCL_Kernel k_zeta; UCL_Texture ts1_tex, ts2_tex, ts3_tex, ts4_tex, ts5_tex, ts6_tex; - int _max_nbors; numtyp _global_e,_global_a_0,_global_epsilon_0; + numtyp _cutshortsq; private: bool _allocated; From ea2b01e83b910d29ef487ff51c88b22d8059d434 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Sat, 8 Jul 2017 20:17:31 -0500 Subject: [PATCH 044/293] Refactored 3-body gpu styles to remove code duplication --- lib/gpu/lal_base_three.cpp | 4 + lib/gpu/lal_base_three.h | 6 +- lib/gpu/lal_tersoff.cpp | 152 ++----------------------------- lib/gpu/lal_tersoff.h | 15 --- lib/gpu/lal_tersoff_mod.cpp | 176 ++---------------------------------- lib/gpu/lal_tersoff_mod.h | 15 --- lib/gpu/lal_tersoff_zbl.cpp | 176 ++---------------------------------- lib/gpu/lal_tersoff_zbl.h | 15 --- 8 files changed, 28 insertions(+), 531 deletions(-) diff --git a/lib/gpu/lal_base_three.cpp b/lib/gpu/lal_base_three.cpp index fd9fc7f272..4e8a95937c 100644 --- a/lib/gpu/lal_base_three.cpp +++ b/lib/gpu/lal_base_three.cpp @@ -180,6 +180,8 @@ int * BaseThreeT::reset_nbors(const int nall, const int inum, const int nlist, if (!success) return NULL; + _nall = nall; + // originally the requirement that nall == nlist was enforced // to allow direct indexing neighbors of neighbors after re-arrangement // nbor->get_host3(nall,nlist,ilist,numj,firstneigh,block_size()); @@ -214,6 +216,8 @@ inline int BaseThreeT::build_nbor_list(const int inum, const int host_inum, return 0; atom->cast_copy_x(host_x,host_type); + _nall = nall; + int mn; nbor->build_nbor_list(host_x, nall, host_inum, nall, *atom, sublo, subhi, tag, nspecial, special, success, mn); diff --git a/lib/gpu/lal_base_three.h b/lib/gpu/lal_base_three.h index d03a7521cd..fde1936b25 100644 --- a/lib/gpu/lal_base_three.h +++ b/lib/gpu/lal_base_three.h @@ -74,7 +74,7 @@ class BaseThree { } /// Check if there is enough storage for neighbors and realloc if not - /** \param nlocal number of particles whose nbors must be stored on device + /** \param inum number of particles whose nbors must be stored on device * \param max_nbors maximum number of neighbors * \param success set to false if insufficient memory * \note olist_size=total number of local particles **/ @@ -83,7 +83,7 @@ class BaseThree { } /// Check if there is enough storage for neighbors and realloc if not - /** \param nlocal number of particles whose nbors must be stored on device + /** \param inum number of particles whose nbors must be stored on device * \param host_inum number of particles whose nbors need to copied to host * \param max_nbors current maximum number of neighbors * \note host_inum is 0 if the host is performing neighboring @@ -203,7 +203,7 @@ class BaseThree { int _block_pair, _block_size, _threads_per_atom, _end_command_queue; int _gpu_nbor; double _max_bytes, _max_an_bytes; - int _max_nbors, _ainum; + int _max_nbors, _ainum, _nall; double _gpu_overhead, _driver_overhead; UCL_D_Vec *_nbor_data; diff --git a/lib/gpu/lal_tersoff.cpp b/lib/gpu/lal_tersoff.cpp index d830499257..cb4a3fdbd6 100644 --- a/lib/gpu/lal_tersoff.cpp +++ b/lib/gpu/lal_tersoff.cpp @@ -225,151 +225,6 @@ double TersoffT::host_memory_usage() const { #define KTHREADS this->_threads_per_atom #define JTHREADS this->_threads_per_atom -// --------------------------------------------------------------------------- -// Copy nbor list from host if necessary and then calculate forces, virials,.. -// --------------------------------------------------------------------------- -template -void TersoffT::compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, - const bool eflag, const bool vflag, const bool eatom, - const bool vatom, int &host_start, - const double cpu_time, bool &success) { - this->acc_timers(); - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return; - } - - int ago=this->hd_balancer.ago_first(f_ago); - int inum=this->hd_balancer.balance(ago,inum_full,cpu_time); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - if (ago==0) { - this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); - if (!success) - return; - this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); - } - - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nlist; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); -} - -// --------------------------------------------------------------------------- -// Reneighbor on GPU if necessary and then compute forces, virials, energies -// --------------------------------------------------------------------------- -template -int ** TersoffT::compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, - double *sublo, double *subhi, tagint *tag, - int **nspecial, tagint **special, const bool eflag, - const bool vflag, const bool eatom, - const bool vatom, int &host_start, - int **ilist, int **jnum, - const double cpu_time, bool &success) { - this->acc_timers(); - - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return NULL; - } - - this->hd_balancer.balance(cpu_time); - int inum=this->hd_balancer.get_gpu_count(ago,inum_full); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - // Build neighbor list on GPU if necessary - if (ago==0) { - this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, - sublo, subhi, tag, nspecial, special, success); - if (!success) - return NULL; - this->hd_balancer.start_timer(); - } else { - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - } - *ilist=this->nbor->host_ilist.begin(); - *jnum=this->nbor->host_acc.begin(); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nall; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); - - return this->nbor->host_jlist.begin()-host_start; -} - // --------------------------------------------------------------------------- // Calculate energies, forces, and torques // --------------------------------------------------------------------------- @@ -400,6 +255,13 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); + // re-allocate zetaij if necessary + int nall = this->_nall; + if (nall*this->_max_nbors > _zetaij.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + _zetaij.resize(this->_max_nbors*_nmax); + } + nbor_pitch=this->nbor->nbor_pitch(); GX=static_cast(ceil(static_cast(this->_ainum)/ (BX/(JTHREADS*KTHREADS)))); diff --git a/lib/gpu/lal_tersoff.h b/lib/gpu/lal_tersoff.h index 5e2bedfeef..fd01af031a 100644 --- a/lib/gpu/lal_tersoff.h +++ b/lib/gpu/lal_tersoff.h @@ -47,21 +47,6 @@ class Tersoff : public BaseThree { const double* h, const double* gamma, const double* beta, const double* powern, const double* cutsq); - /// Pair loop with host neighboring - void compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, const bool eflag, - const bool vflag, const bool eatom, const bool vatom, - int &host_start, const double cpu_time, bool &success); - - /// Pair loop with device neighboring - int ** compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, double *sublo, - double *subhi, tagint *tag, int **nspecial, - tagint **special, const bool eflag, const bool vflag, - const bool eatom, const bool vatom, int &host_start, - int **ilist, int **numj, const double cpu_time, bool &success); - /// Clear all host and device data /** \note This is called at the beginning of the init() routine **/ void clear(); diff --git a/lib/gpu/lal_tersoff_mod.cpp b/lib/gpu/lal_tersoff_mod.cpp index ba1804c37e..02000d77d3 100644 --- a/lib/gpu/lal_tersoff_mod.cpp +++ b/lib/gpu/lal_tersoff_mod.cpp @@ -225,175 +225,6 @@ double TersoffMT::host_memory_usage() const { #define KTHREADS this->_threads_per_atom #define JTHREADS this->_threads_per_atom -// --------------------------------------------------------------------------- -// Copy nbor list from host if necessary and then calculate forces, virials,.. -// --------------------------------------------------------------------------- -template -void TersoffMT::compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, - const bool eflag, const bool vflag, const bool eatom, - const bool vatom, int &host_start, - const double cpu_time, bool &success) { - this->acc_timers(); - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return; - } - - int ago=this->hd_balancer.ago_first(f_ago); - int inum=this->hd_balancer.balance(ago,inum_full,cpu_time); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - if (ago==0) { - this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); - if (!success) - return; - this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); - } - - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nlist; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int ainum=nlist; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); -} - -// --------------------------------------------------------------------------- -// Reneighbor on GPU if necessary and then compute forces, virials, energies -// --------------------------------------------------------------------------- -template -int ** TersoffMT::compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, - double *sublo, double *subhi, tagint *tag, - int **nspecial, tagint **special, const bool eflag, - const bool vflag, const bool eatom, - const bool vatom, int &host_start, - int **ilist, int **jnum, - const double cpu_time, bool &success) { - this->acc_timers(); - - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return NULL; - } - - this->hd_balancer.balance(cpu_time); - int inum=this->hd_balancer.get_gpu_count(ago,inum_full); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - // Build neighbor list on GPU if necessary - if (ago==0) { - this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, - sublo, subhi, tag, nspecial, special, success); - if (!success) - return NULL; - this->hd_balancer.start_timer(); - } else { - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - } - *ilist=this->nbor->host_ilist.begin(); - *jnum=this->nbor->host_acc.begin(); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nall; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int ainum=nall; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); - - return this->nbor->host_jlist.begin()-host_start; -} - // --------------------------------------------------------------------------- // Calculate energies, forces, and torques // --------------------------------------------------------------------------- @@ -424,6 +255,13 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); + // re-allocate zetaij if necessary + int nall = this->_nall; + if (nall*this->_max_nbors > _zetaij.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + _zetaij.resize(this->_max_nbors*_nmax); + } + nbor_pitch=this->nbor->nbor_pitch(); GX=static_cast(ceil(static_cast(this->_ainum)/ (BX/(JTHREADS*KTHREADS)))); diff --git a/lib/gpu/lal_tersoff_mod.h b/lib/gpu/lal_tersoff_mod.h index 286a23fa6f..ab1560d951 100644 --- a/lib/gpu/lal_tersoff_mod.h +++ b/lib/gpu/lal_tersoff_mod.h @@ -47,21 +47,6 @@ class TersoffMod : public BaseThree { const double* h, const double* beta, const double* powern, const double* powern_del, const double* ca1, const double* cutsq); - /// Pair loop with host neighboring - void compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, const bool eflag, - const bool vflag, const bool eatom, const bool vatom, - int &host_start, const double cpu_time, bool &success); - - /// Pair loop with device neighboring - int ** compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, double *sublo, - double *subhi, tagint *tag, int **nspecial, - tagint **special, const bool eflag, const bool vflag, - const bool eatom, const bool vatom, int &host_start, - int **ilist, int **numj, const double cpu_time, bool &success); - /// Clear all host and device data /** \note This is called at the beginning of the init() routine **/ void clear(); diff --git a/lib/gpu/lal_tersoff_zbl.cpp b/lib/gpu/lal_tersoff_zbl.cpp index 6efa8b9487..33edabd799 100644 --- a/lib/gpu/lal_tersoff_zbl.cpp +++ b/lib/gpu/lal_tersoff_zbl.cpp @@ -250,175 +250,6 @@ double TersoffZT::host_memory_usage() const { #define KTHREADS this->_threads_per_atom #define JTHREADS this->_threads_per_atom -// --------------------------------------------------------------------------- -// Copy nbor list from host if necessary and then calculate forces, virials,.. -// --------------------------------------------------------------------------- -template -void TersoffZT::compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, - const bool eflag, const bool vflag, const bool eatom, - const bool vatom, int &host_start, - const double cpu_time, bool &success) { - this->acc_timers(); - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return; - } - - int ago=this->hd_balancer.ago_first(f_ago); - int inum=this->hd_balancer.balance(ago,inum_full,cpu_time); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - if (ago==0) { - this->reset_nbors(nall, inum, nlist, ilist, numj, firstneigh, success); - if (!success) - return; - this->_max_nbors = this->nbor->max_nbor_loop(nlist,numj,ilist); - } - - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nlist; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int ainum=nlist; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &ts6, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom,ilist); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); -} - -// --------------------------------------------------------------------------- -// Reneighbor on GPU if necessary and then compute forces, virials, energies -// --------------------------------------------------------------------------- -template -int ** TersoffZT::compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, - double *sublo, double *subhi, tagint *tag, - int **nspecial, tagint **special, const bool eflag, - const bool vflag, const bool eatom, - const bool vatom, int &host_start, - int **ilist, int **jnum, - const double cpu_time, bool &success) { - this->acc_timers(); - - if (inum_full==0) { - host_start=0; - // Make sure textures are correct if realloc by a different hybrid style - this->resize_atom(0,nall,success); - this->zero_timers(); - return NULL; - } - - this->hd_balancer.balance(cpu_time); - int inum=this->hd_balancer.get_gpu_count(ago,inum_full); - this->ans->inum(inum); - #ifdef THREE_CONCURRENT - this->ans2->inum(inum); - #endif - host_start=inum; - - // Build neighbor list on GPU if necessary - if (ago==0) { - this->_max_nbors = this->build_nbor_list(inum, inum_full-inum, nall, host_x, host_type, - sublo, subhi, tag, nspecial, special, success); - if (!success) - return NULL; - this->hd_balancer.start_timer(); - } else { - this->atom->cast_x_data(host_x,host_type); - this->hd_balancer.start_timer(); - this->atom->add_x_data(host_x,host_type); - } - *ilist=this->nbor->host_ilist.begin(); - *jnum=this->nbor->host_acc.begin(); - - // re-allocate zetaij if necessary - if (nall*this->_max_nbors > _zetaij.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - _zetaij.resize(this->_max_nbors*_nmax); - } - - this->_ainum=nall; - - int _eflag; - if (eflag) - _eflag=1; - else - _eflag=0; - - int ainum=nall; - int nbor_pitch=this->nbor->nbor_pitch(); - int BX=this->block_pair(); - int GX=static_cast(ceil(static_cast(ainum)/ - (BX/(JTHREADS*KTHREADS)))); - - this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &ts6, &cutsq, - &map, &elem2param, &_nelements, &_nparams, &_zetaij, - &this->nbor->dev_nbor, &this->_nbor_data->begin(), - &_eflag, &ainum, &nbor_pitch, &this->_threads_per_atom); - - int evatom=0; - if (eatom || vatom) - evatom=1; - #ifdef THREE_CONCURRENT - this->ucl_device->sync(); - #endif - loop(eflag,vflag,evatom); - this->ans->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans); - #ifdef THREE_CONCURRENT - this->ans2->copy_answers(eflag,vflag,eatom,vatom); - this->device->add_ans_object(this->ans2); - #endif - this->hd_balancer.stop_timer(); - - return this->nbor->host_jlist.begin()-host_start; -} - // --------------------------------------------------------------------------- // Calculate energies, forces, and torques // --------------------------------------------------------------------------- @@ -449,6 +280,13 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); + // re-allocate zetaij if necessary + int nall = this->_nall; + if (nall*this->_max_nbors > _zetaij.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + _zetaij.resize(this->_max_nbors*_nmax); + } + nbor_pitch=this->nbor->nbor_pitch(); GX=static_cast(ceil(static_cast(this->_ainum)/ (BX/(JTHREADS*KTHREADS)))); diff --git a/lib/gpu/lal_tersoff_zbl.h b/lib/gpu/lal_tersoff_zbl.h index a5f1ace754..0e6cac9587 100644 --- a/lib/gpu/lal_tersoff_zbl.h +++ b/lib/gpu/lal_tersoff_zbl.h @@ -49,21 +49,6 @@ class TersoffZBL : public BaseThree { const double* ZBLcut, const double* ZBLexpscale, const double global_e, const double global_a_0, const double global_epsilon_0, const double* cutsq); - /// Pair loop with host neighboring - void compute(const int f_ago, const int inum_full, const int nall, - const int nlist, double **host_x, int *host_type, - int *ilist, int *numj, int **firstneigh, const bool eflag, - const bool vflag, const bool eatom, const bool vatom, - int &host_start, const double cpu_time, bool &success); - - /// Pair loop with device neighboring - int ** compute(const int ago, const int inum_full, - const int nall, double **host_x, int *host_type, double *sublo, - double *subhi, tagint *tag, int **nspecial, - tagint **special, const bool eflag, const bool vflag, - const bool eatom, const bool vatom, int &host_start, - int **ilist, int **numj, const double cpu_time, bool &success); - /// Clear all host and device data /** \note This is called at the beginning of the init() routine **/ void clear(); From 92395e9bb412578dff8742ceea1e9ac3a5122076 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 10 Jul 2017 17:19:37 -0400 Subject: [PATCH 045/293] disallow MC moves with fix rigid and fix shake active. update examples and add shake example --- examples/gcmc/H2O.txt | 62 ++++ examples/gcmc/in.gcmc.co2 | 2 +- examples/gcmc/in.gcmc.h2o | 88 ++++++ examples/gcmc/log.24Mar17.gcmc.co2.g++.4 | 179 ----------- ...mc.co2.g++.1 => log.6Jul17.gcmc.co2.g++.1} | 95 +++--- examples/gcmc/log.6Jul17.gcmc.co2.g++.4 | 180 +++++++++++ examples/gcmc/log.6Jul17.gcmc.h2o.g++.1 | 281 ++++++++++++++++++ examples/gcmc/log.6Jul17.gcmc.h2o.g++.4 | 281 ++++++++++++++++++ ...gcmc.lj.g++.1 => log.6Jul17.gcmc.lj.g++.1} | 23 +- ...gcmc.lj.g++.4 => log.6Jul17.gcmc.lj.g++.4} | 23 +- src/MC/fix_gcmc.cpp | 4 + 11 files changed, 968 insertions(+), 250 deletions(-) create mode 100644 examples/gcmc/H2O.txt create mode 100644 examples/gcmc/in.gcmc.h2o delete mode 100644 examples/gcmc/log.24Mar17.gcmc.co2.g++.4 rename examples/gcmc/{log.24Mar17.gcmc.co2.g++.1 => log.6Jul17.gcmc.co2.g++.1} (50%) create mode 100644 examples/gcmc/log.6Jul17.gcmc.co2.g++.4 create mode 100644 examples/gcmc/log.6Jul17.gcmc.h2o.g++.1 create mode 100644 examples/gcmc/log.6Jul17.gcmc.h2o.g++.4 rename examples/gcmc/{log.24Mar17.gcmc.lj.g++.1 => log.6Jul17.gcmc.lj.g++.1} (88%) rename examples/gcmc/{log.24Mar17.gcmc.lj.g++.4 => log.6Jul17.gcmc.lj.g++.4} (88%) diff --git a/examples/gcmc/H2O.txt b/examples/gcmc/H2O.txt new file mode 100644 index 0000000000..b56f869693 --- /dev/null +++ b/examples/gcmc/H2O.txt @@ -0,0 +1,62 @@ +# CO2 molecule file. TraPPE model. + +3 atoms +2 bonds +1 angles + +Coords + +1 1.12456 0.09298 1.27452 +2 1.53683 0.75606 1.89928 +3 0.49482 0.56390 0.65678 + +Types + +1 1 +2 2 +3 2 + +Charges + +1 -0.8472 +2 0.4236 +3 0.4236 + +Bonds + +1 1 1 2 +2 1 1 3 + +Angles + +1 1 2 1 3 + +Shake Flags + +1 1 +2 1 +3 1 + +Shake Atoms + +1 1 2 3 +2 1 2 3 +3 1 2 3 + +Shake Bond Types + +1 1 1 1 +2 1 1 1 +3 1 1 1 + +Special Bond Counts + +1 2 0 0 +2 1 1 0 +3 1 1 0 + +Special Bonds + +1 2 3 +2 1 3 +3 1 2 diff --git a/examples/gcmc/in.gcmc.co2 b/examples/gcmc/in.gcmc.co2 index 0961e2b556..d11ef72fdd 100644 --- a/examples/gcmc/in.gcmc.co2 +++ b/examples/gcmc/in.gcmc.co2 @@ -64,7 +64,7 @@ fix_modify myrigidnvt dynamic/dof no # gcmc variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) -fix mygcmc all gcmc 100 100 100 0 54341 ${temp} ${mu} ${disp} mol & +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol & co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt # output diff --git a/examples/gcmc/in.gcmc.h2o b/examples/gcmc/in.gcmc.h2o new file mode 100644 index 0000000000..7ffaafa975 --- /dev/null +++ b/examples/gcmc/in.gcmc.h2o @@ -0,0 +1,88 @@ +# fix gcmc example with fix shake + +# variables available on command line + +variable mu index -8.1 +variable disp index 0.5 +variable temp index 338.0 +variable lbox index 10.0 +variable spacing index 5.0 + +# global model settings + +units real +atom_style full +boundary p p p +pair_style lj/cut/coul/long 14 +pair_modify mix arithmetic tail yes +kspace_style ewald 0.0001 +bond_style harmonic +angle_style harmonic + +# box, start molecules on simple cubic lattice + +lattice sc ${spacing} +region box block 0 ${lbox} 0 ${lbox} 0 ${lbox} units box +create_box 2 box & + bond/types 1 & + angle/types 1 & + extra/bond/per/atom 2 & + extra/angle/per/atom 1 & + extra/special/per/atom 2 + +# we can load multiple molecule templates, but don't have to use them all +molecule co2mol CO2.txt +molecule h2omol H2O.txt +create_atoms 0 box mol h2omol 464563 units box + +# rigid SPC/E water model + +pair_coeff 1 1 0.15535 3.166 +pair_coeff * 2 0.0000 0.0000 + +bond_coeff 1 1000 1.0 +angle_coeff 1 100 109.47 + +# masses + +mass 1 15.9994 +mass 2 1.0 + +# MD settings + +group h2o type 1 2 +neighbor 2.0 bin +neigh_modify every 1 delay 1 check yes +velocity all create ${temp} 54654 +timestep 1.0 + +minimize 0.0 0.0 100 1000 +reset_timestep 0 +# rigid constraints with thermostat + +fix mynvt all nvt temp ${temp} ${temp} 100 +fix wshake all shake 0.0001 50 0 b 1 a 1 mol h2omol +# gcmc + + + +run 1000 + +variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol & + h2omol tfac_insert ${tfac} group h2o shake wshake + +# output + +variable tacc equal f_mygcmc[2]/(f_mygcmc[1]+0.1) +variable iacc equal f_mygcmc[4]/(f_mygcmc[3]+0.1) +variable dacc equal f_mygcmc[6]/(f_mygcmc[5]+0.1) +variable racc equal f_mygcmc[8]/(f_mygcmc[7]+0.1) +compute_modify thermo_temp dynamic/dof yes +thermo_style custom step temp press pe ke density atoms v_iacc v_dacc v_tacc v_racc +thermo 1000 + +# run + +run 20000 + diff --git a/examples/gcmc/log.24Mar17.gcmc.co2.g++.4 b/examples/gcmc/log.24Mar17.gcmc.co2.g++.4 deleted file mode 100644 index 65504b8d46..0000000000 --- a/examples/gcmc/log.24Mar17.gcmc.co2.g++.4 +++ /dev/null @@ -1,179 +0,0 @@ -LAMMPS (17 Mar 2017) -# GCMC for CO2 molecular fluid, rigid/small/nvt dynamics -# Rigid CO2 TraPPE model -# [Potoff and J.I. Siepmann, Vapor-liquid equilibria of -# mixtures containing alkanes, carbon dioxide and -# nitrogen AIChE J., 47,1676-1682 (2001)]. - -# variables available on command line - -variable mu index -8.1 -variable disp index 0.5 -variable temp index 338.0 -variable lbox index 10.0 -variable spacing index 5.0 - -# global model settings - -units real -atom_style full -boundary p p p -pair_style lj/cut/coul/long 14 -pair_modify mix arithmetic tail yes -kspace_style ewald 0.0001 -bond_style harmonic -angle_style harmonic - -# box, start molecules on simple cubic lattice - -lattice sc ${spacing} -lattice sc 5.0 -Lattice spacing in x,y,z = 5 5 5 -region box block 0 ${lbox} 0 ${lbox} 0 ${lbox} units box -region box block 0 10.0 0 ${lbox} 0 ${lbox} units box -region box block 0 10.0 0 10.0 0 ${lbox} units box -region box block 0 10.0 0 10.0 0 10.0 units box -create_box 2 box bond/types 1 angle/types 1 extra/bond/per/atom 2 extra/angle/per/atom 1 extra/special/per/atom 2 -Created orthogonal box = (0 0 0) to (10 10 10) - 1 by 2 by 2 MPI processor grid -molecule co2mol CO2.txt -Read molecule co2mol: - 3 atoms with 2 types - 2 bonds with 1 types - 1 angles with 1 types - 0 dihedrals with 0 types - 0 impropers with 0 types -create_atoms 0 box mol co2mol 464563 units box -Created 24 atoms - -# rigid CO2 TraPPE model - -pair_coeff 1 1 0.053649 2.8 -pair_coeff 2 2 0.156973 3.05 -bond_coeff 1 0 1.16 -angle_coeff 1 0 180 - -# masses - -mass 1 12.0107 -mass 2 15.9994 - -# MD settings - -group co2 type 1 2 -24 atoms in group co2 -neighbor 2.0 bin -neigh_modify every 1 delay 10 check yes -velocity all create ${temp} 54654 -velocity all create 338.0 54654 -timestep 1.0 - -# rigid constraints with thermostat - -fix myrigidnvt all rigid/nvt/small molecule temp ${temp} ${temp} 100 mol co2mol -fix myrigidnvt all rigid/nvt/small molecule temp 338.0 ${temp} 100 mol co2mol -fix myrigidnvt all rigid/nvt/small molecule temp 338.0 338.0 100 mol co2mol -8 rigid bodies with 24 atoms - 1.16 = max distance from body owner to body atom -fix_modify myrigidnvt dynamic/dof no - -# gcmc - -variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) -fix mygcmc all gcmc 100 100 100 0 54341 ${temp} ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert 1.66666666666667 group co2 rigid myrigidnvt - -# output - -variable tacc equal f_mygcmc[2]/(f_mygcmc[1]+0.1) -variable iacc equal f_mygcmc[4]/(f_mygcmc[3]+0.1) -variable dacc equal f_mygcmc[6]/(f_mygcmc[5]+0.1) -variable racc equal f_mygcmc[8]/(f_mygcmc[7]+0.1) -compute_modify thermo_temp dynamic/dof yes -thermo_style custom step temp press pe ke density atoms v_iacc v_dacc v_tacc v_racc -thermo 1000 - -# run - -run 20000 -Ewald initialization ... -WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) - G vector (1/distance) = 0.164636 - estimated absolute RMS force accuracy = 0.0332064 - estimated relative force accuracy = 0.0001 - KSpace vectors: actual max1d max3d = 16 2 62 - kxmax kymax kzmax = 2 2 2 -WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:439) -0 atoms in group FixGCMC:gcmc_exclusion_group:mygcmc -0 atoms in group FixGCMC:rotation_gas_atoms:mygcmc -WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:472) -Neighbor list info ... - update every 1 steps, delay 10 steps, check yes - max neighbors/atom: 2000, page size: 100000 - master list distance cutoff = 16 - ghost atom cutoff = 16 - binsize = 8, bins = 2 2 2 - 1 neighbor lists, perpetual/occasional/extra = 1 0 0 - (1) pair lj/cut/coul/long, perpetual - attributes: half, newton on - pair build: half/bin/newton - stencil: half/bin/3d/newton - bin: standard -Per MPI rank memory allocation (min/avg/max) = 15.4 | 15.4 | 15.4 Mbytes -Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_racc - 0 386.52184 23582.465 -3.2433417 14.209828 0.5846359 24 0 0 0 0 -WARNING: Using kspace solver on system with no charge (../kspace.cpp:289) - 1000 760.80877 -39.270882 -3.5239626 12.851016 0.29231795 12 0.24161633 0.22984103 0.71087092 0.85283311 - 2000 308.0739 -255.061 -20.411926 14.386853 0.73079488 30 0.26075352 0.24898725 0.73128383 0.88590474 - 3000 432.34358 -1361.3278 -12.644057 15.894387 0.5846359 24 0.21121583 0.21051229 0.70036003 0.86735027 - 4000 631.524 -63.488785 -3.6517158 13.804656 0.36539744 15 0.22486443 0.22886173 0.72358173 0.87172606 - 5000 730.61244 -1029.284 -6.2144028 19.600352 0.43847693 18 0.23017182 0.22740779 0.72281887 0.87820845 - 6000 752.43412 503.4547 -3.7053679 16.447663 0.36539744 15 0.22943971 0.226183 0.71450085 0.87447436 - 7000 660.68448 828.51735 -10.592278 21.006666 0.51155641 21 0.24702096 0.24218506 0.71815602 0.8740222 - 8000 331.58822 -621.22187 -5.3705759 7.2482776 0.36539744 15 0.23211903 0.22906813 0.70281376 0.86269411 - 9000 413.91538 869.51669 -11.28701 15.216905 0.5846359 24 0.23246466 0.22923961 0.70832684 0.86244176 - 10000 242.20861 -808.23311 -5.4533937 5.2945044 0.36539744 15 0.22024676 0.22031775 0.70785097 0.85712561 - 11000 348.20046 -372.16895 -3.4663358 7.6114092 0.36539744 15 0.2252033 0.22688969 0.71513402 0.86123263 - 12000 251.99682 303.30092 -18.58289 11.768089 0.73079488 30 0.20916844 0.21068047 0.694787 0.84635875 - 13000 306.83592 -1582.0137 -20.810287 14.329041 0.73079488 30 0.19494837 0.196527 0.67554784 0.83056119 - 14000 476.57411 268.94927 -14.185859 19.888076 0.65771539 27 0.19779631 0.20016859 0.67957528 0.83375167 - 15000 267.03534 730.71183 -9.3348616 9.8171066 0.5846359 24 0.19468305 0.19814971 0.68032974 0.83810439 - 16000 639.83235 2190.3244 -9.6666503 26.701062 0.65771539 27 0.19520687 0.19848997 0.68514387 0.84100361 - 17000 2237.1203 -222.59057 -0.18248834 4.4456205 0.073079488 3 0.20412446 0.20757814 0.69175318 0.8434939 - 18000 754.44841 205.54694 -10.501943 27.736031 0.5846359 24 0.2129422 0.21508015 0.69665031 0.84758331 - 19000 1610.1148 1293.6003 -0.20849836 3.1996309 0.073079488 3 0.22061668 0.22356929 0.69949369 0.84851405 - 20000 231.61458 -39.696514 -4.6452226 5.0629266 0.36539744 15 0.21984893 0.22246517 0.69914635 0.85058457 -Loop time of 21.1019 on 4 procs for 20000 steps with 15 atoms - -Performance: 81.888 ns/day, 0.293 hours/ns, 947.781 timesteps/s -98.9% 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.31897 | 0.41973 | 0.49748 | 10.1 | 1.99 -Bond | 0.014808 | 0.015063 | 0.015289 | 0.2 | 0.07 -Kspace | 0.3813 | 0.46228 | 0.56585 | 9.8 | 2.19 -Neigh | 0.049173 | 0.050043 | 0.050868 | 0.3 | 0.24 -Comm | 0.9755 | 0.99686 | 1.0205 | 1.9 | 4.72 -Output | 0.0014546 | 0.0015051 | 0.0016098 | 0.2 | 0.01 -Modify | 19.043 | 19.062 | 19.085 | 0.4 | 90.33 -Other | | 0.09438 | | | 0.45 - -Nlocal: 3.75 ave 6 max 3 min -Histogram: 3 0 0 0 0 0 0 0 0 1 -Nghost: 876.5 ave 937 max 818 min -Histogram: 1 1 0 0 0 0 0 0 1 1 -Neighs: 490.5 ave 647 max 363 min -Histogram: 1 0 1 0 0 1 0 0 0 1 - -Total # of neighbors = 1962 -Ave neighs/atom = 130.8 -Ave special neighs/atom = 2 -Neighbor list builds = 40070 -Dangerous builds = 115 - -Total wall time: 0:00:21 diff --git a/examples/gcmc/log.24Mar17.gcmc.co2.g++.1 b/examples/gcmc/log.6Jul17.gcmc.co2.g++.1 similarity index 50% rename from examples/gcmc/log.24Mar17.gcmc.co2.g++.1 rename to examples/gcmc/log.6Jul17.gcmc.co2.g++.1 index 7562476bf3..f9e494c43f 100644 --- a/examples/gcmc/log.24Mar17.gcmc.co2.g++.1 +++ b/examples/gcmc/log.6Jul17.gcmc.co2.g++.1 @@ -1,4 +1,5 @@ -LAMMPS (17 Mar 2017) +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task # GCMC for CO2 molecular fluid, rigid/small/nvt dynamics # Rigid CO2 TraPPE model # [Potoff and J.I. Siepmann, Vapor-liquid equilibria of @@ -80,11 +81,11 @@ fix_modify myrigidnvt dynamic/dof no # gcmc variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) -fix mygcmc all gcmc 100 100 100 0 54341 ${temp} ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt -fix mygcmc all gcmc 100 100 100 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert 1.66666666666667 group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert 1.66666666666667 group co2 rigid myrigidnvt # output @@ -106,7 +107,7 @@ WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) estimated relative force accuracy = 0.0001 KSpace vectors: actual max1d max3d = 16 2 62 kxmax kymax kzmax = 2 2 2 -WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:439) +WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:445) 0 atoms in group FixGCMC:gcmc_exclusion_group:mygcmc 0 atoms in group FixGCMC:rotation_gas_atoms:mygcmc WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:472) @@ -122,56 +123,58 @@ Neighbor list info ... pair build: half/bin/newton stencil: half/bin/3d/newton bin: standard -Per MPI rank memory allocation (min/avg/max) = 15.61 | 15.61 | 15.61 Mbytes +Per MPI rank memory allocation (min/avg/max) = 15.62 | 15.62 | 15.62 Mbytes Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_racc 0 364.27579 4238.8631 -9.6809388 13.391989 0.5846359 24 0 0 0 0 - 1000 311.39835 -327.93481 -8.6795381 9.9010062 0.51155641 21 0.13302848 0.12331626 0.6894397 0.90997852 WARNING: Using kspace solver on system with no charge (../kspace.cpp:289) - 2000 905.66812 319.43347 -0.50350961 6.2991241 0.14615898 6 0.20952183 0.20430213 0.71797992 0.92626683 - 3000 275.57393 -719.89718 -26.534978 14.238181 0.80387436 33 0.21291069 0.20460696 0.72899202 0.9133259 - 4000 254.70771 -245.01902 -20.981537 13.160079 0.80387436 33 0.17245726 0.16974613 0.70145764 0.90542759 - 5000 96.073601 -517.98124 -34.019065 5.441166 0.87695385 36 0.14174575 0.13607057 0.6776754 0.90155771 - 6000 397.57265 148.92645 -7.2012893 10.665797 0.43847693 18 0.12299956 0.1202471 0.66165464 0.90274793 - 7000 455.4271 -347.44181 -5.9244703 12.217875 0.43847693 18 0.15182038 0.14791307 0.67904236 0.90560829 - 8000 301.03124 -627.45324 -13.251012 11.066909 0.5846359 24 0.16687346 0.16315516 0.6936719 0.91129375 - 9000 256.5747 -565.67983 -17.814128 11.981874 0.73079488 30 0.15458482 0.15131825 0.68966283 0.90993975 - 10000 443.60076 89.586912 -6.077863 11.900606 0.43847693 18 0.16092552 0.16020353 0.69882461 0.91422145 - 11000 436.43777 64.412921 -6.7128469 11.708443 0.43847693 18 0.17453966 0.17480683 0.70679243 0.91369445 - 12000 594.42207 849.07743 -3.3708621 10.040536 0.29231795 12 0.17461606 0.17568622 0.71175869 0.91333367 - 13000 426.85849 -1093.1334 -17.524618 17.813377 0.65771539 27 0.17742896 0.17792831 0.71363306 0.91450124 - 14000 317.75995 336.31107 -10.46774 11.681912 0.5846359 24 0.18331181 0.18427921 0.71715557 0.91652256 - 15000 272.65129 317.50536 -26.428336 14.087176 0.80387436 33 0.17449167 0.175957 0.71122398 0.91528038 - 16000 344.28567 -577.91079 -18.177927 16.077919 0.73079488 30 0.1661682 0.16781514 0.70485136 0.91508882 - 17000 134.55928 -193.5668 -30.297136 7.6208177 0.87695385 36 0.15965609 0.1605036 0.69658104 0.9140445 - 18000 231.87302 -446.07671 -14.875027 9.6763722 0.65771539 27 0.15270985 0.15351831 0.69002918 0.91372795 - 19000 328.6835 -280.22365 -20.001303 16.982214 0.80387436 33 0.15201017 0.15272181 0.69023195 0.91272534 - 20000 0 -20.39554 -0.14872889 -0 0 0 0.15600204 0.15750795 0.69503275 0.9138765 -Loop time of 30.9008 on 1 procs for 20000 steps with 0 atoms + 1000 420.43475 1722.4052 -9.6956123 15.456579 0.5846359 24 0.20879341 0.20713005 0 0 + 2000 302.29516 -547.83641 -22.017674 14.11699 0.73079488 30 0.1742478 0.1678018 0 0 + 3000 316.6934 -1080.2672 -8.2218891 10.069364 0.51155641 21 0.13544917 0.13720634 0 0 + 4000 246.81618 -679.83642 -14.577244 10.29997 0.65771539 27 0.1568939 0.15860229 0 0 + 5000 260.22849 -896.29914 -16.097593 10.859684 0.65771539 27 0.13138744 0.13547049 0 0 + 6000 291.70796 -1521.99 -22.303136 13.622574 0.73079488 30 0.12615476 0.12717694 0 0 + 7000 236.02638 -599.92186 -27.580831 13.367447 0.87695385 36 0.119703 0.12145398 0 0 + 8000 321.45341 688.10577 -10.09204 11.817696 0.5846359 24 0.10917411 0.11032646 0 0 + 9000 502.85382 -302.31056 -0.22330142 0.99927447 0.073079488 3 0.1254105 0.12905828 0 0 + 10000 249.98239 -510.0091 -32.815145 15.399767 0.95003334 39 0.1274504 0.12875623 0 0 + 11000 247.59424 -1129.0274 -25.320205 12.792544 0.80387436 33 0.11739076 0.11916784 0 0 + 12000 0 -20.39554 -0.14872889 -0 0 0 0.1254933 0.12920375 0 0 + 13000 1272.2738 -474.79484 -0.29450485 8.8489483 0.14615898 6 0.13767133 0.14112496 0 0 + 14000 516.54246 -36.296516 -5.0012009 11.291243 0.36539744 15 0.15632744 0.15955377 0 0 + 15000 307.09233 1951.9301 -14.820362 12.815375 0.65771539 27 0.15393544 0.15716192 0 0 + 16000 198.31989 -559.48443 -30.459487 11.231925 0.87695385 36 0.1482565 0.15025652 0 0 + 17000 246.99311 657.85683 -18.579206 11.53442 0.73079488 30 0.14143958 0.14375423 0 0 + 18000 467.13468 167.03738 -1.0945268 5.569759 0.21923846 9 0.13847359 0.14098533 0 0 + 19000 359.54027 -1413.5407 -12.156233 13.217895 0.5846359 24 0.15169146 0.15294205 0 0 + 20000 227.79597 -1204.5652 -23.24144 10.637925 0.73079488 30 0.14917199 0.15022946 0 0 +Loop time of 20.153 on 1 procs for 20000 steps with 30 atoms -Performance: 55.921 ns/day, 0.429 hours/ns, 647.233 timesteps/s -99.8% CPU use with 1 MPI tasks x no OpenMP threads +Performance: 85.744 ns/day, 0.280 hours/ns, 992.408 timesteps/s +99.3% CPU use with 1 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 2.1985 | 2.1985 | 2.1985 | 0.0 | 7.11 -Bond | 0.029596 | 0.029596 | 0.029596 | 0.0 | 0.10 -Kspace | 0.23123 | 0.23123 | 0.23123 | 0.0 | 0.75 -Neigh | 0.16141 | 0.16141 | 0.16141 | 0.0 | 0.52 -Comm | 0.20628 | 0.20628 | 0.20628 | 0.0 | 0.67 -Output | 0.00068831 | 0.00068831 | 0.00068831 | 0.0 | 0.00 -Modify | 28.022 | 28.022 | 28.022 | 0.0 | 90.69 -Other | | 0.05058 | | | 0.16 +Pair | 2.5352 | 2.5352 | 2.5352 | 0.0 | 12.58 +Bond | 0.026112 | 0.026112 | 0.026112 | 0.0 | 0.13 +Kspace | 0.25 | 0.25 | 0.25 | 0.0 | 1.24 +Neigh | 0.10364 | 0.10364 | 0.10364 | 0.0 | 0.51 +Comm | 0.22907 | 0.22907 | 0.22907 | 0.0 | 1.14 +Output | 0.0013065 | 0.0013065 | 0.0013065 | 0.0 | 0.01 +Modify | 16.957 | 16.957 | 16.957 | 0.0 | 84.14 +Other | | 0.05061 | | | 0.25 -Nlocal: 0 ave 0 max 0 min +Nlocal: 30 ave 30 max 30 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Nghost: 0 ave 0 max 0 min +Nghost: 2310 ave 2310 max 2310 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Neighs: 0 ave 0 max 0 min +Neighs: 7736 ave 7736 max 7736 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Total # of neighbors = 0 -Neighbor list builds = 40367 -Dangerous builds = 118 +Total # of neighbors = 7736 +Ave neighs/atom = 257.867 +Ave special neighs/atom = 2 +Neighbor list builds = 20349 +Dangerous builds = 0 -Total wall time: 0:00:30 +Total wall time: 0:00:20 diff --git a/examples/gcmc/log.6Jul17.gcmc.co2.g++.4 b/examples/gcmc/log.6Jul17.gcmc.co2.g++.4 new file mode 100644 index 0000000000..0df25430d2 --- /dev/null +++ b/examples/gcmc/log.6Jul17.gcmc.co2.g++.4 @@ -0,0 +1,180 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# GCMC for CO2 molecular fluid, rigid/small/nvt dynamics +# Rigid CO2 TraPPE model +# [Potoff and J.I. Siepmann, Vapor-liquid equilibria of +# mixtures containing alkanes, carbon dioxide and +# nitrogen AIChE J., 47,1676-1682 (2001)]. + +# variables available on command line + +variable mu index -8.1 +variable disp index 0.5 +variable temp index 338.0 +variable lbox index 10.0 +variable spacing index 5.0 + +# global model settings + +units real +atom_style full +boundary p p p +pair_style lj/cut/coul/long 14 +pair_modify mix arithmetic tail yes +kspace_style ewald 0.0001 +bond_style harmonic +angle_style harmonic + +# box, start molecules on simple cubic lattice + +lattice sc ${spacing} +lattice sc 5.0 +Lattice spacing in x,y,z = 5 5 5 +region box block 0 ${lbox} 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 10.0 units box +create_box 2 box bond/types 1 angle/types 1 extra/bond/per/atom 2 extra/angle/per/atom 1 extra/special/per/atom 2 +Created orthogonal box = (0 0 0) to (10 10 10) + 1 by 2 by 2 MPI processor grid +molecule co2mol CO2.txt +Read molecule co2mol: + 3 atoms with 2 types + 2 bonds with 1 types + 1 angles with 1 types + 0 dihedrals with 0 types + 0 impropers with 0 types +create_atoms 0 box mol co2mol 464563 units box +Created 24 atoms + +# rigid CO2 TraPPE model + +pair_coeff 1 1 0.053649 2.8 +pair_coeff 2 2 0.156973 3.05 +bond_coeff 1 0 1.16 +angle_coeff 1 0 180 + +# masses + +mass 1 12.0107 +mass 2 15.9994 + +# MD settings + +group co2 type 1 2 +24 atoms in group co2 +neighbor 2.0 bin +neigh_modify every 1 delay 10 check yes +velocity all create ${temp} 54654 +velocity all create 338.0 54654 +timestep 1.0 + +# rigid constraints with thermostat + +fix myrigidnvt all rigid/nvt/small molecule temp ${temp} ${temp} 100 mol co2mol +fix myrigidnvt all rigid/nvt/small molecule temp 338.0 ${temp} 100 mol co2mol +fix myrigidnvt all rigid/nvt/small molecule temp 338.0 338.0 100 mol co2mol +8 rigid bodies with 24 atoms + 1.16 = max distance from body owner to body atom +fix_modify myrigidnvt dynamic/dof no + +# gcmc + +variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 ${mu} ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 ${disp} mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert ${tfac} group co2 rigid myrigidnvt +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol co2mol tfac_insert 1.66666666666667 group co2 rigid myrigidnvt + +# output + +variable tacc equal f_mygcmc[2]/(f_mygcmc[1]+0.1) +variable iacc equal f_mygcmc[4]/(f_mygcmc[3]+0.1) +variable dacc equal f_mygcmc[6]/(f_mygcmc[5]+0.1) +variable racc equal f_mygcmc[8]/(f_mygcmc[7]+0.1) +compute_modify thermo_temp dynamic/dof yes +thermo_style custom step temp press pe ke density atoms v_iacc v_dacc v_tacc v_racc +thermo 1000 + +# run + +run 20000 +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.164636 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:445) +0 atoms in group FixGCMC:gcmc_exclusion_group:mygcmc +0 atoms in group FixGCMC:rotation_gas_atoms:mygcmc +WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:472) +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 16 + ghost atom cutoff = 16 + binsize = 8, bins = 2 2 2 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 15.41 | 15.41 | 15.41 Mbytes +Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_racc + 0 386.52184 23582.465 -3.2433417 14.209828 0.5846359 24 0 0 0 0 +WARNING: Using kspace solver on system with no charge (../kspace.cpp:289) + 1000 335.66829 -3.7743052 -4.6268612 7.3374649 0.36539744 15 0.20601899 0.20787963 0 0 + 2000 459.73529 238.91592 -0.42937831 5.4815343 0.21923846 9 0.30392058 0.30105616 0 0 + 3000 255.47773 -479.67802 -36.850434 15.738299 0.95003334 39 0.22220744 0.2197582 0 0 + 4000 182.70803 -1059.2262 -43.044833 12.163134 1.0231128 42 0.16781689 0.16716177 0 0 + 5000 234.00907 -1821.0444 -46.04795 15.578317 1.0231128 42 0.13498091 0.13704201 0 0 + 6000 163.42759 -774.67294 -49.686261 11.691518 1.0961923 45 0.11401677 0.11296973 0 0 + 7000 171.64616 -355.23516 -49.323434 12.27947 1.0961923 45 0.098302308 0.098552065 0 0 + 8000 251.29791 -905.47863 -37.841209 15.480807 0.95003334 39 0.086856972 0.08638658 0 0 + 9000 143.69498 -849.95393 -49.073188 10.279858 1.0961923 45 0.078261061 0.077955243 0 0 + 10000 239.35727 -1158.1879 -43.562047 15.934355 1.0231128 42 0.070789792 0.070807529 0 0 + 11000 169.51213 -1574.7885 -51.125228 12.126803 1.0961923 45 0.065008734 0.06498871 0 0 + 12000 181.39739 160.11631 -46.850937 12.977068 1.0961923 45 0.059648717 0.059514803 0 0 + 13000 164.14601 -1107.7629 -50.726722 11.742914 1.0961923 45 0.055207333 0.055097701 0 0 + 14000 287.26285 418.51463 -41.664766 19.123497 1.0231128 42 0.051346789 0.051222285 0 0 + 15000 256.94593 -532.36615 -41.651618 17.105257 1.0231128 42 0.047870301 0.047861685 0 0 + 16000 166.92132 151.15933 -39.957018 11.11219 1.0231128 42 0.045205599 0.045042211 0 0 + 17000 163.22452 -1299.8119 -42.677558 10.866089 1.0231128 42 0.043122086 0.042993687 0 0 + 18000 158.01154 475.77329 -48.803162 11.304057 1.0961923 45 0.041016683 0.040647229 0 0 + 19000 138.49297 -1585.1508 -47.517099 9.9077098 1.0961923 45 0.038929287 0.038436764 0 0 + 20000 173.84439 -1362.6301 -53.002743 12.436731 1.0961923 45 0.036973919 0.036523816 0 0 +Loop time of 31.8386 on 4 procs for 20000 steps with 45 atoms + +Performance: 54.274 ns/day, 0.442 hours/ns, 628.168 timesteps/s +98.5% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 1.1546 | 1.6687 | 2.1338 | 29.5 | 5.24 +Bond | 0.019769 | 0.020369 | 0.02132 | 0.4 | 0.06 +Kspace | 0.53392 | 0.99911 | 1.5116 | 37.8 | 3.14 +Neigh | 0.06737 | 0.067842 | 0.068412 | 0.2 | 0.21 +Comm | 1.9408 | 1.9582 | 1.9733 | 1.1 | 6.15 +Output | 0.0019503 | 0.0020472 | 0.0022476 | 0.3 | 0.01 +Modify | 26.974 | 26.99 | 27.001 | 0.2 | 84.77 +Other | | 0.1322 | | | 0.42 + +Nlocal: 11.25 ave 14 max 8 min +Histogram: 1 0 0 0 0 1 1 0 0 1 +Nghost: 2639.75 ave 2656 max 2617 min +Histogram: 1 0 0 0 0 0 2 0 0 1 +Neighs: 4320 ave 5824 max 2201 min +Histogram: 1 0 0 0 0 0 1 1 0 1 + +Total # of neighbors = 17280 +Ave neighs/atom = 384 +Ave special neighs/atom = 2 +Neighbor list builds = 20394 +Dangerous builds = 0 + +Total wall time: 0:00:31 diff --git a/examples/gcmc/log.6Jul17.gcmc.h2o.g++.1 b/examples/gcmc/log.6Jul17.gcmc.h2o.g++.1 new file mode 100644 index 0000000000..3b1606e65d --- /dev/null +++ b/examples/gcmc/log.6Jul17.gcmc.h2o.g++.1 @@ -0,0 +1,281 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# fix gcmc example with fix shake + +# variables available on command line + +variable mu index -8.1 +variable disp index 0.5 +variable temp index 338.0 +variable lbox index 10.0 +variable spacing index 5.0 + +# global model settings + +units real +atom_style full +boundary p p p +pair_style lj/cut/coul/long 14 +pair_modify mix arithmetic tail yes +kspace_style ewald 0.0001 +bond_style harmonic +angle_style harmonic + +# box, start molecules on simple cubic lattice + +lattice sc ${spacing} +lattice sc 5.0 +Lattice spacing in x,y,z = 5 5 5 +region box block 0 ${lbox} 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 10.0 units box +create_box 2 box bond/types 1 angle/types 1 extra/bond/per/atom 2 extra/angle/per/atom 1 extra/special/per/atom 2 +Created orthogonal box = (0 0 0) to (10 10 10) + 1 by 1 by 1 MPI processor grid + +# we can load multiple molecule templates, but don't have to use them all +molecule co2mol CO2.txt +Read molecule co2mol: + 3 atoms with 2 types + 2 bonds with 1 types + 1 angles with 1 types + 0 dihedrals with 0 types + 0 impropers with 0 types +molecule h2omol H2O.txt +Read molecule h2omol: + 3 atoms with 2 types + 2 bonds with 1 types + 1 angles with 1 types + 0 dihedrals with 0 types + 0 impropers with 0 types +create_atoms 0 box mol h2omol 464563 units box +Created 24 atoms + +# rigid SPC/E water model + +pair_coeff 1 1 0.15535 3.166 +pair_coeff * 2 0.0000 0.0000 + +bond_coeff 1 1000 1.0 +angle_coeff 1 100 109.47 + +# masses + +mass 1 15.9994 +mass 2 1.0 + +# MD settings + +group h2o type 1 2 +24 atoms in group h2o +neighbor 2.0 bin +neigh_modify every 1 delay 1 check yes +velocity all create ${temp} 54654 +velocity all create 338.0 54654 +timestep 1.0 + +minimize 0.0 0.0 100 1000 +WARNING: Using 'neigh_modify every 1 delay 0 check yes' setting during minimization (../min.cpp:168) +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +Neighbor list info ... + update every 1 steps, delay 0 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 16 + ghost atom cutoff = 16 + binsize = 8, bins = 2 2 2 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 11.88 | 11.88 | 11.88 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 338 -4.1890564 9.2628112e-06 18.98377 739.06991 + 100 338 -30.182886 0.85607237 -6.1539961 -2535.3207 +Loop time of 0.0525794 on 1 procs for 100 steps with 24 atoms + +99.4% CPU use with 1 MPI tasks x 1 OpenMP threads + +Minimization stats: + Stopping criterion = max iterations + Energy initial, next-to-last, final = + -4.18904713252 -28.9258064504 -29.3268133965 + Force two-norm initial, final = 18.0027 42.4511 + Force max component initial, final = 5.8993 16.0523 + Final line search alpha, max atom move = 0.00353207 0.056698 + Iterations, force evaluations = 100 238 + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.044199 | 0.044199 | 0.044199 | 0.0 | 84.06 +Bond | 0.00049019 | 0.00049019 | 0.00049019 | 0.0 | 0.93 +Kspace | 0.0031631 | 0.0031631 | 0.0031631 | 0.0 | 6.02 +Neigh | 0.00046444 | 0.00046444 | 0.00046444 | 0.0 | 0.88 +Comm | 0.0034101 | 0.0034101 | 0.0034101 | 0.0 | 6.49 +Output | 1.9073e-05 | 1.9073e-05 | 1.9073e-05 | 0.0 | 0.04 +Modify | 0 | 0 | 0 | 0.0 | 0.00 +Other | | 0.0008333 | | | 1.58 + +Nlocal: 24 ave 24 max 24 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 2047 ave 2047 max 2047 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 4936 ave 4936 max 4936 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 4936 +Ave neighs/atom = 205.667 +Ave special neighs/atom = 2 +Neighbor list builds = 2 +Dangerous builds = 0 +reset_timestep 0 +# rigid constraints with thermostat + +fix mynvt all nvt temp ${temp} ${temp} 100 +fix mynvt all nvt temp 338.0 ${temp} 100 +fix mynvt all nvt temp 338.0 338.0 100 +fix wshake all shake 0.0001 50 0 b 1 a 1 mol h2omol + 0 = # of size 2 clusters + 0 = # of size 3 clusters + 0 = # of size 4 clusters + 8 = # of frozen angles +# gcmc + + + +run 1000 +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +Per MPI rank memory allocation (min/avg/max) = 11.63 | 11.63 | 11.63 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 518.26667 -30.182886 0 -7.0100684 993.1985 + 1000 326.9865 -62.258445 0 -47.638175 -5.3440813 +Loop time of 0.14263 on 1 procs for 1000 steps with 24 atoms + +Performance: 605.764 ns/day, 0.040 hours/ns, 7011.155 timesteps/s +99.5% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.10849 | 0.10849 | 0.10849 | 0.0 | 76.07 +Bond | 0.00015426 | 0.00015426 | 0.00015426 | 0.0 | 0.11 +Kspace | 0.01205 | 0.01205 | 0.01205 | 0.0 | 8.45 +Neigh | 0.0046577 | 0.0046577 | 0.0046577 | 0.0 | 3.27 +Comm | 0.011531 | 0.011531 | 0.011531 | 0.0 | 8.08 +Output | 1.6212e-05 | 1.6212e-05 | 1.6212e-05 | 0.0 | 0.01 +Modify | 0.0037699 | 0.0037699 | 0.0037699 | 0.0 | 2.64 +Other | | 0.001957 | | | 1.37 + +Nlocal: 24 ave 24 max 24 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1660 ave 1660 max 1660 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 5112 ave 5112 max 5112 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 5112 +Ave neighs/atom = 213 +Ave special neighs/atom = 2 +Neighbor list builds = 25 +Dangerous builds = 0 + +variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 ${mu} ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol h2omol tfac_insert 1.66666666666667 group h2o shake wshake + +# output + +variable tacc equal f_mygcmc[2]/(f_mygcmc[1]+0.1) +variable iacc equal f_mygcmc[4]/(f_mygcmc[3]+0.1) +variable dacc equal f_mygcmc[6]/(f_mygcmc[5]+0.1) +variable racc equal f_mygcmc[8]/(f_mygcmc[7]+0.1) +compute_modify thermo_temp dynamic/dof yes +thermo_style custom step temp press pe ke density atoms v_iacc v_dacc v_tacc v_racc +thermo 1000 + +# run + +run 20000 +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:445) +0 atoms in group FixGCMC:gcmc_exclusion_group:mygcmc +0 atoms in group FixGCMC:rotation_gas_atoms:mygcmc +WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:472) +Per MPI rank memory allocation (min/avg/max) = 11.63 | 11.63 | 11.63 Mbytes +Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_racc + 1000 326.9865 -4.3509713 -62.258445 14.62027 0.23910963 24 0 0 0 0 + 2000 116.99793 -5344.1527 -286.61595 17.088682 0.74721761 75 0.048183096 0.013941446 0 0 + 3000 106.86746 -3920.4926 -361.60598 18.794545 0.89666113 90 0.035637919 0.012768883 0 0 + 4000 75.002668 540.46846 -414.8511 14.531966 0.98632724 99 0.025963651 0.0093451705 0 0 + 5000 79.924788 -2131.1173 -437.21216 15.962121 1.0162159 102 0.019879728 0.0070418993 0 0 + 6000 95.552773 -3647.0233 -438.24276 19.083253 1.0162159 102 0.015753613 0.0056885133 0 0 + 7000 79.501736 -2071.5369 -440.77351 15.877631 1.0162159 102 0.01326216 0.0046915318 0 0 + 8000 62.567091 -3102.9616 -442.21884 12.495541 1.0162159 102 0.011305503 0.0040437885 0 0 + 9000 68.324047 -3812.7866 -440.46835 13.645287 1.0162159 102 0.0099549538 0.0035157329 0 0 + 10000 83.857631 -2158.2659 -444.8183 16.747566 1.0162159 102 0.0088200922 0.0031354281 0 0 + 11000 68.350984 -2084.0789 -440.14081 13.650667 1.0162159 102 0.0081331455 0.0030247424 0 0 + 12000 76.867315 -1585.6723 -443.36199 15.3515 1.0162159 102 0.0073845932 0.0027532534 0 0 + 13000 59.74266 -2211.0211 -446.07791 11.931462 1.0162159 102 0.0067756276 0.0025213898 0 0 + 14000 81.154979 -907.0176 -441.53368 16.207808 1.0162159 102 0.0062527642 0.0023280719 0 0 + 15000 66.814346 -2804.5134 -455.80704 13.7421 1.0461046 105 0.0059590528 0.0021576214 0 0 + 16000 71.42983 -3930.4004 -458.43218 14.691394 1.0461046 105 0.0055547473 0.0020163729 0 0 + 17000 89.624855 -3569.8136 -455.18164 18.433672 1.0461046 105 0.0052173265 0.0018867687 0 0 + 18000 63.519962 -1882.8157 -456.58939 13.064525 1.0461046 105 0.0049082049 0.0017765986 0 0 + 19000 71.872698 -2243.5046 -454.93359 14.782481 1.0461046 105 0.0046439115 0.0016748361 0 0 + 20000 73.660765 -2285.3173 -476.35473 15.589381 1.0759934 108 0.0045124933 0.0015837653 0 0 + 21000 95.675868 987.92089 -475.46736 20.248603 1.0759934 108 0.004285814 0.0015049513 0 0 +Loop time of 226.155 on 1 procs for 20000 steps with 108 atoms + +Performance: 7.641 ns/day, 3.141 hours/ns, 88.435 timesteps/s +99.2% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 38.053 | 38.053 | 38.053 | 0.0 | 16.83 +Bond | 0.089673 | 0.089673 | 0.089673 | 0.0 | 0.04 +Kspace | 0.92778 | 0.92778 | 0.92778 | 0.0 | 0.41 +Neigh | 1.2619 | 1.2619 | 1.2619 | 0.0 | 0.56 +Comm | 0.97483 | 0.97483 | 0.97483 | 0.0 | 0.43 +Output | 0.0013306 | 0.0013306 | 0.0013306 | 0.0 | 0.00 +Modify | 184.68 | 184.68 | 184.68 | 0.0 | 81.66 +Other | | 0.171 | | | 0.08 + +Nlocal: 108 ave 108 max 108 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 7850 ave 7850 max 7850 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 99828 ave 99828 max 99828 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 99828 +Ave neighs/atom = 924.333 +Ave special neighs/atom = 2 +Neighbor list builds = 20439 +Dangerous builds = 0 + +Total wall time: 0:03:46 diff --git a/examples/gcmc/log.6Jul17.gcmc.h2o.g++.4 b/examples/gcmc/log.6Jul17.gcmc.h2o.g++.4 new file mode 100644 index 0000000000..c04b25f45e --- /dev/null +++ b/examples/gcmc/log.6Jul17.gcmc.h2o.g++.4 @@ -0,0 +1,281 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# fix gcmc example with fix shake + +# variables available on command line + +variable mu index -8.1 +variable disp index 0.5 +variable temp index 338.0 +variable lbox index 10.0 +variable spacing index 5.0 + +# global model settings + +units real +atom_style full +boundary p p p +pair_style lj/cut/coul/long 14 +pair_modify mix arithmetic tail yes +kspace_style ewald 0.0001 +bond_style harmonic +angle_style harmonic + +# box, start molecules on simple cubic lattice + +lattice sc ${spacing} +lattice sc 5.0 +Lattice spacing in x,y,z = 5 5 5 +region box block 0 ${lbox} 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 ${lbox} 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 ${lbox} units box +region box block 0 10.0 0 10.0 0 10.0 units box +create_box 2 box bond/types 1 angle/types 1 extra/bond/per/atom 2 extra/angle/per/atom 1 extra/special/per/atom 2 +Created orthogonal box = (0 0 0) to (10 10 10) + 1 by 2 by 2 MPI processor grid + +# we can load multiple molecule templates, but don't have to use them all +molecule co2mol CO2.txt +Read molecule co2mol: + 3 atoms with 2 types + 2 bonds with 1 types + 1 angles with 1 types + 0 dihedrals with 0 types + 0 impropers with 0 types +molecule h2omol H2O.txt +Read molecule h2omol: + 3 atoms with 2 types + 2 bonds with 1 types + 1 angles with 1 types + 0 dihedrals with 0 types + 0 impropers with 0 types +create_atoms 0 box mol h2omol 464563 units box +Created 24 atoms + +# rigid SPC/E water model + +pair_coeff 1 1 0.15535 3.166 +pair_coeff * 2 0.0000 0.0000 + +bond_coeff 1 1000 1.0 +angle_coeff 1 100 109.47 + +# masses + +mass 1 15.9994 +mass 2 1.0 + +# MD settings + +group h2o type 1 2 +24 atoms in group h2o +neighbor 2.0 bin +neigh_modify every 1 delay 1 check yes +velocity all create ${temp} 54654 +velocity all create 338.0 54654 +timestep 1.0 + +minimize 0.0 0.0 100 1000 +WARNING: Using 'neigh_modify every 1 delay 0 check yes' setting during minimization (../min.cpp:168) +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +Neighbor list info ... + update every 1 steps, delay 0 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 16 + ghost atom cutoff = 16 + binsize = 8, bins = 2 2 2 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut/coul/long, perpetual + attributes: half, newton on + pair build: half/bin/newton + stencil: half/bin/3d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 11.85 | 11.85 | 11.85 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 338 -4.9610706 9.2628112e-06 18.211756 730.90791 + 100 338 -15.742442 0.14954269 7.579918 -637.49568 +Loop time of 0.0828406 on 4 procs for 100 steps with 24 atoms + +98.7% CPU use with 4 MPI tasks x 1 OpenMP threads + +Minimization stats: + Stopping criterion = max iterations + Energy initial, next-to-last, final = + -4.96106135393 -15.5388622715 -15.592899346 + Force two-norm initial, final = 15.474 18.1478 + Force max component initial, final = 5.80042 7.56514 + Final line search alpha, max atom move = 0.00151131 0.0114333 + Iterations, force evaluations = 100 328 + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.012844 | 0.025471 | 0.047008 | 8.1 | 30.75 +Bond | 0.00038934 | 0.00046468 | 0.00054336 | 0.0 | 0.56 +Kspace | 0.0061138 | 0.027556 | 0.04014 | 7.8 | 33.26 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.023276 | 0.023636 | 0.023804 | 0.1 | 28.53 +Output | 3.171e-05 | 3.3557e-05 | 3.8147e-05 | 0.0 | 0.04 +Modify | 0 | 0 | 0 | 0.0 | 0.00 +Other | | 0.00568 | | | 6.86 + +Nlocal: 6 ave 8 max 3 min +Histogram: 1 0 0 0 1 0 0 0 0 2 +Nghost: 1722 ave 1725 max 1720 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +Neighs: 1256.75 ave 2101 max 667 min +Histogram: 1 0 1 0 1 0 0 0 0 1 + +Total # of neighbors = 5027 +Ave neighs/atom = 209.458 +Ave special neighs/atom = 2 +Neighbor list builds = 0 +Dangerous builds = 0 +reset_timestep 0 +# rigid constraints with thermostat + +fix mynvt all nvt temp ${temp} ${temp} 100 +fix mynvt all nvt temp 338.0 ${temp} 100 +fix mynvt all nvt temp 338.0 338.0 100 +fix wshake all shake 0.0001 50 0 b 1 a 1 mol h2omol + 0 = # of size 2 clusters + 0 = # of size 3 clusters + 0 = # of size 4 clusters + 8 = # of frozen angles +# gcmc + + + +run 1000 +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +Per MPI rank memory allocation (min/avg/max) = 11.6 | 11.6 | 11.6 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 518.26667 -15.742442 0 7.4303753 -613.0781 + 1000 369.81793 -54.202686 0 -37.667331 294.98823 +Loop time of 0.199641 on 4 procs for 1000 steps with 24 atoms + +Performance: 432.777 ns/day, 0.055 hours/ns, 5008.996 timesteps/s +98.5% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.017161 | 0.034988 | 0.05833 | 8.0 | 17.53 +Bond | 0.00017357 | 0.00021374 | 0.00027347 | 0.0 | 0.11 +Kspace | 0.018025 | 0.044624 | 0.065613 | 8.4 | 22.35 +Neigh | 0.0029755 | 0.0033154 | 0.0036366 | 0.6 | 1.66 +Comm | 0.059933 | 0.06537 | 0.070709 | 1.5 | 32.74 +Output | 3.4571e-05 | 3.6657e-05 | 4.22e-05 | 0.0 | 0.02 +Modify | 0.043458 | 0.045628 | 0.04767 | 0.9 | 22.86 +Other | | 0.005465 | | | 2.74 + +Nlocal: 6 ave 8 max 3 min +Histogram: 1 0 0 0 0 0 1 0 1 1 +Nghost: 1331.5 ave 1369 max 1290 min +Histogram: 1 0 0 0 0 2 0 0 0 1 +Neighs: 1259.75 ave 1642 max 428 min +Histogram: 1 0 0 0 0 0 0 1 0 2 + +Total # of neighbors = 5039 +Ave neighs/atom = 209.958 +Ave special neighs/atom = 2 +Neighbor list builds = 27 +Dangerous builds = 0 + +variable tfac equal 5.0/3.0 # (3 trans + 2 rot)/(3 trans) +fix mygcmc all gcmc 100 100 0 0 54341 ${temp} ${mu} ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 ${mu} ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 ${disp} mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol h2omol tfac_insert ${tfac} group h2o shake wshake +fix mygcmc all gcmc 100 100 0 0 54341 338.0 -8.1 0.5 mol h2omol tfac_insert 1.66666666666667 group h2o shake wshake + +# output + +variable tacc equal f_mygcmc[2]/(f_mygcmc[1]+0.1) +variable iacc equal f_mygcmc[4]/(f_mygcmc[3]+0.1) +variable dacc equal f_mygcmc[6]/(f_mygcmc[5]+0.1) +variable racc equal f_mygcmc[8]/(f_mygcmc[7]+0.1) +compute_modify thermo_temp dynamic/dof yes +thermo_style custom step temp press pe ke density atoms v_iacc v_dacc v_tacc v_racc +thermo 1000 + +# run + +run 20000 +Ewald initialization ... +WARNING: Using 12-bit tables for long-range coulomb (../kspace.cpp:321) + G vector (1/distance) = 0.170448 + estimated absolute RMS force accuracy = 0.0332064 + estimated relative force accuracy = 0.0001 + KSpace vectors: actual max1d max3d = 16 2 62 + kxmax kymax kzmax = 2 2 2 +WARNING: Fix gcmc using full_energy option (../fix_gcmc.cpp:445) +0 atoms in group FixGCMC:gcmc_exclusion_group:mygcmc +0 atoms in group FixGCMC:rotation_gas_atoms:mygcmc +WARNING: Neighbor exclusions used with KSpace solver may give inconsistent Coulombic energies (../neighbor.cpp:472) +Per MPI rank memory allocation (min/avg/max) = 11.6 | 11.6 | 11.6 Mbytes +Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_racc + 1000 369.81793 295.32434 -54.202686 16.535355 0.23910963 24 0 0 0 0 + 2000 84.544466 -2810.9047 -344.81664 14.364627 0.86677242 87 0.052198354 0.0099581757 0 0 + 3000 75.188527 -3688.256 -425.02228 14.567977 0.98632724 99 0.030546787 0.0049111089 0 0 + 4000 75.019396 -5669.3063 -427.69454 14.535207 0.98632724 99 0.019972039 0.0033375609 0 0 + 5000 90.415371 -2141.7596 -434.65925 17.518218 0.98632724 99 0.014909796 0.002514964 0 0 + 6000 78.212628 -943.75125 -428.80584 15.153904 0.98632724 99 0.01181521 0.0020316119 0 0 + 7000 71.754139 -2028.5122 -435.2139 13.902555 0.98632724 99 0.0099466198 0.0016755471 0 0 + 8000 84.446231 -1969.1657 -428.27313 16.361681 0.98632724 99 0.0084791272 0.0014442102 0 0 + 9000 70.952348 -2476.9812 -446.33824 14.170197 1.0162159 102 0.0077150892 0.0012556189 0 0 + 10000 71.418543 -1875.7083 -443.7214 14.263302 1.0162159 102 0.0068355714 0.0011197957 0 0 + 11000 86.094994 -4508.7581 -444.82687 17.194399 1.0162159 102 0.0061494515 0.0010082475 0 0 + 12000 81.906091 -1547.8105 -442.36719 16.357815 1.0162159 102 0.0055834729 0.00091775114 0 0 + 13000 57.221548 -4607.6222 -448.30939 11.42796 1.0162159 102 0.0051230355 0.00084046326 0 0 + 14000 61.288344 -2518.1779 -445.70636 12.240157 1.0162159 102 0.0047276997 0.00077602396 0 0 + 15000 85.787669 -2407.7111 -443.3834 17.133022 1.0162159 102 0.0043983485 0.00071920715 0 0 + 16000 74.845939 -3288.3403 -445.8247 14.947802 1.0162159 102 0.0042321884 0.00080654918 0 0 + 17000 73.835431 -1926.9566 -445.67476 14.745989 1.0162159 102 0.0039751059 0.00075470749 0 0 + 18000 72.634985 -3997.552 -447.2351 14.506243 1.0162159 102 0.0037395847 0.00071063946 0 0 + 19000 96.776472 -714.44132 -453.65552 19.904587 1.0461046 105 0.0036487876 0.00066993446 0 0 + 20000 75.470786 183.16972 -464.04688 15.522521 1.0461046 105 0.0034630763 0.00063350614 0 0 + 21000 65.658309 -773.41266 -466.27068 13.504331 1.0461046 105 0.003289113 0.00060198052 0 0 +Loop time of 93.8859 on 4 procs for 20000 steps with 105 atoms + +Performance: 18.405 ns/day, 1.304 hours/ns, 213.024 timesteps/s +98.8% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 6.7882 | 10.264 | 14.758 | 93.2 | 10.93 +Bond | 0.028286 | 0.034218 | 0.039038 | 2.5 | 0.04 +Kspace | 0.57255 | 5.2227 | 8.8493 | 133.8 | 5.56 +Neigh | 0.3635 | 0.36915 | 0.37473 | 0.9 | 0.39 +Comm | 2.9961 | 3.2542 | 3.509 | 11.4 | 3.47 +Output | 0.0011675 | 0.0012342 | 0.001375 | 0.2 | 0.00 +Modify | 74.428 | 74.499 | 74.571 | 0.7 | 79.35 +Other | | 0.2411 | | | 0.26 + +Nlocal: 26.25 ave 31 max 22 min +Histogram: 1 0 1 0 0 0 1 0 0 1 +Nghost: 6049.25 ave 6133 max 5962 min +Histogram: 1 0 0 0 1 0 1 0 0 1 +Neighs: 23613 ave 35083 max 14025 min +Histogram: 1 0 0 1 1 0 0 0 0 1 + +Total # of neighbors = 94452 +Ave neighs/atom = 899.543 +Ave special neighs/atom = 2 +Neighbor list builds = 20428 +Dangerous builds = 0 + +Total wall time: 0:01:34 diff --git a/examples/gcmc/log.24Mar17.gcmc.lj.g++.1 b/examples/gcmc/log.6Jul17.gcmc.lj.g++.1 similarity index 88% rename from examples/gcmc/log.24Mar17.gcmc.lj.g++.1 rename to examples/gcmc/log.6Jul17.gcmc.lj.g++.1 index 36a9fe885d..69fc2ede1c 100644 --- a/examples/gcmc/log.24Mar17.gcmc.lj.g++.1 +++ b/examples/gcmc/log.6Jul17.gcmc.lj.g++.1 @@ -1,5 +1,4 @@ -LAMMPS (17 Mar 2017) -OMP_NUM_THREADS environment is not set. Defaulting to 1 thread. (../comm.cpp:90) +LAMMPS (6 Jul 2017) using 1 OpenMP thread(s) per MPI task # GCMC for LJ simple fluid, no dynamics # T = 2.0 @@ -100,20 +99,20 @@ Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_rhoav v_pav v 8000 2.2175324 1.5897263 -3.078898 3.2759002 0.528 66 0.068180395 0.067899629 0.11332691 0.53928 1.5488388 -0.01075766 9000 1.8610779 1.0396231 -2.923262 2.7465908 0.496 62 0.068346453 0.068028117 0.1134132 0.52912 1.4352871 0.027082544 10000 2.1079271 1.1746643 -2.9112062 3.1091925 0.48 60 0.068352878 0.068054948 0.11335434 0.5316 1.4462327 0.018503094 -Loop time of 13.05 on 1 procs for 10000 steps with 60 atoms +Loop time of 20.6892 on 1 procs for 10000 steps with 60 atoms -Performance: 331035.016 tau/day, 766.285 timesteps/s -100.0% CPU use with 1 MPI tasks x 1 OpenMP threads +Performance: 208804.611 tau/day, 483.344 timesteps/s +99.4% CPU use with 1 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 0.37239 | 0.37239 | 0.37239 | 0.0 | 2.85 -Neigh | 0.94764 | 0.94764 | 0.94764 | 0.0 | 7.26 -Comm | 0.092473 | 0.092473 | 0.092473 | 0.0 | 0.71 -Output | 0.00023365 | 0.00023365 | 0.00023365 | 0.0 | 0.00 -Modify | 11.627 | 11.627 | 11.627 | 0.0 | 89.09 -Other | | 0.01054 | | | 0.08 +Pair | 0.47227 | 0.47227 | 0.47227 | 0.0 | 2.28 +Neigh | 1.1729 | 1.1729 | 1.1729 | 0.0 | 5.67 +Comm | 0.17133 | 0.17133 | 0.17133 | 0.0 | 0.83 +Output | 0.00028253 | 0.00028253 | 0.00028253 | 0.0 | 0.00 +Modify | 18.852 | 18.852 | 18.852 | 0.0 | 91.12 +Other | | 0.02063 | | | 0.10 Nlocal: 60 ave 60 max 60 min Histogram: 1 0 0 0 0 0 0 0 0 0 @@ -126,4 +125,4 @@ Total # of neighbors = 2133 Ave neighs/atom = 35.55 Neighbor list builds = 10000 Dangerous builds = 0 -Total wall time: 0:00:13 +Total wall time: 0:00:20 diff --git a/examples/gcmc/log.24Mar17.gcmc.lj.g++.4 b/examples/gcmc/log.6Jul17.gcmc.lj.g++.4 similarity index 88% rename from examples/gcmc/log.24Mar17.gcmc.lj.g++.4 rename to examples/gcmc/log.6Jul17.gcmc.lj.g++.4 index 8694d8b95e..6bd3b3189c 100644 --- a/examples/gcmc/log.24Mar17.gcmc.lj.g++.4 +++ b/examples/gcmc/log.6Jul17.gcmc.lj.g++.4 @@ -1,5 +1,4 @@ -LAMMPS (17 Mar 2017) -OMP_NUM_THREADS environment is not set. Defaulting to 1 thread. (../comm.cpp:90) +LAMMPS (6 Jul 2017) using 1 OpenMP thread(s) per MPI task # GCMC for LJ simple fluid, no dynamics # T = 2.0 @@ -100,20 +99,20 @@ Step Temp Press PotEng KinEng Density Atoms v_iacc v_dacc v_tacc v_rhoav v_pav v 8000 1.7790467 1.8680568 -2.8028819 2.6275151 0.52 65 0.070454494 0.070172368 0.11736806 0.524 1.4213649 0.047985191 9000 1.7968847 1.3195587 -3.261001 2.6550983 0.536 67 0.069952011 0.069618327 0.11650087 0.53904 1.4624201 -0.01069837 10000 2.1566109 1.1015729 -3.4999837 3.1880335 0.552 69 0.069603309 0.069284134 0.11625548 0.53128 1.3587249 0.02075238 -Loop time of 13.0611 on 4 procs for 10000 steps with 69 atoms +Loop time of 24.9916 on 4 procs for 10000 steps with 69 atoms -Performance: 330753.007 tau/day, 765.632 timesteps/s -99.7% CPU use with 4 MPI tasks x 1 OpenMP threads +Performance: 172857.936 tau/day, 400.134 timesteps/s +98.2% CPU use with 4 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 0.08888 | 0.09443 | 0.099889 | 1.4 | 0.72 -Neigh | 0.27721 | 0.28532 | 0.29177 | 1.1 | 2.18 -Comm | 0.27648 | 0.28875 | 0.30268 | 1.9 | 2.21 -Output | 0.00029635 | 0.00043058 | 0.00048113 | 0.0 | 0.00 -Modify | 12.384 | 12.384 | 12.384 | 0.0 | 94.82 -Other | | 0.008055 | | | 0.06 +Pair | 0.11696 | 0.12516 | 0.1321 | 1.7 | 0.50 +Neigh | 0.34874 | 0.35644 | 0.36545 | 1.2 | 1.43 +Comm | 0.48531 | 0.51366 | 0.54755 | 3.8 | 2.06 +Output | 0.0005362 | 0.00069767 | 0.00076008 | 0.0 | 0.00 +Modify | 23.956 | 23.972 | 23.988 | 0.3 | 95.92 +Other | | 0.02376 | | | 0.10 Nlocal: 17.25 ave 23 max 10 min Histogram: 1 0 0 0 0 0 2 0 0 1 @@ -126,4 +125,4 @@ Total # of neighbors = 2823 Ave neighs/atom = 40.913 Neighbor list builds = 10000 Dangerous builds = 0 -Total wall time: 0:00:13 +Total wall time: 0:00:24 diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp index fbe6b6bb62..4405a680f2 100644 --- a/src/MC/fix_gcmc.cpp +++ b/src/MC/fix_gcmc.cpp @@ -188,6 +188,10 @@ FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) : error->all(FLERR,"Cannot use fix gcmc shake and not molecule"); if (rigidflag && shakeflag) error->all(FLERR,"Cannot use fix gcmc rigid and shake"); + if (rigidflag && (nmcmoves > 0)) + error->all(FLERR,"Cannot use fix gcmc rigid with MC moves"); + if (shakeflag && (nmcmoves > 0)) + error->all(FLERR,"Cannot use fix gcmc shake with MC moves"); // setup of coords and imageflags array From b5e9e90bb66d7e7363664b1b56d049fdb206e12d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 10 Jul 2017 17:21:20 -0400 Subject: [PATCH 046/293] white space cleanup --- src/MC/fix_gcmc.cpp | 54 ++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/MC/fix_gcmc.cpp b/src/MC/fix_gcmc.cpp index 4405a680f2..48ba8ed5cf 100644 --- a/src/MC/fix_gcmc.cpp +++ b/src/MC/fix_gcmc.cpp @@ -71,7 +71,7 @@ enum{ATOM,MOLECULE}; FixGCMC::FixGCMC(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), idregion(NULL), full_flag(0), ngroups(0), groupstrings(NULL), ngrouptypes(0), grouptypestrings(NULL), - grouptypebits(NULL), grouptypes(NULL), local_gas_list(NULL), atom_coord(NULL), random_equal(NULL), random_unequal(NULL), + grouptypebits(NULL), grouptypes(NULL), local_gas_list(NULL), atom_coord(NULL), random_equal(NULL), random_unequal(NULL), coords(NULL), imageflags(NULL), fixrigid(NULL), fixshake(NULL), idrigid(NULL), idshake(NULL) { if (narg < 11) error->all(FLERR,"Illegal fix gcmc command"); @@ -637,7 +637,7 @@ void FixGCMC::init() force->boltz*reservoir_temperature)); zz = exp(beta*chemical_potential)/(pow(lambda,3.0)); } - + sigma = sqrt(force->boltz*reservoir_temperature*tfac_insert/gas_mass/force->mvv2e); if (pressure_flag) zz = pressure*fugacity_coeff*beta/force->nktv2p; @@ -962,21 +962,21 @@ void FixGCMC::attempt_atomic_insertion() zz*volume*exp(-beta*insertion_energy)/(ngas+1)) { atom->avec->create_atom(ngcmc_type,coord); int m = atom->nlocal - 1; - + // add to groups // optionally add to type-based groups - + atom->mask[m] = groupbitall; for (int igroup = 0; igroup < ngrouptypes; igroup++) { if (ngcmc_type == grouptypes[igroup]) atom->mask[m] |= grouptypebits[igroup]; } - + atom->v[m][0] = random_unequal->gaussian()*sigma; atom->v[m][1] = random_unequal->gaussian()*sigma; atom->v[m][2] = random_unequal->gaussian()*sigma; modify->create_attribute(m); - + success = 1; } } @@ -1349,7 +1349,7 @@ void FixGCMC::attempt_molecule_insertion() if (insertion_energy_sum < MAXENERGYTEST && random_equal->uniform() < zz*volume*natoms_per_molecule* exp(-beta*insertion_energy_sum)/(ngas + natoms_per_molecule)) { - + tagint maxmol = 0; for (int i = 0; i < atom->nlocal; i++) maxmol = MAX(maxmol,atom->molecule[i]); tagint maxmol_all; @@ -1357,33 +1357,33 @@ void FixGCMC::attempt_molecule_insertion() maxmol_all++; if (maxmol_all >= MAXTAGINT) error->all(FLERR,"Fix gcmc ran out of available molecule IDs"); - + tagint maxtag = 0; for (int i = 0; i < atom->nlocal; i++) maxtag = MAX(maxtag,atom->tag[i]); tagint maxtag_all; MPI_Allreduce(&maxtag,&maxtag_all,1,MPI_LMP_TAGINT,MPI_MAX,world); - + int nlocalprev = atom->nlocal; - + double vnew[3]; vnew[0] = random_equal->gaussian()*sigma; vnew[1] = random_equal->gaussian()*sigma; vnew[2] = random_equal->gaussian()*sigma; - + for (int i = 0; i < natoms_per_molecule; i++) { if (procflag[i]) { atom->avec->create_atom(onemols[imol]->type[i],atom_coord[i]); int m = atom->nlocal - 1; - + // add to groups // optionally add to type-based groups - + atom->mask[m] = groupbitall; for (int igroup = 0; igroup < ngrouptypes; igroup++) { if (ngcmc_type == grouptypes[igroup]) atom->mask[m] |= grouptypebits[igroup]; } - + atom->image[m] = imagezero; domain->remap(atom->x[m],atom->image[m]); atom->molecule[m] = maxmol_all; @@ -1393,7 +1393,7 @@ void FixGCMC::attempt_molecule_insertion() atom->v[m][0] = vnew[0]; atom->v[m][1] = vnew[1]; atom->v[m][2] = vnew[2]; - + atom->add_molecule_atom(onemols[imol],i,m,maxtag_all); modify->create_attribute(m); } @@ -1494,13 +1494,13 @@ void FixGCMC::attempt_atomic_translation_full() energy_stored = energy_after; ntranslation_successes += 1.0; } else { - + tagint tmptag_all; MPI_Allreduce(&tmptag,&tmptag_all,1,MPI_LMP_TAGINT,MPI_MAX,world); - + double xtmp_all[3]; MPI_Allreduce(&xtmp,&xtmp_all,3,MPI_DOUBLE,MPI_SUM,world); - + for (int i = 0; i < atom->nlocal; i++) { if (tmptag_all == atom->tag[i]) { x[i][0] = xtmp_all[0]; @@ -1655,7 +1655,7 @@ void FixGCMC::attempt_atomic_insertion_full() if (energy_after < MAXENERGYTEST && random_equal->uniform() < zz*volume*exp(beta*(energy_before - energy_after))/(ngas+1)) { - + ninsertion_successes += 1.0; energy_stored = energy_after; } else { @@ -2150,11 +2150,11 @@ double FixGCMC::energy(int i, int itype, tagint imolecule, double *coord) int jtype = type[j]; // if overlap check requested, if overlap, - // return signal value for energy + // return signal value for energy if (overlap_flag && rsq < overlap_cutoffsq) return MAXENERGYSIGNAL; - + if (rsq < cutsq[itype][jtype]) total_energy += pair->single(i,j,itype,jtype,rsq,factor_coul,factor_lj,fpair); @@ -2189,7 +2189,7 @@ double FixGCMC::molecule_energy(tagint gas_molecule_id) double FixGCMC::energy_full() { int imolecule; - + if (triclinic) domain->x2lamda(atom->nlocal); domain->pbc(); comm->exchange(); @@ -2202,7 +2202,7 @@ double FixGCMC::energy_full() int vflag = 0; // if overlap check requested, if overlap, - // return signal value for energy + // return signal value for energy if (overlap_flag) { int overlaptestall; @@ -2216,12 +2216,12 @@ double FixGCMC::energy_full() for (int j = i+1; j < nall; j++) { if (mode == MOLECULE) if (imolecule == molecule[j]) continue; - + delx = x[i][0] - x[j][0]; dely = x[i][1] - x[j][1]; delz = x[i][2] - x[j][2]; rsq = delx*delx + dely*dely + delz*delz; - + if (rsq < overlap_cutoffsq) { overlaptest = 1; break; @@ -2236,7 +2236,7 @@ double FixGCMC::energy_full() // clear forces so they don't accumulate over multiple // calls within fix gcmc timestep, e.g. for fix shake - + size_t nbytes = sizeof(double) * (atom->nlocal + atom->nghost); if (nbytes) memset(&atom->f[0][0],0,3*nbytes); @@ -2374,7 +2374,7 @@ void FixGCMC::update_gas_atoms_list() group->xcm(molecule_group,gas_mass,com); // remap unwrapped com into periodic box - + domain->remap(com); comx[imolecule] = com[0]; comy[imolecule] = com[1]; From c9a0d38a3effa82a95decbfaa3a8145aa0545260 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 10 Jul 2017 17:34:00 -0400 Subject: [PATCH 047/293] mention restriction for use with fix shake or fix rigid in fix gcmc docs --- doc/src/fix_gcmc.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/src/fix_gcmc.txt b/doc/src/fix_gcmc.txt index 41ec38cffb..405738276f 100644 --- a/doc/src/fix_gcmc.txt +++ b/doc/src/fix_gcmc.txt @@ -383,6 +383,9 @@ called. Reneighboring is required. Can be run in parallel, but aspects of the GCMC part will not scale well in parallel. Only usable for 3D simulations. +When using fix gcmc in combination with fix shake or fix rigid, +only gcmc exchange moves are supported. + Note that very lengthy simulations involving insertions/deletions of billions of gas molecules may run out of atom or molecule IDs and trigger an error, so it is better to run multiple shorter-duration From 8d592f4b9e4350abacefef31380c626ff8d7095e Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Mon, 10 Jul 2017 16:43:23 -0500 Subject: [PATCH 048/293] Finalized code for lib/kim/install.py --- lib/kim/.gitignore | 1 + lib/kim/Makefile.lammps | 2 +- lib/kim/install.py | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/lib/kim/.gitignore b/lib/kim/.gitignore index eb55b3d4b8..3be8ecbdd6 100644 --- a/lib/kim/.gitignore +++ b/lib/kim/.gitignore @@ -1 +1,2 @@ /Makefile.KIM_DIR +/Makefile.KIM_Config diff --git a/lib/kim/Makefile.lammps b/lib/kim/Makefile.lammps index 3964e662b5..b66d7005a4 100644 --- a/lib/kim/Makefile.lammps +++ b/lib/kim/Makefile.lammps @@ -16,7 +16,7 @@ # Settings that the LAMMPS build will import when this package is installed -include ./Makefile.KIM_DIR +include ../../lib/kim/Makefile.KIM_DIR ifeq ($(wildcard $(KIM_INSTALL_DIR)/bin/kim-api-build-config),) KIM_CONFIG_HELPER = kim-api-build-config diff --git a/lib/kim/install.py b/lib/kim/install.py index bfc97a0983..ca426f3f2e 100644 --- a/lib/kim/install.py +++ b/lib/kim/install.py @@ -70,10 +70,12 @@ url = "https://s3.openkim.org/kim-api/%s.tgz" % version if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) + open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) else: if dirflag == 1: open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) + open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) print "Updated %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) @@ -119,7 +121,7 @@ if buildflag == 1: if txt[0] != 0: error() # remove source files - print "Removing kim-api source and build files" + print "Removing kim-api source and build files ..." cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) txt = commands.getstatusoutput(cmd) print txt[1] @@ -136,4 +138,14 @@ if addflag == 1: if txt[0] != 0: error() # print "Building item ..." - #..... + cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + # + print "Removing kim item source and build files ..." + cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() + From c29e8fba9bd09ac734ab6ef7e04b6ca0ef6c1fc4 Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Mon, 10 Jul 2017 17:00:30 -0500 Subject: [PATCH 049/293] Updated lib/kim/README file to go along with new install.py --- lib/kim/README | 74 ++++++++++++++++++++++++-------------------------- 1 file changed, 36 insertions(+), 38 deletions(-) diff --git a/lib/kim/README b/lib/kim/README index 086bbce90c..00d6ea8fad 100644 --- a/lib/kim/README +++ b/lib/kim/README @@ -11,66 +11,64 @@ kim command. To download, build, and install the KIM API on your system, follow these steps. You can use the install.py script to automate these steps. -**Note** The process described below will compile the kim-api using absolute -paths names. This means that if you move your lammps directory to a new -location after compilation the kim-api library will not be able to find some of -its components. It is best to recompile after moving the lammps directory. +----------------- -The KIM API is available for download from "this site"_https://openkim.org, -namely https://openkim.org. The tarball you download is "kim-api-vX.Y.Z.tgz", -which can be unpacked in this directory or whereever you wish: +Instructions: -tar xvfz kim*tgz -Note that if you unpack and build KIM in this directory, when you -download a new LAMMPS tarball, the files you have added here will be -lost. So you likely want to build it somewhere else. +1. Configure lammps for use with the kim-api library installed in this directory -The kim-api-vX.Y.Z/docs/ directory has further documentation for the -KIM API. In order to compile and install the KIM API follow the -instructions found in the file kim-api-vX.Y.Z/INSTALL. (Don't forget -to download and compile any Model Drivers and Models that you want to -use.) +$ printf "KIM_INSTALL_DIR=${PWD}\n" > ./Makefile.KIM_DIR +$ printf "include ${PWD}/lib/kim-api/Makefile.KIM_Config\n" > ./Makefile.KIM_Config -Once you have successfully compiled and installed the KIM API, you -need to make sure the utility kim-api-build-config is in your PATH so -that the LAMMPS build system can properly work with the KIM API. - -The following are example commands that perform these steps: +2. Download and unpack the kim-api # replace X.Y.Z as appropriate here and below $ wget http://s3.openkim.org/kim-api/kim-api-vX.Y.Z.tgz $ tar zxvf kim-api-vX.Y.Z.tgz -# get OpenKIM models, setup and compile +# configure the kim-api $ cd kim-api-vX.Y.Z -$ ./configure --prefix=?????? +$ ./configure --prefix=${PWD}/../ + +# setup the desired kim item +$ make add-Pair_Johnson_Fe__MO_857282754307_002 + +3. Build and install the kim-api and model -$ make add-EAM_Dynamo_Angelo_Moody_NiAlH__MO_418978237058_001 $ make $ make install # replace X with the KIM API major version number $ make install-set-default-to-vX +$ cd ../ -# In order to permanently add the kim-api-build-config utility to your -# PATH variable, perform the following: -# -# For the bash shell: -$ printf "export PATH=${PATH}:${HOME}/local/bin\n" >> ${HOME}/.bashrc -$ source ${HOME}/.bashrc -# -# For the csh shell: -% printf "setenv PATH ${PATH}:${HOME}/local/bin\b" >> ${HOME}/.cshrc -% source ${HOME}/.cshrc +4. Remove source and build files + +$ rm -rf kim-api-vX.Y.Z +$ rm -rf kim-api-vX.Y.Z.tgz + +5. To add additional items do the following (replace the kim item name with your + desired value) + +$ wget https://openkim.org/download/EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz +$ tar zxvf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz +$ cd EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001 +$ make +$ make install +$ cd .. +$ rm -rf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001 +$ rm -rf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz + +----------------- When these steps are complete you can build LAMMPS with the KIM package installed: -$ cd lammps/src +$ cd ../../src $ make yes-kim $ make g++ (or whatever target you wish) -Note that the Makefile.lammps file in this directory is required -to allow the LAMMPS build to find the necessary KIM files. You -should not normally need to edit this file. +Note that the Makefile.lammps and Makefile.KIM_DIR files in this directory +are required to allow the LAMMPS build to find the necessary KIM files. +You should not normally need to edit this file. From e30c5fc9560c82a7da026fbe951e852d40e3c088 Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Mon, 10 Jul 2017 21:05:29 -0500 Subject: [PATCH 050/293] Fixed shebang and renamed to lib/kim/Install.py --- lib/kim/{install.py => Install.py} | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) rename lib/kim/{install.py => Install.py} (99%) diff --git a/lib/kim/install.py b/lib/kim/Install.py similarity index 99% rename from lib/kim/install.py rename to lib/kim/Install.py index ca426f3f2e..bcd22dcbb3 100644 --- a/lib/kim/install.py +++ b/lib/kim/Install.py @@ -1,4 +1,4 @@ -#!usr/local/python +#!/usr/bin/env python # install.py tool to setup the kim-api library # used to automate the steps described in the README file in this dir @@ -148,4 +148,3 @@ if addflag == 1: txt = commands.getstatusoutput(cmd) print txt[1] if txt[0] != 0: error() - From 8c9db3ea0010be90236beb490e8deb64c9c2a785 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Mon, 10 Jul 2017 23:50:21 -0500 Subject: [PATCH 051/293] Built 2-body short neighbor list and used for 2-body kernels in tersoff gpu styles --- lib/gpu/lal_tersoff.cpp | 4 +- lib/gpu/lal_tersoff.cu | 75 ++++++++++++++++++-------------- lib/gpu/lal_tersoff_mod.cpp | 4 +- lib/gpu/lal_tersoff_mod.cu | 73 ++++++++++++++++++------------- lib/gpu/lal_tersoff_zbl.cpp | 4 +- lib/gpu/lal_tersoff_zbl.cu | 85 +++++++++++++++++++++---------------- 6 files changed, 145 insertions(+), 100 deletions(-) diff --git a/lib/gpu/lal_tersoff.cpp b/lib/gpu/lal_tersoff.cpp index cb4a3fdbd6..a63d286d9c 100644 --- a/lib/gpu/lal_tersoff.cpp +++ b/lib/gpu/lal_tersoff.cpp @@ -250,7 +250,8 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { (BX/this->_threads_per_atom))); this->k_short_nbor.set_size(GX,BX); - this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + this->k_short_nbor.run(&this->atom->x, &cutsq, &map, + &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); @@ -283,6 +284,7 @@ void TersoffT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_pair.run(&this->atom->x, &ts1, &ts2, &cutsq, &map, &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom); diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu index 9faa59c34d..0026fb97cb 100644 --- a/lib/gpu/lal_tersoff.cu +++ b/lib/gpu/lal_tersoff.cu @@ -165,7 +165,10 @@ texture ts5_tex; #endif __kernel void k_tersoff_short_nbor(const __global numtyp4 *restrict x_, - const numtyp cutshortsq, + const __global numtyp *restrict cutsq, + const __global int *restrict map, + const __global int *restrict elem2param, + const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, __global int * dev_short_nbor, @@ -182,6 +185,8 @@ __kernel void k_tersoff_short_nbor(const __global numtyp4 *restrict x_, n_stride,nbor_end,nbor); numtyp4 ix; fetch4(ix,i,pos_tex); //x_[i]; + int itype=ix.w; + itype=map[itype]; int ncount = 0; int m = nbor; @@ -195,6 +200,9 @@ __kernel void k_tersoff_short_nbor(const __global numtyp4 *restrict x_, j &= NEIGHMASK; numtyp4 jx; fetch4(jx,j,pos_tex); //x_[j]; + int jtype=jx.w; + jtype=map[jtype]; + int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; // Compute r12 numtyp delx = ix.x-jx.x; @@ -202,7 +210,7 @@ __kernel void k_tersoff_short_nbor(const __global numtyp4 *restrict x_, numtyp delz = ix.z-jx.z; numtyp rsq = delx*delx+dely*dely+delz*delz; - if (rsq cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; // compute zeta_ij z = (acctyp)0; @@ -391,6 +399,7 @@ __kernel void k_tersoff_repulsive(const __global numtyp4 *restrict x_, const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, @@ -426,9 +435,14 @@ __kernel void k_tersoff_repulsive(const __global numtyp4 *restrict x_, int itype=ix.w; itype=map[itype]; + // recalculate numj and nbor_end for use of the short nbor list + numj = dev_short_nbor[nbor]; + nbor += n_stride; + nbor_end = nbor+fast_mul(numj,n_stride); + for ( ; nbor0) - energy+=feng[1]; - if (vflag>0) { - virial[0] += delx*delx*force; - virial[1] += dely*dely*force; - virial[2] += delz*delz*force; - virial[3] += delx*dely*force; - virial[4] += delx*delz*force; - virial[5] += dely*delz*force; - } + if (eflag>0) + energy+=feng[1]; + if (vflag>0) { + virial[0] += delx*delx*force; + virial[1] += dely*dely*force; + virial[2] += delz*delz*force; + virial[3] += delx*dely*force; + virial[4] += delx*delz*force; + virial[5] += dely*delz*force; } } // for nbor @@ -556,7 +569,7 @@ __kernel void k_tersoff_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -669,7 +682,7 @@ __kernel void k_tersoff_three_end(const __global numtyp4 *restrict x_, const __global int * dev_nbor, const __global int * dev_packed, const __global int * dev_acc, - const __global int * dev_short_nbor, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, @@ -738,7 +751,7 @@ __kernel void k_tersoff_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; @@ -978,7 +991,7 @@ __kernel void k_tersoff_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; diff --git a/lib/gpu/lal_tersoff_mod.cpp b/lib/gpu/lal_tersoff_mod.cpp index 02000d77d3..c37c07f1a1 100644 --- a/lib/gpu/lal_tersoff_mod.cpp +++ b/lib/gpu/lal_tersoff_mod.cpp @@ -250,7 +250,8 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { (BX/this->_threads_per_atom))); this->k_short_nbor.set_size(GX,BX); - this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + this->k_short_nbor.run(&this->atom->x, &cutsq, &map, + &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); @@ -283,6 +284,7 @@ void TersoffMT::loop(const bool _eflag, const bool _vflag, const int evatom) { this->k_pair.run(&this->atom->x, &ts1, &ts2, &cutsq, &map, &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom); diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu index 75bacc2179..555485a1b2 100644 --- a/lib/gpu/lal_tersoff_mod.cu +++ b/lib/gpu/lal_tersoff_mod.cu @@ -165,7 +165,10 @@ texture ts5_tex; #endif __kernel void k_tersoff_mod_short_nbor(const __global numtyp4 *restrict x_, - const numtyp cutshortsq, + const __global numtyp *restrict cutsq, + const __global int *restrict map, + const __global int *restrict elem2param, + const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, __global int * dev_short_nbor, @@ -182,6 +185,8 @@ __kernel void k_tersoff_mod_short_nbor(const __global numtyp4 *restrict x_, n_stride,nbor_end,nbor); numtyp4 ix; fetch4(ix,i,pos_tex); //x_[i]; + int itype=ix.w; + itype=map[itype]; int ncount = 0; int m = nbor; @@ -195,6 +200,9 @@ __kernel void k_tersoff_mod_short_nbor(const __global numtyp4 *restrict x_, j &= NEIGHMASK; numtyp4 jx; fetch4(jx,j,pos_tex); //x_[j]; + int jtype=jx.w; + jtype=map[jtype]; + int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; // Compute r12 numtyp delx = ix.x-jx.x; @@ -202,7 +210,7 @@ __kernel void k_tersoff_mod_short_nbor(const __global numtyp4 *restrict x_, numtyp delz = ix.z-jx.z; numtyp rsq = delx*delx+dely*dely+delz*delz; - if (rsq cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; // compute zeta_ij z = (acctyp)0; @@ -392,6 +400,7 @@ __kernel void k_tersoff_mod_repulsive(const __global numtyp4 *restrict x_, const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, @@ -427,9 +436,14 @@ __kernel void k_tersoff_mod_repulsive(const __global numtyp4 *restrict x_, int itype=ix.w; itype=map[itype]; + // recalculate numj and nbor_end for use of the short nbor list + numj = dev_short_nbor[nbor]; + nbor += n_stride; + nbor_end = nbor+fast_mul(numj,n_stride); + for ( ; nbor0) - energy+=feng[1]; - if (vflag>0) { - virial[0] += delx*delx*force; - virial[1] += dely*dely*force; - virial[2] += delz*delz*force; - virial[3] += delx*dely*force; - virial[4] += delx*delz*force; - virial[5] += dely*delz*force; - } + if (eflag>0) + energy+=feng[1]; + if (vflag>0) { + virial[0] += delx*delx*force; + virial[1] += dely*dely*force; + virial[2] += delz*delz*force; + virial[3] += delx*dely*force; + virial[4] += delx*delz*force; + virial[5] += dely*delz*force; } } // for nbor @@ -560,7 +573,7 @@ __kernel void k_tersoff_mod_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -748,7 +761,7 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; @@ -997,7 +1010,7 @@ __kernel void k_tersoff_mod_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; diff --git a/lib/gpu/lal_tersoff_zbl.cpp b/lib/gpu/lal_tersoff_zbl.cpp index 33edabd799..827613067c 100644 --- a/lib/gpu/lal_tersoff_zbl.cpp +++ b/lib/gpu/lal_tersoff_zbl.cpp @@ -275,7 +275,8 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { (BX/this->_threads_per_atom))); this->k_short_nbor.set_size(GX,BX); - this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + this->k_short_nbor.run(&this->atom->x, &cutsq, &map, + &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); @@ -309,6 +310,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { &_global_e, &_global_a_0, &_global_epsilon_0, &cutsq, &map, &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->dev_short_nbor, &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom); diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu index 439d4028df..89ae72df8a 100644 --- a/lib/gpu/lal_tersoff_zbl.cu +++ b/lib/gpu/lal_tersoff_zbl.cu @@ -168,7 +168,10 @@ texture ts6_tex; #endif __kernel void k_tersoff_zbl_short_nbor(const __global numtyp4 *restrict x_, - const numtyp cutshortsq, + const __global numtyp *restrict cutsq, + const __global int *restrict map, + const __global int *restrict elem2param, + const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, __global int * dev_short_nbor, @@ -185,6 +188,8 @@ __kernel void k_tersoff_zbl_short_nbor(const __global numtyp4 *restrict x_, n_stride,nbor_end,nbor); numtyp4 ix; fetch4(ix,i,pos_tex); //x_[i]; + int itype=ix.w; + itype=map[itype]; int ncount = 0; int m = nbor; @@ -198,6 +203,9 @@ __kernel void k_tersoff_zbl_short_nbor(const __global numtyp4 *restrict x_, j &= NEIGHMASK; numtyp4 jx; fetch4(jx,j,pos_tex); //x_[j]; + int jtype=jx.w; + jtype=map[jtype]; + int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; // Compute r12 numtyp delx = ix.x-jx.x; @@ -205,7 +213,7 @@ __kernel void k_tersoff_zbl_short_nbor(const __global numtyp4 *restrict x_, numtyp delz = ix.z-jx.z; numtyp rsq = delx*delx+dely*dely+delz*delz; - if (rsq cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; // compute zeta_ij z = (acctyp)0; @@ -403,6 +411,7 @@ __kernel void k_tersoff_zbl_repulsive(const __global numtyp4 *restrict x_, const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, @@ -440,9 +449,14 @@ __kernel void k_tersoff_zbl_repulsive(const __global numtyp4 *restrict x_, int itype=ix.w; itype=map[itype]; + // recalculate numj and nbor_end for use of the short nbor list + numj = dev_short_nbor[nbor]; + nbor += n_stride; + nbor_end = nbor+fast_mul(numj,n_stride); + for ( ; nbor0) - energy+=feng[1]; - if (vflag>0) { - virial[0] += delx*delx*force; - virial[1] += dely*dely*force; - virial[2] += delz*delz*force; - virial[3] += delx*dely*force; - virial[4] += delx*delz*force; - virial[5] += dely*delz*force; - } + if (eflag>0) + energy+=feng[1]; + if (vflag>0) { + virial[0] += delx*delx*force; + virial[1] += dely*dely*force; + virial[2] += delz*delz*force; + virial[3] += delx*dely*force; + virial[4] += delx*delz*force; + virial[5] += dely*delz*force; } } // for nbor @@ -576,7 +589,7 @@ __kernel void k_tersoff_zbl_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -758,7 +771,7 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; @@ -998,7 +1011,7 @@ __kernel void k_tersoff_zbl_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; - if (rsq1 > cutsq[ijparam]) continue; +// if (rsq1 > cutsq[ijparam]) continue; numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; From cdac5f496c531a851b1bdc5b6177f590150c9fff Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Tue, 11 Jul 2017 00:13:56 -0500 Subject: [PATCH 052/293] Built 3-body short neighbor list for the 3-body kernels using per-pair cutoffs for vashishta gpu style --- lib/gpu/lal_vashishta.cpp | 3 ++- lib/gpu/lal_vashishta.cu | 22 +++++++++++++++++----- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/gpu/lal_vashishta.cpp b/lib/gpu/lal_vashishta.cpp index 55318bb3b0..d03ac992bd 100644 --- a/lib/gpu/lal_vashishta.cpp +++ b/lib/gpu/lal_vashishta.cpp @@ -233,7 +233,8 @@ void VashishtaT::loop(const bool _eflag, const bool _vflag, const int evatom) { (BX/this->_threads_per_atom))); this->k_short_nbor.set_size(GX,BX); - this->k_short_nbor.run(&this->atom->x, &_cutshortsq, + this->k_short_nbor.run(&this->atom->x, ¶m4, &map, + &elem2param, &_nelements, &_nparams, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->dev_short_nbor, &ainum, &nbor_pitch, &this->_threads_per_atom); diff --git a/lib/gpu/lal_vashishta.cu b/lib/gpu/lal_vashishta.cu index 7449b18f6b..d226aba6dd 100644 --- a/lib/gpu/lal_vashishta.cu +++ b/lib/gpu/lal_vashishta.cu @@ -137,7 +137,10 @@ texture param5_tex; #endif __kernel void k_vashishta_short_nbor(const __global numtyp4 *restrict x_, - const numtyp cutshortsq, + const __global numtyp4 *restrict param4, + const __global int *restrict map, + const __global int *restrict elem2param, + const int nelements, const int nparams, const __global int * dev_nbor, const __global int * dev_packed, __global int * dev_short_nbor, @@ -154,6 +157,8 @@ __kernel void k_vashishta_short_nbor(const __global numtyp4 *restrict x_, n_stride,nbor_end,nbor); numtyp4 ix; fetch4(ix,i,pos_tex); //x_[i]; + int itype=ix.w; + itype=map[itype]; int ncount = 0; int m = nbor; @@ -167,6 +172,9 @@ __kernel void k_vashishta_short_nbor(const __global numtyp4 *restrict x_, j &= NEIGHMASK; numtyp4 jx; fetch4(jx,j,pos_tex); //x_[j]; + int jtype=jx.w; + jtype=map[jtype]; + int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; // Compute r12 numtyp delx = ix.x-jx.x; @@ -174,7 +182,7 @@ __kernel void k_vashishta_short_nbor(const __global numtyp4 *restrict x_, numtyp delz = ix.z-jx.z; numtyp rsq = delx*delx+dely*dely+delz*delz; - if (rsq param_r0sq_ij) continue; + +// if (rsq1 > param_r0sq_ij) continue; + param_gamma_ij=param4_ijparam.y; param_r0_ij=param4_ijparam.w; @@ -592,7 +602,8 @@ __kernel void k_vashishta_three_end(const __global numtyp4 *restrict x_, int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; numtyp4 param4_ijparam; fetch4(param4_ijparam,ijparam,param4_tex); param_r0sq_ij = param4_ijparam.x; - if (rsq1 > param_r0sq_ij) continue; + +// if (rsq1 > param_r0sq_ij) continue; param_gamma_ij=param4_ijparam.y; param_r0_ij = param4_ijparam.w; @@ -742,7 +753,8 @@ __kernel void k_vashishta_three_end_vatom(const __global numtyp4 *restrict x_, int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; numtyp4 param4_ijparam; fetch4(param4_ijparam,ijparam,param4_tex); param_r0sq_ij=param4_ijparam.x; - if (rsq1 > param_r0sq_ij) continue; + +// if (rsq1 > param_r0sq_ij) continue; param_gamma_ij=param4_ijparam.y; param_r0_ij=param4_ijparam.w; From c8939d8df6dac59494e5bfa5f9d2543d2a913260 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 11 Jul 2017 09:43:54 -0400 Subject: [PATCH 053/293] clarify explanation of body style molecule in rigid fixes --- doc/src/fix_rigid.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/src/fix_rigid.txt b/doc/src/fix_rigid.txt index dbadd3fa63..87021b8551 100644 --- a/doc/src/fix_rigid.txt +++ b/doc/src/fix_rigid.txt @@ -212,8 +212,9 @@ pour"_fix_pour.html. For bodystyle {single} the entire fix group of atoms is treated as one rigid body. This option is only allowed for the {rigid} styles. -For bodystyle {molecule}, each set of atoms in the fix group with a -different molecule ID is treated as a rigid body. This option is +For bodystyle {molecule}, atoms are grouped into rigid bodies by their +respective molecule IDs: each set of atoms in the fix group with the +same molecule ID is treated as a different rigid body. This option is allowed for both the {rigid} and {rigid/small} styles. Note that atoms with a molecule ID = 0 will be treated as a single rigid body. For a system with atomic solvent (typically this is atoms with From 5a1e020bf01c8a3454dd9159fe41de4ec4dbffa2 Mon Sep 17 00:00:00 2001 From: "H. Metin Aktulga" Date: Tue, 11 Jul 2017 08:05:36 -0700 Subject: [PATCH 054/293] updated the credits and citations for pair style reaxc/omp and qeq/reax/omp --- src/USER-OMP/fix_qeq_reax_omp.cpp | 32 +++++++++++++++++--- src/USER-OMP/fix_qeq_reax_omp.h | 10 ------ src/USER-OMP/pair_reaxc_omp.cpp | 37 +++++++++++++++++++---- src/USER-OMP/pair_reaxc_omp.h | 10 ------ src/USER-OMP/reaxc_bond_orders_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_bond_orders_omp.h | 14 +++++---- src/USER-OMP/reaxc_bonds_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_bonds_omp.h | 14 +++++---- src/USER-OMP/reaxc_forces_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_forces_omp.h | 14 +++++---- src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_hydrogen_bonds_omp.h | 14 +++++---- src/USER-OMP/reaxc_init_md_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_init_md_omp.h | 14 +++++---- src/USER-OMP/reaxc_multi_body_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_multi_body_omp.h | 14 +++++---- src/USER-OMP/reaxc_nonbonded_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_nonbonded_omp.h | 14 +++++---- src/USER-OMP/reaxc_torsion_angles_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_torsion_angles_omp.h | 14 +++++---- src/USER-OMP/reaxc_valence_angles_omp.cpp | 14 +++++---- src/USER-OMP/reaxc_valence_angles_omp.h | 14 +++++---- 22 files changed, 203 insertions(+), 138 deletions(-) diff --git a/src/USER-OMP/fix_qeq_reax_omp.cpp b/src/USER-OMP/fix_qeq_reax_omp.cpp index df586132d4..0db3ffdc43 100644 --- a/src/USER-OMP/fix_qeq_reax_omp.cpp +++ b/src/USER-OMP/fix_qeq_reax_omp.cpp @@ -12,11 +12,24 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Hasan Metin Aktulga, Purdue University - (now at Lawrence Berkeley National Laboratory, hmaktulga@lbl.gov) + Contributing author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu - Hybrid and sub-group capabilities: Ray Shan (Sandia) -------------------------------------------------------------------------- */ + Hybrid & sub-group capabilities added by Ray Shan (Materials Design) + + OpenMP based threading support for fix qeq/reax/omp added + by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), + Kurt O'Hearn (MSU), Ray Shan (Materials Design), Wei Jiang (ALCF) + + Integration of the pair_style reax/c/omp into the User-OMP package + by Axel Kohlmeyer (Temple U.) + + Please cite the related publication: + H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, + W. Jiang, "Optimizing the performance of reactive molecular dynamics + simulations for multi-core architectures", International Journal of + High Performance Computing Applications, to appear. + ------------------------------------------------------------------------- */ #include #include @@ -50,11 +63,22 @@ using namespace FixConst; #define CUBE(x) ((x)*(x)*(x)) #define MIN_NBRS 100 +static const char cite_fix_qeq_reax_omp[] = + "fix qeq/reax/omp command:\n\n" + "@Article{Aktulga17,\n" + " author = {H. M. Aktulga, C. Knight, P. Coffman, K. A. OHearn, T. R. Shan, W. Jiang},\n" + " title = {Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures},\n" + " journal = {International Journal of High Performance Computing Applications},\n" + " year = to appear\n" + "}\n\n"; + /* ---------------------------------------------------------------------- */ FixQEqReaxOMP::FixQEqReaxOMP(LAMMPS *lmp, int narg, char **arg) : FixQEqReax(lmp, narg, arg) { + if (lmp->citeme) lmp->citeme->add(cite_fix_qeq_reax_omp); + if (narg<8 || narg>9) error->all(FLERR,"Illegal fix qeq/reax/omp command"); b_temp = NULL; diff --git a/src/USER-OMP/fix_qeq_reax_omp.h b/src/USER-OMP/fix_qeq_reax_omp.h index 7565f0aff0..46210647e5 100644 --- a/src/USER-OMP/fix_qeq_reax_omp.h +++ b/src/USER-OMP/fix_qeq_reax_omp.h @@ -11,16 +11,6 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing author: Hasan Metin Aktulga, Purdue University - (now at Lawrence Berkeley National Laboratory, hmaktulga@lbl.gov) - - Please cite the related publication: - H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, - "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. -------------------------------------------------------------------------- */ - #ifdef FIX_CLASS FixStyle(qeq/reax/omp,FixQEqReaxOMP) diff --git a/src/USER-OMP/pair_reaxc_omp.cpp b/src/USER-OMP/pair_reaxc_omp.cpp index 45c4bce0c0..5489651782 100644 --- a/src/USER-OMP/pair_reaxc_omp.cpp +++ b/src/USER-OMP/pair_reaxc_omp.cpp @@ -12,12 +12,26 @@ ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- - Contributing author: Hasan Metin Aktulga, Purdue University - (now at Lawrence Berkeley National Laboratory, hmaktulga@lbl.gov) - Per-atom energy/virial added by Ray Shan (Sandia) - Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added by - Ray Shan (Sandia) -------------------------------------------------------------------------- */ + Contributing author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu + + Per-atom energy/virial added by Ray Shan (Materials Design, Inc.) + Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added + by Ray Shan (Materials Design) + + OpenMP based threading support for pair_style reax/c/omp added + by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), + Kurt O'Hearn (MSU), Ray Shan (Materials Design), Wei Jiang (ALCF) + + Integration of the pair_style reax/c/omp into the User-OMP package + by Axel Kohlmeyer (Temple U.) + + Please cite the related publication: + H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, + W. Jiang, "Optimizing the performance of reactive molecular dynamics + simulations for multi-core architectures", International Journal of + High Performance Computing Applications, to appear. + ------------------------------------------------------------------------- */ #include "pair_reaxc_omp.h" #include "atom.h" @@ -62,10 +76,21 @@ int ompTimingCount[LASTTIMINGINDEX]; int ompTimingCGCount[LASTTIMINGINDEX]; #endif +static const char cite_pair_reax_c_omp[] = + "pair reax/c/omp command:\n\n" + "@Article{Aktulga17,\n" + " author = {H. M. Aktulga, C. Knight, P. Coffman, K. A. OHearn, T. R. Shan, W. Jiang},\n" + " title = {Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures},\n" + " journal = {International Journal of High Performance Computing Applications},\n" + " year = to appear\n" + "}\n\n"; + /* ---------------------------------------------------------------------- */ PairReaxCOMP::PairReaxCOMP(LAMMPS *lmp) : PairReaxC(lmp), ThrOMP(lmp, THR_PAIR) { + if (lmp->citeme) lmp->citeme->add(cite_pair_reax_c_omp); + suffix_flag |= Suffix::OMP; system->pair_ptr = this; diff --git a/src/USER-OMP/pair_reaxc_omp.h b/src/USER-OMP/pair_reaxc_omp.h index 156627ece0..d0dedf7e3c 100644 --- a/src/USER-OMP/pair_reaxc_omp.h +++ b/src/USER-OMP/pair_reaxc_omp.h @@ -11,16 +11,6 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing author: Hasan Metin Aktulga, Purdue University - (now at Lawrence Berkeley National Laboratory, hmaktulga@lbl.gov) - - Please cite the related publication: - H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, - "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. -------------------------------------------------------------------------- */ - #ifdef PAIR_CLASS PairStyle(reax/c/omp,PairReaxCOMP) diff --git a/src/USER-OMP/reaxc_bond_orders_omp.cpp b/src/USER-OMP/reaxc_bond_orders_omp.cpp index 85755a39a3..9b863e8984 100644 --- a/src/USER-OMP/reaxc_bond_orders_omp.cpp +++ b/src/USER-OMP/reaxc_bond_orders_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_bond_orders_omp.h b/src/USER-OMP/reaxc_bond_orders_omp.h index 272309cadd..5fe0c4611c 100644 --- a/src/USER-OMP/reaxc_bond_orders_omp.h +++ b/src/USER-OMP/reaxc_bond_orders_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_bonds_omp.cpp b/src/USER-OMP/reaxc_bonds_omp.cpp index 9e16919007..d079db6674 100644 --- a/src/USER-OMP/reaxc_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_bonds_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_bonds_omp.h b/src/USER-OMP/reaxc_bonds_omp.h index 8c07fd8957..1d4e44ca11 100644 --- a/src/USER-OMP/reaxc_bonds_omp.h +++ b/src/USER-OMP/reaxc_bonds_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_forces_omp.cpp b/src/USER-OMP/reaxc_forces_omp.cpp index 5e93f31125..6fec7a7e4d 100644 --- a/src/USER-OMP/reaxc_forces_omp.cpp +++ b/src/USER-OMP/reaxc_forces_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_forces_omp.h b/src/USER-OMP/reaxc_forces_omp.h index f4941fc7fa..a438543900 100644 --- a/src/USER-OMP/reaxc_forces_omp.h +++ b/src/USER-OMP/reaxc_forces_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp index c446151150..be1444824b 100644 --- a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_hydrogen_bonds_omp.h b/src/USER-OMP/reaxc_hydrogen_bonds_omp.h index b4a2d78dbb..45a15cee36 100644 --- a/src/USER-OMP/reaxc_hydrogen_bonds_omp.h +++ b/src/USER-OMP/reaxc_hydrogen_bonds_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_init_md_omp.cpp b/src/USER-OMP/reaxc_init_md_omp.cpp index 6cce08a041..79fec8b268 100644 --- a/src/USER-OMP/reaxc_init_md_omp.cpp +++ b/src/USER-OMP/reaxc_init_md_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_init_md_omp.h b/src/USER-OMP/reaxc_init_md_omp.h index bb4e9c7061..157268dbd6 100644 --- a/src/USER-OMP/reaxc_init_md_omp.h +++ b/src/USER-OMP/reaxc_init_md_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_multi_body_omp.cpp b/src/USER-OMP/reaxc_multi_body_omp.cpp index ff8baa3c1a..13d250750b 100644 --- a/src/USER-OMP/reaxc_multi_body_omp.cpp +++ b/src/USER-OMP/reaxc_multi_body_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_multi_body_omp.h b/src/USER-OMP/reaxc_multi_body_omp.h index b0746569ca..f98529e217 100644 --- a/src/USER-OMP/reaxc_multi_body_omp.h +++ b/src/USER-OMP/reaxc_multi_body_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_nonbonded_omp.cpp b/src/USER-OMP/reaxc_nonbonded_omp.cpp index c509be8a26..0c595e07df 100644 --- a/src/USER-OMP/reaxc_nonbonded_omp.cpp +++ b/src/USER-OMP/reaxc_nonbonded_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_nonbonded_omp.h b/src/USER-OMP/reaxc_nonbonded_omp.h index 1ea51257cf..66ecefa05b 100644 --- a/src/USER-OMP/reaxc_nonbonded_omp.h +++ b/src/USER-OMP/reaxc_nonbonded_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_torsion_angles_omp.cpp b/src/USER-OMP/reaxc_torsion_angles_omp.cpp index 4ede439ed4..b6920c6709 100644 --- a/src/USER-OMP/reaxc_torsion_angles_omp.cpp +++ b/src/USER-OMP/reaxc_torsion_angles_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_torsion_angles_omp.h b/src/USER-OMP/reaxc_torsion_angles_omp.h index 51b05f7ae1..742de36eb7 100644 --- a/src/USER-OMP/reaxc_torsion_angles_omp.h +++ b/src/USER-OMP/reaxc_torsion_angles_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_valence_angles_omp.cpp b/src/USER-OMP/reaxc_valence_angles_omp.cpp index d6f0962020..888eeab4a1 100644 --- a/src/USER-OMP/reaxc_valence_angles_omp.cpp +++ b/src/USER-OMP/reaxc_valence_angles_omp.cpp @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as diff --git a/src/USER-OMP/reaxc_valence_angles_omp.h b/src/USER-OMP/reaxc_valence_angles_omp.h index ce304acced..17d797707f 100644 --- a/src/USER-OMP/reaxc_valence_angles_omp.h +++ b/src/USER-OMP/reaxc_valence_angles_omp.h @@ -1,16 +1,18 @@ /*---------------------------------------------------------------------- PuReMD - Purdue ReaxFF Molecular Dynamics Program - + Website: https://www.cs.purdue.edu/puremd + Copyright (2010) Purdue University - Hasan Metin Aktulga, hmaktulga@lbl.gov - Joseph Fogarty, jcfogart@mail.usf.edu - Sagar Pandit, pandit@usf.edu - Ananth Y Grama, ayg@cs.purdue.edu + + Contributing authors: + H. M. Aktulga, J. Fogarty, S. Pandit, A. Grama + Corresponding author: + Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Please cite the related publication: H. M. Aktulga, J. C. Fogarty, S. A. Pandit, A. Y. Grama, "Parallel Reactive Molecular Dynamics: Numerical Methods and - Algorithmic Techniques", Parallel Computing, in press. + Algorithmic Techniques", Parallel Computing, 38 (4-5), 245-259 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as From 338fc28970731ea4d7ec7bb2cec97c875f47d8cf Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 11 Jul 2017 14:59:08 -0400 Subject: [PATCH 055/293] combine citeme.log entry for pair reax/c/omp and fix qeq/reax/omp --- src/USER-OMP/fix_qeq_reax_omp.cpp | 12 ------------ src/USER-OMP/pair_reaxc_omp.cpp | 2 +- 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/src/USER-OMP/fix_qeq_reax_omp.cpp b/src/USER-OMP/fix_qeq_reax_omp.cpp index 0db3ffdc43..3578a6da37 100644 --- a/src/USER-OMP/fix_qeq_reax_omp.cpp +++ b/src/USER-OMP/fix_qeq_reax_omp.cpp @@ -49,7 +49,6 @@ #include "pair.h" #include "respa.h" #include "memory.h" -#include "citeme.h" #include "error.h" #include "reaxc_defs.h" @@ -63,22 +62,11 @@ using namespace FixConst; #define CUBE(x) ((x)*(x)*(x)) #define MIN_NBRS 100 -static const char cite_fix_qeq_reax_omp[] = - "fix qeq/reax/omp command:\n\n" - "@Article{Aktulga17,\n" - " author = {H. M. Aktulga, C. Knight, P. Coffman, K. A. OHearn, T. R. Shan, W. Jiang},\n" - " title = {Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures},\n" - " journal = {International Journal of High Performance Computing Applications},\n" - " year = to appear\n" - "}\n\n"; - /* ---------------------------------------------------------------------- */ FixQEqReaxOMP::FixQEqReaxOMP(LAMMPS *lmp, int narg, char **arg) : FixQEqReax(lmp, narg, arg) { - if (lmp->citeme) lmp->citeme->add(cite_fix_qeq_reax_omp); - if (narg<8 || narg>9) error->all(FLERR,"Illegal fix qeq/reax/omp command"); b_temp = NULL; diff --git a/src/USER-OMP/pair_reaxc_omp.cpp b/src/USER-OMP/pair_reaxc_omp.cpp index 5489651782..078b9d63d4 100644 --- a/src/USER-OMP/pair_reaxc_omp.cpp +++ b/src/USER-OMP/pair_reaxc_omp.cpp @@ -77,7 +77,7 @@ int ompTimingCGCount[LASTTIMINGINDEX]; #endif static const char cite_pair_reax_c_omp[] = - "pair reax/c/omp command:\n\n" + "pair reax/c/omp and fix qeq/reax/omp command:\n\n" "@Article{Aktulga17,\n" " author = {H. M. Aktulga, C. Knight, P. Coffman, K. A. OHearn, T. R. Shan, W. Jiang},\n" " title = {Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures},\n" From f7f4a24930ba18badcc090a8c0dd9c3c1e889372 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 11 Jul 2017 15:00:39 -0400 Subject: [PATCH 056/293] whitspace cleanup --- src/USER-OMP/fix_qeq_reax_omp.cpp | 168 +++++++++++++++--------------- src/USER-OMP/pair_reaxc_omp.cpp | 14 +-- 2 files changed, 91 insertions(+), 91 deletions(-) diff --git a/src/USER-OMP/fix_qeq_reax_omp.cpp b/src/USER-OMP/fix_qeq_reax_omp.cpp index 3578a6da37..4457ab6592 100644 --- a/src/USER-OMP/fix_qeq_reax_omp.cpp +++ b/src/USER-OMP/fix_qeq_reax_omp.cpp @@ -17,16 +17,16 @@ Hybrid & sub-group capabilities added by Ray Shan (Materials Design) - OpenMP based threading support for fix qeq/reax/omp added - by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), + OpenMP based threading support for fix qeq/reax/omp added + by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), Kurt O'Hearn (MSU), Ray Shan (Materials Design), Wei Jiang (ALCF) - - Integration of the pair_style reax/c/omp into the User-OMP package + + Integration of the pair_style reax/c/omp into the User-OMP package by Axel Kohlmeyer (Temple U.) Please cite the related publication: - H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, - W. Jiang, "Optimizing the performance of reactive molecular dynamics + H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, + W. Jiang, "Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures", International Journal of High Performance Computing Applications, to appear. ------------------------------------------------------------------------- */ @@ -204,46 +204,46 @@ void FixQEqReaxOMP::compute_H() for (ii = 0; ii < inum; ii++) { i = ilist[ii]; if (mask[i] & groupbit) { - jlist = firstneigh[i]; - jnum = numneigh[i]; - mfill = H.firstnbr[i]; - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - - dx = x[j][0] - x[i][0]; - dy = x[j][1] - x[i][1]; - dz = x[j][2] - x[i][2]; - r_sqr = SQR(dx) + SQR(dy) + SQR(dz); - - flag = 0; - if (r_sqr <= SQR(swb)) { - if (j < n) flag = 1; - else if (tag[i] < tag[j]) flag = 1; - else if (tag[i] == tag[j]) { - if (dz > SMALL) flag = 1; - else if (fabs(dz) < SMALL) { - if (dy > SMALL) flag = 1; - else if (fabs(dy) < SMALL && dx > SMALL) flag = 1; - } - } - } - - if (flag) { - H.jlist[mfill] = j; - H.val[mfill] = calculate_H( sqrt(r_sqr), shld[type[i]][type[j]] ); - mfill++; - } - } - - H.numnbrs[i] = mfill - H.firstnbr[i]; + jlist = firstneigh[i]; + jnum = numneigh[i]; + mfill = H.firstnbr[i]; + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + + dx = x[j][0] - x[i][0]; + dy = x[j][1] - x[i][1]; + dz = x[j][2] - x[i][2]; + r_sqr = SQR(dx) + SQR(dy) + SQR(dz); + + flag = 0; + if (r_sqr <= SQR(swb)) { + if (j < n) flag = 1; + else if (tag[i] < tag[j]) flag = 1; + else if (tag[i] == tag[j]) { + if (dz > SMALL) flag = 1; + else if (fabs(dz) < SMALL) { + if (dy > SMALL) flag = 1; + else if (fabs(dy) < SMALL && dx > SMALL) flag = 1; + } + } + } + + if (flag) { + H.jlist[mfill] = j; + H.val[mfill] = calculate_H( sqrt(r_sqr), shld[type[i]][type[j]] ); + mfill++; + } + } + + H.numnbrs[i] = mfill - H.firstnbr[i]; } } if (mfill >= H.m) { char str[128]; sprintf(str,"H matrix size has been exceeded: mfill=%d H.m=%d\n", - mfill, H.m); + mfill, H.m); error->warning(FLERR,str); error->all(FLERR,"Fix qeq/reax/omp has insufficient QEq matrix size"); } @@ -313,7 +313,7 @@ void FixQEqReaxOMP::pre_force(int vflag) if (dual_enabled) { matvecs = dual_CG(b_s, b_t, s, t); // OMP_TIMING inside dual_CG } else { - matvecs_s = CG(b_s, s); // CG on s - parallel + matvecs_s = CG(b_s, s); // CG on s - parallel #ifdef OMP_TIMING endTimeBase = MPI_Wtime(); @@ -323,7 +323,7 @@ void FixQEqReaxOMP::pre_force(int vflag) startTimeBase = endTimeBase; #endif - matvecs_t = CG(b_t, t); // CG on t - parallel + matvecs_t = CG(b_t, t); // CG on t - parallel #ifdef OMP_TIMING endTimeBase = MPI_Wtime(); @@ -390,23 +390,23 @@ void FixQEqReaxOMP::init_matvec() for (int ii = 0; ii < nn; ++ii) { i = ilist[ii]; if (atom->mask[i] & groupbit) { - - /* init pre-conditioner for H and init solution vectors */ - Hdia_inv[i] = 1. / eta[ atom->type[i] ]; - b_s[i] = -chi[ atom->type[i] ]; - b_t[i] = -1.0; - - // Predictor Step - double tp = 0.0; - double sp = 0.0; - for (int j=0; jtype[i] ]; + b_s[i] = -chi[ atom->type[i] ]; + b_t[i] = -1.0; + + // Predictor Step + double tp = 0.0; + double sp = 0.0; + for (int j=0; jmask[i] & groupbit) { - - /* init pre-conditioner for H and init solution vectors */ - Hdia_inv[i] = 1. / eta[ atom->type[i] ]; - b_s[i] = -chi[ atom->type[i] ]; - b_t[i] = -1.0; - - /* linear extrapolation for s & t from previous solutions */ - //s[i] = 2 * s_hist[i][0] - s_hist[i][1]; - //t[i] = 2 * t_hist[i][0] - t_hist[i][1]; - - /* quadratic extrapolation for s & t from previous solutions */ - //s[i] = s_hist[i][2] + 3 * ( s_hist[i][0] - s_hist[i][1] ); - t[i] = t_hist[i][2] + 3 * ( t_hist[i][0] - t_hist[i][1] ); - - /* cubic extrapolation for s & t from previous solutions */ - s[i] = 4*(s_hist[i][0]+s_hist[i][2])-(6*s_hist[i][1]+s_hist[i][3]); - //t[i] = 4*(t_hist[i][0]+t_hist[i][2])-(6*t_hist[i][1]+t_hist[i][3]); + + /* init pre-conditioner for H and init solution vectors */ + Hdia_inv[i] = 1. / eta[ atom->type[i] ]; + b_s[i] = -chi[ atom->type[i] ]; + b_t[i] = -1.0; + + /* linear extrapolation for s & t from previous solutions */ + //s[i] = 2 * s_hist[i][0] - s_hist[i][1]; + //t[i] = 2 * t_hist[i][0] - t_hist[i][1]; + + /* quadratic extrapolation for s & t from previous solutions */ + //s[i] = s_hist[i][2] + 3 * ( s_hist[i][0] - s_hist[i][1] ); + t[i] = t_hist[i][2] + 3 * ( t_hist[i][0] - t_hist[i][1] ); + + /* cubic extrapolation for s & t from previous solutions */ + s[i] = 4*(s_hist[i][0]+s_hist[i][2])-(6*s_hist[i][1]+s_hist[i][3]); + //t[i] = 4*(t_hist[i][0]+t_hist[i][2])-(6*t_hist[i][1]+t_hist[i][3]); } } } @@ -526,7 +526,7 @@ int FixQEqReaxOMP::CG( double *b, double *x) #endif { MPI_Allreduce(&tmp1, &tmp2, 1, MPI_DOUBLE, MPI_SUM, world); - + alpha = sig_new / tmp2; tmp1 = 0.0; } @@ -540,7 +540,7 @@ int FixQEqReaxOMP::CG( double *b, double *x) if (atom->mask[ii] & groupbit) { x[ii] += alpha * d[ii]; r[ii] -= alpha * q[ii]; - + // pre-conditioning p[ii] = r[ii] * Hdia_inv[ii]; tmp1 += r[ii] * p[ii]; @@ -628,7 +628,7 @@ void FixQEqReaxOMP::sparse_matvec( sparse_matrix *A, double *x, double *b) #if defined(_OPENMP) #pragma omp barrier #pragma omp for schedule(dynamic,50) -#endif +#endif for (ii = 0; ii < nn; ++ii) { i = ilist[ii]; if (atom->mask[i] & groupbit) { @@ -858,9 +858,9 @@ int FixQEqReaxOMP::dual_CG( double *b1, double *b2, double *x1, double *x2) { my_buf[0] = tmp1; my_buf[1] = tmp2; - + MPI_Allreduce(&my_buf, &buf, 2, MPI_DOUBLE, MPI_SUM, world); - + alpha_s = sig_new_s / buf[0]; alpha_t = sig_new_t / buf[1]; @@ -877,14 +877,14 @@ int FixQEqReaxOMP::dual_CG( double *b1, double *b2, double *x1, double *x2) int indxI = 2 * ii; x1[ii] += alpha_s * d[indxI ]; x2[ii] += alpha_t * d[indxI+1]; - + r[indxI ] -= alpha_s * q[indxI ]; r[indxI+1] -= alpha_t * q[indxI+1]; - + // pre-conditioning p[indxI ] = r[indxI ] * Hdia_inv[ii]; p[indxI+1] = r[indxI+1] * Hdia_inv[ii]; - + tmp1 += r[indxI ] * p[indxI ]; tmp2 += r[indxI+1] * p[indxI+1]; } @@ -915,7 +915,7 @@ int FixQEqReaxOMP::dual_CG( double *b1, double *b2, double *x1, double *x2) ii = ilist[jj]; if (atom->mask[ii] & groupbit) { int indxI = 2 * ii; - + d[indxI ] = p[indxI ] + beta_s * d[indxI ]; d[indxI+1] = p[indxI+1] + beta_t * d[indxI+1]; } diff --git a/src/USER-OMP/pair_reaxc_omp.cpp b/src/USER-OMP/pair_reaxc_omp.cpp index 078b9d63d4..0c16284e25 100644 --- a/src/USER-OMP/pair_reaxc_omp.cpp +++ b/src/USER-OMP/pair_reaxc_omp.cpp @@ -16,19 +16,19 @@ Hasan Metin Aktulga, Michigan State University, hma@cse.msu.edu Per-atom energy/virial added by Ray Shan (Materials Design, Inc.) - Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added + Fix reax/c/bonds and fix reax/c/species for pair_style reax/c added by Ray Shan (Materials Design) - OpenMP based threading support for pair_style reax/c/omp added - by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), + OpenMP based threading support for pair_style reax/c/omp added + by Hasan Metin Aktulga (MSU), Chris Knight (ALCF), Paul Coffman (ALCF), Kurt O'Hearn (MSU), Ray Shan (Materials Design), Wei Jiang (ALCF) - - Integration of the pair_style reax/c/omp into the User-OMP package + + Integration of the pair_style reax/c/omp into the User-OMP package by Axel Kohlmeyer (Temple U.) Please cite the related publication: - H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, - W. Jiang, "Optimizing the performance of reactive molecular dynamics + H. M. Aktulga, C. Knight, P. Coffman, K. A. O'Hearn, T. R. Shan, + W. Jiang, "Optimizing the performance of reactive molecular dynamics simulations for multi-core architectures", International Journal of High Performance Computing Applications, to appear. ------------------------------------------------------------------------- */ From f717a70638f91c0ac50bd160b7a63a8be86858dc Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 11 Jul 2017 16:16:03 -0600 Subject: [PATCH 057/293] tools/Makefile: remove remains of data2xmovie data2xmovie was removed in e110d6961a48017274256e23d15530974aec55ff --- tools/Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tools/Makefile b/tools/Makefile index 2cf46fcc23..cd3c5756ae 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -5,7 +5,7 @@ # all: - $(MAKE) binary2txt chain micelle2d data2xmovie + $(MAKE) binary2txt chain micelle2d binary2txt: binary2txt.o g++ -g binary2txt.o -o binary2txt @@ -16,14 +16,11 @@ chain: chain.o micelle2d: micelle2d.o ifort micelle2d.o -o micelle2d -data2xmovie: data2xmovie.o - g++ -g data2xmovie.o -o data2xmovie - thermo_extract: thermo_extract.o gcc -g thermo_extract.o -o thermo_extract clean: - rm binary2txt chain micelle2d data2xmovie + rm binary2txt chain micelle2d rm thermo_extract rm *.o From ddc96213255a15932fe9d1a12b8a69fc7e1d414b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 11 Jul 2017 18:30:41 -0400 Subject: [PATCH 058/293] remove absolutely last reference to xmovie --- examples/README | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/README b/examples/README index 090ed733ac..e4312e2598 100644 --- a/examples/README +++ b/examples/README @@ -37,9 +37,8 @@ produce dump snapshots of the running simulation in any of 3 formats. If you uncomment the dump command in the input script, a text dump file will be produced, which can be animated by various visualization -programs (see http://lammps.sandia.gov/viz.html) such as VMD or -AtomEye. It can also be animated using the xmovie tool described in -the Additional Tools section of the LAMMPS documentation. +programs (see http://lammps.sandia.gov/viz.html) such as Ovito, VMD, +or AtomEye. If you uncomment the dump image command in the input script, and assuming you have built LAMMPS with a JPG library, JPG snapshot images From a9ff593763c74082df4df53d268e2ddcc172a3fb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 09:48:07 -0400 Subject: [PATCH 059/293] avoid segfault when calling enforce2d before langevin data has been initialized --- src/RIGID/fix_rigid.cpp | 2 +- src/RIGID/fix_rigid_small.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/RIGID/fix_rigid.cpp b/src/RIGID/fix_rigid.cpp index d0c931a466..9d46968273 100644 --- a/src/RIGID/fix_rigid.cpp +++ b/src/RIGID/fix_rigid.cpp @@ -949,7 +949,7 @@ void FixRigid::enforce2d() angmom[ibody][1] = 0.0; omega[ibody][0] = 0.0; omega[ibody][1] = 0.0; - if (langflag) { + if (langflag && langextra) { langextra[ibody][2] = 0.0; langextra[ibody][3] = 0.0; langextra[ibody][4] = 0.0; diff --git a/src/RIGID/fix_rigid_small.cpp b/src/RIGID/fix_rigid_small.cpp index b4de4f53bb..60afeecbf0 100644 --- a/src/RIGID/fix_rigid_small.cpp +++ b/src/RIGID/fix_rigid_small.cpp @@ -786,7 +786,7 @@ void FixRigidSmall::enforce2d() b->angmom[1] = 0.0; b->omega[0] = 0.0; b->omega[1] = 0.0; - if (langflag) { + if (langflag && langextra) { langextra[ibody][2] = 0.0; langextra[ibody][3] = 0.0; langextra[ibody][4] = 0.0; From 69d97fa60cf04a6364f9714baf031337fd048151 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 11:26:16 -0400 Subject: [PATCH 060/293] fix enforce2d has to be defined after fixes with enforce2d_flag set this check currently only applies to rigid fixes and is needed so that their respective enforce2d function is called _after_ the post force functions. this is required in combination with commit a9ff593763c74082df4df53d268e2ddcc172a3fb to allow rigid fixes use the langevin option correctly for 2d systems --- src/fix_enforce2d.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/fix_enforce2d.cpp b/src/fix_enforce2d.cpp index 21a99e3c16..336fd12556 100644 --- a/src/fix_enforce2d.cpp +++ b/src/fix_enforce2d.cpp @@ -66,12 +66,21 @@ void FixEnforce2D::init() if (modify->fix[i]->enforce2d_flag) nfixlist++; if (nfixlist) { + int myindex = -1; delete [] flist; flist = new Fix*[nfixlist]; nfixlist = 0; for (int i = 0; i < modify->nfix; i++) { - if (modify->fix[i]->enforce2d_flag) - flist[nfixlist++] = modify->fix[i]; + if (modify->fix[i]->enforce2d_flag) { + if (myindex < 0) + flist[nfixlist++] = modify->fix[i]; + else { + char msg[256]; + sprintf(msg,"Fix enforce2d must be defined after fix %s",modify->fix[i]->style); + error->all(FLERR,msg); + } + } + if (modify->fix[i] == this) myindex = i; } } } From a419c7c57c52f9017ec2c0f5b8d247ac43501572 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 11:40:35 -0400 Subject: [PATCH 061/293] update src/.gitignore for fix wall*/ees sources --- src/.gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/.gitignore b/src/.gitignore index 1c7f468e6e..306b123c14 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -508,6 +508,10 @@ /fix_tune_kspace.h /fix_wall_colloid.cpp /fix_wall_colloid.h +/fix_wall_ees.cpp +/fix_wall_ees.h +/fix_wall_region_ees.cpp +/fix_wall_region_ees.h /fix_wall_gran.cpp /fix_wall_gran.h /fix_wall_gran_region.cpp From 734729b0a4d5772a4f4d0c17c11a16813fa730f3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 17:27:49 -0400 Subject: [PATCH 062/293] avoid small memory leak with USER-REAXC + USER-OMP, spotted by GCC's address sanitizer --- src/USER-REAXC/reaxc_allocate.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/USER-REAXC/reaxc_allocate.cpp b/src/USER-REAXC/reaxc_allocate.cpp index 0d9c51c878..e3fc54c504 100644 --- a/src/USER-REAXC/reaxc_allocate.cpp +++ b/src/USER-REAXC/reaxc_allocate.cpp @@ -196,11 +196,10 @@ void DeAllocate_Workspace( control_params *control, storage *workspace ) /* reductions */ #ifdef LMP_USER_OMP - if(workspace->CdDeltaReduction) sfree( workspace->CdDeltaReduction, "cddelta_reduce" ); - if(workspace->forceReduction) sfree( workspace->forceReduction, "f_reduce" ); - if(workspace->valence_angle_atom_myoffset) sfree( workspace->valence_angle_atom_myoffset, "valence_angle_atom_myoffset"); - - if (control->virial && workspace->my_ext_pressReduction) sfree( workspace->my_ext_pressReduction, "ext_press_reduce"); + if (workspace->CdDeltaReduction) sfree( workspace->CdDeltaReduction, "cddelta_reduce" ); + if (workspace->forceReduction) sfree( workspace->forceReduction, "f_reduce" ); + if (workspace->valence_angle_atom_myoffset) sfree( workspace->valence_angle_atom_myoffset, "valence_angle_atom_myoffset"); + if (workspace->my_ext_pressReduction) sfree( workspace->my_ext_pressReduction, "ext_press_reduce"); #endif } @@ -307,9 +306,7 @@ int Allocate_Workspace( reax_system *system, control_params *control, "forceReduction", comm); workspace->valence_angle_atom_myoffset = (int *) scalloc(sizeof(int), total_cap, "valence_angle_atom_myoffset", comm); - - if (control->virial) - workspace->my_ext_pressReduction = (rvec *) calloc(sizeof(rvec), control->nthreads); + workspace->my_ext_pressReduction = (rvec *) calloc(sizeof(rvec), control->nthreads); #endif return SUCCESS; From 01e848387ac85e6bc013dc233c20a01e7ea127c7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 18:00:38 -0400 Subject: [PATCH 063/293] avoid accessing uninitialized data when exiting LAMMPS early --- src/comm_brick.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/comm_brick.cpp b/src/comm_brick.cpp index d6cbed40af..3c972b8244 100644 --- a/src/comm_brick.cpp +++ b/src/comm_brick.cpp @@ -124,6 +124,7 @@ void CommBrick::init_buffers() maxrecv = BUFMIN; memory->create(buf_recv,maxrecv,"comm:buf_recv"); + nswap = 0; maxswap = 6; allocate_swap(maxswap); From c24fca61f37aa7abfa1c907fd51a1da7478a18a3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 18:14:11 -0400 Subject: [PATCH 064/293] fix possible uninitialized data access with pppm and pppm/disp --- src/KSPACE/pppm.cpp | 5 +++++ src/KSPACE/pppm_disp.cpp | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/src/KSPACE/pppm.cpp b/src/KSPACE/pppm.cpp index 05169fca1c..6add8b58b7 100644 --- a/src/KSPACE/pppm.cpp +++ b/src/KSPACE/pppm.cpp @@ -95,6 +95,11 @@ PPPM::PPPM(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg), MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); + nfft_both = 0; + nxhi_in = nxlo_in = nxhi_out = nxlo_out = 0; + nyhi_in = nylo_in = nyhi_out = nylo_out = 0; + nzhi_in = nzlo_in = nzhi_out = nzlo_out = 0; + density_brick = vdx_brick = vdy_brick = vdz_brick = NULL; density_fft = NULL; u_brick = NULL; diff --git a/src/KSPACE/pppm_disp.cpp b/src/KSPACE/pppm_disp.cpp index b31d42a815..43b2c8236a 100644 --- a/src/KSPACE/pppm_disp.cpp +++ b/src/KSPACE/pppm_disp.cpp @@ -121,6 +121,13 @@ PPPMDisp::PPPMDisp(LAMMPS *lmp, int narg, char **arg) : KSpace(lmp, narg, arg), MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); + nfft_both = nfft_both_6 = 0; + nxhi_in = nxlo_in = nxhi_out = nxlo_out = 0; + nyhi_in = nylo_in = nyhi_out = nylo_out = 0; + nzhi_in = nzlo_in = nzhi_out = nzlo_out = 0; + nxhi_in_6 = nxlo_in_6 = nxhi_out_6 = nxlo_out_6 = 0; + nyhi_in_6 = nylo_in_6 = nyhi_out_6 = nylo_out_6 = 0; + nzhi_in_6 = nzlo_in_6 = nzhi_out_6 = nzlo_out_6 = 0; csumflag = 0; B = NULL; From 6b19016deb3ef6357bb7b912e24d4d498f79fad0 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 12 Jul 2017 15:54:44 -0600 Subject: [PATCH 065/293] cmake: initial commit --- .gitignore | 8 +++++ CMakeLists.txt | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 CMakeLists.txt diff --git a/.gitignore b/.gitignore index 74e511515e..50b970249a 100644 --- a/.gitignore +++ b/.gitignore @@ -32,3 +32,11 @@ log.cite .Trashes ehthumbs.db Thumbs.db + +#cmake +/build* +/CMakeCache.txt +/CMakeFiles/ +/Makefile +/cmake_install.cmake +/lmp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..9bcf3118ae --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,84 @@ +cmake_minimum_required(VERSION 3.1) + +project(lammps) +set(SOVERSION 0) + +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) + #release comes with -O3 by default + set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) +endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) + +enable_language(CXX) + +###################################################################### +# compiler tests +# these need ot be done early (before further tests). +##################################################################### + +include(CheckCCompilerFlag) + +######################################################################## +# User input options # +######################################################################## +option(BUILD_SHARED_LIBS "Build shared libs" OFF) +include(GNUInstallDirs) + +option(ENABLE_MPI "Build MPI version" OFF) +if(ENABLE_MPI) + find_package(MPI) + include_directories(${MPI_C_INCLUDE_PATH}) + set(MPI_SOURCES) +else() + file(GLOB MPI_SOURCES src/STUBS/mpi.c) + include_directories(src/STUBS) + set(MPI_CXX_LIBRARIES) +endif() + +find_package(UnixCommands) + +option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) + +######################################################################## +# Basic system tests (standard libraries, headers, functions, types) # +######################################################################## +include(CheckIncludeFile) +foreach(HEADER math.h) + check_include_file(${HEADER} FOUND_${HEADER}) + if(NOT FOUND_${HEADER}) + message(FATAL_ERROR "Could not find needed header - ${HEADER}") + endif(NOT FOUND_${HEADER}) +endforeach(HEADER) + +set(MATH_LIBRARIES "m" CACHE STRING "math library") +mark_as_advanced( MATH_LIBRARIES ) +include(CheckLibraryExists) +foreach(FUNC sin cos) + check_library_exists(${MATH_LIBRARIES} ${FUNC} "" FOUND_${FUNC}_${MATH_LIBRARIES}) + if(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) + message(FATAL_ERROR "Could not find needed math function - ${FUNC}") + endif(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) +endforeach(FUNC) + +###################################### +# Include the following subdirectory # +###################################### + +#Do NOT go into src to not conflict with old Makefile build system +#add_subdirectory(src) + +file(GLOB LIB_SOURCES src/*.cpp) +file(GLOB LMP_SOURCES src/main.cpp) +list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) + +add_custom_target(style COMMAND ${BASH} Make.sh style WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src) +add_library(lammps ${LIB_SOURCES} ${MPI_SOURCES}) +add_dependencies(lammps style) +# better but slower +#add_custom_command(TARGET lammps PRE_BUILD COMMAND ${BASH} Make.sh style WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src) +target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${MATH_LIBRARIES}) +set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) +install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + +add_executable(lmp ${LMP_SOURCES}) +target_link_libraries(lmp lammps) +install(TARGETS lammps DESTINATION ${CMAKE_INSTALL_BINDIR}) From 0af9203fdc991af03cb77a7bbc649170d74c4088 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 12 Jul 2017 18:32:04 -0400 Subject: [PATCH 066/293] remove useless and incorrect neighbor list request in fix qeq/comb/omp --- src/USER-OMP/fix_qeq_comb_omp.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/USER-OMP/fix_qeq_comb_omp.cpp b/src/USER-OMP/fix_qeq_comb_omp.cpp index 0c69876b86..351003b668 100644 --- a/src/USER-OMP/fix_qeq_comb_omp.cpp +++ b/src/USER-OMP/fix_qeq_comb_omp.cpp @@ -70,17 +70,6 @@ void FixQEQCombOMP::init() ngroup = group->count(igroup); if (ngroup == 0) error->all(FLERR,"Fix qeq/comb group has no atoms"); - - // determine status of neighbor flag of the omp package command - int ifix = modify->find_fix("package_omp"); - int use_omp = 0; - if (ifix >=0) { - FixOMP * fix = static_cast(lmp->modify->fix[ifix]); - if (fix->get_neighbor()) use_omp = 1; - } - - int irequest = neighbor->request(this,instance_me); - neighbor->requests[irequest]->omp = use_omp; } /* ---------------------------------------------------------------------- */ From de8d417aeccdcee893ae50ccb6f47fd41bcf802e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 13 Jul 2017 10:55:13 -0400 Subject: [PATCH 067/293] fix off-by-one memory allocation bug --- src/USER-OMP/fix_nphug_omp.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/USER-OMP/fix_nphug_omp.cpp b/src/USER-OMP/fix_nphug_omp.cpp index bc3c2cdd5c..75ff393e28 100644 --- a/src/USER-OMP/fix_nphug_omp.cpp +++ b/src/USER-OMP/fix_nphug_omp.cpp @@ -157,7 +157,7 @@ FixNPHugOMP::FixNPHugOMP(LAMMPS *lmp, int narg, char **arg) : // create a new compute potential energy compute - n = strlen(id) + 3; + n = strlen(id) + 4; id_pe = new char[n]; strcpy(id_pe,id); strcat(id_pe,"_pe"); From d0cc1dfbb80ccd9e8bad183d7a4fb380e085b4c2 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Thu, 13 Jul 2017 11:19:35 -0600 Subject: [PATCH 068/293] changes to SNAP virial from Aidan --- doc/src/Section_start.txt | 51 ++++++++++++++++++++++++++++++--------- src/SNAP/pair_snap.cpp | 27 +++++++++++++-------- 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/doc/src/Section_start.txt b/doc/src/Section_start.txt index dcd320655f..b7a471c3fa 100644 --- a/doc/src/Section_start.txt +++ b/doc/src/Section_start.txt @@ -434,20 +434,39 @@ files. Note that on some large parallel machines which use "modules" for their compile/link environements, you may simply need to include the correct module in your build environment. Or the parallel machine may have a vendor-provided FFT library which the compiler has no -trouble finding. +trouble finding. See the src/MAKE/OPTIONS/Makefile.fftw file for an +example of how to specify these variables to use the FFTW3 library. -FFTW is a fast, portable library that should also work on any -platform. You can download it from +FFTW is fast, portable library that should also work on any platform +and typically be faster than KISS FFT. You can download it from "www.fftw.org"_http://www.fftw.org. Both the legacy version 2.1.X and the newer 3.X versions are supported as -DFFT_FFTW2 or -DFFT_FFTW3. -Building FFTW for your box should be as simple as ./configure; make. -Note that on some platforms FFTW2 has been pre-installed, and uses -renamed files indicating the precision it was compiled with, -e.g. sfftw.h, or dfftw.h instead of fftw.h. In this case, you can -specify an additional define variable for FFT_INC called -DFFTW_SIZE, -which will select the correct include file. In this case, for FFT_LIB -you must also manually specify the correct library, namely -lsfftw or --ldfftw. +Building FFTW for your box should be as simple as ./configure; make; +make install. The install command typically requires root privileges +(e.g. invoke it via sudo), unless you specify a local directory with +the "--prefix" option of configure. Type "./configure --help" to see +various options. + +If you wish to have FFTW support for single-precision FFTs (see below +about -DFFT_SINGLE) in addition to the default double-precision FFTs, +you will need to build FFTW a second time for single-precision. For +FFTW3, do this via: + +make clean +./configure --enable-single; make; make install :pre + +which should produce the additional library libfftw3f.a. + +For FFTW2, do this: + +make clean +./configure --enable-float --enable-type-prefix; make; make install :pre + +which should produce the additional library libsfftw.a and additional +include file sfttw.a. Note that on some platforms FFTW2 has been +pre-installed for both single- and double-precision, and may already +have these files as well as libdfftw.a and dfftw.h for double +precision. The FFT_INC variable also allows for a -DFFT_SINGLE setting that will use single-precision FFTs with PPPM, which can speed-up long-range @@ -459,6 +478,16 @@ accuracy for reduced memory use and parallel communication costs for transposing 3d FFT data. Note that single precision FFTs have only been tested with the FFTW3, FFTW2, MKL, and KISS FFT options. +When using -DFFT_SINGLE with FFTW3 or FFTW2, you need to build FFTW +with support for single-precision, as explained above. For FFTW3 you +also need to include -lfftw3f with the FFT_LIB setting, in addition to +-lfftw3. For FFTW2, you also need to specify -DFFT_SIZE with the +FFT_INC setting and -lsfftw with the FFT_LIB setting (in place of +-lfftw). Similarly, if FFTW2 has been preinstalled with an explicit +double-precision library (libdfftw.a and not the default libfftw.a), +then you can specify -DFFT_SIZE (and not -DFFT_SINGLE), and specify +-ldfftw to use double-precision FFTs. + Step 7 :h6 The 3 JPG variables allow you to specify a JPEG and/or PNG library diff --git a/src/SNAP/pair_snap.cpp b/src/SNAP/pair_snap.cpp index 492e9ad643..696f910a11 100644 --- a/src/SNAP/pair_snap.cpp +++ b/src/SNAP/pair_snap.cpp @@ -289,7 +289,7 @@ void PairSNAP::compute_regular(int eflag, int vflag) } } } - + f[i][0] += fij[0]; f[i][1] += fij[1]; f[i][2] += fij[2]; @@ -297,13 +297,17 @@ void PairSNAP::compute_regular(int eflag, int vflag) f[j][1] -= fij[1]; f[j][2] -= fij[2]; - if (evflag) - ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0, + // tally per-atom virial contribution + + if (vflag) + ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0, fij[0],fij[1],fij[2], - snaptr->rij[jj][0],snaptr->rij[jj][1], - snaptr->rij[jj][2]); + -snaptr->rij[jj][0],-snaptr->rij[jj][1], + -snaptr->rij[jj][2]); } + // tally energy contribution + if (eflag) { // evdwl = energy of atom I, sum over coeffs_k * Bi_k @@ -336,7 +340,7 @@ void PairSNAP::compute_regular(int eflag, int vflag) } } } - ev_tally_full(i,2.0*evdwl,0.0,0.0,delx,dely,delz); + ev_tally_full(i,2.0*evdwl,0.0,0.0,0.0,0.0,0.0); } } @@ -655,11 +659,14 @@ void PairSNAP::compute_optimized(int eflag, int vflag) f[j][0] -= fij[0]; f[j][1] -= fij[1]; f[j][2] -= fij[2]; - if (evflag) + + // tally per-atom virial contribution + + if (vflag) ev_tally_xyz(i,j,nlocal,newton_pair,0.0,0.0, fij[0],fij[1],fij[2], - sna[tid]->rij[jj][0],sna[tid]->rij[jj][1], - sna[tid]->rij[jj][2]); + -sna[tid]->rij[jj][0],-sna[tid]->rij[jj][1], + -sna[tid]->rij[jj][2]); } } @@ -699,7 +706,7 @@ void PairSNAP::compute_optimized(int eflag, int vflag) #if defined(_OPENMP) #pragma omp critical #endif - ev_tally_full(i,2.0*evdwl,0.0,0.0,delx,dely,delz); + ev_tally_full(i,2.0*evdwl,0.0,0.0,0.0,0.0,0.0); } } From 609c8b1e87742b539dd5ce1556d7d53b1c0af771 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 13 Jul 2017 17:32:27 -0400 Subject: [PATCH 069/293] add flag to reax/c system struct to signaling, whether OpenMP is active --- src/USER-OMP/pair_reaxc_omp.cpp | 1 + src/USER-REAXC/pair_reaxc.cpp | 2 ++ src/USER-REAXC/reaxc_types.h | 1 + 3 files changed, 4 insertions(+) diff --git a/src/USER-OMP/pair_reaxc_omp.cpp b/src/USER-OMP/pair_reaxc_omp.cpp index 0c16284e25..7ac8952b1e 100644 --- a/src/USER-OMP/pair_reaxc_omp.cpp +++ b/src/USER-OMP/pair_reaxc_omp.cpp @@ -93,6 +93,7 @@ PairReaxCOMP::PairReaxCOMP(LAMMPS *lmp) : PairReaxC(lmp), ThrOMP(lmp, THR_PAIR) suffix_flag |= Suffix::OMP; system->pair_ptr = this; + system->omp_active = 1; num_nbrs_offset = NULL; diff --git a/src/USER-REAXC/pair_reaxc.cpp b/src/USER-REAXC/pair_reaxc.cpp index bf3b2e4467..300ccbe330 100644 --- a/src/USER-REAXC/pair_reaxc.cpp +++ b/src/USER-REAXC/pair_reaxc.cpp @@ -108,6 +108,8 @@ PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp) system->my_atoms = NULL; system->pair_ptr = this; + system->omp_active = 0; + fix_reax = NULL; tmpid = NULL; tmpbo = NULL; diff --git a/src/USER-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h index 547602feb4..ac23329985 100644 --- a/src/USER-REAXC/reaxc_types.h +++ b/src/USER-REAXC/reaxc_types.h @@ -415,6 +415,7 @@ struct _reax_system int mincap; double safezone, saferzone; + int omp_active; }; typedef _reax_system reax_system; From 132cee9840515d3f076576c8f6e58ec9136753b0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 13 Jul 2017 17:33:00 -0400 Subject: [PATCH 070/293] protect warning printf()s to be only printed on rank 0 --- src/USER-REAXC/reaxc_ffield.cpp | 63 ++++++++++++++++++--------------- 1 file changed, 35 insertions(+), 28 deletions(-) diff --git a/src/USER-REAXC/reaxc_ffield.cpp b/src/USER-REAXC/reaxc_ffield.cpp index 58a347ebf7..fcface79fd 100644 --- a/src/USER-REAXC/reaxc_ffield.cpp +++ b/src/USER-REAXC/reaxc_ffield.cpp @@ -40,8 +40,10 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, int errorflag = 1; double val; MPI_Comm comm; + int me; comm = MPI_COMM_WORLD; + MPI_Comm_rank(comm, &me); s = (char*) malloc(sizeof(char)*MAX_LINE); tmp = (char**) malloc(sizeof(char*)*MAX_TOKENS); @@ -58,7 +60,8 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, /* reading the number of global parameters */ n = atoi(tmp[0]); if (n < 1) { - fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" ); + if (me == 0) + fprintf( stderr, "WARNING: number of globals in ffield file is 0!\n" ); fclose(fp); free(s); free(tmp); @@ -199,7 +202,8 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, /* Sanity check */ if (c < 3) { - fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n"); + if (me == 0) + fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n"); MPI_Abort( comm, FILE_NOT_FOUND ); } @@ -219,7 +223,8 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, /* Sanity check */ if (c > 3) { - fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n"); + if (me == 0) + fprintf(stderr, "Inconsistent ffield file (reaxc_ffield.cpp) \n"); MPI_Abort( comm, FILE_NOT_FOUND ); } @@ -230,50 +235,51 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, if( reax->sbp[i].rcore2>0.01 && reax->sbp[i].acore2>0.01 ){ // Inner-wall if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 3 ) { - if (errorflag) - fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ - "Force field parameters for element %s\n" \ - "indicate inner wall+shielding, but earlier\n" \ - "atoms indicate different vdWaals-method.\n" \ - "This may cause division-by-zero errors.\n" \ + if (errorflag && (me == 0)) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ + "indicate inner wall+shielding, but earlier\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ "Keeping vdWaals-setting for earlier atoms.\n", reax->sbp[i].name ); errorflag = 0; - } - else{ + } else{ reax->gp.vdw_type = 3; } } else { // No shielding vdWaals parameters present - if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 ) - fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ - "Force field parameters for element %s\n" \ + if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 2 ) { + if (me == 0) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ "indicate inner wall without shielding, but earlier\n" \ - "atoms indicate different vdWaals-method.\n" \ - "This may cause division-by-zero errors.\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ "Keeping vdWaals-setting for earlier atoms.\n", reax->sbp[i].name ); - else{ + } else { reax->gp.vdw_type = 2; } } } else{ // No Inner wall parameters present if( reax->sbp[i].gamma_w>0.5 ){ // Shielding vdWaals - if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 ) - fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ - "Force field parameters for element %s\n" \ + if( reax->gp.vdw_type != 0 && reax->gp.vdw_type != 1 ) { + if (me == 0) + fprintf( stderr, "Warning: inconsistent vdWaals-parameters\n" \ + "Force field parameters for element %s\n" \ "indicate shielding without inner wall, but earlier\n" \ - "atoms indicate different vdWaals-method.\n" \ - "This may cause division-by-zero errors.\n" \ + "atoms indicate different vdWaals-method.\n" \ + "This may cause division-by-zero errors.\n" \ "Keeping vdWaals-setting for earlier atoms.\n", reax->sbp[i].name ); - else{ + } else { reax->gp.vdw_type = 1; } - } - else{ - fprintf( stderr, "Error: inconsistent vdWaals-parameters\n"\ + } else { + if (me == 0) + fprintf( stderr, "Error: inconsistent vdWaals-parameters\n" \ "No shielding or inner-wall set for element %s\n", reax->sbp[i].name ); MPI_Abort( comm, INVALID_INPUT ); @@ -284,8 +290,9 @@ char Read_Force_Field( FILE *fp, reax_interaction *reax, /* Equate vval3 to valf for first-row elements (25/10/2004) */ for( i = 0; i < reax->num_atom_types; i++ ) if( reax->sbp[i].mass < 21 && - reax->sbp[i].valency_val != reax->sbp[i].valency_boc ){ - fprintf( stderr, "Warning: changed valency_val to valency_boc for %s\n", + reax->sbp[i].valency_val != reax->sbp[i].valency_boc ) { + if (me == 0) + fprintf(stderr,"Warning: changed valency_val to valency_boc for %s\n", reax->sbp[i].name ); reax->sbp[i].valency_val = reax->sbp[i].valency_boc; } From 111786e92e0ff34125d32c6d60d01959c6ab4e03 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 13 Jul 2017 17:33:56 -0400 Subject: [PATCH 071/293] avoid trying to free NULL pointers and reallocate storage for OpenMP, when not using OpenMP styles --- src/USER-REAXC/reaxc_allocate.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/USER-REAXC/reaxc_allocate.cpp b/src/USER-REAXC/reaxc_allocate.cpp index e3fc54c504..1b8274916e 100644 --- a/src/USER-REAXC/reaxc_allocate.cpp +++ b/src/USER-REAXC/reaxc_allocate.cpp @@ -367,8 +367,9 @@ static int Reallocate_Bonds_List( reax_system *system, reax_list *bonds, *total_bonds = (int)(MAX( *total_bonds * safezone, mincap*MIN_BONDS )); #ifdef LMP_USER_OMP - for (i = 0; i < bonds->num_intrs; ++i) - sfree(bonds->select.bond_list[i].bo_data.CdboReduction, "CdboReduction"); + if (system->omp_active) + for (i = 0; i < bonds->num_intrs; ++i) + sfree(bonds->select.bond_list[i].bo_data.CdboReduction, "CdboReduction"); #endif Delete_List( bonds, comm ); @@ -384,9 +385,10 @@ static int Reallocate_Bonds_List( reax_system *system, reax_list *bonds, int nthreads = 1; #endif - for (i = 0; i < bonds->num_intrs; ++i) - bonds->select.bond_list[i].bo_data.CdboReduction = - (double*) smalloc(sizeof(double)*nthreads, "CdboReduction", comm); + if (system->omp_active) + for (i = 0; i < bonds->num_intrs; ++i) + bonds->select.bond_list[i].bo_data.CdboReduction = + (double*) smalloc(sizeof(double)*nthreads, "CdboReduction", comm); #endif return SUCCESS; From 32ca58bdf23ca8b8e39035d168d3e56d54eb99e6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 13 Jul 2017 17:34:30 -0400 Subject: [PATCH 072/293] whitespace cleanup --- src/USER-OMP/reaxc_init_md_omp.cpp | 4 +-- src/USER-REAXC/reaxc_types.h | 41 +++++++++++++++--------------- 2 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/USER-OMP/reaxc_init_md_omp.cpp b/src/USER-OMP/reaxc_init_md_omp.cpp index 79fec8b268..c0e4a45eaa 100644 --- a/src/USER-OMP/reaxc_init_md_omp.cpp +++ b/src/USER-OMP/reaxc_init_md_omp.cpp @@ -39,7 +39,7 @@ #include "reaxc_tool_box.h" #include "reaxc_vector.h" -// Functions definedd in reaxc_init_md.cpp +// Functions defined in reaxc_init_md.cpp extern int Init_MPI_Datatypes(reax_system*, storage*, mpi_datatypes*, MPI_Comm, char*); extern int Init_System(reax_system*, control_params*, char*); extern int Init_Simulation_Data(reax_system*, control_params*, simulation_data*, char*); @@ -104,7 +104,7 @@ int Init_ListsOMP( reax_system *system, control_params *control, /* 3bodies list */ cap_3body = (int)(MAX( num_3body*safezone, MIN_3BODIES )); if( !Make_List( bond_cap, cap_3body, TYP_THREE_BODY, - *lists+THREE_BODIES, comm ) ){ + *lists+THREE_BODIES, comm ) ){ fprintf( stderr, "Problem in initializing angles list. Terminating!\n" ); MPI_Abort( comm, INSUFFICIENT_MEMORY ); diff --git a/src/USER-REAXC/reaxc_types.h b/src/USER-REAXC/reaxc_types.h index ac23329985..14078feb0c 100644 --- a/src/USER-REAXC/reaxc_types.h +++ b/src/USER-REAXC/reaxc_types.h @@ -44,26 +44,26 @@ #ifdef OMP_TIMING // pkcoff timing fields enum { - COMPUTEINDEX=0, - COMPUTEWLINDEX, - COMPUTEBFINDEX, - COMPUTEQEQINDEX, - COMPUTENBFINDEX, - COMPUTEIFINDEX, - COMPUTETFINDEX, - COMPUTEBOINDEX, - COMPUTEBONDSINDEX, - COMPUTEATOMENERGYINDEX, - COMPUTEVALENCEANGLESBOINDEX, - COMPUTETORSIONANGLESBOINDEX, - COMPUTEHBONDSINDEX, - COMPUTECG1INDEX, - COMPUTECG2INDEX, - COMPUTECGCOMPUTEINDEX, - COMPUTECALCQINDEX, - COMPUTEINITMVINDEX, - COMPUTEMVCOMPINDEX, - LASTTIMINGINDEX + COMPUTEINDEX=0, + COMPUTEWLINDEX, + COMPUTEBFINDEX, + COMPUTEQEQINDEX, + COMPUTENBFINDEX, + COMPUTEIFINDEX, + COMPUTETFINDEX, + COMPUTEBOINDEX, + COMPUTEBONDSINDEX, + COMPUTEATOMENERGYINDEX, + COMPUTEVALENCEANGLESBOINDEX, + COMPUTETORSIONANGLESBOINDEX, + COMPUTEHBONDSINDEX, + COMPUTECG1INDEX, + COMPUTECG2INDEX, + COMPUTECGCOMPUTEINDEX, + COMPUTECALCQINDEX, + COMPUTEINITMVINDEX, + COMPUTEMVCOMPINDEX, + LASTTIMINGINDEX }; extern double ompTimingData[LASTTIMINGINDEX]; @@ -745,7 +745,6 @@ typedef struct double *CdDeltaReduction; int *valence_angle_atom_myoffset; - reallocate_data realloc; } storage; From bfb449cec9788dfa649ab7bbb17964364768c3be Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 13 Jul 2017 22:54:48 -0600 Subject: [PATCH 073/293] cmake: furhter improvments * Add support for one package * Add support for JPEG as external package * Use pre-generated style header * TODO write a script to generate them --- CMakeLists.txt => cmake/CMakeLists.txt | 39 ++++++++--- cmake/Headers/package.h.cmakein | 1 + cmake/Headers/style_angle.h | 3 + cmake/Headers/style_atom.h | 9 +++ cmake/Headers/style_body.h | 1 + cmake/Headers/style_bond.h | 3 + cmake/Headers/style_command.h | 23 +++++++ cmake/Headers/style_compute.h | 66 +++++++++++++++++++ cmake/Headers/style_dihedral.h | 3 + cmake/Headers/style_dump.h | 9 +++ cmake/Headers/style_fix.h | 89 ++++++++++++++++++++++++++ cmake/Headers/style_improper.h | 3 + cmake/Headers/style_integrate.h | 3 + cmake/Headers/style_kspace.h | 1 + cmake/Headers/style_minimize.h | 6 ++ cmake/Headers/style_nbin.h | 2 + cmake/Headers/style_npair.h | 36 +++++++++++ cmake/Headers/style_nstencil.h | 21 ++++++ cmake/Headers/style_ntopo.h | 13 ++++ cmake/Headers/style_pair.h | 47 ++++++++++++++ cmake/Headers/style_reader.h | 3 + cmake/Headers/style_region.h | 9 +++ 22 files changed, 381 insertions(+), 9 deletions(-) rename CMakeLists.txt => cmake/CMakeLists.txt (71%) create mode 100644 cmake/Headers/package.h.cmakein create mode 100644 cmake/Headers/style_angle.h create mode 100644 cmake/Headers/style_atom.h create mode 100644 cmake/Headers/style_body.h create mode 100644 cmake/Headers/style_bond.h create mode 100644 cmake/Headers/style_command.h create mode 100644 cmake/Headers/style_compute.h create mode 100644 cmake/Headers/style_dihedral.h create mode 100644 cmake/Headers/style_dump.h create mode 100644 cmake/Headers/style_fix.h create mode 100644 cmake/Headers/style_improper.h create mode 100644 cmake/Headers/style_integrate.h create mode 100644 cmake/Headers/style_kspace.h create mode 100644 cmake/Headers/style_minimize.h create mode 100644 cmake/Headers/style_nbin.h create mode 100644 cmake/Headers/style_npair.h create mode 100644 cmake/Headers/style_nstencil.h create mode 100644 cmake/Headers/style_ntopo.h create mode 100644 cmake/Headers/style_pair.h create mode 100644 cmake/Headers/style_reader.h create mode 100644 cmake/Headers/style_region.h diff --git a/CMakeLists.txt b/cmake/CMakeLists.txt similarity index 71% rename from CMakeLists.txt rename to cmake/CMakeLists.txt index 9bcf3118ae..4dd54ddf90 100644 --- a/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -29,8 +29,8 @@ if(ENABLE_MPI) include_directories(${MPI_C_INCLUDE_PATH}) set(MPI_SOURCES) else() - file(GLOB MPI_SOURCES src/STUBS/mpi.c) - include_directories(src/STUBS) + file(GLOB MPI_SOURCES ${CMAKE_SOURCE_DIR}/../src/STUBS/mpi.c) + include_directories(${CMAKE_SOURCE_DIR}/../src/STUBS) set(MPI_CXX_LIBRARIES) endif() @@ -38,6 +38,19 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) +set(PACKAGES ASPHERE) +foreach(PKG ${PACKAGES}) + option(ENABLE_${PKG} "Build ${PKG} Package" OFF) +endforeach() + +find_package(JPEG) +if(JPEG_FOUND) + add_definitions(-DLAMMPS_JPEG) + include_directories(${JPEG_INCLUDE_DIR}) +else() + set(JPEG_LIBRARIES) +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## @@ -66,16 +79,24 @@ endforeach(FUNC) #Do NOT go into src to not conflict with old Makefile build system #add_subdirectory(src) -file(GLOB LIB_SOURCES src/*.cpp) -file(GLOB LMP_SOURCES src/main.cpp) +file(GLOB LIB_SOURCES ${CMAKE_SOURCE_DIR}/../src/*.cpp) +file(GLOB LMP_SOURCES ${CMAKE_SOURCE_DIR}/../src/main.cpp) list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) -add_custom_target(style COMMAND ${BASH} Make.sh style WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src) +foreach(PKG ${PACKAGES}) + if(ENABLE_${PKG}) + file(GLOB ${PKG}_SOURCES ${CMAKE_SOURCE_DIR}/../src/${PKG}/*.cpp) + list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) + include_directories(${CMAKE_SOURCE_DIR}/../src/${PKG}) + endif() +endforeach() +include_directories(${CMAKE_SOURCE_DIR}/../src) +include_directories(${CMAKE_SOURCE_DIR}/Headers) +configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR}/cmake/package.h) +include_directories(${CMAKE_BINARY_DIR}/cmake) + add_library(lammps ${LIB_SOURCES} ${MPI_SOURCES}) -add_dependencies(lammps style) -# better but slower -#add_custom_command(TARGET lammps PRE_BUILD COMMAND ${BASH} Make.sh style WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/src) -target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${MATH_LIBRARIES}) +target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${JPEG_LIBRARIES} ${MATH_LIBRARIES}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/cmake/Headers/package.h.cmakein b/cmake/Headers/package.h.cmakein new file mode 100644 index 0000000000..f582f6f7d5 --- /dev/null +++ b/cmake/Headers/package.h.cmakein @@ -0,0 +1 @@ +#cmakedefine ENABLE_ASPHERE diff --git a/cmake/Headers/style_angle.h b/cmake/Headers/style_angle.h new file mode 100644 index 0000000000..8b395b557f --- /dev/null +++ b/cmake/Headers/style_angle.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "angle_hybrid.h" +#include "angle_zero.h" diff --git a/cmake/Headers/style_atom.h b/cmake/Headers/style_atom.h new file mode 100644 index 0000000000..ec4e5d7d20 --- /dev/null +++ b/cmake/Headers/style_atom.h @@ -0,0 +1,9 @@ +#include "package.h" +#include "atom_vec_atomic.h" +#include "atom_vec_body.h" +#include "atom_vec_charge.h" +#include "atom_vec_ellipsoid.h" +#include "atom_vec_hybrid.h" +#include "atom_vec_line.h" +#include "atom_vec_sphere.h" +#include "atom_vec_tri.h" diff --git a/cmake/Headers/style_body.h b/cmake/Headers/style_body.h new file mode 100644 index 0000000000..b2b5c1f82e --- /dev/null +++ b/cmake/Headers/style_body.h @@ -0,0 +1 @@ +#include "package.h" diff --git a/cmake/Headers/style_bond.h b/cmake/Headers/style_bond.h new file mode 100644 index 0000000000..d18a31ca91 --- /dev/null +++ b/cmake/Headers/style_bond.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "bond_hybrid.h" +#include "bond_zero.h" diff --git a/cmake/Headers/style_command.h b/cmake/Headers/style_command.h new file mode 100644 index 0000000000..08f90396f7 --- /dev/null +++ b/cmake/Headers/style_command.h @@ -0,0 +1,23 @@ +#include "balance.h" +#include "change_box.h" +#include "create_atoms.h" +#include "create_bonds.h" +#include "create_box.h" +#include "delete_atoms.h" +#include "delete_bonds.h" +#include "displace_atoms.h" +#include "info.h" +#include "minimize.h" +#include "read_data.h" +#include "read_dump.h" +#include "read_restart.h" +#include "replicate.h" +#include "rerun.h" +#include "run.h" +#include "set.h" +#include "velocity.h" +#include "write_coeff.h" +#include "write_data.h" +#include "write_dump.h" +#include "package.h" +#include "write_restart.h" diff --git a/cmake/Headers/style_compute.h b/cmake/Headers/style_compute.h new file mode 100644 index 0000000000..bfcd053ed6 --- /dev/null +++ b/cmake/Headers/style_compute.h @@ -0,0 +1,66 @@ +#include "package.h" +#include "compute_angle.h" +#include "compute_angle_local.h" +#include "compute_angmom_chunk.h" +#include "compute_bond.h" +#include "compute_bond_local.h" +#include "compute_centro_atom.h" +#include "compute_chunk_atom.h" +#include "compute_cluster_atom.h" +#include "compute_cna_atom.h" +#include "compute_com.h" +#include "compute_com_chunk.h" +#include "compute_contact_atom.h" +#include "compute_coord_atom.h" +#include "compute_dihedral.h" +#include "compute_dihedral_local.h" +#include "compute_dipole_chunk.h" +#include "compute_displace_atom.h" +#ifdef ENABLE_ASPHERE +#include "compute_erotate_asphere.h" +#endif +#include "compute_erotate_sphere.h" +#include "compute_erotate_sphere_atom.h" +#include "compute_global_atom.h" +#include "compute_group_group.h" +#include "compute_gyration.h" +#include "compute_gyration_chunk.h" +#include "compute_heat_flux.h" +#include "compute_hexorder_atom.h" +#include "compute_improper.h" +#include "compute_improper_local.h" +#include "compute_inertia_chunk.h" +#include "compute_ke.h" +#include "compute_ke_atom.h" +#include "compute_msd.h" +#include "compute_msd_chunk.h" +#include "compute_omega_chunk.h" +#include "compute_orientorder_atom.h" +#include "compute_pair.h" +#include "compute_pair_local.h" +#include "compute_pe.h" +#include "compute_pe_atom.h" +#include "compute_pressure.h" +#include "compute_property_atom.h" +#include "compute_property_chunk.h" +#include "compute_property_local.h" +#include "compute_rdf.h" +#include "compute_reduce.h" +#include "compute_reduce_region.h" +#include "compute_slice.h" +#include "compute_stress_atom.h" +#include "compute_temp.h" +#ifdef ENABLE_ASPHERE +#include "compute_temp_asphere.h" +#endif +#include "compute_temp_chunk.h" +#include "compute_temp_com.h" +#include "compute_temp_deform.h" +#include "compute_temp_partial.h" +#include "compute_temp_profile.h" +#include "compute_temp_ramp.h" +#include "compute_temp_region.h" +#include "compute_temp_sphere.h" +#include "compute_torque_chunk.h" +#include "compute_vacf.h" +#include "compute_vcm_chunk.h" diff --git a/cmake/Headers/style_dihedral.h b/cmake/Headers/style_dihedral.h new file mode 100644 index 0000000000..26cb4a815a --- /dev/null +++ b/cmake/Headers/style_dihedral.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "dihedral_hybrid.h" +#include "dihedral_zero.h" diff --git a/cmake/Headers/style_dump.h b/cmake/Headers/style_dump.h new file mode 100644 index 0000000000..bc8477a6bf --- /dev/null +++ b/cmake/Headers/style_dump.h @@ -0,0 +1,9 @@ +#include "package.h" +#include "dump_atom.h" +#include "dump_cfg.h" +#include "dump_custom.h" +#include "dump_dcd.h" +#include "dump_image.h" +#include "dump_local.h" +#include "dump_movie.h" +#include "dump_xyz.h" diff --git a/cmake/Headers/style_fix.h b/cmake/Headers/style_fix.h new file mode 100644 index 0000000000..5d142e086b --- /dev/null +++ b/cmake/Headers/style_fix.h @@ -0,0 +1,89 @@ +#include "package.h" +#include "fix_adapt.h" +#include "fix_addforce.h" +#include "fix_ave_atom.h" +#include "fix_ave_chunk.h" +#include "fix_ave_correlate.h" +#include "fix_ave_histo.h" +#include "fix_ave_histo_weight.h" +#include "fix_ave_time.h" +#include "fix_aveforce.h" +#include "fix_balance.h" +#include "fix_box_relax.h" +#include "fix_controller.h" +#include "fix_deform.h" +#include "fix_deprecated.h" +#include "fix_drag.h" +#include "fix_dt_reset.h" +#include "fix_enforce2d.h" +#include "fix_external.h" +#include "fix_gravity.h" +#include "fix_group.h" +#include "fix_halt.h" +#include "fix_heat.h" +#include "fix_indent.h" +#include "fix_langevin.h" +#include "fix_lineforce.h" +#include "fix_minimize.h" +#include "fix_momentum.h" +#include "fix_move.h" +#include "fix_nph.h" +#ifdef ENABLE_ASPHERE +#include "fix_nph_asphere.h" +#endif +#include "fix_nph_sphere.h" +#include "fix_npt.h" +#ifdef ENABLE_ASPHERE +#include "fix_npt_asphere.h" +#endif +#include "fix_npt_sphere.h" +#include "fix_nve.h" +#ifdef ENABLE_ASPHERE +#include "fix_nve_asphere.h" +#include "fix_nve_asphere_noforce.h" +#endif +#include "fix_nve_limit.h" +#ifdef ENABLE_ASPHERE +#include "fix_nve_line.h" +#endif +#include "fix_nve_noforce.h" +#include "fix_nve_sphere.h" +#ifdef ENABLE_ASPHERE +#include "fix_nve_tri.h" +#endif +#include "fix_nvt.h" +#ifdef ENABLE_ASPHERE +#include "fix_nvt_asphere.h" +#endif +#include "fix_nvt_sllod.h" +#include "fix_nvt_sphere.h" +#include "fix_planeforce.h" +#include "fix_press_berendsen.h" +#include "fix_print.h" +#include "fix_property_atom.h" +#include "fix_read_restart.h" +#include "fix_recenter.h" +#include "fix_respa.h" +#include "fix_restrain.h" +#include "fix_setforce.h" +#include "fix_shear_history.h" +#include "fix_spring.h" +#include "fix_spring_chunk.h" +#include "fix_spring_rg.h" +#include "fix_spring_self.h" +#include "fix_store.h" +#include "fix_store_force.h" +#include "fix_store_state.h" +#include "fix_temp_berendsen.h" +#include "fix_temp_csld.h" +#include "fix_temp_csvr.h" +#include "fix_temp_rescale.h" +#include "fix_tmd.h" +#include "fix_vector.h" +#include "fix_viscous.h" +#include "fix_wall_harmonic.h" +#include "fix_wall_lj1043.h" +#include "fix_wall_lj126.h" +#include "fix_wall_lj93.h" +#include "fix_wall_reflect.h" +#include "fix_wall_region.h" diff --git a/cmake/Headers/style_improper.h b/cmake/Headers/style_improper.h new file mode 100644 index 0000000000..3de3047d73 --- /dev/null +++ b/cmake/Headers/style_improper.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "improper_hybrid.h" +#include "improper_zero.h" diff --git a/cmake/Headers/style_integrate.h b/cmake/Headers/style_integrate.h new file mode 100644 index 0000000000..0a2fd00cf7 --- /dev/null +++ b/cmake/Headers/style_integrate.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "respa.h" +#include "verlet.h" diff --git a/cmake/Headers/style_kspace.h b/cmake/Headers/style_kspace.h new file mode 100644 index 0000000000..b2b5c1f82e --- /dev/null +++ b/cmake/Headers/style_kspace.h @@ -0,0 +1 @@ +#include "package.h" diff --git a/cmake/Headers/style_minimize.h b/cmake/Headers/style_minimize.h new file mode 100644 index 0000000000..35d9188e8d --- /dev/null +++ b/cmake/Headers/style_minimize.h @@ -0,0 +1,6 @@ +#include "package.h" +#include "min_cg.h" +#include "min_fire.h" +#include "min_hftn.h" +#include "min_quickmin.h" +#include "min_sd.h" diff --git a/cmake/Headers/style_nbin.h b/cmake/Headers/style_nbin.h new file mode 100644 index 0000000000..f0d52b05bc --- /dev/null +++ b/cmake/Headers/style_nbin.h @@ -0,0 +1,2 @@ +#include "package.h" +#include "nbin_standard.h" diff --git a/cmake/Headers/style_npair.h b/cmake/Headers/style_npair.h new file mode 100644 index 0000000000..bd403ebeeb --- /dev/null +++ b/cmake/Headers/style_npair.h @@ -0,0 +1,36 @@ +#include "package.h" +#include "npair_copy.h" +#include "npair_full_bin.h" +#include "npair_full_bin_atomonly.h" +#include "npair_full_bin_ghost.h" +#include "npair_full_multi.h" +#include "npair_full_nsq.h" +#include "npair_full_nsq_ghost.h" +#include "npair_half_bin_atomonly_newton.h" +#include "npair_half_bin_newtoff.h" +#include "npair_half_bin_newtoff_ghost.h" +#include "npair_half_bin_newton.h" +#include "npair_half_bin_newton_tri.h" +#include "npair_half_multi_newtoff.h" +#include "npair_half_multi_newton.h" +#include "npair_half_multi_newton_tri.h" +#include "npair_half_nsq_newtoff.h" +#include "npair_half_nsq_newtoff_ghost.h" +#include "npair_half_nsq_newton.h" +#include "npair_half_respa_bin_newtoff.h" +#include "npair_half_respa_bin_newton.h" +#include "npair_half_respa_bin_newton_tri.h" +#include "npair_half_respa_nsq_newtoff.h" +#include "npair_half_respa_nsq_newton.h" +#include "npair_half_size_bin_newtoff.h" +#include "npair_half_size_bin_newton.h" +#include "npair_half_size_bin_newton_tri.h" +#include "npair_half_size_nsq_newtoff.h" +#include "npair_half_size_nsq_newton.h" +#include "npair_halffull_newtoff.h" +#include "npair_halffull_newton.h" +#include "npair_skip.h" +#include "npair_skip_respa.h" +#include "npair_skip_size.h" +#include "npair_skip_size_off2on.h" +#include "npair_skip_size_off2on_oneside.h" diff --git a/cmake/Headers/style_nstencil.h b/cmake/Headers/style_nstencil.h new file mode 100644 index 0000000000..d28e4b23b1 --- /dev/null +++ b/cmake/Headers/style_nstencil.h @@ -0,0 +1,21 @@ +#include "package.h" +#include "nstencil_full_bin_2d.h" +#include "nstencil_full_bin_3d.h" +#include "nstencil_full_ghost_bin_2d.h" +#include "nstencil_full_ghost_bin_3d.h" +#include "nstencil_full_multi_2d.h" +#include "nstencil_full_multi_3d.h" +#include "nstencil_half_bin_2d_newtoff.h" +#include "nstencil_half_bin_2d_newton.h" +#include "nstencil_half_bin_2d_newton_tri.h" +#include "nstencil_half_bin_3d_newtoff.h" +#include "nstencil_half_bin_3d_newton.h" +#include "nstencil_half_bin_3d_newton_tri.h" +#include "nstencil_half_ghost_bin_2d_newtoff.h" +#include "nstencil_half_ghost_bin_3d_newtoff.h" +#include "nstencil_half_multi_2d_newtoff.h" +#include "nstencil_half_multi_2d_newton.h" +#include "nstencil_half_multi_2d_newton_tri.h" +#include "nstencil_half_multi_3d_newtoff.h" +#include "nstencil_half_multi_3d_newton.h" +#include "nstencil_half_multi_3d_newton_tri.h" diff --git a/cmake/Headers/style_ntopo.h b/cmake/Headers/style_ntopo.h new file mode 100644 index 0000000000..130b10200f --- /dev/null +++ b/cmake/Headers/style_ntopo.h @@ -0,0 +1,13 @@ +#include "package.h" +#include "ntopo_angle_all.h" +#include "ntopo_angle_partial.h" +#include "ntopo_angle_template.h" +#include "ntopo_bond_all.h" +#include "ntopo_bond_partial.h" +#include "ntopo_bond_template.h" +#include "ntopo_dihedral_all.h" +#include "ntopo_dihedral_partial.h" +#include "ntopo_dihedral_template.h" +#include "ntopo_improper_all.h" +#include "ntopo_improper_partial.h" +#include "ntopo_improper_template.h" diff --git a/cmake/Headers/style_pair.h b/cmake/Headers/style_pair.h new file mode 100644 index 0000000000..b2ecef6a2a --- /dev/null +++ b/cmake/Headers/style_pair.h @@ -0,0 +1,47 @@ +#include "package.h" +#include "pair_beck.h" +#include "pair_born.h" +#include "pair_born_coul_dsf.h" +#include "pair_born_coul_wolf.h" +#include "pair_buck.h" +#include "pair_buck_coul_cut.h" +#include "pair_coul_cut.h" +#include "pair_coul_debye.h" +#include "pair_coul_dsf.h" +#include "pair_coul_streitz.h" +#include "pair_coul_wolf.h" +#include "pair_dpd.h" +#include "pair_dpd_tstat.h" +#include "pair_gauss.h" +#ifdef ENABLE_ASPHERE +#include "pair_gayberne.h" +#endif +#include "pair_hybrid.h" +#include "pair_hybrid_overlay.h" +#ifdef ENABLE_ASPHERE +#include "pair_line_lj.h" +#endif +#include "pair_lj96_cut.h" +#include "pair_lj_cubic.h" +#include "pair_lj_cut.h" +#include "pair_lj_cut_coul_cut.h" +#include "pair_lj_cut_coul_debye.h" +#include "pair_lj_cut_coul_dsf.h" +#include "pair_lj_expand.h" +#include "pair_lj_gromacs.h" +#include "pair_lj_gromacs_coul_gromacs.h" +#include "pair_lj_smooth.h" +#include "pair_lj_smooth_linear.h" +#include "pair_mie_cut.h" +#include "pair_morse.h" +#ifdef ENABLE_ASPHERE +#include "pair_resquared.h" +#endif +#include "pair_soft.h" +#include "pair_table.h" +#ifdef ENABLE_ASPHERE +#include "pair_tri_lj.h" +#endif +#include "pair_yukawa.h" +#include "pair_zbl.h" +#include "pair_zero.h" diff --git a/cmake/Headers/style_reader.h b/cmake/Headers/style_reader.h new file mode 100644 index 0000000000..0b8145e13d --- /dev/null +++ b/cmake/Headers/style_reader.h @@ -0,0 +1,3 @@ +#include "package.h" +#include "reader_native.h" +#include "reader_xyz.h" diff --git a/cmake/Headers/style_region.h b/cmake/Headers/style_region.h new file mode 100644 index 0000000000..dc467b2a3d --- /dev/null +++ b/cmake/Headers/style_region.h @@ -0,0 +1,9 @@ +#include "package.h" +#include "region_block.h" +#include "region_cone.h" +#include "region_cylinder.h" +#include "region_intersect.h" +#include "region_plane.h" +#include "region_prism.h" +#include "region_sphere.h" +#include "region_union.h" From 7f1789a0c44c77a3eee1bf05cf0ea66a04a1fe0b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 13 Jul 2017 23:27:55 -0600 Subject: [PATCH 074/293] cmake: add support for REAX and hence Fortran --- cmake/CMakeLists.txt | 9 ++++++++- cmake/Headers/package.h.cmakein | 1 + cmake/Headers/style_command.h | 2 +- cmake/Headers/style_fix.h | 3 +++ cmake/Headers/style_pair.h | 3 +++ 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4dd54ddf90..cd3db7b7e9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -38,7 +38,7 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) -set(PACKAGES ASPHERE) +set(PACKAGES ASPHERE REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -90,6 +90,13 @@ foreach(PKG ${PACKAGES}) include_directories(${CMAKE_SOURCE_DIR}/../src/${PKG}) endif() endforeach() + +if(ENABLE_REAX) + enable_language(Fortran) + file(GLOB REAX_SOURCES ${CMAKE_SOURCE_DIR}/../lib/reax/*.F) + list(APPEND LIB_SOURCES ${REAX_SOURCES}) + include_directories(${CMAKE_SOURCE_DIR}/../lib/reax) +endif() include_directories(${CMAKE_SOURCE_DIR}/../src) include_directories(${CMAKE_SOURCE_DIR}/Headers) configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR}/cmake/package.h) diff --git a/cmake/Headers/package.h.cmakein b/cmake/Headers/package.h.cmakein index f582f6f7d5..9c7ff403a4 100644 --- a/cmake/Headers/package.h.cmakein +++ b/cmake/Headers/package.h.cmakein @@ -1 +1,2 @@ #cmakedefine ENABLE_ASPHERE +#cmakedefine ENABLE_REAX diff --git a/cmake/Headers/style_command.h b/cmake/Headers/style_command.h index 08f90396f7..d795f4ba0a 100644 --- a/cmake/Headers/style_command.h +++ b/cmake/Headers/style_command.h @@ -1,3 +1,4 @@ +#include "package.h" #include "balance.h" #include "change_box.h" #include "create_atoms.h" @@ -19,5 +20,4 @@ #include "write_coeff.h" #include "write_data.h" #include "write_dump.h" -#include "package.h" #include "write_restart.h" diff --git a/cmake/Headers/style_fix.h b/cmake/Headers/style_fix.h index 5d142e086b..146616124d 100644 --- a/cmake/Headers/style_fix.h +++ b/cmake/Headers/style_fix.h @@ -62,6 +62,9 @@ #include "fix_print.h" #include "fix_property_atom.h" #include "fix_read_restart.h" +#ifdef ENABLE_REAX +#include "fix_reax_bonds.h" +#endif #include "fix_recenter.h" #include "fix_respa.h" #include "fix_restrain.h" diff --git a/cmake/Headers/style_pair.h b/cmake/Headers/style_pair.h index b2ecef6a2a..067e2cdb23 100644 --- a/cmake/Headers/style_pair.h +++ b/cmake/Headers/style_pair.h @@ -34,6 +34,9 @@ #include "pair_lj_smooth_linear.h" #include "pair_mie_cut.h" #include "pair_morse.h" +#ifdef ENABLE_REAX +#include "pair_reax.h" +#endif #ifdef ENABLE_ASPHERE #include "pair_resquared.h" #endif From a86b0d4c1b3e9a98aa47907401b72cd49a1637b2 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 03:53:07 -0500 Subject: [PATCH 075/293] Add PNG library detection to CMakeList.txt --- cmake/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index cd3db7b7e9..4692372cec 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -51,6 +51,14 @@ else() set(JPEG_LIBRARIES) endif() +find_package(PNG) +if(PNG_FOUND) + include_directories(${PNG_INCLUDE_DIR}) + add_definitions(-DLAMMPS_PNG) +else(PNG_FOUND) + set(PNG_LIBRARIES) +endif(PNG_FOUND) + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## @@ -103,7 +111,7 @@ configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR} include_directories(${CMAKE_BINARY_DIR}/cmake) add_library(lammps ${LIB_SOURCES} ${MPI_SOURCES}) -target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${JPEG_LIBRARIES} ${MATH_LIBRARIES}) +target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${MATH_LIBRARIES}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) From fdd3d802f06e24c5f0501f6ff9e12d25f1f78198 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 04:00:38 -0500 Subject: [PATCH 076/293] Clean up CMakeList.txt by introducing LAMMPS_SOURCE_DIR variable --- cmake/CMakeLists.txt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4692372cec..14ec5059f1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.1) project(lammps) set(SOVERSION 0) +set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) #release comes with -O3 by default @@ -29,8 +30,8 @@ if(ENABLE_MPI) include_directories(${MPI_C_INCLUDE_PATH}) set(MPI_SOURCES) else() - file(GLOB MPI_SOURCES ${CMAKE_SOURCE_DIR}/../src/STUBS/mpi.c) - include_directories(${CMAKE_SOURCE_DIR}/../src/STUBS) + file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) + include_directories(${LAMMPS_SOURCE_DIR}/STUBS) set(MPI_CXX_LIBRARIES) endif() @@ -87,15 +88,15 @@ endforeach(FUNC) #Do NOT go into src to not conflict with old Makefile build system #add_subdirectory(src) -file(GLOB LIB_SOURCES ${CMAKE_SOURCE_DIR}/../src/*.cpp) -file(GLOB LMP_SOURCES ${CMAKE_SOURCE_DIR}/../src/main.cpp) +file(GLOB LIB_SOURCES ${LAMMPS_SOURCE_DIR}/*.cpp) +file(GLOB LMP_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) foreach(PKG ${PACKAGES}) if(ENABLE_${PKG}) - file(GLOB ${PKG}_SOURCES ${CMAKE_SOURCE_DIR}/../src/${PKG}/*.cpp) + file(GLOB ${PKG}_SOURCES ${LAMMPS_SOURCE_DIR}/${PKG}/*.cpp) list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) - include_directories(${CMAKE_SOURCE_DIR}/../src/${PKG}) + include_directories(${LAMMPS_SOURCE_DIR}/${PKG}) endif() endforeach() @@ -105,7 +106,7 @@ if(ENABLE_REAX) list(APPEND LIB_SOURCES ${REAX_SOURCES}) include_directories(${CMAKE_SOURCE_DIR}/../lib/reax) endif() -include_directories(${CMAKE_SOURCE_DIR}/../src) +include_directories(${LAMMPS_SOURCE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/Headers) configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR}/cmake/package.h) include_directories(${CMAKE_BINARY_DIR}/cmake) From a566419ca6916f047f9b855437c1729a98638822 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 04:36:52 -0500 Subject: [PATCH 077/293] Add LAMMPS_LIB_SOURCE_DIR variable in CMakeLists.txt --- cmake/CMakeLists.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 14ec5059f1..f69d84e852 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -3,6 +3,7 @@ cmake_minimum_required(VERSION 3.1) project(lammps) set(SOVERSION 0) set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) +set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) #release comes with -O3 by default @@ -102,9 +103,9 @@ endforeach() if(ENABLE_REAX) enable_language(Fortran) - file(GLOB REAX_SOURCES ${CMAKE_SOURCE_DIR}/../lib/reax/*.F) + file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) list(APPEND LIB_SOURCES ${REAX_SOURCES}) - include_directories(${CMAKE_SOURCE_DIR}/../lib/reax) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) endif() include_directories(${LAMMPS_SOURCE_DIR}) include_directories(${CMAKE_SOURCE_DIR}/Headers) From 8a1db83b73060e93606c0bfb92afbe1b47d48bde Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 10:31:51 -0400 Subject: [PATCH 078/293] silence static code analysis warning --- src/MANYBODY/pair_airebo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 67e1e5262a..77b43f8d0e 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -4157,7 +4157,7 @@ def output_matrix(n, k, A): void PairAIREBO::Sptricubic_patch_adjust(double * dl, double wid, double lo, char dir) { - int rowOuterL = 16, rowInnerL = 1, colL; + int rowOuterL = 16, rowInnerL = 1, colL = 4; if (dir == 'R') { rowOuterL = 4; colL = 16; From e5405cdb04770283b1de48edf7167bb99e57ac2d Mon Sep 17 00:00:00 2001 From: Markus Hoehnerbach Date: Fri, 14 Jul 2017 17:57:25 +0200 Subject: [PATCH 079/293] AIREBO: Add doc about OpenKIM issue --- src/MANYBODY/pair_airebo.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/MANYBODY/pair_airebo.cpp b/src/MANYBODY/pair_airebo.cpp index 67e1e5262a..d05558eb19 100644 --- a/src/MANYBODY/pair_airebo.cpp +++ b/src/MANYBODY/pair_airebo.cpp @@ -2105,6 +2105,14 @@ accordingly zero. This function should be kept in sync with bondorder(), i.e. changes there probably also need to be performed here. +The OpenKIM Fortran implementation chooses option (1) instead, which +means that the internal values computed by the two codes are not +directly comparable. +Note that of 7/2017 the OpenKIM code contains an issue where the it +assumes dt2dij[] to be zero (since it is a r_ij derivative). This is +incorrect since dt2dij is not a derivative of the scalar distance r_ij, +but of the vector r_ij. + */ double PairAIREBO::bondorderLJ(int i, int j, double rij_mod[3], double rijmag_mod, From 4d4c03a1e4f5af2619f02c528b92bdeb2672cf55 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 12:33:40 -0400 Subject: [PATCH 080/293] restore gaussian flow example that was lost. tweak input to make it usable for comparing --- examples/USER/flow_gauss/README | 45 + examples/USER/flow_gauss/in.GD | 262 +++++ examples/USER/flow_gauss/log.6Jul17.GD.g++.1 | 909 ++++++++++++++++++ examples/USER/flow_gauss/log.6Jul17.GD.g++.4 | 909 ++++++++++++++++++ examples/USER/flow_gauss/output-files/GD.out | 41 + .../USER/flow_gauss/output-files/Vy_profile | 134 +++ .../USER/flow_gauss/output-files/x_profiles | 36 + 7 files changed, 2336 insertions(+) create mode 100644 examples/USER/flow_gauss/README create mode 100644 examples/USER/flow_gauss/in.GD create mode 100644 examples/USER/flow_gauss/log.6Jul17.GD.g++.1 create mode 100644 examples/USER/flow_gauss/log.6Jul17.GD.g++.4 create mode 100644 examples/USER/flow_gauss/output-files/GD.out create mode 100644 examples/USER/flow_gauss/output-files/Vy_profile create mode 100644 examples/USER/flow_gauss/output-files/x_profiles diff --git a/examples/USER/flow_gauss/README b/examples/USER/flow_gauss/README new file mode 100644 index 0000000000..ef7cc82d96 --- /dev/null +++ b/examples/USER/flow_gauss/README @@ -0,0 +1,45 @@ +The input script in.GD is an example simulation using Gaussian dynamics (GD). +The simulation is of a simple 2d Lennard-Jones fluid flowing through a pipe. +For details see online LAMMPS documentation and +Strong and Eaves, J. Phys. Chem. Lett. 7(10) 2016, p. 1907. + +Note that the run times and box size are chosen to allow a fast example run. +They are not adequate for a real simulation. + +The script has the following parts: +1) initialize variables + These can be modified to customize the simulation. Note that if the + pipe dimensions L or d are changed, the geometry should be checked + by visualizing the coordinates in all.init.lammpstrj. + +2) create box + +3) set up potential + +4) create atoms + +5) set up profile-unbiased thermostat (PUT) + see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 + By default, this uses boxes which contain on average 8 molecules. + +6) equilibrate without GD + +7) initialize the center-of-mass velocity and run to achieve steady-state + The system is initialized with a uniform velocity profile, which + relaxes over the course of the simulation. + +8) collect data + The data is output in several files: + GD.out contains the force that GD applies, and the flux in the x- and + y- directions. The output Jx should be equal to the value of + J set in section 1, which is 0.1 by default. + x_profiles contains the velocity, density, and pressure profiles in + the x-direction. The pressure profile is given by + (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a + slice. The pressure profile is computed with IK1, see + Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627. + Note that to compare with the pump method, or to + compute a pressure drop, you must correct this pressure + profile as described in Strong 2016 above. + Vy_profile is the velocity profile inside the pipe along the + y-direction, u_x(y). diff --git a/examples/USER/flow_gauss/in.GD b/examples/USER/flow_gauss/in.GD new file mode 100644 index 0000000000..bcff4d4c57 --- /dev/null +++ b/examples/USER/flow_gauss/in.GD @@ -0,0 +1,262 @@ +#LAMMPS input script +#in.GD +#see README for details + +############################################################################### +#initialize variables +clear + +#frequency for outputting info (timesteps) +variable dump_rate equal 50 +variable thermo_rate equal 10 + +#equilibration time (timesteps) +variable equil equal 1000 + +#stabilization time (timesteps to reach steady-state) +variable stabil equal 1000 + +#data collection time (timesteps) +variable run equal 2000 + +#length of pipe +variable L equal 30 + +#width of pipe +variable d equal 20 + +#flux (mass/sigma*tau) +variable J equal 0.1 + +#simulation box dimensions +variable Lx equal 100 +variable Ly equal 40 + +#bulk fluid density +variable dens equal 0.8 + +#lattice spacing for wall atoms +variable aWall equal 1.0 #1.7472 + +#timestep +variable ts equal 0.001 + +#temperature +variable T equal 2.0 + +#thermostat damping constant +variable tdamp equal ${ts}*100 + +units lj +dimension 2 +atom_style atomic + + +############################################################################### +#create box + +#create lattice with the spacing aWall +variable rhoWall equal ${aWall}^(-2) +lattice sq ${rhoWall} + +#modify input dimensions to be multiples of aWall +variable L1 equal round($L/${aWall})*${aWall} +variable d1 equal round($d/${aWall})*${aWall} +variable Ly1 equal round(${Ly}/${aWall})*${aWall} +variable Lx1 equal round(${Lx}/${aWall})*${aWall} + +#create simulation box +variable lx2 equal ${Lx1}/2 +variable ly2 equal ${Ly1}/2 +region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box +create_box 2 simbox + +##################################################################### +#set up potential + +mass 1 1.0 #fluid atoms +mass 2 1.0 #wall atoms + +pair_style lj/cut 2.5 +pair_modify shift yes +pair_coeff 1 1 1.0 1.0 2.5 +pair_coeff 1 2 1.0 1.0 1.12246 +pair_coeff 2 2 0.0 0.0 + +neigh_modify exclude type 2 2 + +timestep ${ts} + +##################################################################### +#create atoms + +#create wall atoms everywhere +create_atoms 2 box + +#define region which is "walled off" +variable dhalf equal ${d1}/2 +variable Lhalf equal ${L1}/2 +region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 & + units box +region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 & + units box +region outsidewall union 2 walltop wallbot side out + +#remove wall atoms outside wall region +group outside region outsidewall +delete_atoms group outside + +#remove wall atoms that aren't on edge of wall region +variable x1 equal ${Lhalf}-${aWall} +variable y1 equal ${dhalf}+${aWall} +region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box +region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box +region insideWall union 2 insideTop insideBot +group insideWall region insideWall +delete_atoms group insideWall + +#define new lattice, to give correct fluid density +#y lattice const must be a multiple of aWall +variable atrue equal ${dens}^(-1/2) +variable ay equal round(${atrue}/${aWall})*${aWall} + +#choose x lattice const to give correct density +variable ax equal (${ay}*${dens})^(-1) + +#change Lx to be multiple of ax +variable Lx1 equal round(${Lx}/${ax})*${ax} +variable lx2 equal ${Lx1}/2 +change_box all x final -${lx2} ${lx2} units box + +#define new lattice +lattice custom ${dens} & + a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 & + basis 0.0 0.0 0.0 + +#fill in rest of box with bulk particles +variable delta equal 0.001 +variable Ldelt equal ${Lhalf}+${delta} +variable dDelt equal ${dhalf}-${delta} +region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box +region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box +region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 & + units box + +region bulk union 3 left pipe right +create_atoms 1 region bulk + +group bulk type 1 +group wall type 2 + +#remove atoms that are too close to wall +delete_atoms overlap 0.9 bulk wall + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes +neigh_modify exclude group wall wall + +velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom + +##################################################################### +#set up PUT +#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 + +#average number of particles per box, Evans and Morriss used 2.0 +variable NperBox equal 8.0 + +#calculate box sizes +variable boxSide equal sqrt(${NperBox}/${dens}) +variable nX equal round(lx/${boxSide}) +variable nY equal round(ly/${boxSide}) +variable dX equal lx/${nX} +variable dY equal ly/${nY} + +#temperature of fluid (excluding wall) +compute myT bulk temp + +#profile-unbiased temperature of fluid +compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} + +#thermo setup +thermo ${thermo_rate} +thermo_style custom step c_myT c_myTp etotal press + +#dump initial configuration +# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz +# dump 56 wall custom 1 wall.init.lammpstrj id type x y z +# dump_modify 55 sort id +# dump_modify 56 sort id +run 0 +# undump 55 +# undump 56 + +##################################################################### +#equilibrate without GD + +fix nvt bulk nvt temp $T $T ${tdamp} +fix_modify nvt temp myTp +fix 2 bulk enforce2d + +run ${equil} + +##################################################################### +#initialize the COM velocity and run to achieve steady-state + +#calculate velocity to add: V=J/rho_total +variable Vadd equal $J*lx*ly/count(bulk) + +#first remove any COM velocity, then add back the streaming velocity +velocity bulk zero linear +velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no + +fix GD bulk flow/gauss 1 0 0 #energy yes +#fix_modify GD energy yes + +run ${stabil} + +##################################################################### +#collect data + +#print the applied force and total flux to ensure conservation of Jx +variable Fapp equal f_GD[1] +compute vxBulk bulk reduce sum vx +compute vyBulk bulk reduce sum vy +variable invVol equal 1.0/(lx*ly) +variable jx equal c_vxBulk*${invVol} +variable jy equal c_vyBulk*${invVol} +variable curr_step equal step +variable p_Fapp format Fapp %.3f +variable p_jx format jx %.5g +variable p_jy format jy %.5g +fix print_vCOM all print ${dump_rate} & + "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no & + title "timestep Fapp Jx Jy" + +#compute IK1 pressure profile +#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627 +#use profile-unbiased temperature to remove the streaming velocity +#from the kinetic part of the pressure +compute spa bulk stress/atom myTp + +#for the pressure profile, use the same grid as the PUT +compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box + +#output pressure profile and other profiles +#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where +#V is the volume of a slice +fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX & + vx density/mass c_spa[1] c_spa[2] & + file x_profiles ave running overwrite + +#compute velocity profile across the pipe with a finer grid +variable dYnew equal ${dY}/10 +compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box & + region pipe +fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY & + vx file Vy_profile ave running overwrite + +#full trajectory +# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z +# dump_modify 7 sort id + +run ${run} diff --git a/examples/USER/flow_gauss/log.6Jul17.GD.g++.1 b/examples/USER/flow_gauss/log.6Jul17.GD.g++.1 new file mode 100644 index 0000000000..bb9167f490 --- /dev/null +++ b/examples/USER/flow_gauss/log.6Jul17.GD.g++.1 @@ -0,0 +1,909 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +#LAMMPS input script +#in.GD +#see README for details + +############################################################################### +#initialize variables +clear + using 1 OpenMP thread(s) per MPI task + +#frequency for outputting info (timesteps) +variable dump_rate equal 50 +variable thermo_rate equal 10 + +#equilibration time (timesteps) +variable equil equal 1000 + +#stabilization time (timesteps to reach steady-state) +variable stabil equal 1000 + +#data collection time (timesteps) +variable run equal 2000 + +#length of pipe +variable L equal 30 + +#width of pipe +variable d equal 20 + +#flux (mass/sigma*tau) +variable J equal 0.1 + +#simulation box dimensions +variable Lx equal 100 +variable Ly equal 40 + +#bulk fluid density +variable dens equal 0.8 + +#lattice spacing for wall atoms +variable aWall equal 1.0 #1.7472 + +#timestep +variable ts equal 0.001 + +#temperature +variable T equal 2.0 + +#thermostat damping constant +variable tdamp equal ${ts}*100 +variable tdamp equal 0.001*100 + +units lj +dimension 2 +atom_style atomic + + +############################################################################### +#create box + +#create lattice with the spacing aWall +variable rhoWall equal ${aWall}^(-2) +variable rhoWall equal 1^(-2) +lattice sq ${rhoWall} +lattice sq 1 +Lattice spacing in x,y,z = 1 1 1 + +#modify input dimensions to be multiples of aWall +variable L1 equal round($L/${aWall})*${aWall} +variable L1 equal round(30/${aWall})*${aWall} +variable L1 equal round(30/1)*${aWall} +variable L1 equal round(30/1)*1 +variable d1 equal round($d/${aWall})*${aWall} +variable d1 equal round(20/${aWall})*${aWall} +variable d1 equal round(20/1)*${aWall} +variable d1 equal round(20/1)*1 +variable Ly1 equal round(${Ly}/${aWall})*${aWall} +variable Ly1 equal round(40/${aWall})*${aWall} +variable Ly1 equal round(40/1)*${aWall} +variable Ly1 equal round(40/1)*1 +variable Lx1 equal round(${Lx}/${aWall})*${aWall} +variable Lx1 equal round(100/${aWall})*${aWall} +variable Lx1 equal round(100/1)*${aWall} +variable Lx1 equal round(100/1)*1 + +#create simulation box +variable lx2 equal ${Lx1}/2 +variable lx2 equal 100/2 +variable ly2 equal ${Ly1}/2 +variable ly2 equal 40/2 +region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 ${lx2} -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 50 -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 50 -20 ${ly2} 0 0.1 units box +region simbox block -50 50 -20 20 0 0.1 units box +create_box 2 simbox +Created orthogonal box = (-50 -20 0) to (50 20 0.1) + 1 by 1 by 1 MPI processor grid + +##################################################################### +#set up potential + +mass 1 1.0 #fluid atoms +mass 2 1.0 #wall atoms + +pair_style lj/cut 2.5 +pair_modify shift yes +pair_coeff 1 1 1.0 1.0 2.5 +pair_coeff 1 2 1.0 1.0 1.12246 +pair_coeff 2 2 0.0 0.0 + +neigh_modify exclude type 2 2 + +timestep ${ts} +timestep 0.001 + +##################################################################### +#create atoms + +#create wall atoms everywhere +create_atoms 2 box +Created 4000 atoms + +#define region which is "walled off" +variable dhalf equal ${d1}/2 +variable dhalf equal 20/2 +variable Lhalf equal ${L1}/2 +variable Lhalf equal 30/2 +region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 15 ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 15 10 EDGE -0.1 0.1 units box +region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 15 EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 15 EDGE -10 -0.1 0.1 units box +region outsidewall union 2 walltop wallbot side out + +#remove wall atoms outside wall region +group outside region outsidewall +3349 atoms in group outside +delete_atoms group outside +Deleted 3349 atoms, new total = 651 + +#remove wall atoms that aren't on edge of wall region +variable x1 equal ${Lhalf}-${aWall} +variable x1 equal 15-${aWall} +variable x1 equal 15-1 +variable y1 equal ${dhalf}+${aWall} +variable y1 equal 10+${aWall} +variable y1 equal 10+1 +region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 ${x1} ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 14 ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 14 11 EDGE -0.1 0.1 units box +region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 ${x1} EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 14 EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 14 EDGE -11 -0.1 0.1 units box +region insideWall union 2 insideTop insideBot +group insideWall region insideWall +551 atoms in group insideWall +delete_atoms group insideWall +Deleted 551 atoms, new total = 100 + +#define new lattice, to give correct fluid density +#y lattice const must be a multiple of aWall +variable atrue equal ${dens}^(-1/2) +variable atrue equal 0.8^(-1/2) +variable ay equal round(${atrue}/${aWall})*${aWall} +variable ay equal round(1.11803398874989/${aWall})*${aWall} +variable ay equal round(1.11803398874989/1)*${aWall} +variable ay equal round(1.11803398874989/1)*1 + +#choose x lattice const to give correct density +variable ax equal (${ay}*${dens})^(-1) +variable ax equal (1*${dens})^(-1) +variable ax equal (1*0.8)^(-1) + +#change Lx to be multiple of ax +variable Lx1 equal round(${Lx}/${ax})*${ax} +variable Lx1 equal round(100/${ax})*${ax} +variable Lx1 equal round(100/1.25)*${ax} +variable Lx1 equal round(100/1.25)*1.25 +variable lx2 equal ${Lx1}/2 +variable lx2 equal 100/2 +change_box all x final -${lx2} ${lx2} units box +change_box all x final -50 ${lx2} units box +change_box all x final -50 50 units box + orthogonal box = (-50 -20 0) to (50 20 0.1) + +#define new lattice +lattice custom ${dens} a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 1 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +Lattice spacing in x,y,z = 1.25 1 1 + +#fill in rest of box with bulk particles +variable delta equal 0.001 +variable Ldelt equal ${Lhalf}+${delta} +variable Ldelt equal 15+${delta} +variable Ldelt equal 15+0.001 +variable dDelt equal ${dhalf}-${delta} +variable dDelt equal 10-${delta} +variable dDelt equal 10-0.001 +region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box +region left block EDGE -15.001 EDGE EDGE -0.1 0.1 units box +region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box +region right block 15.001 EDGE EDGE EDGE -0.1 0.1 units box +region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -9.999 ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -9.999 9.999 -0.1 0.1 units box + +region bulk union 3 left pipe right +create_atoms 1 region bulk +Created 2675 atoms + +group bulk type 1 +2675 atoms in group bulk +group wall type 2 +100 atoms in group wall + +#remove atoms that are too close to wall +delete_atoms overlap 0.9 bulk wall +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 2.8 + ghost atom cutoff = 2.8 + binsize = 1.4, bins = 72 29 1 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) command delete_atoms, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/2d + bin: standard + (2) pair lj/cut, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/2d/newton + bin: standard +Deleted 0 atoms, new total = 2775 + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes +neigh_modify exclude group wall wall + +velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom +velocity bulk create 2 78915 dist gaussian rot yes mom yes loop geom + +##################################################################### +#set up PUT +#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 + +#average number of particles per box, Evans and Morriss used 2.0 +variable NperBox equal 8.0 + +#calculate box sizes +variable boxSide equal sqrt(${NperBox}/${dens}) +variable boxSide equal sqrt(8/${dens}) +variable boxSide equal sqrt(8/0.8) +variable nX equal round(lx/${boxSide}) +variable nX equal round(lx/3.16227766016838) +variable nY equal round(ly/${boxSide}) +variable nY equal round(ly/3.16227766016838) +variable dX equal lx/${nX} +variable dX equal lx/32 +variable dY equal ly/${nY} +variable dY equal ly/13 + +#temperature of fluid (excluding wall) +compute myT bulk temp + +#profile-unbiased temperature of fluid +compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} +compute myTp bulk temp/profile 1 1 0 xy 32 ${nY} +compute myTp bulk temp/profile 1 1 0 xy 32 13 + +#thermo setup +thermo ${thermo_rate} +thermo 10 +thermo_style custom step c_myT c_myTp etotal press + +#dump initial configuration +# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz +# dump 56 wall custom 1 wall.init.lammpstrj id type x y z +# dump_modify 55 sort id +# dump_modify 56 sort id +run 0 +WARNING: No fixes defined, atoms won't move (../verlet.cpp:55) +Neighbor list info ... + update every 1 steps, delay 0 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 2.8 + ghost atom cutoff = 2.8 + binsize = 1.4, bins = 72 29 1 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/2d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 3.103 | 3.103 | 3.103 Mbytes +Step c_myT c_myTp TotEng Press + 0 2 2.0555109 0.77892922 7.3417096 +Loop time of 9.53674e-07 on 1 procs for 0 steps with 2775 atoms + +314.6% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0 | 0 | 0 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0 | 0 | 0 | 0.0 | 0.00 +Output | 0 | 0 | 0 | 0.0 | 0.00 +Modify | 0 | 0 | 0 | 0.0 | 0.00 +Other | | 9.537e-07 | | |100.00 + +Nlocal: 2775 ave 2775 max 2775 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 510 ave 510 max 510 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 26406 ave 26406 max 26406 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 26406 +Ave neighs/atom = 9.51568 +Neighbor list builds = 0 +Dangerous builds = 0 +# undump 55 +# undump 56 + +##################################################################### +#equilibrate without GD + +fix nvt bulk nvt temp $T $T ${tdamp} +fix nvt bulk nvt temp 2 $T ${tdamp} +fix nvt bulk nvt temp 2 2 ${tdamp} +fix nvt bulk nvt temp 2 2 0.1 +fix_modify nvt temp myTp +WARNING: Temperature for fix modify is not for group all (../fix_nh.cpp:1395) +fix 2 bulk enforce2d + +run ${equil} +run 1000 +Per MPI rank memory allocation (min/avg/max) = 3.166 | 3.166 | 3.166 Mbytes +Step c_myT c_myTp TotEng Press + 0 2 2.0555109 0.77892922 7.3417096 + 10 1.9173594 1.9390034 0.77876976 7.6702228 + 20 1.7033394 1.6974676 0.77977799 8.5614784 + 30 1.5026161 1.4723993 0.78456655 9.4308258 + 40 1.4880481 1.4591602 0.79486693 9.6134304 + 50 1.6192437 1.6150635 0.81109069 9.2592835 + 60 1.7404087 1.7583444 0.82955456 8.952392 + 70 1.7757591 1.8006606 0.8452778 8.9717917 + 80 1.7573847 1.7813629 0.85769389 9.1936368 + 90 1.7491183 1.7726908 0.86882429 9.3712357 + 100 1.7798944 1.8079583 0.88029084 9.3871755 + 110 1.8440582 1.8793133 0.89259397 9.2582848 + 120 1.9191606 1.9673434 0.90533438 9.0680574 + 130 1.9883299 2.0484299 0.91755461 8.88117 + 140 2.0463366 2.1111872 0.92818114 8.7184178 + 150 2.0953769 2.167849 0.93639789 8.5713408 + 160 2.1442147 2.2216228 0.94145082 8.4082835 + 170 2.1797848 2.2631458 0.94246877 8.2767903 + 180 2.1863476 2.2700986 0.93873326 8.2311689 + 190 2.1832866 2.2710551 0.93003012 8.1959062 + 200 2.1937154 2.2868403 0.91642537 8.0842007 + 210 2.2022708 2.2915142 0.89824533 7.9575312 + 220 2.1884715 2.2770564 0.87677613 7.9000591 + 230 2.1671124 2.2496063 0.85409501 7.8673156 + 240 2.1560417 2.2379998 0.83167878 7.8003228 + 250 2.1421449 2.2240624 0.81004723 7.7491508 + 260 2.1172164 2.1971044 0.78931978 7.7457415 + 270 2.0856847 2.1672998 0.76956352 7.7719788 + 280 2.0670685 2.1449303 0.75073364 7.7524614 + 290 2.0639481 2.1428374 0.73258016 7.6727716 + 300 2.055776 2.1361719 0.7147669 7.6095248 + 310 2.038425 2.1209353 0.69722853 7.5797085 + 320 2.0203023 2.1066031 0.68006634 7.5521081 + 330 2.0118478 2.1039797 0.66330302 7.4877535 + 340 2.0159442 2.1096258 0.64673694 7.3761703 + 350 2.0166408 2.1075061 0.63020017 7.2788 + 360 2.0059407 2.0806316 0.61387618 7.2263941 + 370 1.9964281 2.0642074 0.59814148 7.1728041 + 380 1.9918446 2.0567527 0.58303017 7.101597 + 390 1.992835 2.0548138 0.56852431 7.0084774 + 400 2.0012934 2.0615016 0.55438401 6.8865948 + 410 2.0084291 2.073418 0.54034073 6.7697478 + 420 2.007464 2.0786717 0.52617041 6.6849032 + 430 1.9983712 2.0704366 0.51188183 6.6323103 + 440 1.9884651 2.0588515 0.49765394 6.5868356 + 450 1.982221 2.0467396 0.4837102 6.5311681 + 460 1.9738673 2.031238 0.47021649 6.4882783 + 470 1.9574246 2.0060447 0.45740021 6.4814923 + 480 1.9361065 1.9734507 0.44557947 6.4995199 + 490 1.9251024 1.9562469 0.43506067 6.4858343 + 500 1.9279545 1.9572145 0.42577835 6.4274765 + 510 1.9267504 1.9570246 0.41755013 6.3927027 + 520 1.9093405 1.9393872 0.41031829 6.4281888 + 530 1.8820555 1.9060756 0.40432569 6.5099401 + 540 1.86537 1.8912682 0.3999087 6.55843 + 550 1.8694252 1.9043192 0.39717519 6.5337875 + 560 1.8835224 1.9294105 0.39589322 6.4760141 + 570 1.8898719 1.9462433 0.39573596 6.4520041 + 580 1.8887698 1.9472764 0.39649878 6.4602989 + 590 1.8945125 1.9550624 0.39810844 6.4470226 + 600 1.9106571 1.9735939 0.40045321 6.3971026 + 610 1.9273243 1.98509 0.40330026 6.3474421 + 620 1.9351802 1.9888986 0.4064498 6.3340566 + 630 1.9337889 1.9846794 0.40981479 6.3610556 + 640 1.9257018 1.9757153 0.4134641 6.4184721 + 650 1.9204429 1.9718256 0.41750942 6.4679594 + 660 1.9220449 1.9701963 0.42202455 6.4919724 + 670 1.9230578 1.9707406 0.4270412 6.5178484 + 680 1.9204554 1.9740485 0.43255127 6.5572507 + 690 1.9201811 1.9762854 0.43847123 6.5869126 + 700 1.9271511 1.9867455 0.44474356 6.5882669 + 710 1.9418851 2.0042477 0.45120727 6.558573 + 720 1.9544547 2.0186724 0.4576061 6.5338329 + 730 1.9687971 2.0326169 0.46367507 6.4988775 + 740 1.9830308 2.0466267 0.46920367 6.4618136 + 750 1.9936981 2.0526606 0.47397868 6.4367349 + 760 2.0008431 2.0535449 0.47786748 6.4249001 + 770 1.9982133 2.0483219 0.48085757 6.4504786 + 780 1.9841544 2.0311693 0.48306488 6.5200512 + 790 1.9683122 2.0158738 0.48475632 6.5959263 + 800 1.9604618 2.003224 0.48619405 6.6392559 + 810 1.9629155 2.0075077 0.48756075 6.6406486 + 820 1.9683056 2.0110554 0.48883443 6.6269424 + 830 1.975409 2.0189161 0.48995399 6.6030215 + 840 1.9897264 2.035016 0.4907852 6.5485575 + 850 2.0094338 2.0555358 0.49104505 6.4719926 + 860 2.0217589 2.0643603 0.49040437 6.4233305 + 870 2.0147718 2.0641627 0.48866908 6.4491964 + 880 1.9883859 2.0324092 0.48592007 6.5488061 + 890 1.9625853 2.0028776 0.48263002 6.6452734 + 900 1.9520401 1.9889124 0.47925524 6.6808078 + 910 1.9559583 1.9952984 0.47597346 6.6573059 + 920 1.9657244 2.0083503 0.47268726 6.6073704 + 930 1.969288 2.0152339 0.4692054 6.5780416 + 940 1.9652206 2.0116384 0.4654438 6.5769812 + 950 1.9567495 1.9960693 0.46147541 6.5942022 + 960 1.9418452 1.980858 0.45753557 6.6369454 + 970 1.9247196 1.9585585 0.45390337 6.6888821 + 980 1.9128262 1.9481721 0.45090045 6.7198221 + 990 1.9167211 1.9451096 0.44869731 6.6912394 + 1000 1.935529 1.9662384 0.44728238 6.6079829 +Loop time of 1.307 on 1 procs for 1000 steps with 2775 atoms + +Performance: 66105.601 tau/day, 765.111 timesteps/s +98.7% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.7676 | 0.7676 | 0.7676 | 0.0 | 58.73 +Neigh | 0.088947 | 0.088947 | 0.088947 | 0.0 | 6.81 +Comm | 0.0094135 | 0.0094135 | 0.0094135 | 0.0 | 0.72 +Output | 0.019547 | 0.019547 | 0.019547 | 0.0 | 1.50 +Modify | 0.39755 | 0.39755 | 0.39755 | 0.0 | 30.42 +Other | | 0.02394 | | | 1.83 + +Nlocal: 2775 ave 2775 max 2775 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 527 ave 527 max 527 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 24332 ave 24332 max 24332 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 24332 +Ave neighs/atom = 8.76829 +Neighbor list builds = 38 +Dangerous builds = 0 + +##################################################################### +#initialize the COM velocity and run to achieve steady-state + +#calculate velocity to add: V=J/rho_total +variable Vadd equal $J*lx*ly/count(bulk) +variable Vadd equal 0.1*lx*ly/count(bulk) + +#first remove any COM velocity, then add back the streaming velocity +velocity bulk zero linear +velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no +velocity bulk set 0.149532710280374 0.0 0.0 units box sum yes mom no + +fix GD bulk flow/gauss 1 0 0 #energy yes +#fix_modify GD energy yes + +run ${stabil} +run 1000 +Per MPI rank memory allocation (min/avg/max) = 3.166 | 3.166 | 3.166 Mbytes +Step c_myT c_myTp TotEng Press + 1000 1.9466974 1.9662384 0.45804438 6.615449 + 1010 1.9605467 1.9815754 0.45717241 6.5545496 + 1020 1.9560139 1.9823875 0.45660431 6.5672421 + 1030 1.9348326 1.9691606 0.45633148 6.6463667 + 1040 1.9167809 1.9449522 0.45657707 6.7139486 + 1050 1.9193541 1.943342 0.45767968 6.7014054 + 1060 1.9410751 1.9720491 0.45967742 6.6150379 + 1070 1.9658493 1.9964883 0.46221539 6.5178418 + 1080 1.9767205 2.0074304 0.46491236 6.4768594 + 1090 1.9714544 2.0003054 0.46759126 6.5026957 + 1100 1.9647035 1.9927455 0.4703109 6.5400181 + 1110 1.9657667 1.9959656 0.47317481 6.5519094 + 1120 1.9706062 1.9980802 0.476185 6.5512675 + 1130 1.9747655 2.0062292 0.47932281 6.554091 + 1140 1.9761245 2.0075076 0.48248327 6.5670381 + 1150 1.9744197 2.0073027 0.48562483 6.5914441 + 1160 1.9722698 2.0046687 0.48874207 6.6165575 + 1170 1.9692145 2.0013845 0.49187442 6.6438115 + 1180 1.9665609 1.9970724 0.49508053 6.6693821 + 1190 1.9625031 1.9908427 0.49843816 6.7002606 + 1200 1.960528 1.993084 0.50203044 6.7237076 + 1210 1.9649156 1.9981485 0.50587066 6.7217755 + 1220 1.9788059 2.0134511 0.50987442 6.6833452 + 1230 1.9952283 2.0343101 0.51379781 6.6340278 + 1240 2.0039391 2.0494196 0.51730872 6.6129751 + 1250 2.0019006 2.0526773 0.52014603 6.6320217 + 1260 1.9974025 2.0528914 0.52221385 6.6601786 + 1270 1.9953949 2.0561121 0.5234754 6.6796142 + 1280 1.9893864 2.0470375 0.5238632 6.7140134 + 1290 1.9694951 2.019253 0.5235093 6.798442 + 1300 1.9473901 1.9965919 0.52280384 6.8863369 + 1310 1.9511151 2.006161 0.52203882 6.8700917 + 1320 1.979341 2.0388959 0.52106938 6.7529595 + 1330 2.0073235 2.0720045 0.51935291 6.6297731 + 1340 2.0202482 2.0841419 0.51624273 6.55803 + 1350 2.0177489 2.0669046 0.51142591 6.5401753 + 1360 2.0069274 2.04717 0.50505824 6.5506533 + 1370 1.994854 2.0311383 0.49743042 6.5633001 + 1380 1.9793176 2.0077184 0.48890503 6.5859072 + 1390 1.9580907 1.9839831 0.48004316 6.6288992 + 1400 1.9415542 1.9594192 0.47143599 6.6534105 + 1410 1.9405188 1.9591825 0.46353105 6.620549 + 1420 1.9504784 1.9730647 0.45640199 6.5471784 + 1430 1.9594158 1.9819854 0.44995052 6.4802874 + 1440 1.9615108 1.9863792 0.44406411 6.44391 + 1450 1.9544127 1.9806249 0.43873409 6.4484818 + 1460 1.9384927 1.9614953 0.43408605 6.4905259 + 1470 1.9214711 1.9425515 0.43035972 6.5390434 + 1480 1.9170761 1.9300809 0.42775046 6.5409502 + 1490 1.9242904 1.9385731 0.42631007 6.5005057 + 1500 1.9307133 1.9446119 0.4258836 6.4660754 + 1510 1.9303576 1.9435389 0.42633976 6.4616415 + 1520 1.9248382 1.9408306 0.42765441 6.4832059 + 1530 1.9120794 1.9278123 0.42986958 6.5380951 + 1540 1.899122 1.9125029 0.4331459 6.5987181 + 1550 1.9030956 1.9187821 0.43765067 6.6012019 + 1560 1.9182961 1.9453782 0.44330842 6.5674222 + 1570 1.9272863 1.9613129 0.44971962 6.5619794 + 1580 1.931679 1.9698134 0.45643436 6.5780809 + 1590 1.9336692 1.9728684 0.46314752 6.6035675 + 1600 1.938895 1.9823104 0.46964519 6.6138411 + 1610 1.9510838 1.9937914 0.47568807 6.5916989 + 1620 1.9685387 2.0087314 0.48102339 6.5424432 + 1630 1.9894416 2.0295715 0.48539861 6.4757743 + 1640 1.9982699 2.0426949 0.48860411 6.4512418 + 1650 1.9901677 2.0363837 0.49062424 6.4879985 + 1660 1.9814216 2.0291326 0.49172203 6.5248034 + 1670 1.9812111 2.0293629 0.49218297 6.5253876 + 1680 1.9903906 2.0408376 0.49211747 6.4852787 + 1690 2.0015983 2.0538843 0.4914581 6.4325081 + 1700 2.009727 2.0503407 0.49011163 6.3878577 + 1710 2.0167822 2.0531002 0.4881688 6.3477054 + 1720 2.0189021 2.0445033 0.48564798 6.3273063 + 1730 2.0129713 2.0354734 0.48270666 6.3385541 + 1740 2.0048763 2.0199836 0.47950943 6.3587586 + 1750 1.9994843 2.0085942 0.47624908 6.3694119 + 1760 1.9940025 2.0072098 0.47305283 6.3816295 + 1770 1.9817431 1.9974066 0.46994486 6.4224295 + 1780 1.965171 1.9805421 0.4670779 6.4832371 + 1790 1.9474078 1.9662605 0.46466823 6.5516524 + 1800 1.9286009 1.9507751 0.46292015 6.6263366 + 1810 1.9168087 1.9437961 0.46199899 6.6759834 + 1820 1.9107555 1.9306323 0.46204129 6.7029857 + 1830 1.9135569 1.930819 0.46316484 6.6949737 + 1840 1.9345342 1.9553413 0.46532704 6.6178988 + 1850 1.9630349 1.9929548 0.46822932 6.5137866 + 1860 1.9820746 2.0188839 0.47135068 6.4489028 + 1870 1.9834959 2.0217145 0.47427805 6.4552721 + 1880 1.9731564 2.0120293 0.47692755 6.5100251 + 1890 1.9653605 2.0070624 0.47943307 6.5594235 + 1900 1.9630631 2.0095488 0.48192185 6.5912876 + 1910 1.9556778 2.0035006 0.48443107 6.6437189 + 1920 1.9408788 1.9828296 0.48710124 6.7228731 + 1930 1.9292393 1.9732376 0.49025327 6.7880112 + 1940 1.9263081 1.9708942 0.49416086 6.8162477 + 1950 1.9358375 1.976323 0.49899895 6.7946964 + 1960 1.9520543 1.9936542 0.50485961 6.7467481 + 1970 1.9709064 2.0108957 0.51165586 6.6909455 + 1980 1.9940026 2.0375428 0.51918913 6.6250463 + 1990 2.0171261 2.0646948 0.52705638 6.5649879 + 2000 2.0302713 2.0802515 0.53472229 6.5470853 +Loop time of 1.34877 on 1 procs for 1000 steps with 2775 atoms + +Performance: 64058.154 tau/day, 741.414 timesteps/s +98.7% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.77091 | 0.77091 | 0.77091 | 0.0 | 57.16 +Neigh | 0.085835 | 0.085835 | 0.085835 | 0.0 | 6.36 +Comm | 0.0093472 | 0.0093472 | 0.0093472 | 0.0 | 0.69 +Output | 0.019047 | 0.019047 | 0.019047 | 0.0 | 1.41 +Modify | 0.43949 | 0.43949 | 0.43949 | 0.0 | 32.58 +Other | | 0.02415 | | | 1.79 + +Nlocal: 2775 ave 2775 max 2775 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 530 ave 530 max 530 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 24404 ave 24404 max 24404 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 24404 +Ave neighs/atom = 8.79423 +Neighbor list builds = 36 +Dangerous builds = 0 + +##################################################################### +#collect data + +#print the applied force and total flux to ensure conservation of Jx +variable Fapp equal f_GD[1] +compute vxBulk bulk reduce sum vx +compute vyBulk bulk reduce sum vy +variable invVol equal 1.0/(lx*ly) +variable jx equal c_vxBulk*${invVol} +variable jx equal c_vxBulk*0.00025 +variable jy equal c_vyBulk*${invVol} +variable jy equal c_vyBulk*0.00025 +variable curr_step equal step +variable p_Fapp format Fapp %.3f +variable p_jx format jx %.5g +variable p_jy format jy %.5g +fix print_vCOM all print ${dump_rate} "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy" +fix print_vCOM all print 50 "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy" + +#compute IK1 pressure profile +#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627 +#use profile-unbiased temperature to remove the streaming velocity +#from the kinetic part of the pressure +compute spa bulk stress/atom myTp + +#for the pressure profile, use the same grid as the PUT +compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box +compute chunkX bulk chunk/atom bin/1d x lower 3.125 units box + +#output pressure profile and other profiles +#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where +#V is the volume of a slice +fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite +fix profiles bulk ave/chunk 1 1 50 chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite + +#compute velocity profile across the pipe with a finer grid +variable dYnew equal ${dY}/10 +variable dYnew equal 3.07692307692308/10 +compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box region pipe +compute chunkY bulk chunk/atom bin/1d y center 0.307692307692308 units box region pipe +fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY vx file Vy_profile ave running overwrite +fix velYprof bulk ave/chunk 1 1 50 chunkY vx file Vy_profile ave running overwrite + +#full trajectory +# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z +# dump_modify 7 sort id + +run ${run} +run 2000 +Per MPI rank memory allocation (min/avg/max) = 5.174 | 5.174 | 5.174 Mbytes +Step c_myT c_myTp TotEng Press + 2000 2.0302713 2.0802515 0.53472229 6.5470853 + 2010 2.0303419 2.0806129 0.54177821 6.5808527 + 2020 2.0245167 2.0792991 0.54803523 6.6381758 + 2030 2.0169072 2.065404 0.55345227 6.7008962 + 2040 2.0052526 2.0513817 0.55818432 6.7755868 + 2050 1.9953625 2.0366564 0.56245299 6.8382569 + 2060 2.0003667 2.0462109 0.56649798 6.8390557 + 2070 2.0238288 2.0834553 0.57023651 6.7637821 + 2080 2.045765 2.1173867 0.5730944 6.6861321 + 2090 2.0563925 2.1370313 0.57430831 6.6422581 + 2100 2.0620437 2.1480293 0.57319824 6.6080678 + 2110 2.0584437 2.1473173 0.56913597 6.5969671 + 2120 2.0532825 2.1393006 0.56154606 6.5799417 + 2130 2.0450143 2.1234905 0.55009479 6.5616931 + 2140 2.0229537 2.1004507 0.53511912 6.5854627 + 2150 1.9832556 2.0554119 0.51812599 6.6700591 + 2160 1.9444027 2.0110758 0.50163049 6.7534263 + 2170 1.9267473 1.9904528 0.48759542 6.76469 + 2180 1.9262232 1.9809353 0.47662199 6.7188048 + 2190 1.9359331 1.9854626 0.46836289 6.6406985 + 2200 1.9530728 1.9971865 0.4620366 6.5409943 + 2210 1.9657099 2.0056761 0.45692542 6.4639397 + 2220 1.9661008 2.0046161 0.45253504 6.4388081 + 2230 1.9574696 1.9947839 0.44864257 6.4528687 + 2240 1.9522284 1.9922663 0.44518111 6.4584458 + 2250 1.9518203 1.9950044 0.44206844 6.4491722 + 2260 1.9527908 1.9989603 0.4391804 6.4377912 + 2270 1.9452231 1.9932538 0.43643529 6.4607516 + 2280 1.9249341 1.9759145 0.43392742 6.5320897 + 2290 1.9087464 1.960985 0.43186869 6.5875176 + 2300 1.9103289 1.964731 0.43039882 6.5765021 + 2310 1.9182062 1.9783814 0.4294628 6.5434488 + 2320 1.9204281 1.9796609 0.42889381 6.5351629 + 2330 1.916279 1.9720659 0.42866391 6.5562619 + 2340 1.9062866 1.9587628 0.42890166 6.6033936 + 2350 1.9024117 1.9566812 0.42979475 6.6297969 + 2360 1.908153 1.960687 0.43141898 6.6215148 + 2370 1.9115944 1.9663337 0.43376668 6.6236491 + 2380 1.9086193 1.9637867 0.4367911 6.6529568 + 2390 1.9039907 1.9610268 0.44053991 6.6926343 + 2400 1.9034944 1.9609406 0.44508818 6.7193441 + 2410 1.9151521 1.9753641 0.4504458 6.7015957 + 2420 1.9314517 1.9925924 0.45644382 6.6669864 + 2430 1.9433933 2.0062001 0.46277215 6.6481527 + 2440 1.9504631 2.0087015 0.46917209 6.6475757 + 2450 1.9550092 2.0094957 0.47550077 6.6556459 + 2460 1.9609689 2.0147997 0.48170141 6.6568282 + 2470 1.9730726 2.0328127 0.48763131 6.6337545 + 2480 1.9838562 2.0466643 0.49303443 6.6143423 + 2490 1.9862031 2.0473388 0.49767532 6.6245587 + 2500 1.9817565 2.0455432 0.50152131 6.6573893 + 2510 1.9785788 2.0423176 0.50460561 6.6808042 + 2520 1.9823006 2.0505106 0.50696374 6.6726698 + 2530 1.9907178 2.0553736 0.50852885 6.6402082 + 2540 2.0005205 2.0690408 0.50919421 6.5966469 + 2550 2.0079727 2.0809816 0.50872954 6.5568419 + 2560 2.0133128 2.096271 0.50682742 6.5199915 + 2570 2.0141298 2.0990846 0.50314491 6.4951991 + 2580 2.0048768 2.0874319 0.49750096 6.5025454 + 2590 1.9876498 2.0638834 0.4900201 6.5333038 + 2600 1.9720479 2.0474479 0.48105263 6.5527157 + 2610 1.9596324 2.0355764 0.4710001 6.5547867 + 2620 1.9439039 2.0106405 0.46046644 6.5646889 + 2630 1.9321714 1.9924346 0.45021207 6.5589454 + 2640 1.9349378 1.9923889 0.44082833 6.5012762 + 2650 1.9448459 2.0069955 0.43251999 6.4228945 + 2660 1.9446852 2.0050346 0.42525857 6.3921645 + 2670 1.9325594 1.9884937 0.41913362 6.4169726 + 2680 1.9121687 1.9606084 0.41434428 6.4821267 + 2690 1.8923613 1.9339385 0.41105831 6.5517615 + 2700 1.8807238 1.9191801 0.40933203 6.5949447 + 2710 1.8797367 1.918758 0.40906826 6.6001309 + 2720 1.8852961 1.9225996 0.41005611 6.58191 + 2730 1.8937478 1.9357751 0.41204348 6.5541946 + 2740 1.9019279 1.9449374 0.41476104 6.5278575 + 2750 1.9134396 1.9614415 0.41800066 6.4890769 + 2760 1.9339551 1.9913779 0.42150554 6.4159805 + 2770 1.9597826 2.0220988 0.42487614 6.3232273 + 2780 1.9753466 2.0414907 0.42771704 6.2715489 + 2790 1.9720423 2.0402016 0.42976012 6.2949288 + 2800 1.9512893 2.0172711 0.43109201 6.3878056 + 2810 1.9232302 1.9870212 0.4320928 6.5101822 + 2820 1.9026913 1.959286 0.43326424 6.6024967 + 2830 1.9033802 1.9621601 0.43500785 6.6114274 + 2840 1.9214292 1.9833838 0.43733454 6.5508757 + 2850 1.9440563 2.0087358 0.43995473 6.4713496 + 2860 1.9589136 2.0211107 0.44250821 6.4232961 + 2870 1.9588429 2.022232 0.44477492 6.4355861 + 2880 1.9456751 2.0009513 0.44676532 6.5021746 + 2890 1.9269155 1.9782929 0.44877858 6.5926531 + 2900 1.9125262 1.9554653 0.45121196 6.6657808 + 2910 1.9187855 1.9572583 0.45438665 6.6589954 + 2920 1.9416112 1.9784518 0.45839212 6.5888253 + 2930 1.9613579 1.9975032 0.46305788 6.5317424 + 2940 1.9711529 2.0102501 0.46812715 6.5148943 + 2950 1.9707865 2.0133283 0.47345305 6.5389543 + 2960 1.9732526 2.0170219 0.47898306 6.5537092 + 2970 1.9871126 2.0282309 0.48465048 6.5273492 + 2980 1.9953449 2.0404164 0.49032615 6.5227325 + 2990 1.9909136 2.037246 0.49581423 6.5664662 + 3000 1.9872474 2.0307896 0.5011051 6.6060698 + 3010 1.9944885 2.0457308 0.5062755 6.6031811 + 3020 2.0103461 2.0599491 0.51116655 6.5654871 + 3030 2.0240275 2.077342 0.5154921 6.5358852 + 3040 2.0205953 2.0704954 0.51898871 6.5708937 + 3050 2.0032184 2.0463036 0.52167438 6.657741 + 3060 1.9889341 2.0265284 0.52385964 6.7329171 + 3070 1.9795143 2.0201081 0.52588914 6.7881407 + 3080 1.9713362 2.0123964 0.52797238 6.8362858 + 3090 1.9692592 2.0106467 0.53025538 6.8616268 + 3100 1.9722487 2.0259566 0.53277635 6.8689898 + 3110 1.9703322 2.0314028 0.53541462 6.895271 + 3120 1.9594359 2.0217586 0.53808512 6.954362 + 3130 1.9524729 2.0148628 0.5409094 6.9965233 + 3140 1.9630381 2.0260807 0.54400259 6.968082 + 3150 1.9902598 2.0549364 0.54720142 6.8698796 + 3160 2.029715 2.0923999 0.54995378 6.7193678 + 3170 2.0581544 2.1137995 0.55150021 6.6053728 + 3180 2.0590739 2.1156535 0.55123668 6.5919337 + 3190 2.0400682 2.0904721 0.54894762 6.6505757 + 3200 2.0211594 2.0682597 0.54484887 6.7046468 + 3210 2.012712 2.0573114 0.53922056 6.7130909 + 3220 2.0102377 2.0554701 0.53219251 6.6919068 + 3230 2.0017671 2.0505068 0.52386898 6.6867054 + 3240 1.9854941 2.0308454 0.51458791 6.7051085 + 3250 1.9767009 2.0187664 0.50486784 6.6916859 + 3260 1.9771733 2.0186148 0.49510721 6.6424305 + 3270 1.974003 2.0136039 0.48556818 6.6078903 + 3280 1.9627665 1.9989122 0.47654147 6.6067904 + 3290 1.9491247 1.9826247 0.46834865 6.6186709 + 3300 1.9414093 1.9724941 0.4612122 6.6119543 + 3310 1.9433901 1.9715482 0.45518879 6.570612 + 3320 1.9518837 1.9872717 0.45010165 6.5057947 + 3330 1.9603874 1.9957995 0.44566728 6.4428221 + 3340 1.9615962 1.9945224 0.44167201 6.4099339 + 3350 1.955918 1.9882866 0.4380303 6.4070811 + 3360 1.9463445 1.9763654 0.43480086 6.4241178 + 3370 1.9411187 1.9683081 0.4320639 6.4296577 + 3380 1.9407224 1.9580074 0.42991627 6.4210217 + 3390 1.9402479 1.9530447 0.42850635 6.4170536 + 3400 1.9451337 1.9555771 0.42787382 6.3990336 + 3410 1.9475586 1.9612432 0.42797178 6.3953251 + 3420 1.9434927 1.960532 0.4286887 6.4210681 + 3430 1.9339054 1.9516935 0.43003682 6.4707071 + 3440 1.9234014 1.9464343 0.43214965 6.5248205 + 3450 1.9191846 1.9444777 0.43516361 6.5558451 + 3460 1.923218 1.9594606 0.43915611 6.5549213 + 3470 1.9328953 1.9792053 0.44397878 6.5327637 + 3480 1.9466227 1.9997841 0.44940599 6.4954965 + 3490 1.9672374 2.0323219 0.45511091 6.4358811 + 3500 1.9799622 2.0479841 0.46061029 6.4100217 + 3510 1.97942 2.0493411 0.46551964 6.4368108 + 3520 1.9725674 2.0389602 0.46976379 6.4892049 + 3530 1.9716429 2.0389798 0.47344292 6.5200899 + 3540 1.9789254 2.0486162 0.47659268 6.5198212 + 3550 1.9872455 2.0577517 0.47908145 6.5144586 + 3560 1.9808834 2.0545963 0.48076562 6.5633282 + 3570 1.9637165 2.0335394 0.4816783 6.6519124 + 3580 1.9407948 2.0067763 0.48212406 6.7605224 + 3590 1.9226532 1.9825887 0.482523 6.8486041 + 3600 1.9135067 1.9700999 0.48328349 6.8977859 + 3610 1.9157516 1.9720028 0.48470695 6.8977759 + 3620 1.9328644 2.0001154 0.48688778 6.8361569 + 3630 1.9568208 2.0243053 0.48963934 6.7442107 + 3640 1.9824587 2.0569223 0.49259174 6.6452535 + 3650 1.9934906 2.0686357 0.49529039 6.6020218 + 3660 1.9996281 2.0747054 0.49732231 6.5808905 + 3670 2.0038801 2.0772777 0.49838834 6.5691351 + 3680 1.9941342 2.0712365 0.49826732 6.6088108 + 3690 1.9762631 2.0486045 0.49689109 6.6739003 + 3700 1.9667284 2.034939 0.49438991 6.7010266 + 3710 1.9615089 2.0168112 0.49093736 6.7040385 + 3720 1.9613068 2.014749 0.48673789 6.6813041 + 3730 1.9731234 2.0290151 0.48175562 6.6096756 + 3740 1.9829764 2.0461907 0.47575174 6.5424752 + 3750 1.9792839 2.0454423 0.4685271 6.5237752 + 3760 1.9599692 2.0287015 0.46022485 6.5616271 + 3770 1.935975 2.0000948 0.45138017 6.6136471 + 3780 1.9236713 1.9834802 0.44262437 6.6187463 + 3790 1.9268004 1.9875324 0.43430113 6.5632772 + 3800 1.932601 1.9872595 0.42649564 6.4984765 + 3810 1.9322506 1.9814946 0.41928856 6.4617054 + 3820 1.9245737 1.9712821 0.4128224 6.461378 + 3830 1.9148568 1.9555602 0.40721003 6.4774474 + 3840 1.9049961 1.9457058 0.4026118 6.5029211 + 3850 1.8915137 1.9265199 0.39914962 6.5483592 + 3860 1.8784768 1.9058055 0.39700153 6.5962113 + 3870 1.8755236 1.9045158 0.39632769 6.6079033 + 3880 1.8841415 1.9140314 0.39710038 6.5777071 + 3890 1.8958027 1.9331148 0.39918951 6.5359786 + 3900 1.9064085 1.948805 0.40238576 6.4998591 + 3910 1.9185092 1.9675732 0.40647523 6.4610682 + 3920 1.9342595 1.9933225 0.41115392 6.4122308 + 3930 1.9482664 2.007614 0.41603495 6.373684 + 3940 1.9557759 2.0161573 0.42084462 6.3636707 + 3950 1.9573687 2.016612 0.42540421 6.3804123 + 3960 1.9486354 1.9998027 0.42974612 6.4404943 + 3970 1.936214 1.980721 0.43412037 6.5176787 + 3980 1.9274292 1.9595259 0.43885103 6.5846211 + 3990 1.9233082 1.953436 0.44425085 6.6354275 + 4000 1.9289165 1.9522097 0.45042645 6.6513836 +Loop time of 2.49114 on 1 procs for 2000 steps with 2775 atoms + +Performance: 69365.902 tau/day, 802.846 timesteps/s +98.9% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 1.4257 | 1.4257 | 1.4257 | 0.0 | 57.23 +Neigh | 0.15501 | 0.15501 | 0.15501 | 0.0 | 6.22 +Comm | 0.017206 | 0.017206 | 0.017206 | 0.0 | 0.69 +Output | 0.034183 | 0.034183 | 0.034183 | 0.0 | 1.37 +Modify | 0.81531 | 0.81531 | 0.81531 | 0.0 | 32.73 +Other | | 0.04374 | | | 1.76 + +Nlocal: 2775 ave 2775 max 2775 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 517 ave 517 max 517 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 24366 ave 24366 max 24366 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 24366 +Ave neighs/atom = 8.78054 +Neighbor list builds = 72 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:05 diff --git a/examples/USER/flow_gauss/log.6Jul17.GD.g++.4 b/examples/USER/flow_gauss/log.6Jul17.GD.g++.4 new file mode 100644 index 0000000000..6171c0da5c --- /dev/null +++ b/examples/USER/flow_gauss/log.6Jul17.GD.g++.4 @@ -0,0 +1,909 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +#LAMMPS input script +#in.GD +#see README for details + +############################################################################### +#initialize variables +clear + using 1 OpenMP thread(s) per MPI task + +#frequency for outputting info (timesteps) +variable dump_rate equal 50 +variable thermo_rate equal 10 + +#equilibration time (timesteps) +variable equil equal 1000 + +#stabilization time (timesteps to reach steady-state) +variable stabil equal 1000 + +#data collection time (timesteps) +variable run equal 2000 + +#length of pipe +variable L equal 30 + +#width of pipe +variable d equal 20 + +#flux (mass/sigma*tau) +variable J equal 0.1 + +#simulation box dimensions +variable Lx equal 100 +variable Ly equal 40 + +#bulk fluid density +variable dens equal 0.8 + +#lattice spacing for wall atoms +variable aWall equal 1.0 #1.7472 + +#timestep +variable ts equal 0.001 + +#temperature +variable T equal 2.0 + +#thermostat damping constant +variable tdamp equal ${ts}*100 +variable tdamp equal 0.001*100 + +units lj +dimension 2 +atom_style atomic + + +############################################################################### +#create box + +#create lattice with the spacing aWall +variable rhoWall equal ${aWall}^(-2) +variable rhoWall equal 1^(-2) +lattice sq ${rhoWall} +lattice sq 1 +Lattice spacing in x,y,z = 1 1 1 + +#modify input dimensions to be multiples of aWall +variable L1 equal round($L/${aWall})*${aWall} +variable L1 equal round(30/${aWall})*${aWall} +variable L1 equal round(30/1)*${aWall} +variable L1 equal round(30/1)*1 +variable d1 equal round($d/${aWall})*${aWall} +variable d1 equal round(20/${aWall})*${aWall} +variable d1 equal round(20/1)*${aWall} +variable d1 equal round(20/1)*1 +variable Ly1 equal round(${Ly}/${aWall})*${aWall} +variable Ly1 equal round(40/${aWall})*${aWall} +variable Ly1 equal round(40/1)*${aWall} +variable Ly1 equal round(40/1)*1 +variable Lx1 equal round(${Lx}/${aWall})*${aWall} +variable Lx1 equal round(100/${aWall})*${aWall} +variable Lx1 equal round(100/1)*${aWall} +variable Lx1 equal round(100/1)*1 + +#create simulation box +variable lx2 equal ${Lx1}/2 +variable lx2 equal 100/2 +variable ly2 equal ${Ly1}/2 +variable ly2 equal 40/2 +region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 ${lx2} -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 50 -${ly2} ${ly2} 0 0.1 units box +region simbox block -50 50 -20 ${ly2} 0 0.1 units box +region simbox block -50 50 -20 20 0 0.1 units box +create_box 2 simbox +Created orthogonal box = (-50 -20 0) to (50 20 0.1) + 4 by 1 by 1 MPI processor grid + +##################################################################### +#set up potential + +mass 1 1.0 #fluid atoms +mass 2 1.0 #wall atoms + +pair_style lj/cut 2.5 +pair_modify shift yes +pair_coeff 1 1 1.0 1.0 2.5 +pair_coeff 1 2 1.0 1.0 1.12246 +pair_coeff 2 2 0.0 0.0 + +neigh_modify exclude type 2 2 + +timestep ${ts} +timestep 0.001 + +##################################################################### +#create atoms + +#create wall atoms everywhere +create_atoms 2 box +Created 4000 atoms + +#define region which is "walled off" +variable dhalf equal ${d1}/2 +variable dhalf equal 20/2 +variable Lhalf equal ${L1}/2 +variable Lhalf equal 30/2 +region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 ${Lhalf} ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 15 ${dhalf} EDGE -0.1 0.1 units box +region walltop block -15 15 10 EDGE -0.1 0.1 units box +region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 ${Lhalf} EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 15 EDGE -${dhalf} -0.1 0.1 units box +region wallbot block -15 15 EDGE -10 -0.1 0.1 units box +region outsidewall union 2 walltop wallbot side out + +#remove wall atoms outside wall region +group outside region outsidewall +3349 atoms in group outside +delete_atoms group outside +Deleted 3349 atoms, new total = 651 + +#remove wall atoms that aren't on edge of wall region +variable x1 equal ${Lhalf}-${aWall} +variable x1 equal 15-${aWall} +variable x1 equal 15-1 +variable y1 equal ${dhalf}+${aWall} +variable y1 equal 10+${aWall} +variable y1 equal 10+1 +region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 ${x1} ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 14 ${y1} EDGE -0.1 0.1 units box +region insideTop block -14 14 11 EDGE -0.1 0.1 units box +region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 ${x1} EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 14 EDGE -${y1} -0.1 0.1 units box +region insideBot block -14 14 EDGE -11 -0.1 0.1 units box +region insideWall union 2 insideTop insideBot +group insideWall region insideWall +551 atoms in group insideWall +delete_atoms group insideWall +Deleted 551 atoms, new total = 100 + +#define new lattice, to give correct fluid density +#y lattice const must be a multiple of aWall +variable atrue equal ${dens}^(-1/2) +variable atrue equal 0.8^(-1/2) +variable ay equal round(${atrue}/${aWall})*${aWall} +variable ay equal round(1.11803398874989/${aWall})*${aWall} +variable ay equal round(1.11803398874989/1)*${aWall} +variable ay equal round(1.11803398874989/1)*1 + +#choose x lattice const to give correct density +variable ax equal (${ay}*${dens})^(-1) +variable ax equal (1*${dens})^(-1) +variable ax equal (1*0.8)^(-1) + +#change Lx to be multiple of ax +variable Lx1 equal round(${Lx}/${ax})*${ax} +variable Lx1 equal round(100/${ax})*${ax} +variable Lx1 equal round(100/1.25)*${ax} +variable Lx1 equal round(100/1.25)*1.25 +variable lx2 equal ${Lx1}/2 +variable lx2 equal 100/2 +change_box all x final -${lx2} ${lx2} units box +change_box all x final -50 ${lx2} units box +change_box all x final -50 50 units box + orthogonal box = (-50 -20 0) to (50 20 0.1) + +#define new lattice +lattice custom ${dens} a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +lattice custom 0.8 a1 1.25 0.0 0.0 a2 0.0 1 0.0 a3 0.0 0.0 1.0 basis 0.0 0.0 0.0 +Lattice spacing in x,y,z = 1.25 1 1 + +#fill in rest of box with bulk particles +variable delta equal 0.001 +variable Ldelt equal ${Lhalf}+${delta} +variable Ldelt equal 15+${delta} +variable Ldelt equal 15+0.001 +variable dDelt equal ${dhalf}-${delta} +variable dDelt equal 10-${delta} +variable dDelt equal 10-0.001 +region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box +region left block EDGE -15.001 EDGE EDGE -0.1 0.1 units box +region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box +region right block 15.001 EDGE EDGE EDGE -0.1 0.1 units box +region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -${dDelt} ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -9.999 ${dDelt} -0.1 0.1 units box +region pipe block -15.001 15.001 -9.999 9.999 -0.1 0.1 units box + +region bulk union 3 left pipe right +create_atoms 1 region bulk +Created 2675 atoms + +group bulk type 1 +2675 atoms in group bulk +group wall type 2 +100 atoms in group wall + +#remove atoms that are too close to wall +delete_atoms overlap 0.9 bulk wall +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 2.8 + ghost atom cutoff = 2.8 + binsize = 1.4, bins = 72 29 1 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) command delete_atoms, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/2d + bin: standard + (2) pair lj/cut, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/2d/newton + bin: standard +Deleted 0 atoms, new total = 2775 + +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes +neigh_modify exclude group wall wall + +velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom +velocity bulk create 2 78915 dist gaussian rot yes mom yes loop geom + +##################################################################### +#set up PUT +#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 + +#average number of particles per box, Evans and Morriss used 2.0 +variable NperBox equal 8.0 + +#calculate box sizes +variable boxSide equal sqrt(${NperBox}/${dens}) +variable boxSide equal sqrt(8/${dens}) +variable boxSide equal sqrt(8/0.8) +variable nX equal round(lx/${boxSide}) +variable nX equal round(lx/3.16227766016838) +variable nY equal round(ly/${boxSide}) +variable nY equal round(ly/3.16227766016838) +variable dX equal lx/${nX} +variable dX equal lx/32 +variable dY equal ly/${nY} +variable dY equal ly/13 + +#temperature of fluid (excluding wall) +compute myT bulk temp + +#profile-unbiased temperature of fluid +compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} +compute myTp bulk temp/profile 1 1 0 xy 32 ${nY} +compute myTp bulk temp/profile 1 1 0 xy 32 13 + +#thermo setup +thermo ${thermo_rate} +thermo 10 +thermo_style custom step c_myT c_myTp etotal press + +#dump initial configuration +# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz +# dump 56 wall custom 1 wall.init.lammpstrj id type x y z +# dump_modify 55 sort id +# dump_modify 56 sort id +run 0 +WARNING: No fixes defined, atoms won't move (../verlet.cpp:55) +Neighbor list info ... + update every 1 steps, delay 0 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 2.8 + ghost atom cutoff = 2.8 + binsize = 1.4, bins = 72 29 1 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair lj/cut, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/2d/newton + bin: standard +Per MPI rank memory allocation (min/avg/max) = 3.067 | 3.068 | 3.07 Mbytes +Step c_myT c_myTp TotEng Press + 0 2 2.0555109 0.77892922 7.3417096 +Loop time of 4.35114e-06 on 4 procs for 0 steps with 2775 atoms + +114.9% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0 | 0 | 0 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0 | 0 | 0 | 0.0 | 0.00 +Output | 0 | 0 | 0 | 0.0 | 0.00 +Modify | 0 | 0 | 0 | 0.0 | 0.00 +Other | | 4.351e-06 | | |100.00 + +Nlocal: 693.75 ave 800 max 578 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 266.25 ave 325 max 198 min +Histogram: 1 1 0 0 0 0 0 0 0 2 +Neighs: 6601.5 ave 8000 max 5147 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 26406 +Ave neighs/atom = 9.51568 +Neighbor list builds = 0 +Dangerous builds = 0 +# undump 55 +# undump 56 + +##################################################################### +#equilibrate without GD + +fix nvt bulk nvt temp $T $T ${tdamp} +fix nvt bulk nvt temp 2 $T ${tdamp} +fix nvt bulk nvt temp 2 2 ${tdamp} +fix nvt bulk nvt temp 2 2 0.1 +fix_modify nvt temp myTp +WARNING: Temperature for fix modify is not for group all (../fix_nh.cpp:1395) +fix 2 bulk enforce2d + +run ${equil} +run 1000 +Per MPI rank memory allocation (min/avg/max) = 3.13 | 3.131 | 3.132 Mbytes +Step c_myT c_myTp TotEng Press + 0 2 2.0555109 0.77892922 7.3417096 + 10 1.9173594 1.9390034 0.77876976 7.6702228 + 20 1.7033394 1.6974676 0.77977799 8.5614784 + 30 1.5026161 1.4723993 0.78456655 9.4308258 + 40 1.4880481 1.4591602 0.79486693 9.6134304 + 50 1.6192437 1.6150635 0.81109069 9.2592835 + 60 1.7404087 1.7583444 0.82955456 8.952392 + 70 1.7757591 1.8006606 0.8452778 8.9717917 + 80 1.7573847 1.7813629 0.85769389 9.1936368 + 90 1.7491183 1.7726908 0.86882429 9.3712357 + 100 1.7798944 1.8079583 0.88029084 9.3871755 + 110 1.8440582 1.8793133 0.89259397 9.2582848 + 120 1.9191606 1.9673434 0.90533438 9.0680574 + 130 1.9883299 2.0484299 0.91755461 8.88117 + 140 2.0463366 2.1111872 0.92818114 8.7184178 + 150 2.0953769 2.167849 0.93639789 8.5713408 + 160 2.1442147 2.2216228 0.94145082 8.4082835 + 170 2.1797848 2.2631458 0.94246877 8.2767903 + 180 2.1863476 2.2700986 0.93873326 8.2311689 + 190 2.1832866 2.2710551 0.93003012 8.1959062 + 200 2.1937154 2.2868403 0.91642537 8.0842007 + 210 2.2022708 2.2915142 0.89824533 7.9575312 + 220 2.1884715 2.2770564 0.87677613 7.9000591 + 230 2.1671124 2.2496063 0.85409501 7.8673156 + 240 2.1560417 2.2379998 0.83167878 7.8003228 + 250 2.1421449 2.2240624 0.81004723 7.7491508 + 260 2.1172164 2.1971044 0.78931978 7.7457415 + 270 2.0856847 2.1672998 0.76956352 7.7719788 + 280 2.0670685 2.1449303 0.75073364 7.7524614 + 290 2.0639481 2.1428374 0.73258016 7.6727716 + 300 2.055776 2.1361719 0.7147669 7.6095248 + 310 2.038425 2.1209353 0.69722853 7.5797085 + 320 2.0203023 2.1066031 0.68006634 7.5521081 + 330 2.0118478 2.1039797 0.66330302 7.4877535 + 340 2.0159442 2.1096258 0.64673694 7.3761703 + 350 2.0166408 2.1075061 0.63020017 7.2788 + 360 2.0059407 2.0806316 0.61387618 7.2263941 + 370 1.9964281 2.0642074 0.59814148 7.1728041 + 380 1.9918446 2.0567527 0.58303017 7.101597 + 390 1.992835 2.0548138 0.56852431 7.0084774 + 400 2.0012934 2.0615016 0.55438401 6.8865948 + 410 2.0084291 2.073418 0.54034073 6.7697478 + 420 2.007464 2.0786717 0.52617041 6.6849032 + 430 1.9983712 2.0704366 0.51188183 6.6323103 + 440 1.9884651 2.0588515 0.49765394 6.5868356 + 450 1.982221 2.0467396 0.4837102 6.5311681 + 460 1.9738673 2.031238 0.47021649 6.4882783 + 470 1.9574246 2.0060447 0.45740021 6.4814923 + 480 1.9361065 1.9734507 0.44557947 6.4995199 + 490 1.9251024 1.9562469 0.43506067 6.4858343 + 500 1.9279545 1.9572145 0.42577835 6.4274765 + 510 1.9267504 1.9570246 0.41755013 6.3927027 + 520 1.9093405 1.9393872 0.41031829 6.4281888 + 530 1.8820555 1.9060756 0.40432569 6.5099401 + 540 1.86537 1.8912682 0.3999087 6.55843 + 550 1.8694252 1.9043192 0.39717519 6.5337875 + 560 1.8835224 1.9294105 0.39589322 6.4760141 + 570 1.8898719 1.9462433 0.39573596 6.4520041 + 580 1.8887698 1.9472764 0.39649878 6.4602989 + 590 1.8945125 1.9550624 0.39810844 6.4470226 + 600 1.9106571 1.9735939 0.40045321 6.3971026 + 610 1.9273243 1.98509 0.40330026 6.3474421 + 620 1.9351802 1.9888986 0.4064498 6.3340566 + 630 1.9337889 1.9846794 0.40981479 6.3610556 + 640 1.9257018 1.9757153 0.4134641 6.4184721 + 650 1.9204429 1.9718256 0.41750942 6.4679594 + 660 1.9220449 1.9701963 0.42202455 6.4919724 + 670 1.9230578 1.9707406 0.4270412 6.5178484 + 680 1.9204554 1.9740485 0.43255127 6.5572507 + 690 1.9201811 1.9762854 0.43847123 6.5869126 + 700 1.9271511 1.9867455 0.44474356 6.5882669 + 710 1.9418851 2.0042477 0.45120727 6.558573 + 720 1.9544547 2.0186724 0.4576061 6.5338329 + 730 1.9687971 2.0326169 0.46367507 6.4988775 + 740 1.9830308 2.0466267 0.46920367 6.4618136 + 750 1.9936981 2.0526606 0.47397868 6.4367349 + 760 2.0008431 2.0535449 0.47786748 6.4249001 + 770 1.9982133 2.0483219 0.48085757 6.4504786 + 780 1.9841544 2.0311693 0.48306488 6.5200512 + 790 1.9683122 2.0158738 0.48475632 6.5959263 + 800 1.9604618 2.003224 0.48619405 6.6392559 + 810 1.9629155 2.0075077 0.48756075 6.6406486 + 820 1.9683056 2.0110554 0.48883443 6.6269424 + 830 1.975409 2.0189161 0.48995399 6.6030215 + 840 1.9897264 2.035016 0.4907852 6.5485575 + 850 2.0094338 2.0555358 0.49104505 6.4719926 + 860 2.0217589 2.0643603 0.49040437 6.4233305 + 870 2.0147718 2.0641627 0.48866908 6.4491964 + 880 1.9883859 2.0324092 0.48592007 6.5488061 + 890 1.9625853 2.0028776 0.48263002 6.6452734 + 900 1.9520401 1.9889124 0.47925524 6.6808078 + 910 1.9559583 1.9952984 0.47597346 6.6573059 + 920 1.9657244 2.0083503 0.47268726 6.6073704 + 930 1.969288 2.0152339 0.4692054 6.5780416 + 940 1.9652206 2.0116384 0.4654438 6.5769812 + 950 1.9567495 1.9960693 0.46147541 6.5942022 + 960 1.9418452 1.980858 0.45753557 6.6369454 + 970 1.9247196 1.9585585 0.45390337 6.6888821 + 980 1.9128262 1.9481721 0.45090045 6.7198221 + 990 1.9167211 1.9451096 0.44869731 6.6912394 + 1000 1.935529 1.9662384 0.44728238 6.6079829 +Loop time of 0.474418 on 4 procs for 1000 steps with 2775 atoms + +Performance: 182118.045 tau/day, 2107.848 timesteps/s +98.4% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.13953 | 0.19068 | 0.23764 | 10.4 | 40.19 +Neigh | 0.016439 | 0.022345 | 0.027069 | 3.2 | 4.71 +Comm | 0.018215 | 0.068071 | 0.12178 | 18.6 | 14.35 +Output | 0.011982 | 0.012633 | 0.013047 | 0.4 | 2.66 +Modify | 0.14494 | 0.15597 | 0.16628 | 2.4 | 32.88 +Other | | 0.02472 | | | 5.21 + +Nlocal: 693.75 ave 800 max 584 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 255.5 ave 323 max 192 min +Histogram: 2 0 0 0 0 0 0 0 1 1 +Neighs: 6083 ave 7384 max 4742 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 24332 +Ave neighs/atom = 8.76829 +Neighbor list builds = 38 +Dangerous builds = 0 + +##################################################################### +#initialize the COM velocity and run to achieve steady-state + +#calculate velocity to add: V=J/rho_total +variable Vadd equal $J*lx*ly/count(bulk) +variable Vadd equal 0.1*lx*ly/count(bulk) + +#first remove any COM velocity, then add back the streaming velocity +velocity bulk zero linear +velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no +velocity bulk set 0.149532710280374 0.0 0.0 units box sum yes mom no + +fix GD bulk flow/gauss 1 0 0 #energy yes +#fix_modify GD energy yes + +run ${stabil} +run 1000 +Per MPI rank memory allocation (min/avg/max) = 3.13 | 3.131 | 3.132 Mbytes +Step c_myT c_myTp TotEng Press + 1000 1.9466974 1.9662384 0.45804438 6.615449 + 1010 1.9605467 1.9815754 0.45717241 6.5545496 + 1020 1.9560139 1.9823875 0.45660431 6.5672421 + 1030 1.9348326 1.9691606 0.45633148 6.6463667 + 1040 1.9167809 1.9449522 0.45657707 6.7139486 + 1050 1.9193541 1.943342 0.45767968 6.7014054 + 1060 1.9410751 1.9720491 0.45967742 6.6150379 + 1070 1.9658493 1.9964883 0.46221539 6.5178418 + 1080 1.9767205 2.0074304 0.46491236 6.4768594 + 1090 1.9714544 2.0003054 0.46759126 6.5026957 + 1100 1.9647035 1.9927455 0.4703109 6.5400181 + 1110 1.9657667 1.9959656 0.47317481 6.5519094 + 1120 1.9706062 1.9980802 0.476185 6.5512675 + 1130 1.9747655 2.0062292 0.47932281 6.554091 + 1140 1.9761245 2.0075076 0.48248327 6.5670381 + 1150 1.9744197 2.0073027 0.48562483 6.5914441 + 1160 1.9722698 2.0046687 0.48874207 6.6165575 + 1170 1.9692145 2.0013845 0.49187442 6.6438115 + 1180 1.9665609 1.9970724 0.49508053 6.6693821 + 1190 1.9625031 1.9908427 0.49843816 6.7002606 + 1200 1.960528 1.993084 0.50203044 6.7237076 + 1210 1.9649156 1.9981485 0.50587066 6.7217755 + 1220 1.9788059 2.0134511 0.50987442 6.6833452 + 1230 1.9952283 2.0343101 0.51379781 6.6340278 + 1240 2.0039391 2.0494196 0.51730872 6.6129751 + 1250 2.0019006 2.0526773 0.52014603 6.6320217 + 1260 1.9974025 2.0528914 0.52221385 6.6601786 + 1270 1.9953949 2.0561121 0.5234754 6.6796142 + 1280 1.9893864 2.0470375 0.5238632 6.7140134 + 1290 1.9694951 2.019253 0.5235093 6.798442 + 1300 1.9473901 1.9965919 0.52280384 6.8863369 + 1310 1.9511151 2.006161 0.52203882 6.8700917 + 1320 1.979341 2.0388959 0.52106938 6.7529595 + 1330 2.0073235 2.0720045 0.51935291 6.6297731 + 1340 2.0202482 2.0841419 0.51624273 6.55803 + 1350 2.0177489 2.0669046 0.51142591 6.5401753 + 1360 2.0069274 2.04717 0.50505824 6.5506533 + 1370 1.994854 2.0311383 0.49743042 6.5633001 + 1380 1.9793176 2.0077184 0.48890503 6.5859072 + 1390 1.9580907 1.9839831 0.48004316 6.6288992 + 1400 1.9415542 1.9594192 0.47143599 6.6534105 + 1410 1.9405188 1.9591825 0.46353105 6.620549 + 1420 1.9504784 1.9730647 0.45640199 6.5471784 + 1430 1.9594158 1.9819854 0.44995052 6.4802874 + 1440 1.9615108 1.9863792 0.44406411 6.44391 + 1450 1.9544127 1.9806249 0.43873409 6.4484818 + 1460 1.9384927 1.9614953 0.43408605 6.4905259 + 1470 1.9214711 1.9425515 0.43035972 6.5390434 + 1480 1.9170761 1.9300809 0.42775046 6.5409502 + 1490 1.9242904 1.9385731 0.42631007 6.5005057 + 1500 1.9307133 1.9446119 0.4258836 6.4660754 + 1510 1.9303576 1.9435389 0.42633976 6.4616415 + 1520 1.9248382 1.9408306 0.42765441 6.4832059 + 1530 1.9120794 1.9278123 0.42986958 6.5380951 + 1540 1.899122 1.9125029 0.4331459 6.5987181 + 1550 1.9030956 1.9187821 0.43765067 6.6012019 + 1560 1.9182961 1.9453782 0.44330842 6.5674222 + 1570 1.9272863 1.9613129 0.44971962 6.5619794 + 1580 1.931679 1.9698134 0.45643436 6.5780809 + 1590 1.9336692 1.9728684 0.46314752 6.6035675 + 1600 1.938895 1.9823104 0.46964519 6.6138411 + 1610 1.9510838 1.9937914 0.47568807 6.5916989 + 1620 1.9685387 2.0087314 0.48102339 6.5424432 + 1630 1.9894416 2.0295715 0.48539861 6.4757743 + 1640 1.9982699 2.0426949 0.48860411 6.4512418 + 1650 1.9901677 2.0363837 0.49062424 6.4879985 + 1660 1.9814216 2.0291326 0.49172203 6.5248034 + 1670 1.9812111 2.0293629 0.49218297 6.5253876 + 1680 1.9903906 2.0408376 0.49211747 6.4852787 + 1690 2.0015983 2.0538843 0.4914581 6.4325081 + 1700 2.009727 2.0503407 0.49011163 6.3878577 + 1710 2.0167822 2.0531002 0.4881688 6.3477054 + 1720 2.0189021 2.0445033 0.48564798 6.3273063 + 1730 2.0129713 2.0354734 0.48270666 6.3385541 + 1740 2.0048763 2.0199836 0.47950943 6.3587586 + 1750 1.9994843 2.0085942 0.47624908 6.3694119 + 1760 1.9940025 2.0072098 0.47305283 6.3816295 + 1770 1.9817431 1.9974066 0.46994486 6.4224295 + 1780 1.965171 1.9805421 0.4670779 6.4832371 + 1790 1.9474078 1.9662605 0.46466823 6.5516524 + 1800 1.9286009 1.9507751 0.46292015 6.6263366 + 1810 1.9168087 1.9437961 0.46199899 6.6759834 + 1820 1.9107555 1.9306323 0.46204129 6.7029857 + 1830 1.9135569 1.930819 0.46316484 6.6949737 + 1840 1.9345342 1.9553413 0.46532704 6.6178988 + 1850 1.9630349 1.9929548 0.46822932 6.5137866 + 1860 1.9820746 2.0188839 0.47135068 6.4489028 + 1870 1.9834959 2.0217145 0.47427805 6.4552721 + 1880 1.9731564 2.0120293 0.47692755 6.5100251 + 1890 1.9653605 2.0070624 0.47943307 6.5594235 + 1900 1.9630631 2.0095488 0.48192185 6.5912876 + 1910 1.9556778 2.0035006 0.48443107 6.6437189 + 1920 1.9408788 1.9828296 0.48710124 6.7228731 + 1930 1.9292393 1.9732376 0.49025327 6.7880112 + 1940 1.9263081 1.9708942 0.49416086 6.8162477 + 1950 1.9358375 1.976323 0.49899895 6.7946964 + 1960 1.9520543 1.9936542 0.50485961 6.7467481 + 1970 1.9709064 2.0108957 0.51165586 6.6909455 + 1980 1.9940026 2.0375428 0.51918913 6.6250463 + 1990 2.0171261 2.0646948 0.52705638 6.5649879 + 2000 2.0302713 2.0802515 0.53472229 6.5470853 +Loop time of 0.482133 on 4 procs for 1000 steps with 2775 atoms + +Performance: 179203.608 tau/day, 2074.116 timesteps/s +98.6% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.1081 | 0.18228 | 0.23471 | 12.7 | 37.81 +Neigh | 0.011443 | 0.019967 | 0.025651 | 4.1 | 4.14 +Comm | 0.01639 | 0.073615 | 0.15634 | 21.8 | 15.27 +Output | 0.011851 | 0.012603 | 0.013287 | 0.5 | 2.61 +Modify | 0.14306 | 0.16634 | 0.18018 | 3.6 | 34.50 +Other | | 0.02733 | | | 5.67 + +Nlocal: 693.75 ave 797 max 590 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 259 ave 320 max 195 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Neighs: 6101 ave 7360 max 4853 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 24404 +Ave neighs/atom = 8.79423 +Neighbor list builds = 36 +Dangerous builds = 0 + +##################################################################### +#collect data + +#print the applied force and total flux to ensure conservation of Jx +variable Fapp equal f_GD[1] +compute vxBulk bulk reduce sum vx +compute vyBulk bulk reduce sum vy +variable invVol equal 1.0/(lx*ly) +variable jx equal c_vxBulk*${invVol} +variable jx equal c_vxBulk*0.00025 +variable jy equal c_vyBulk*${invVol} +variable jy equal c_vyBulk*0.00025 +variable curr_step equal step +variable p_Fapp format Fapp %.3f +variable p_jx format jx %.5g +variable p_jy format jy %.5g +fix print_vCOM all print ${dump_rate} "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy" +fix print_vCOM all print 50 "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no title "timestep Fapp Jx Jy" + +#compute IK1 pressure profile +#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627 +#use profile-unbiased temperature to remove the streaming velocity +#from the kinetic part of the pressure +compute spa bulk stress/atom myTp + +#for the pressure profile, use the same grid as the PUT +compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box +compute chunkX bulk chunk/atom bin/1d x lower 3.125 units box + +#output pressure profile and other profiles +#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where +#V is the volume of a slice +fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite +fix profiles bulk ave/chunk 1 1 50 chunkX vx density/mass c_spa[1] c_spa[2] file x_profiles ave running overwrite + +#compute velocity profile across the pipe with a finer grid +variable dYnew equal ${dY}/10 +variable dYnew equal 3.07692307692308/10 +compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box region pipe +compute chunkY bulk chunk/atom bin/1d y center 0.307692307692308 units box region pipe +fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY vx file Vy_profile ave running overwrite +fix velYprof bulk ave/chunk 1 1 50 chunkY vx file Vy_profile ave running overwrite + +#full trajectory +# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z +# dump_modify 7 sort id + +run ${run} +run 2000 +Per MPI rank memory allocation (min/avg/max) = 5.138 | 5.139 | 5.14 Mbytes +Step c_myT c_myTp TotEng Press + 2000 2.0302713 2.0802515 0.53472229 6.5470853 + 2010 2.0303419 2.0806129 0.54177821 6.5808527 + 2020 2.0245167 2.0792991 0.54803523 6.6381758 + 2030 2.0169072 2.065404 0.55345227 6.7008962 + 2040 2.0052526 2.0513817 0.55818432 6.7755868 + 2050 1.9953625 2.0366564 0.56245299 6.8382569 + 2060 2.0003667 2.0462109 0.56649798 6.8390557 + 2070 2.0238288 2.0834553 0.57023651 6.7637821 + 2080 2.045765 2.1173867 0.5730944 6.6861321 + 2090 2.0563925 2.1370313 0.57430831 6.6422581 + 2100 2.0620437 2.1480293 0.57319824 6.6080678 + 2110 2.0584437 2.1473173 0.56913597 6.5969671 + 2120 2.0532825 2.1393006 0.56154606 6.5799417 + 2130 2.0450143 2.1234905 0.55009479 6.5616931 + 2140 2.0229537 2.1004507 0.53511912 6.5854627 + 2150 1.9832556 2.0554119 0.51812599 6.6700591 + 2160 1.9444027 2.0110758 0.50163049 6.7534263 + 2170 1.9267473 1.9904528 0.48759542 6.76469 + 2180 1.9262232 1.9809353 0.47662199 6.7188048 + 2190 1.9359331 1.9854626 0.46836289 6.6406985 + 2200 1.9530728 1.9971865 0.4620366 6.5409943 + 2210 1.9657099 2.0056761 0.45692542 6.4639397 + 2220 1.9661008 2.0046161 0.45253504 6.4388081 + 2230 1.9574696 1.9947839 0.44864257 6.4528687 + 2240 1.9522284 1.9922663 0.44518111 6.4584458 + 2250 1.9518203 1.9950044 0.44206844 6.4491722 + 2260 1.9527908 1.9989603 0.4391804 6.4377912 + 2270 1.9452231 1.9932538 0.43643529 6.4607516 + 2280 1.9249341 1.9759145 0.43392742 6.5320897 + 2290 1.9087464 1.960985 0.43186869 6.5875176 + 2300 1.9103289 1.964731 0.43039882 6.5765021 + 2310 1.9182062 1.9783814 0.4294628 6.5434488 + 2320 1.9204281 1.9796609 0.42889381 6.5351629 + 2330 1.916279 1.9720659 0.42866391 6.5562619 + 2340 1.9062866 1.9587628 0.42890166 6.6033936 + 2350 1.9024117 1.9566812 0.42979475 6.6297969 + 2360 1.908153 1.960687 0.43141898 6.6215148 + 2370 1.9115944 1.9663337 0.43376668 6.6236491 + 2380 1.9086193 1.9637867 0.4367911 6.6529568 + 2390 1.9039907 1.9610268 0.44053991 6.6926343 + 2400 1.9034944 1.9609406 0.44508818 6.7193441 + 2410 1.9151521 1.9753641 0.4504458 6.7015957 + 2420 1.9314517 1.9925924 0.45644382 6.6669864 + 2430 1.9433933 2.0062001 0.46277215 6.6481527 + 2440 1.9504631 2.0087015 0.46917209 6.6475757 + 2450 1.9550092 2.0094957 0.47550077 6.6556459 + 2460 1.9609689 2.0147997 0.48170141 6.6568282 + 2470 1.9730726 2.0328127 0.48763131 6.6337545 + 2480 1.9838562 2.0466643 0.49303443 6.6143423 + 2490 1.9862031 2.0473388 0.49767532 6.6245587 + 2500 1.9817565 2.0455432 0.50152131 6.6573893 + 2510 1.9785788 2.0423176 0.50460561 6.6808042 + 2520 1.9823006 2.0505106 0.50696374 6.6726698 + 2530 1.9907178 2.0553736 0.50852885 6.6402082 + 2540 2.0005205 2.0690408 0.50919421 6.5966469 + 2550 2.0079727 2.0809816 0.50872954 6.5568419 + 2560 2.0133128 2.096271 0.50682742 6.5199915 + 2570 2.0141298 2.0990846 0.50314491 6.4951991 + 2580 2.0048768 2.0874319 0.49750096 6.5025454 + 2590 1.9876498 2.0638834 0.4900201 6.5333038 + 2600 1.9720479 2.0474479 0.48105263 6.5527157 + 2610 1.9596324 2.0355764 0.4710001 6.5547867 + 2620 1.9439039 2.0106405 0.46046644 6.5646889 + 2630 1.9321714 1.9924346 0.45021207 6.5589454 + 2640 1.9349378 1.9923889 0.44082833 6.5012762 + 2650 1.9448459 2.0069955 0.43251999 6.4228945 + 2660 1.9446852 2.0050346 0.42525857 6.3921645 + 2670 1.9325594 1.9884937 0.41913362 6.4169726 + 2680 1.9121687 1.9606084 0.41434428 6.4821267 + 2690 1.8923613 1.9339385 0.41105831 6.5517615 + 2700 1.8807238 1.9191801 0.40933203 6.5949447 + 2710 1.8797367 1.918758 0.40906826 6.6001309 + 2720 1.8852961 1.9225996 0.41005611 6.58191 + 2730 1.8937478 1.9357751 0.41204348 6.5541946 + 2740 1.9019279 1.9449374 0.41476104 6.5278575 + 2750 1.9134396 1.9614415 0.41800066 6.4890769 + 2760 1.9339551 1.9913779 0.42150554 6.4159805 + 2770 1.9597826 2.0220988 0.42487614 6.3232273 + 2780 1.9753466 2.0414907 0.42771704 6.2715489 + 2790 1.9720423 2.0402016 0.42976012 6.2949288 + 2800 1.9512893 2.0172711 0.43109201 6.3878056 + 2810 1.9232302 1.9870212 0.4320928 6.5101822 + 2820 1.9026913 1.959286 0.43326424 6.6024967 + 2830 1.9033802 1.9621601 0.43500785 6.6114274 + 2840 1.9214292 1.9833838 0.43733454 6.5508757 + 2850 1.9440563 2.0087358 0.43995473 6.4713496 + 2860 1.9589136 2.0211107 0.44250821 6.4232961 + 2870 1.9588429 2.022232 0.44477492 6.4355861 + 2880 1.9456751 2.0009513 0.44676532 6.5021746 + 2890 1.9269155 1.9782929 0.44877858 6.5926531 + 2900 1.9125262 1.9554653 0.45121196 6.6657808 + 2910 1.9187855 1.9572583 0.45438665 6.6589954 + 2920 1.9416112 1.9784518 0.45839212 6.5888253 + 2930 1.9613579 1.9975032 0.46305788 6.5317424 + 2940 1.9711529 2.0102501 0.46812715 6.5148943 + 2950 1.9707865 2.0133283 0.47345305 6.5389543 + 2960 1.9732526 2.0170219 0.47898306 6.5537092 + 2970 1.9871126 2.0282309 0.48465048 6.5273492 + 2980 1.9953449 2.0404164 0.49032615 6.5227325 + 2990 1.9909136 2.037246 0.49581423 6.5664662 + 3000 1.9872474 2.0307896 0.50110509 6.6060698 + 3010 1.9944885 2.0457308 0.5062755 6.6031811 + 3020 2.0103461 2.0599491 0.51116655 6.5654871 + 3030 2.0240275 2.077342 0.5154921 6.5358852 + 3040 2.0205953 2.0704954 0.51898871 6.5708937 + 3050 2.0032184 2.0463036 0.52167438 6.657741 + 3060 1.9889341 2.0265284 0.52385964 6.7329171 + 3070 1.9795143 2.0201081 0.52588914 6.7881407 + 3080 1.9713362 2.0123964 0.52797238 6.8362858 + 3090 1.9692592 2.0106467 0.53025538 6.8616268 + 3100 1.9722487 2.0259566 0.53277635 6.8689898 + 3110 1.9703322 2.0314028 0.53541462 6.895271 + 3120 1.9594359 2.0217586 0.53808512 6.954362 + 3130 1.9524729 2.0148628 0.5409094 6.9965233 + 3140 1.9630381 2.0260807 0.54400259 6.968082 + 3150 1.9902598 2.0549364 0.54720142 6.8698796 + 3160 2.029715 2.0923999 0.54995378 6.7193678 + 3170 2.0581544 2.1137995 0.55150021 6.6053728 + 3180 2.059074 2.1156535 0.55123668 6.5919337 + 3190 2.0400682 2.0904721 0.54894762 6.6505757 + 3200 2.0211594 2.0682597 0.54484887 6.7046468 + 3210 2.012712 2.0573114 0.53922057 6.7130909 + 3220 2.0102377 2.0554701 0.53219251 6.6919069 + 3230 2.0017671 2.0505068 0.52386898 6.6867054 + 3240 1.9854941 2.0308454 0.51458792 6.7051085 + 3250 1.9767009 2.0187664 0.50486785 6.6916859 + 3260 1.9771733 2.0186148 0.49510722 6.6424305 + 3270 1.974003 2.0136039 0.48556819 6.6078903 + 3280 1.9627665 1.9989122 0.47654147 6.6067904 + 3290 1.9491247 1.9826248 0.46834866 6.6186709 + 3300 1.9414093 1.9724941 0.4612122 6.6119543 + 3310 1.9433901 1.9715482 0.45518879 6.570612 + 3320 1.9518837 1.9872717 0.45010165 6.5057947 + 3330 1.9603874 1.9957995 0.44566728 6.4428221 + 3340 1.9615962 1.9945224 0.44167201 6.4099339 + 3350 1.955918 1.9882866 0.4380303 6.4070811 + 3360 1.9463445 1.9763654 0.43480086 6.4241178 + 3370 1.9411187 1.9683081 0.43206391 6.4296577 + 3380 1.9407224 1.9580074 0.42991627 6.4210217 + 3390 1.9402479 1.9530447 0.42850635 6.4170536 + 3400 1.9451337 1.9555771 0.42787382 6.3990336 + 3410 1.9475586 1.9612432 0.42797178 6.3953251 + 3420 1.9434927 1.960532 0.4286887 6.4210681 + 3430 1.9339054 1.9516935 0.43003682 6.4707071 + 3440 1.9234014 1.9464343 0.43214965 6.5248205 + 3450 1.9191846 1.9444777 0.43516361 6.5558451 + 3460 1.923218 1.9594606 0.43915611 6.5549213 + 3470 1.9328953 1.9792053 0.44397878 6.5327637 + 3480 1.9466227 1.9997841 0.44940599 6.4954965 + 3490 1.9672374 2.0323219 0.45511091 6.4358811 + 3500 1.9799622 2.0479841 0.46061029 6.4100217 + 3510 1.97942 2.0493411 0.46551964 6.4368108 + 3520 1.9725674 2.0389602 0.46976378 6.4892049 + 3530 1.9716429 2.0389798 0.47344292 6.5200899 + 3540 1.9789254 2.0486162 0.47659268 6.5198212 + 3550 1.9872455 2.0577517 0.47908145 6.5144586 + 3560 1.9808834 2.0545962 0.48076561 6.5633282 + 3570 1.9637165 2.0335394 0.4816783 6.6519124 + 3580 1.9407948 2.0067763 0.48212405 6.7605224 + 3590 1.9226532 1.9825887 0.48252299 6.8486041 + 3600 1.9135067 1.9700999 0.48328348 6.8977858 + 3610 1.9157516 1.9720028 0.48470695 6.8977759 + 3620 1.9328644 2.0001154 0.48688777 6.8361569 + 3630 1.9568208 2.0243053 0.48963933 6.7442107 + 3640 1.9824587 2.0569223 0.49259173 6.6452535 + 3650 1.9934906 2.0686356 0.49529038 6.6020218 + 3660 1.9996281 2.0747054 0.4973223 6.5808904 + 3670 2.0038801 2.0772777 0.49838833 6.5691351 + 3680 1.9941342 2.0712365 0.49826732 6.6088107 + 3690 1.9762631 2.0486045 0.49689108 6.6739002 + 3700 1.9667284 2.0349391 0.4943899 6.7010265 + 3710 1.9615089 2.0168112 0.49093735 6.7040384 + 3720 1.9613068 2.0147489 0.48673788 6.6813041 + 3730 1.9731234 2.0290151 0.48175561 6.6096757 + 3740 1.9829764 2.0461907 0.47575173 6.5424752 + 3750 1.9792839 2.0454423 0.46852709 6.5237753 + 3760 1.9599692 2.0287014 0.46022484 6.5616271 + 3770 1.935975 2.0000948 0.45138016 6.6136471 + 3780 1.9236713 1.9834802 0.44262435 6.6187463 + 3790 1.9268004 1.9875324 0.43430112 6.5632772 + 3800 1.932601 1.9872595 0.42649563 6.4984764 + 3810 1.9322506 1.9814946 0.41928855 6.4617054 + 3820 1.9245737 1.9712821 0.4128224 6.4613779 + 3830 1.9148568 1.9555602 0.40721003 6.4774474 + 3840 1.9049961 1.9457058 0.40261179 6.5029211 + 3850 1.8915137 1.9265199 0.39914961 6.5483592 + 3860 1.8784768 1.9058055 0.39700153 6.5962113 + 3870 1.8755236 1.9045158 0.39632768 6.6079033 + 3880 1.8841415 1.9140314 0.39710037 6.577707 + 3890 1.8958027 1.9331149 0.39918951 6.5359785 + 3900 1.9064085 1.948805 0.40238576 6.499859 + 3910 1.9185092 1.9675733 0.40647523 6.4610682 + 3920 1.9342595 1.9933225 0.41115392 6.4122308 + 3930 1.9482664 2.0076139 0.41603495 6.3736841 + 3940 1.9557759 2.0161573 0.42084462 6.3636708 + 3950 1.9573687 2.016612 0.42540421 6.3804124 + 3960 1.9486354 1.9998027 0.42974612 6.4404944 + 3970 1.936214 1.9807209 0.43412037 6.5176788 + 3980 1.9274292 1.9595259 0.43885103 6.5846212 + 3990 1.9233082 1.953436 0.44425085 6.6354276 + 4000 1.9289166 1.9522097 0.45042645 6.6513835 +Loop time of 0.998413 on 4 procs for 2000 steps with 2775 atoms + +Performance: 173074.634 tau/day, 2003.179 timesteps/s +98.9% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.25646 | 0.3672 | 0.47947 | 15.7 | 36.78 +Neigh | 0.027925 | 0.039163 | 0.050221 | 4.5 | 3.92 +Comm | 0.032807 | 0.14565 | 0.27684 | 25.4 | 14.59 +Output | 0.025572 | 0.032272 | 0.035355 | 2.2 | 3.23 +Modify | 0.31519 | 0.35781 | 0.375 | 4.1 | 35.84 +Other | | 0.05632 | | | 5.64 + +Nlocal: 693.75 ave 805 max 582 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Nghost: 255.5 ave 312 max 199 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +Neighs: 6091.5 ave 7423 max 4780 min +Histogram: 2 0 0 0 0 0 0 0 0 2 + +Total # of neighbors = 24366 +Ave neighs/atom = 8.78054 +Neighbor list builds = 72 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:01 diff --git a/examples/USER/flow_gauss/output-files/GD.out b/examples/USER/flow_gauss/output-files/GD.out new file mode 100644 index 0000000000..e3049830bc --- /dev/null +++ b/examples/USER/flow_gauss/output-files/GD.out @@ -0,0 +1,41 @@ +timestep Fapp Jx Jy +2050 -215.835 0.1 -0.002562 +2100 -220.455 0.1 -0.0019705 +2150 55.212 0.1 -0.0028338 +2200 87.052 0.1 -0.0042335 +2250 -62.998 0.1 -0.0045646 +2300 71.630 0.1 -0.0039858 +2350 43.159 0.1 -0.0029771 +2400 109.930 0.1 -0.0018522 +2450 110.735 0.1 -0.0011188 +2500 107.071 0.1 0.0005978 +2550 335.449 0.1 0.0010164 +2600 159.694 0.1 -0.00015953 +2650 6.532 0.1 -0.0004907 +2700 65.524 0.1 -0.00093116 +2750 79.662 0.1 -0.0033425 +2800 69.846 0.1 -0.0055377 +2850 122.175 0.1 -0.00721 +2900 32.456 0.1 -0.0086166 +2950 -85.137 0.1 -0.01107 +3000 154.735 0.1 -0.011337 +3050 72.979 0.1 -0.0095316 +3100 -24.457 0.1 -0.0098708 +3150 -0.383 0.1 -0.0094961 +3200 132.434 0.1 -0.011524 +3250 48.222 0.1 -0.014966 +3300 -73.186 0.1 -0.016999 +3350 172.062 0.1 -0.018554 +3400 106.144 0.1 -0.021202 +3450 -22.860 0.1 -0.01949 +3500 22.120 0.1 -0.016033 +3550 -254.920 0.1 -0.012172 +3600 -147.218 0.1 -0.011162 +3650 -12.508 0.1 -0.010255 +3700 81.846 0.1 -0.0085117 +3750 -79.406 0.1 -0.0061294 +3800 -34.994 0.1 -0.0026239 +3850 94.992 0.1 -0.0015312 +3900 -0.345 0.1 -0.0011157 +3950 -88.693 0.1 -0.0018929 +4000 156.029 0.1 -0.0024547 diff --git a/examples/USER/flow_gauss/output-files/Vy_profile b/examples/USER/flow_gauss/output-files/Vy_profile new file mode 100644 index 0000000000..2df7468364 --- /dev/null +++ b/examples/USER/flow_gauss/output-files/Vy_profile @@ -0,0 +1,134 @@ +# Chunk-averaged data for fix velYprof and group file +# Timestep Number-of-chunks Total-count +# Chunk Coord1 Ncount vx +4000 130 18774 + 1 -19.8462 0 0 + 2 -19.5385 0 0 + 3 -19.2308 0 0 + 4 -18.9231 0 0 + 5 -18.6154 0 0 + 6 -18.3077 0 0 + 7 -18 0 0 + 8 -17.6923 0 0 + 9 -17.3846 0 0 + 10 -17.0769 0 0 + 11 -16.7692 0 0 + 12 -16.4615 0 0 + 13 -16.1538 0 0 + 14 -15.8462 0 0 + 15 -15.5385 0 0 + 16 -15.2308 0 0 + 17 -14.9231 0 0 + 18 -14.6154 0 0 + 19 -14.3077 0 0 + 20 -14 0 0 + 21 -13.6923 0 0 + 22 -13.3846 0 0 + 23 -13.0769 0 0 + 24 -12.7692 0 0 + 25 -12.4615 0 0 + 26 -12.1538 0 0 + 27 -11.8462 0 0 + 28 -11.5385 0 0 + 29 -11.2308 0 0 + 30 -10.9231 0 0 + 31 -10.6154 0 0 + 32 -10.3077 0 0 + 33 -10 0 0 + 34 -9.69231 0 0 + 35 -9.38462 0 0 + 36 -9.07692 12.3415 0.126356 + 37 -8.76923 9.14634 0.119194 + 38 -8.46154 3.46341 0.0688559 + 39 -8.15385 7.26829 0.180935 + 40 -7.84615 9.97561 0.114685 + 41 -7.53846 6.14634 0.158317 + 42 -7.23077 7.17073 0.128092 + 43 -6.92308 8.56098 0.30356 + 44 -6.61538 7.7561 0.118822 + 45 -6.30769 6.04878 0.170019 + 46 -6 8.19512 0.146873 + 47 -5.69231 8.4878 0.258003 + 48 -5.38462 7.21951 0.0612577 + 49 -5.07692 7.14634 0.394221 + 50 -4.76923 7.34146 0.214609 + 51 -4.46154 7.90244 0.1583 + 52 -4.15385 6.36585 0.191919 + 53 -3.84615 8.04878 0.202891 + 54 -3.53846 7.2439 -0.00173288 + 55 -3.23077 7.53659 0.117062 + 56 -2.92308 6.41463 0.324614 + 57 -2.61538 7.60976 0.496272 + 58 -2.30769 8.39024 0.364642 + 59 -2 6.73171 0.292624 + 60 -1.69231 7.02439 0.517913 + 61 -1.38462 8.43902 0.534594 + 62 -1.07692 7.21951 0.497622 + 63 -0.769231 6.95122 0.303701 + 64 -0.461538 8.68293 0.406682 + 65 -0.153846 7.5122 0.218835 + 66 0.153846 6.82927 0.189413 + 67 0.461538 8.26829 0.228409 + 68 0.769231 7.2439 0.506845 + 69 1.07692 7.97561 0.154118 + 70 1.38462 8.26829 0.144882 + 71 1.69231 6.58537 0.192568 + 72 2 7.46341 0.360144 + 73 2.30769 8.95122 0.0112179 + 74 2.61538 6.58537 0.276061 + 75 2.92308 6.53659 0.114354 + 76 3.23077 8.46341 0.0386417 + 77 3.53846 8 0.0711626 + 78 3.84615 6.92683 0.203194 + 79 4.15385 8.4878 0.317789 + 80 4.46154 7.5122 0.268122 + 81 4.76923 6.58537 -0.112372 + 82 5.07692 9.02439 0.115702 + 83 5.38462 7.41463 -0.067424 + 84 5.69231 6.07317 0.0626918 + 85 6 8.34146 -0.0153977 + 86 6.30769 8.21951 0.281342 + 87 6.61538 6.29268 0.359939 + 88 6.92308 8.87805 0.110875 + 89 7.23077 6.09756 0.134999 + 90 7.53846 6.65854 0.0841478 + 91 7.84615 10.8537 0.144519 + 92 8.15385 5.58537 0.309331 + 93 8.46154 5.80488 0.103667 + 94 8.76923 7.60976 0.39288 + 95 9.07692 12.0244 0.462022 + 96 9.38462 0 0 + 97 9.69231 0 0 + 98 10 0 0 + 99 10.3077 0 0 + 100 10.6154 0 0 + 101 10.9231 0 0 + 102 11.2308 0 0 + 103 11.5385 0 0 + 104 11.8462 0 0 + 105 12.1538 0 0 + 106 12.4615 0 0 + 107 12.7692 0 0 + 108 13.0769 0 0 + 109 13.3846 0 0 + 110 13.6923 0 0 + 111 14 0 0 + 112 14.3077 0 0 + 113 14.6154 0 0 + 114 14.9231 0 0 + 115 15.2308 0 0 + 116 15.5385 0 0 + 117 15.8462 0 0 + 118 16.1538 0 0 + 119 16.4615 0 0 + 120 16.7692 0 0 + 121 17.0769 0 0 + 122 17.3846 0 0 + 123 17.6923 0 0 + 124 18 0 0 + 125 18.3077 0 0 + 126 18.6154 0 0 + 127 18.9231 0 0 + 128 19.2308 0 0 + 129 19.5385 0 0 + 130 19.8462 0 0 diff --git a/examples/USER/flow_gauss/output-files/x_profiles b/examples/USER/flow_gauss/output-files/x_profiles new file mode 100644 index 0000000000..7a761345af --- /dev/null +++ b/examples/USER/flow_gauss/output-files/x_profiles @@ -0,0 +1,36 @@ +# Chunk-averaged data for fix profiles and group density/mass +# Timestep Number-of-chunks Total-count +# Chunk Coord1 Ncount vx density/mass c_spa[1] c_spa[2] +4000 32 109675 + 1 -48.4375 97.7805 0.159561 0.782244 -9.17487 -8.9018 + 2 -45.3125 100.927 0.187846 0.807415 -9.24302 -9.92813 + 3 -42.1875 99.0976 0.227036 0.79278 -9.03415 -9.66032 + 4 -39.0625 101.146 0.243495 0.809171 -8.89515 -9.25314 + 5 -35.9375 98.7805 0.194616 0.790244 -9.13265 -8.52663 + 6 -32.8125 97.8049 0.165768 0.782439 -9.26009 -8.52446 + 7 -29.6875 100.195 0.0758064 0.801561 -9.02933 -8.50733 + 8 -26.5625 98.4878 0.054432 0.787902 -9.61672 -9.24963 + 9 -23.4375 99.9268 0.0740914 0.799415 -9.88959 -9.94984 + 10 -20.3125 99.7561 0.130294 0.798049 -10.2459 -9.39412 + 11 -17.1875 102.463 0.120168 0.819707 -10.6072 -10.254 + 12 -14.0625 47.6341 0.208545 0.381073 -9.85715 -10.0799 + 13 -10.9375 48.1951 0.238051 0.385561 -9.81349 -10.569 + 14 -7.8125 47.439 0.287107 0.379512 -10.0184 -9.63087 + 15 -4.6875 48.2439 0.22506 0.385951 -9.83794 -9.6963 + 16 -1.5625 48.4634 0.208869 0.387707 -9.29366 -10.0114 + 17 1.5625 46.4878 0.19447 0.371902 -10.2409 -9.84627 + 18 4.6875 47.2927 0.168034 0.378341 -10.1523 -11.908 + 19 7.8125 48.6829 0.145552 0.389463 -10.24 -11.0582 + 20 10.9375 48.8293 0.214036 0.390634 -9.27729 -10.1074 + 21 14.0625 46.9756 0.267083 0.375805 -9.24833 -9.83182 + 22 17.1875 97.2683 0.175404 0.778146 -9.64001 -8.61724 + 23 20.3125 101.146 0.10746 0.809171 -9.33416 -9.82308 + 24 23.4375 101.927 0.157503 0.815415 -9.76491 -10.1909 + 25 26.5625 101.024 0.179934 0.808195 -9.72775 -9.98559 + 26 29.6875 100.976 0.180631 0.807805 -9.33871 -10.0228 + 27 32.8125 96.4146 0.144418 0.771317 -9.74826 -9.79723 + 28 35.9375 101.244 0.117224 0.809951 -8.95584 -8.80226 + 29 39.0625 102 0.10507 0.816 -9.15563 -8.98232 + 30 42.1875 101.195 0.040236 0.809561 -9.1499 -8.95112 + 31 45.3125 96.9512 0.0312252 0.77561 -9.20475 -9.0005 + 32 48.4375 100.244 0.103032 0.801951 -9.16324 -8.77526 From 3b1134c1649a83c5be60aa0ff1f75f47d54d92c0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 13:42:02 -0400 Subject: [PATCH 081/293] correct formatting error in peridynamics pair style docs --- doc/src/pair_peri.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/pair_peri.txt b/doc/src/pair_peri.txt index 6ffd8122aa..7abe6378dd 100644 --- a/doc/src/pair_peri.txt +++ b/doc/src/pair_peri.txt @@ -127,7 +127,7 @@ G (force/area units) horizon (distance units) s00 (unitless) alpha (unitless) -m_yield_stress (force/area units) +m_yield_stress (force/area units) :ul K is the bulk modulus and G is the shear modulus. The horizon is a cutoff distance and s00 and alpha are used as a bond breaking From 14f1d646ad76653d8cee44489fc9504f5917a0f6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 13:44:12 -0400 Subject: [PATCH 082/293] provide working examples for all four peridynamics models and reference outputs --- examples/peri/{in.peri => in.peri-pmb} | 0 examples/peri/in.peri.eps | 45 +++++++ examples/peri/in.peri.lps | 45 +++++++ examples/peri/in.peri.pmb | 45 +++++++ examples/peri/in.peri.ves | 45 +++++++ examples/peri/log.6Jul17.peri.eps.g++.1 | 115 ++++++++++++++++++ examples/peri/log.6Jul17.peri.eps.g++.4 | 115 ++++++++++++++++++ examples/peri/log.6Jul17.peri.lps.g++.1 | 115 ++++++++++++++++++ examples/peri/log.6Jul17.peri.lps.g++.4 | 115 ++++++++++++++++++ ...6.peri.g++.1 => log.6Jul17.peri.pmb.g++.1} | 57 +++++---- ...6.peri.g++.4 => log.6Jul17.peri.pmb.g++.4} | 67 +++++----- examples/peri/log.6Jul17.peri.ves.g++.1 | 115 ++++++++++++++++++ examples/peri/log.6Jul17.peri.ves.g++.4 | 115 ++++++++++++++++++ 13 files changed, 943 insertions(+), 51 deletions(-) rename examples/peri/{in.peri => in.peri-pmb} (100%) create mode 100644 examples/peri/in.peri.eps create mode 100644 examples/peri/in.peri.lps create mode 100644 examples/peri/in.peri.pmb create mode 100644 examples/peri/in.peri.ves create mode 100644 examples/peri/log.6Jul17.peri.eps.g++.1 create mode 100644 examples/peri/log.6Jul17.peri.eps.g++.4 create mode 100644 examples/peri/log.6Jul17.peri.lps.g++.1 create mode 100644 examples/peri/log.6Jul17.peri.lps.g++.4 rename examples/peri/{log.5Oct16.peri.g++.1 => log.6Jul17.peri.pmb.g++.1} (62%) rename examples/peri/{log.5Oct16.peri.g++.4 => log.6Jul17.peri.pmb.g++.4} (58%) create mode 100644 examples/peri/log.6Jul17.peri.ves.g++.1 create mode 100644 examples/peri/log.6Jul17.peri.ves.g++.4 diff --git a/examples/peri/in.peri b/examples/peri/in.peri-pmb similarity index 100% rename from examples/peri/in.peri rename to examples/peri/in.peri-pmb diff --git a/examples/peri/in.peri.eps b/examples/peri/in.peri.eps new file mode 100644 index 0000000000..5ddea41722 --- /dev/null +++ b/examples/peri/in.peri.eps @@ -0,0 +1,45 @@ +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +create_atoms 1 region target + +pair_style peri/eps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8 +set group all density 2200 +set group all volume 1.25e-10 +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 diff --git a/examples/peri/in.peri.lps b/examples/peri/in.peri.lps new file mode 100644 index 0000000000..af0462b5d4 --- /dev/null +++ b/examples/peri/in.peri.lps @@ -0,0 +1,45 @@ +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +create_atoms 1 region target + +pair_style peri/lps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 +set group all density 2200 +set group all volume 1.25e-10 +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 diff --git a/examples/peri/in.peri.pmb b/examples/peri/in.peri.pmb new file mode 100644 index 0000000000..f9f5d54231 --- /dev/null +++ b/examples/peri/in.peri.pmb @@ -0,0 +1,45 @@ +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +create_atoms 1 region target + +pair_style peri/pmb +pair_coeff * * 1.6863e22 0.0015001 0.0005 0.25 +set group all density 2200 +set group all volume 1.25e-10 +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 diff --git a/examples/peri/in.peri.ves b/examples/peri/in.peri.ves new file mode 100644 index 0000000000..3787e676a4 --- /dev/null +++ b/examples/peri/in.peri.ves @@ -0,0 +1,45 @@ +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +create_atoms 1 region target + +pair_style peri/ves +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001 +set group all density 2200 +set group all volume 1.25e-10 +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type & +# axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 diff --git a/examples/peri/log.6Jul17.peri.eps.g++.1 b/examples/peri/log.6Jul17.peri.eps.g++.1 new file mode 100644 index 0000000000..6aa4314d53 --- /dev/null +++ b/examples/peri/log.6Jul17.peri.eps.g++.1 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 1 by 1 by 1 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/eps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/eps, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 50.29 | 50.29 | 50.29 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 8.3466308e+24 247103.03 0 849681.45 8.0295601e+11 5.0030006e-07 + 200 1.1784921e+27 1098605.6 0 86178912 1.0246967e+14 5.5353162e-07 + 300 2.6263212e+27 4118581.6 0 1.9372377e+08 1.662415e+14 7.6036043e-07 + 400 3.3085888e+27 9397203.3 0 2.4825816e+08 1.561692e+14 1.0196674e-06 + 500 3.9151799e+27 18408722 0 3.0106204e+08 1.5298661e+14 1.2317127e-06 + 600 6.2936721e+27 11346143 0 4.6571282e+08 1.9645007e+14 1.5419242e-06 + 700 1.2721597e+28 3830223.2 0 9.2225588e+08 3.0235577e+14 2.0250441e-06 + 800 1.3190107e+28 2831668.7 0 9.5508099e+08 2.4853932e+14 2.5542553e-06 + 900 1.3166045e+28 1911868.6 0 9.524241e+08 1.9729649e+14 3.2117896e-06 + 1000 1.3159578e+28 1995827.6 0 9.5204114e+08 1.6722163e+14 3.7875695e-06 +Loop time of 72.5574 on 1 procs for 1000 steps with 3487 atoms + +99.7% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 71.779 | 71.779 | 71.779 | 0.0 | 98.93 +Neigh | 0.5596 | 0.5596 | 0.5596 | 0.0 | 0.77 +Comm | 0.0040631 | 0.0040631 | 0.0040631 | 0.0 | 0.01 +Output | 0.00056624 | 0.00056624 | 0.00056624 | 0.0 | 0.00 +Modify | 0.18403 | 0.18403 | 0.18403 | 0.0 | 0.25 +Other | | 0.03016 | | | 0.04 + +Nlocal: 3487 ave 3487 max 3487 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 569177 ave 569177 max 569177 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 40 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:01:12 diff --git a/examples/peri/log.6Jul17.peri.eps.g++.4 b/examples/peri/log.6Jul17.peri.eps.g++.4 new file mode 100644 index 0000000000..1423ec4637 --- /dev/null +++ b/examples/peri/log.6Jul17.peri.eps.g++.4 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 2 by 1 by 2 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/eps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 10.0e8 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/eps, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 44.77 | 45.04 | 45.14 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 8.3466308e+24 247103.03 0 849681.45 8.0295601e+11 5.0030006e-07 + 200 1.1784921e+27 1098605.6 0 86178912 1.0246967e+14 5.5353162e-07 + 300 2.6263212e+27 4118581.6 0 1.9372377e+08 1.662415e+14 7.6036043e-07 + 400 3.3085888e+27 9397203.3 0 2.4825816e+08 1.561692e+14 1.0196674e-06 + 500 3.9151799e+27 18408722 0 3.0106204e+08 1.5298661e+14 1.2317127e-06 + 600 6.2936721e+27 11346143 0 4.6571282e+08 1.9645007e+14 1.5419242e-06 + 700 1.2721597e+28 3830223.2 0 9.2225588e+08 3.0235577e+14 2.0250441e-06 + 800 1.3190107e+28 2831668.7 0 9.5508099e+08 2.4853932e+14 2.5542553e-06 + 900 1.3166045e+28 1911869.3 0 9.524241e+08 1.9729649e+14 3.2117896e-06 + 1000 1.3159578e+28 1995833.9 0 9.5204114e+08 1.6722163e+14 3.7875695e-06 +Loop time of 29.6266 on 4 procs for 1000 steps with 3487 atoms + +98.8% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 25.905 | 26.18 | 26.326 | 3.2 | 88.37 +Neigh | 0.15352 | 0.1872 | 0.22394 | 7.6 | 0.63 +Comm | 3.0374 | 3.1471 | 3.3731 | 7.5 | 10.62 +Output | 0.00047588 | 0.00062978 | 0.00097752 | 0.0 | 0.00 +Modify | 0.073521 | 0.081854 | 0.093222 | 2.7 | 0.28 +Other | | 0.02989 | | | 0.10 + +Nlocal: 871.75 ave 908 max 838 min +Histogram: 1 0 0 0 1 1 0 0 0 1 +Nghost: 1368.25 ave 1402 max 1332 min +Histogram: 1 0 0 0 1 1 0 0 0 1 +Neighs: 142294 ave 159233 max 124729 min +Histogram: 2 0 0 0 0 0 0 0 0 2 +FullNghs: 302269 ave 346070 max 260820 min +Histogram: 1 0 0 0 2 0 0 0 0 1 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 40 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:29 diff --git a/examples/peri/log.6Jul17.peri.lps.g++.1 b/examples/peri/log.6Jul17.peri.lps.g++.1 new file mode 100644 index 0000000000..4b2ac532d1 --- /dev/null +++ b/examples/peri/log.6Jul17.peri.lps.g++.1 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 1 by 1 by 1 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/lps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/lps, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 34.91 | 34.91 | 34.91 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 1.684629e+24 133446.65 0 255067.11 1.6206343e+11 5.0030006e-07 + 200 1.1380148e+27 684478.05 0 82842557 9.9178307e+13 5.5225839e-07 + 300 2.5659218e+27 5944645.9 0 1.9118934e+08 1.6231114e+14 7.6086254e-07 + 400 2.9916164e+27 13677434 0 2.2965481e+08 1.4081705e+14 1.0224963e-06 + 500 3.3570343e+27 11130894 0 2.5348933e+08 1.2577633e+14 1.2846002e-06 + 600 3.9506165e+27 6986672.5 0 2.9219831e+08 1.2659956e+14 1.5019096e-06 + 700 7.8366157e+27 11716082 0 5.7747436e+08 1.9480124e+14 1.9361899e-06 + 800 8.2483231e+27 4671647.2 0 6.0015282e+08 1.7040064e+14 2.3297298e-06 + 900 8.2720965e+27 1249680.9 0 5.9844715e+08 1.4117116e+14 2.8202052e-06 + 1000 8.2441462e+27 2278265.6 0 5.9745788e+08 1.234652e+14 3.213751e-06 +Loop time of 62.3833 on 1 procs for 1000 steps with 3487 atoms + +99.5% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 61.608 | 61.608 | 61.608 | 0.0 | 98.76 +Neigh | 0.57177 | 0.57177 | 0.57177 | 0.0 | 0.92 +Comm | 0.0030825 | 0.0030825 | 0.0030825 | 0.0 | 0.00 +Output | 0.00051951 | 0.00051951 | 0.00051951 | 0.0 | 0.00 +Modify | 0.17278 | 0.17278 | 0.17278 | 0.0 | 0.28 +Other | | 0.02745 | | | 0.04 + +Nlocal: 3487 ave 3487 max 3487 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 576568 ave 576568 max 576568 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 37 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:01:02 diff --git a/examples/peri/log.6Jul17.peri.lps.g++.4 b/examples/peri/log.6Jul17.peri.lps.g++.4 new file mode 100644 index 0000000000..04244f0123 --- /dev/null +++ b/examples/peri/log.6Jul17.peri.lps.g++.4 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 2 by 1 by 2 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/lps +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/lps, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 29.4 | 29.66 | 29.76 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 1.684629e+24 133446.65 0 255067.11 1.6206343e+11 5.0030006e-07 + 200 1.1380148e+27 684478.05 0 82842557 9.9178307e+13 5.5225839e-07 + 300 2.5659218e+27 5944645.9 0 1.9118934e+08 1.6231114e+14 7.6086254e-07 + 400 2.9916164e+27 13677434 0 2.2965481e+08 1.4081705e+14 1.0224963e-06 + 500 3.3570343e+27 11130894 0 2.5348933e+08 1.2577633e+14 1.2846002e-06 + 600 3.9506165e+27 6986672.5 0 2.9219831e+08 1.2659956e+14 1.5019096e-06 + 700 7.8366157e+27 11716082 0 5.7747436e+08 1.9480124e+14 1.9361899e-06 + 800 8.2483231e+27 4671647.2 0 6.0015282e+08 1.7040064e+14 2.3297298e-06 + 900 8.2720965e+27 1249680.9 0 5.9844715e+08 1.4117116e+14 2.8202052e-06 + 1000 8.2441489e+27 2277476.2 0 5.9745729e+08 1.2346524e+14 3.213751e-06 +Loop time of 23.2656 on 4 procs for 1000 steps with 3487 atoms + +99.2% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 20.801 | 21.119 | 21.525 | 6.3 | 90.78 +Neigh | 0.13851 | 0.18557 | 0.22747 | 8.5 | 0.80 +Comm | 1.5175 | 1.8689 | 2.1386 | 18.0 | 8.03 +Output | 0.00049806 | 0.00059026 | 0.00071931 | 0.0 | 0.00 +Modify | 0.063441 | 0.066235 | 0.069135 | 0.9 | 0.28 +Other | | 0.02496 | | | 0.11 + +Nlocal: 871.75 ave 939 max 805 min +Histogram: 1 0 0 0 1 1 0 0 0 1 +Nghost: 1343.25 ave 1410 max 1276 min +Histogram: 1 0 0 0 1 1 0 0 0 1 +Neighs: 144142 ave 176488 max 113797 min +Histogram: 1 0 1 0 0 0 1 0 0 1 +FullNghs: 302269 ave 346070 max 260820 min +Histogram: 1 0 0 0 2 0 0 0 0 1 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 37 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:23 diff --git a/examples/peri/log.5Oct16.peri.g++.1 b/examples/peri/log.6Jul17.peri.pmb.g++.1 similarity index 62% rename from examples/peri/log.5Oct16.peri.g++.1 rename to examples/peri/log.6Jul17.peri.pmb.g++.1 index 687876f97f..84a439674b 100644 --- a/examples/peri/log.5Oct16.peri.g++.1 +++ b/examples/peri/log.6Jul17.peri.pmb.g++.1 @@ -1,10 +1,11 @@ -LAMMPS (5 Oct 2016) +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task # small Peridynamic cylinder hit by projectile -units si +units si boundary s s s atom_style peri -atom_modify map array +atom_modify map array neighbor 0.0010 bin # small target @@ -41,24 +42,34 @@ thermo 100 #dump 1 all custom 100 dump.peri id type x y z c_1 -#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 -#dump_modify 2 pad 4 +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 -#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 -#dump_modify 3 pad 4 +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 run 1000 Neighbor list info ... - 2 neighbor list requests update every 1 steps, delay 10 steps, check yes max neighbors/atom: 2000, page size: 100000 master list distance cutoff = 0.0025001 ghost atom cutoff = 0.0025001 - binsize = 0.00125005 -> bins = 9 5 9 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/pmb, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard Peridynamic bonds: total # of bonds = 335966 bonds/atom = 96.3482 -Memory usage per processor = 26.6858 Mbytes +Per MPI rank memory allocation (min/avg/max) = 34.79 | 34.79 | 34.79 Mbytes Step Temp E_pair E_mol TotEng Press Volume 0 0 0 0 0 0 5.0030006e-07 100 1.7890585e+24 552721.8 0 681881.47 1.7210968e+11 5.0030006e-07 @@ -68,28 +79,28 @@ Step Temp E_pair E_mol TotEng Press Volume 500 4.2580877e+27 20212686 0 3.2762196e+08 1.6249923e+14 1.2611723e-06 600 5.5126512e+27 30861342 0 4.2884284e+08 1.7320038e+14 1.531873e-06 700 1.1807414e+28 23119941 0 8.7554687e+08 2.9477434e+14 1.9278632e-06 - 800 1.2424839e+28 2407361.6 0 8.994088e+08 2.3787786e+14 2.5138992e-06 - 900 1.2358395e+28 4532520.6 0 8.9673706e+08 1.9097312e+14 3.1145903e-06 - 1000 1.2341057e+28 3219939.5 0 8.9417279e+08 1.5968597e+14 3.7196039e-06 -Loop time of 20.3026 on 1 procs for 1000 steps with 3487 atoms + 800 1.2424839e+28 2407365.1 0 8.994088e+08 2.3787786e+14 2.5138992e-06 + 900 1.2358397e+28 4532424.3 0 8.9673716e+08 1.9097316e+14 3.1145903e-06 + 1000 1.2341048e+28 3219355.8 0 8.9417154e+08 1.5968585e+14 3.7196039e-06 +Loop time of 28.565 on 1 procs for 1000 steps with 3487 atoms -99.9% CPU use with 1 MPI tasks x no OpenMP threads +99.5% CPU use with 1 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 19.625 | 19.625 | 19.625 | 0.0 | 96.66 -Neigh | 0.57013 | 0.57013 | 0.57013 | 0.0 | 2.81 -Comm | 0.0014448 | 0.0014448 | 0.0014448 | 0.0 | 0.01 -Output | 0.00024772 | 0.00024772 | 0.00024772 | 0.0 | 0.00 -Modify | 0.092173 | 0.092173 | 0.092173 | 0.0 | 0.45 -Other | | 0.01359 | | | 0.07 +Pair | 27.721 | 27.721 | 27.721 | 0.0 | 97.04 +Neigh | 0.66353 | 0.66353 | 0.66353 | 0.0 | 2.32 +Comm | 0.0027969 | 0.0027969 | 0.0027969 | 0.0 | 0.01 +Output | 0.00042295 | 0.00042295 | 0.00042295 | 0.0 | 0.00 +Modify | 0.1566 | 0.1566 | 0.1566 | 0.0 | 0.55 +Other | | 0.02086 | | | 0.07 Nlocal: 3487 ave 3487 max 3487 min Histogram: 1 0 0 0 0 0 0 0 0 0 Nghost: 0 ave 0 max 0 min Histogram: 1 0 0 0 0 0 0 0 0 0 -Neighs: 567140 ave 567140 max 567140 min +Neighs: 567132 ave 567132 max 567132 min Histogram: 1 0 0 0 0 0 0 0 0 0 FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min Histogram: 1 0 0 0 0 0 0 0 0 0 @@ -101,4 +112,4 @@ Dangerous builds = 0 Please see the log.cite file for references relevant to this simulation -Total wall time: 0:00:20 +Total wall time: 0:00:28 diff --git a/examples/peri/log.5Oct16.peri.g++.4 b/examples/peri/log.6Jul17.peri.pmb.g++.4 similarity index 58% rename from examples/peri/log.5Oct16.peri.g++.4 rename to examples/peri/log.6Jul17.peri.pmb.g++.4 index cb478772af..637b2cc26a 100644 --- a/examples/peri/log.5Oct16.peri.g++.4 +++ b/examples/peri/log.6Jul17.peri.pmb.g++.4 @@ -1,10 +1,11 @@ -LAMMPS (5 Oct 2016) +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task # small Peridynamic cylinder hit by projectile -units si +units si boundary s s s atom_style peri -atom_modify map array +atom_modify map array neighbor 0.0010 bin # small target @@ -41,24 +42,34 @@ thermo 100 #dump 1 all custom 100 dump.peri id type x y z c_1 -#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 -#dump_modify 2 pad 4 +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 -#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 -#dump_modify 3 pad 4 +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 run 1000 Neighbor list info ... - 2 neighbor list requests update every 1 steps, delay 10 steps, check yes max neighbors/atom: 2000, page size: 100000 master list distance cutoff = 0.0025001 ghost atom cutoff = 0.0025001 - binsize = 0.00125005 -> bins = 9 5 9 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/pmb, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard Peridynamic bonds: total # of bonds = 335966 bonds/atom = 96.3482 -Memory usage per processor = 26.9049 Mbytes +Per MPI rank memory allocation (min/avg/max) = 29.27 | 29.54 | 29.64 Mbytes Step Temp E_pair E_mol TotEng Press Volume 0 0 0 0 0 0 5.0030006e-07 100 1.7890585e+24 552721.8 0 681881.47 1.7210968e+11 5.0030006e-07 @@ -68,29 +79,29 @@ Step Temp E_pair E_mol TotEng Press Volume 500 4.2580877e+27 20212686 0 3.2762196e+08 1.6249923e+14 1.2611723e-06 600 5.5126512e+27 30861342 0 4.2884284e+08 1.7320038e+14 1.531873e-06 700 1.1807414e+28 23119941 0 8.7554687e+08 2.9477434e+14 1.9278632e-06 - 800 1.2424839e+28 2407361.5 0 8.994088e+08 2.3787786e+14 2.5138992e-06 - 900 1.2358395e+28 4532520.1 0 8.9673706e+08 1.9097312e+14 3.1145903e-06 - 1000 1.2341057e+28 3219974.3 0 8.9417286e+08 1.5968598e+14 3.7196039e-06 -Loop time of 5.91321 on 4 procs for 1000 steps with 3487 atoms + 800 1.2424839e+28 2407365.2 0 8.994088e+08 2.3787786e+14 2.5138992e-06 + 900 1.2358397e+28 4532423 0 8.9673716e+08 1.9097316e+14 3.1145903e-06 + 1000 1.2341048e+28 3219408.7 0 8.9417158e+08 1.5968585e+14 3.7196039e-06 +Loop time of 9.59889 on 4 procs for 1000 steps with 3487 atoms -99.6% CPU use with 4 MPI tasks x no OpenMP threads +99.2% CPU use with 4 MPI tasks x 1 OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 4.5763 | 5.0164 | 5.502 | 15.8 | 84.83 -Neigh | 0.11212 | 0.14636 | 0.1811 | 7.8 | 2.48 -Comm | 0.18545 | 0.70922 | 1.1869 | 45.6 | 11.99 -Output | 0.00026011 | 0.00030977 | 0.00038433 | 0.3 | 0.01 -Modify | 0.028668 | 0.029356 | 0.030043 | 0.4 | 0.50 -Other | | 0.01158 | | | 0.20 +Pair | 7.9131 | 8.1341 | 8.3286 | 6.7 | 84.74 +Neigh | 0.19736 | 0.22539 | 0.25643 | 5.6 | 2.35 +Comm | 0.92843 | 1.1536 | 1.402 | 18.4 | 12.02 +Output | 0.00053358 | 0.00059688 | 0.00070548 | 0.0 | 0.01 +Modify | 0.060774 | 0.06358 | 0.068375 | 1.2 | 0.66 +Other | | 0.02165 | | | 0.23 -Nlocal: 871.75 ave 920 max 824 min -Histogram: 1 0 0 1 0 0 1 0 0 1 -Nghost: 1343.25 ave 1391 max 1295 min -Histogram: 1 0 0 1 0 0 1 0 0 1 -Neighs: 141785 ave 170754 max 115891 min -Histogram: 1 1 0 0 0 0 0 1 0 1 +Nlocal: 871.75 ave 920 max 829 min +Histogram: 1 0 0 0 2 0 0 0 0 1 +Nghost: 1343.25 ave 1386 max 1295 min +Histogram: 1 0 0 0 0 2 0 0 0 1 +Neighs: 141783 ave 157099 max 127518 min +Histogram: 2 0 0 0 0 0 0 0 1 1 FullNghs: 302269 ave 346070 max 260820 min Histogram: 1 0 0 0 2 0 0 0 0 1 @@ -101,4 +112,4 @@ Dangerous builds = 0 Please see the log.cite file for references relevant to this simulation -Total wall time: 0:00:05 +Total wall time: 0:00:09 diff --git a/examples/peri/log.6Jul17.peri.ves.g++.1 b/examples/peri/log.6Jul17.peri.ves.g++.1 new file mode 100644 index 0000000000..3d1d156d4a --- /dev/null +++ b/examples/peri/log.6Jul17.peri.ves.g++.1 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 1 by 1 by 1 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/ves +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/ves, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 65.41 | 65.41 | 65.41 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 8.3392177e+24 247040.57 0 849083.8 8.0224286e+11 5.0030006e-07 + 200 1.1849022e+27 1158030.5 0 86701105 1.0301578e+14 5.5359205e-07 + 300 2.6287222e+27 4389155.1 0 1.9416767e+08 1.6636212e+14 7.6050375e-07 + 400 3.2718778e+27 7458219 0 2.4366885e+08 1.5439709e+14 1.0199269e-06 + 500 3.8413187e+27 6151611.4 0 2.8347258e+08 1.5008974e+14 1.2318007e-06 + 600 6.1409926e+27 18424316 0 4.6176842e+08 1.9507512e+14 1.5151227e-06 + 700 1.0046131e+28 11478344 0 7.3675086e+08 2.4228512e+14 1.9956447e-06 + 800 1.0402132e+28 4421233.6 0 7.5539495e+08 2.0512303e+14 2.4407262e-06 + 900 1.0419515e+28 7223261.3 0 7.594519e+08 1.6647307e+14 3.0124137e-06 + 1000 1.0503737e+28 2621490.6 0 7.6093049e+08 1.4315634e+14 3.5313793e-06 +Loop time of 77.2175 on 1 procs for 1000 steps with 3487 atoms + +99.4% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 76.421 | 76.421 | 76.421 | 0.0 | 98.97 +Neigh | 0.56616 | 0.56616 | 0.56616 | 0.0 | 0.73 +Comm | 0.0038247 | 0.0038247 | 0.0038247 | 0.0 | 0.00 +Output | 0.00051951 | 0.00051951 | 0.00051951 | 0.0 | 0.00 +Modify | 0.19434 | 0.19434 | 0.19434 | 0.0 | 0.25 +Other | | 0.03197 | | | 0.04 + +Nlocal: 3487 ave 3487 max 3487 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 561942 ave 561942 max 561942 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 1.20908e+06 ave 1.20908e+06 max 1.20908e+06 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 37 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:01:17 diff --git a/examples/peri/log.6Jul17.peri.ves.g++.4 b/examples/peri/log.6Jul17.peri.ves.g++.4 new file mode 100644 index 0000000000..bd05d58e9f --- /dev/null +++ b/examples/peri/log.6Jul17.peri.ves.g++.4 @@ -0,0 +1,115 @@ +LAMMPS (6 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# small Peridynamic cylinder hit by projectile + +units si +boundary s s s +atom_style peri +atom_modify map array +neighbor 0.0010 bin + +# small target + +lattice sc 0.0005 +Lattice spacing in x,y,z = 0.0005 0.0005 0.0005 +region target cylinder y 0.0 0.0 0.0050 -0.0050 0.0 units box +create_box 1 target +Created orthogonal box = (-0.005 -0.005 -0.005) to (0.005 0 0.005) + 2 by 1 by 2 MPI processor grid +create_atoms 1 region target +Created 3487 atoms + +pair_style peri/ves +pair_coeff * * 14.9e9 14.9e9 0.0015001 0.0005 0.25 0.5 0.001 +set group all density 2200 + 3487 settings made for density +set group all volume 1.25e-10 + 3487 settings made for volume +velocity all set 0.0 0.0 0.0 sum no units box +fix 1 all nve + +# spherical indenter to shatter target + +variable y0 equal 0.00155 +variable vy equal -100 +variable y equal "v_y0 + step*dt*v_vy" + +fix 2 all indent 1e17 sphere 0.0000 v_y 0.0000 0.0015 units box + +compute 1 all damage/atom +timestep 1.0e-7 +thermo 100 + +#dump 1 all custom 100 dump.peri id type x y z c_1 + +#dump 2 all image 50 image.*.jpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 2 pad 4 + +#dump 3 all movie 50 movie.mpg type type # axes yes 0.8 0.02 view 80 -30 adiam 0.0006 +#dump_modify 3 pad 4 + +run 1000 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0.0025001 + ghost atom cutoff = 0.0025001 + binsize = 0.00125005, bins = 9 5 9 + 2 neighbor lists, perpetual/occasional/extra = 1 1 0 + (1) pair peri/ves, perpetual + attributes: half, newton on + pair build: half/bin/atomonly/newton + stencil: half/bin/3d/newton + bin: standard + (2) fix PERI_NEIGH, occasional + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Peridynamic bonds: + total # of bonds = 335966 + bonds/atom = 96.3482 +Per MPI rank memory allocation (min/avg/max) = 59.9 | 60.16 | 60.26 Mbytes +Step Temp E_pair E_mol TotEng Press Volume + 0 0 0 0 0 0 5.0030006e-07 + 100 8.3392177e+24 247040.57 0 849083.8 8.0224286e+11 5.0030006e-07 + 200 1.1849022e+27 1158030.5 0 86701105 1.0301578e+14 5.5359205e-07 + 300 2.6287222e+27 4389155.1 0 1.9416767e+08 1.6636212e+14 7.6050375e-07 + 400 3.2718778e+27 7458219 0 2.4366885e+08 1.5439709e+14 1.0199269e-06 + 500 3.8413187e+27 6151611.4 0 2.8347258e+08 1.5008974e+14 1.2318007e-06 + 600 6.1409926e+27 18424316 0 4.6176842e+08 1.9507512e+14 1.5151227e-06 + 700 1.0046131e+28 11478344 0 7.3675086e+08 2.4228512e+14 1.9956447e-06 + 800 1.0402132e+28 4421233.6 0 7.5539495e+08 2.0512303e+14 2.4407262e-06 + 900 1.0419515e+28 7223258.7 0 7.594519e+08 1.6647307e+14 3.0124137e-06 + 1000 1.0503738e+28 2621480.4 0 7.6093057e+08 1.4315636e+14 3.5313793e-06 +Loop time of 25.9768 on 4 procs for 1000 steps with 3487 atoms + +99.1% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 22.455 | 23.348 | 24.175 | 14.1 | 89.88 +Neigh | 0.14472 | 0.18294 | 0.2299 | 8.6 | 0.70 +Comm | 1.4715 | 2.3485 | 3.2075 | 44.8 | 9.04 +Output | 0.000489 | 0.00059682 | 0.0007987 | 0.0 | 0.00 +Modify | 0.063634 | 0.071411 | 0.076907 | 1.9 | 0.27 +Other | | 0.02506 | | | 0.10 + +Nlocal: 871.75 ave 896 max 852 min +Histogram: 2 0 0 0 0 0 0 1 0 1 +Nghost: 1293.25 ave 1313 max 1269 min +Histogram: 1 0 1 0 0 0 0 0 0 2 +Neighs: 140486 ave 167239 max 121255 min +Histogram: 2 0 0 0 0 0 1 0 0 1 +FullNghs: 302269 ave 346070 max 260820 min +Histogram: 1 0 0 0 2 0 0 0 0 1 + +Total # of neighbors = 1209076 +Ave neighs/atom = 346.738 +Neighbor list builds = 37 +Dangerous builds = 0 + +Please see the log.cite file for references relevant to this simulation + +Total wall time: 0:00:26 From 522bc13d678627d3e4af071f4a0daf1231f06021 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 13:47:49 -0400 Subject: [PATCH 083/293] avoid casts to the wrong derived class, which upsets code analysis tools. seems to improve performance, too. --- src/PERI/fix_peri_neigh.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/PERI/fix_peri_neigh.cpp b/src/PERI/fix_peri_neigh.cpp index a84ce31609..d92f355c53 100644 --- a/src/PERI/fix_peri_neigh.cpp +++ b/src/PERI/fix_peri_neigh.cpp @@ -302,9 +302,15 @@ void FixPeriNeigh::setup(int vflag) double **x0 = atom->x0; double half_lc = 0.5*(domain->lattice->xlattice); double vfrac_scale; - PairPeriLPS *pairlps = static_cast(anypair); - PairPeriVES *pairves = static_cast(anypair); - PairPeriEPS *paireps = static_cast(anypair); + PairPeriLPS *pairlps = NULL; + PairPeriVES *pairves = NULL; + PairPeriEPS *paireps = NULL; + if (isLPS) + pairlps = static_cast(anypair); + else if (isVES) + pairves = static_cast(anypair); + else if (isEPS) + paireps = static_cast(anypair); for (i = 0; i < nlocal; i++) { double xtmp0 = x0[i][0]; From e084d4dad633b3fac81a9b66b0081507aa3b2b81 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 13:48:21 -0400 Subject: [PATCH 084/293] print warnings in Pair::init() only on MPI rank 0 --- src/pair.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pair.cpp b/src/pair.cpp index 06792060ce..ce711c4f5d 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -196,10 +196,10 @@ void Pair::init() error->all(FLERR,"Cannot use pair tail corrections with 2d simulations"); if (tail_flag && domain->nonperiodic && comm->me == 0) error->warning(FLERR,"Using pair tail corrections with nonperiodic system"); - if (!compute_flag && tail_flag) + if (!compute_flag && tail_flag && comm->me == 0) error->warning(FLERR,"Using pair tail corrections with " "pair_modify compute no"); - if (!compute_flag && offset_flag) + if (!compute_flag && offset_flag && comm->me == 0) error->warning(FLERR,"Using pair potential shift with " "pair_modify compute no"); From a04711b21f06b78270f852bb62beed12eb7e4475 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 13:49:28 -0400 Subject: [PATCH 085/293] do not allow pairwise cutoffs <= 0.0. avoids undefined behavior and division by zero errors --- src/pair.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pair.cpp b/src/pair.cpp index ce711c4f5d..21c8fe00e5 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -242,6 +242,7 @@ void Pair::init() for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { cut = init_one(i,j); + if (cut <= 0.0) error->all(FLERR,"Illegal pair style cutoff <= 0.0"); cutsq[i][j] = cutsq[j][i] = cut*cut; cutforce = MAX(cutforce,cut); if (tail_flag) { From 1c92eecea7fca7ac5c479c5cfd0cf7436d38d19a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 14:01:41 -0400 Subject: [PATCH 086/293] move updated gauss_flow example to the correct folder --- examples/USER/flow_gauss/README | 45 --- examples/USER/flow_gauss/in.GD | 262 ------------------ examples/USER/misc/flow_gauss/README | 52 ++-- examples/USER/misc/flow_gauss/in.GD | 254 ++++++++--------- .../{ => misc}/flow_gauss/log.6Jul17.GD.g++.1 | 0 .../{ => misc}/flow_gauss/log.6Jul17.GD.g++.4 | 0 .../{ => misc}/flow_gauss/output-files/GD.out | 0 .../flow_gauss/output-files/Vy_profile | 0 .../flow_gauss/output-files/x_profiles | 0 9 files changed, 155 insertions(+), 458 deletions(-) delete mode 100644 examples/USER/flow_gauss/README delete mode 100644 examples/USER/flow_gauss/in.GD mode change 100755 => 100644 examples/USER/misc/flow_gauss/in.GD rename examples/USER/{ => misc}/flow_gauss/log.6Jul17.GD.g++.1 (100%) rename examples/USER/{ => misc}/flow_gauss/log.6Jul17.GD.g++.4 (100%) rename examples/USER/{ => misc}/flow_gauss/output-files/GD.out (100%) rename examples/USER/{ => misc}/flow_gauss/output-files/Vy_profile (100%) rename examples/USER/{ => misc}/flow_gauss/output-files/x_profiles (100%) diff --git a/examples/USER/flow_gauss/README b/examples/USER/flow_gauss/README deleted file mode 100644 index ef7cc82d96..0000000000 --- a/examples/USER/flow_gauss/README +++ /dev/null @@ -1,45 +0,0 @@ -The input script in.GD is an example simulation using Gaussian dynamics (GD). -The simulation is of a simple 2d Lennard-Jones fluid flowing through a pipe. -For details see online LAMMPS documentation and -Strong and Eaves, J. Phys. Chem. Lett. 7(10) 2016, p. 1907. - -Note that the run times and box size are chosen to allow a fast example run. -They are not adequate for a real simulation. - -The script has the following parts: -1) initialize variables - These can be modified to customize the simulation. Note that if the - pipe dimensions L or d are changed, the geometry should be checked - by visualizing the coordinates in all.init.lammpstrj. - -2) create box - -3) set up potential - -4) create atoms - -5) set up profile-unbiased thermostat (PUT) - see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 - By default, this uses boxes which contain on average 8 molecules. - -6) equilibrate without GD - -7) initialize the center-of-mass velocity and run to achieve steady-state - The system is initialized with a uniform velocity profile, which - relaxes over the course of the simulation. - -8) collect data - The data is output in several files: - GD.out contains the force that GD applies, and the flux in the x- and - y- directions. The output Jx should be equal to the value of - J set in section 1, which is 0.1 by default. - x_profiles contains the velocity, density, and pressure profiles in - the x-direction. The pressure profile is given by - (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a - slice. The pressure profile is computed with IK1, see - Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627. - Note that to compare with the pump method, or to - compute a pressure drop, you must correct this pressure - profile as described in Strong 2016 above. - Vy_profile is the velocity profile inside the pipe along the - y-direction, u_x(y). diff --git a/examples/USER/flow_gauss/in.GD b/examples/USER/flow_gauss/in.GD deleted file mode 100644 index bcff4d4c57..0000000000 --- a/examples/USER/flow_gauss/in.GD +++ /dev/null @@ -1,262 +0,0 @@ -#LAMMPS input script -#in.GD -#see README for details - -############################################################################### -#initialize variables -clear - -#frequency for outputting info (timesteps) -variable dump_rate equal 50 -variable thermo_rate equal 10 - -#equilibration time (timesteps) -variable equil equal 1000 - -#stabilization time (timesteps to reach steady-state) -variable stabil equal 1000 - -#data collection time (timesteps) -variable run equal 2000 - -#length of pipe -variable L equal 30 - -#width of pipe -variable d equal 20 - -#flux (mass/sigma*tau) -variable J equal 0.1 - -#simulation box dimensions -variable Lx equal 100 -variable Ly equal 40 - -#bulk fluid density -variable dens equal 0.8 - -#lattice spacing for wall atoms -variable aWall equal 1.0 #1.7472 - -#timestep -variable ts equal 0.001 - -#temperature -variable T equal 2.0 - -#thermostat damping constant -variable tdamp equal ${ts}*100 - -units lj -dimension 2 -atom_style atomic - - -############################################################################### -#create box - -#create lattice with the spacing aWall -variable rhoWall equal ${aWall}^(-2) -lattice sq ${rhoWall} - -#modify input dimensions to be multiples of aWall -variable L1 equal round($L/${aWall})*${aWall} -variable d1 equal round($d/${aWall})*${aWall} -variable Ly1 equal round(${Ly}/${aWall})*${aWall} -variable Lx1 equal round(${Lx}/${aWall})*${aWall} - -#create simulation box -variable lx2 equal ${Lx1}/2 -variable ly2 equal ${Ly1}/2 -region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box -create_box 2 simbox - -##################################################################### -#set up potential - -mass 1 1.0 #fluid atoms -mass 2 1.0 #wall atoms - -pair_style lj/cut 2.5 -pair_modify shift yes -pair_coeff 1 1 1.0 1.0 2.5 -pair_coeff 1 2 1.0 1.0 1.12246 -pair_coeff 2 2 0.0 0.0 - -neigh_modify exclude type 2 2 - -timestep ${ts} - -##################################################################### -#create atoms - -#create wall atoms everywhere -create_atoms 2 box - -#define region which is "walled off" -variable dhalf equal ${d1}/2 -variable Lhalf equal ${L1}/2 -region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 & - units box -region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 & - units box -region outsidewall union 2 walltop wallbot side out - -#remove wall atoms outside wall region -group outside region outsidewall -delete_atoms group outside - -#remove wall atoms that aren't on edge of wall region -variable x1 equal ${Lhalf}-${aWall} -variable y1 equal ${dhalf}+${aWall} -region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box -region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box -region insideWall union 2 insideTop insideBot -group insideWall region insideWall -delete_atoms group insideWall - -#define new lattice, to give correct fluid density -#y lattice const must be a multiple of aWall -variable atrue equal ${dens}^(-1/2) -variable ay equal round(${atrue}/${aWall})*${aWall} - -#choose x lattice const to give correct density -variable ax equal (${ay}*${dens})^(-1) - -#change Lx to be multiple of ax -variable Lx1 equal round(${Lx}/${ax})*${ax} -variable lx2 equal ${Lx1}/2 -change_box all x final -${lx2} ${lx2} units box - -#define new lattice -lattice custom ${dens} & - a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 & - basis 0.0 0.0 0.0 - -#fill in rest of box with bulk particles -variable delta equal 0.001 -variable Ldelt equal ${Lhalf}+${delta} -variable dDelt equal ${dhalf}-${delta} -region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box -region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box -region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 & - units box - -region bulk union 3 left pipe right -create_atoms 1 region bulk - -group bulk type 1 -group wall type 2 - -#remove atoms that are too close to wall -delete_atoms overlap 0.9 bulk wall - -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes -neigh_modify exclude group wall wall - -velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom - -##################################################################### -#set up PUT -#see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 - -#average number of particles per box, Evans and Morriss used 2.0 -variable NperBox equal 8.0 - -#calculate box sizes -variable boxSide equal sqrt(${NperBox}/${dens}) -variable nX equal round(lx/${boxSide}) -variable nY equal round(ly/${boxSide}) -variable dX equal lx/${nX} -variable dY equal ly/${nY} - -#temperature of fluid (excluding wall) -compute myT bulk temp - -#profile-unbiased temperature of fluid -compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} - -#thermo setup -thermo ${thermo_rate} -thermo_style custom step c_myT c_myTp etotal press - -#dump initial configuration -# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz -# dump 56 wall custom 1 wall.init.lammpstrj id type x y z -# dump_modify 55 sort id -# dump_modify 56 sort id -run 0 -# undump 55 -# undump 56 - -##################################################################### -#equilibrate without GD - -fix nvt bulk nvt temp $T $T ${tdamp} -fix_modify nvt temp myTp -fix 2 bulk enforce2d - -run ${equil} - -##################################################################### -#initialize the COM velocity and run to achieve steady-state - -#calculate velocity to add: V=J/rho_total -variable Vadd equal $J*lx*ly/count(bulk) - -#first remove any COM velocity, then add back the streaming velocity -velocity bulk zero linear -velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no - -fix GD bulk flow/gauss 1 0 0 #energy yes -#fix_modify GD energy yes - -run ${stabil} - -##################################################################### -#collect data - -#print the applied force and total flux to ensure conservation of Jx -variable Fapp equal f_GD[1] -compute vxBulk bulk reduce sum vx -compute vyBulk bulk reduce sum vy -variable invVol equal 1.0/(lx*ly) -variable jx equal c_vxBulk*${invVol} -variable jy equal c_vyBulk*${invVol} -variable curr_step equal step -variable p_Fapp format Fapp %.3f -variable p_jx format jx %.5g -variable p_jy format jy %.5g -fix print_vCOM all print ${dump_rate} & - "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no & - title "timestep Fapp Jx Jy" - -#compute IK1 pressure profile -#see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627 -#use profile-unbiased temperature to remove the streaming velocity -#from the kinetic part of the pressure -compute spa bulk stress/atom myTp - -#for the pressure profile, use the same grid as the PUT -compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box - -#output pressure profile and other profiles -#the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where -#V is the volume of a slice -fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX & - vx density/mass c_spa[1] c_spa[2] & - file x_profiles ave running overwrite - -#compute velocity profile across the pipe with a finer grid -variable dYnew equal ${dY}/10 -compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box & - region pipe -fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY & - vx file Vy_profile ave running overwrite - -#full trajectory -# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z -# dump_modify 7 sort id - -run ${run} diff --git a/examples/USER/misc/flow_gauss/README b/examples/USER/misc/flow_gauss/README index 4966cd2dc9..ef7cc82d96 100644 --- a/examples/USER/misc/flow_gauss/README +++ b/examples/USER/misc/flow_gauss/README @@ -1,45 +1,45 @@ The input script in.GD is an example simulation using Gaussian dynamics (GD). The simulation is of a simple 2d Lennard-Jones fluid flowing through a pipe. -For details see online LAMMPS documentation and +For details see online LAMMPS documentation and Strong and Eaves, J. Phys. Chem. Lett. 7(10) 2016, p. 1907. -Note that the run times and box size are chosen to allow a fast example run. -They are not adequate for a real simulation. +Note that the run times and box size are chosen to allow a fast example run. +They are not adequate for a real simulation. The script has the following parts: 1) initialize variables - These can be modified to customize the simulation. Note that if the - pipe dimensions L or d are changed, the geometry should be checked - by visualizing the coordinates in all.init.lammpstrj. + These can be modified to customize the simulation. Note that if the + pipe dimensions L or d are changed, the geometry should be checked + by visualizing the coordinates in all.init.lammpstrj. 2) create box - + 3) set up potential 4) create atoms 5) set up profile-unbiased thermostat (PUT) - see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 - By default, this uses boxes which contain on average 8 molecules. + see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 + By default, this uses boxes which contain on average 8 molecules. 6) equilibrate without GD - + 7) initialize the center-of-mass velocity and run to achieve steady-state - The system is initialized with a uniform velocity profile, which - relaxes over the course of the simulation. + The system is initialized with a uniform velocity profile, which + relaxes over the course of the simulation. 8) collect data - The data is output in several files: - GD.out contains the force that GD applies, and the flux in the x- and - y- directions. The output Jx should be equal to the value of - J set in section 1, which is 0.1 by default. - x_profiles contains the velocity, density, and pressure profiles in - the x-direction. The pressure profile is given by - (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a - slice. The pressure profile is computed with IK1, see - Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627. - Note that to compare with the pump method, or to - compute a pressure drop, you must correct this pressure - profile as described in Strong 2016 above. - Vy_profile is the velocity profile inside the pipe along the - y-direction, u_x(y). + The data is output in several files: + GD.out contains the force that GD applies, and the flux in the x- and + y- directions. The output Jx should be equal to the value of + J set in section 1, which is 0.1 by default. + x_profiles contains the velocity, density, and pressure profiles in + the x-direction. The pressure profile is given by + (-1/2V)*(c_spa[1] + c_spa[2]), where V is the volume of a + slice. The pressure profile is computed with IK1, see + Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627. + Note that to compare with the pump method, or to + compute a pressure drop, you must correct this pressure + profile as described in Strong 2016 above. + Vy_profile is the velocity profile inside the pipe along the + y-direction, u_x(y). diff --git a/examples/USER/misc/flow_gauss/in.GD b/examples/USER/misc/flow_gauss/in.GD old mode 100755 new mode 100644 index 8117715c12..bcff4d4c57 --- a/examples/USER/misc/flow_gauss/in.GD +++ b/examples/USER/misc/flow_gauss/in.GD @@ -7,83 +7,85 @@ clear #frequency for outputting info (timesteps) -variable dump_rate equal 50 -variable thermo_rate equal 10 +variable dump_rate equal 50 +variable thermo_rate equal 10 #equilibration time (timesteps) -variable equil equal 1000 +variable equil equal 1000 #stabilization time (timesteps to reach steady-state) -variable stabil equal 1000 +variable stabil equal 1000 #data collection time (timesteps) -variable run equal 2000 +variable run equal 2000 #length of pipe -variable L equal 30 +variable L equal 30 #width of pipe -variable d equal 20 +variable d equal 20 #flux (mass/sigma*tau) -variable J equal 0.1 +variable J equal 0.1 #simulation box dimensions -variable Lx equal 100 -variable Ly equal 40 +variable Lx equal 100 +variable Ly equal 40 #bulk fluid density -variable dens equal 0.8 +variable dens equal 0.8 #lattice spacing for wall atoms -variable aWall equal 1.0 #1.7472 +variable aWall equal 1.0 #1.7472 #timestep -variable ts equal 0.001 +variable ts equal 0.001 #temperature -variable T equal 2.0 +variable T equal 2.0 #thermostat damping constant -variable tdamp equal ${ts}*100 +variable tdamp equal ${ts}*100 -units lj -dimension 2 -atom_style atomic +units lj +dimension 2 +atom_style atomic ############################################################################### #create box #create lattice with the spacing aWall -variable rhoWall equal ${aWall}^(-2) -lattice sq ${rhoWall} +variable rhoWall equal ${aWall}^(-2) +lattice sq ${rhoWall} #modify input dimensions to be multiples of aWall -variable L1 equal round($L/${aWall})*${aWall} -variable d1 equal round($d/${aWall})*${aWall} -variable Ly1 equal round(${Ly}/${aWall})*${aWall} -variable Lx1 equal round(${Lx}/${aWall})*${aWall} +variable L1 equal round($L/${aWall})*${aWall} +variable d1 equal round($d/${aWall})*${aWall} +variable Ly1 equal round(${Ly}/${aWall})*${aWall} +variable Lx1 equal round(${Lx}/${aWall})*${aWall} #create simulation box -variable lx2 equal ${Lx1}/2 -variable ly2 equal ${Ly1}/2 -region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box -create_box 2 simbox +variable lx2 equal ${Lx1}/2 +variable ly2 equal ${Ly1}/2 +region simbox block -${lx2} ${lx2} -${ly2} ${ly2} 0 0.1 units box +create_box 2 simbox ##################################################################### #set up potential -mass 1 1.0 #fluid atoms -mass 2 1.0 #wall atoms +mass 1 1.0 #fluid atoms +mass 2 1.0 #wall atoms -pair_style lj/cut 2.5 -pair_modify shift yes -pair_coeff 1 1 1.0 1.0 2.5 -pair_coeff 1 2 1.0 1.0 1.12246 -pair_coeff 2 2 0.0 0.0 0.0 +pair_style lj/cut 2.5 +pair_modify shift yes +pair_coeff 1 1 1.0 1.0 2.5 +pair_coeff 1 2 1.0 1.0 1.12246 +pair_coeff 2 2 0.0 0.0 -timestep ${ts} +neigh_modify exclude type 2 2 + +timestep ${ts} ##################################################################### #create atoms @@ -92,167 +94,169 @@ timestep ${ts} create_atoms 2 box #define region which is "walled off" -variable dhalf equal ${d1}/2 -variable Lhalf equal ${L1}/2 -region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 & - units box -region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 & - units box -region outsidewall union 2 walltop wallbot side out +variable dhalf equal ${d1}/2 +variable Lhalf equal ${L1}/2 +region walltop block -${Lhalf} ${Lhalf} ${dhalf} EDGE -0.1 0.1 & + units box +region wallbot block -${Lhalf} ${Lhalf} EDGE -${dhalf} -0.1 0.1 & + units box +region outsidewall union 2 walltop wallbot side out #remove wall atoms outside wall region -group outside region outsidewall -delete_atoms group outside +group outside region outsidewall +delete_atoms group outside #remove wall atoms that aren't on edge of wall region -variable x1 equal ${Lhalf}-${aWall} -variable y1 equal ${dhalf}+${aWall} -region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box -region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box -region insideWall union 2 insideTop insideBot -group insideWall region insideWall -delete_atoms group insideWall +variable x1 equal ${Lhalf}-${aWall} +variable y1 equal ${dhalf}+${aWall} +region insideTop block -${x1} ${x1} ${y1} EDGE -0.1 0.1 units box +region insideBot block -${x1} ${x1} EDGE -${y1} -0.1 0.1 units box +region insideWall union 2 insideTop insideBot +group insideWall region insideWall +delete_atoms group insideWall #define new lattice, to give correct fluid density #y lattice const must be a multiple of aWall -variable atrue equal ${dens}^(-1/2) -variable ay equal round(${atrue}/${aWall})*${aWall} +variable atrue equal ${dens}^(-1/2) +variable ay equal round(${atrue}/${aWall})*${aWall} #choose x lattice const to give correct density -variable ax equal (${ay}*${dens})^(-1) +variable ax equal (${ay}*${dens})^(-1) #change Lx to be multiple of ax -variable Lx1 equal round(${Lx}/${ax})*${ax} -variable lx2 equal ${Lx1}/2 -change_box all x final -${lx2} ${lx2} units box +variable Lx1 equal round(${Lx}/${ax})*${ax} +variable lx2 equal ${Lx1}/2 +change_box all x final -${lx2} ${lx2} units box #define new lattice -lattice custom ${dens} & - a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 & - basis 0.0 0.0 0.0 +lattice custom ${dens} & + a1 ${ax} 0.0 0.0 a2 0.0 ${ay} 0.0 a3 0.0 0.0 1.0 & + basis 0.0 0.0 0.0 #fill in rest of box with bulk particles -variable delta equal 0.001 -variable Ldelt equal ${Lhalf}+${delta} -variable dDelt equal ${dhalf}-${delta} -region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box -region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box -region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 & - units box +variable delta equal 0.001 +variable Ldelt equal ${Lhalf}+${delta} +variable dDelt equal ${dhalf}-${delta} +region left block EDGE -${Ldelt} EDGE EDGE -0.1 0.1 units box +region right block ${Ldelt} EDGE EDGE EDGE -0.1 0.1 units box +region pipe block -${Ldelt} ${Ldelt} -${dDelt} ${dDelt} -0.1 0.1 & + units box -region bulk union 3 left pipe right -create_atoms 1 region bulk +region bulk union 3 left pipe right +create_atoms 1 region bulk -group bulk type 1 -group wall type 2 +group bulk type 1 +group wall type 2 #remove atoms that are too close to wall delete_atoms overlap 0.9 bulk wall -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes neigh_modify exclude group wall wall -velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom +velocity bulk create $T 78915 dist gaussian rot yes mom yes loop geom ##################################################################### #set up PUT #see Evans and Morriss, Phys. Rev. Lett. 56(20) 1986, p. 2172 #average number of particles per box, Evans and Morriss used 2.0 -variable NperBox equal 8.0 +variable NperBox equal 8.0 #calculate box sizes -variable boxSide equal sqrt(${NperBox}/${dens}) -variable nX equal round(lx/${boxSide}) -variable nY equal round(ly/${boxSide}) -variable dX equal lx/${nX} -variable dY equal ly/${nY} +variable boxSide equal sqrt(${NperBox}/${dens}) +variable nX equal round(lx/${boxSide}) +variable nY equal round(ly/${boxSide}) +variable dX equal lx/${nX} +variable dY equal ly/${nY} #temperature of fluid (excluding wall) -compute myT bulk temp +compute myT bulk temp #profile-unbiased temperature of fluid -compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} +compute myTp bulk temp/profile 1 1 0 xy ${nX} ${nY} #thermo setup -thermo ${thermo_rate} -thermo_style custom step c_myT c_myTp etotal press +thermo ${thermo_rate} +thermo_style custom step c_myT c_myTp etotal press #dump initial configuration -dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz -dump 56 wall custom 1 wall.init.lammpstrj id type x y z -dump_modify 55 sort id -dump_modify 56 sort id -run 0 -undump 55 -undump 56 +# dump 55 all custom 1 all.init.lammpstrj id type x y z vx vy vz +# dump 56 wall custom 1 wall.init.lammpstrj id type x y z +# dump_modify 55 sort id +# dump_modify 56 sort id +run 0 +# undump 55 +# undump 56 ##################################################################### #equilibrate without GD -fix nvt bulk nvt temp $T $T ${tdamp} -fix_modify nvt temp myTp -fix 2 bulk enforce2d +fix nvt bulk nvt temp $T $T ${tdamp} +fix_modify nvt temp myTp +fix 2 bulk enforce2d -run ${equil} +run ${equil} ##################################################################### #initialize the COM velocity and run to achieve steady-state #calculate velocity to add: V=J/rho_total -variable Vadd equal $J*lx*ly/count(bulk) +variable Vadd equal $J*lx*ly/count(bulk) #first remove any COM velocity, then add back the streaming velocity velocity bulk zero linear -velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no +velocity bulk set ${Vadd} 0.0 0.0 units box sum yes mom no -fix GD bulk flow/gauss 1 0 0 #energy yes -#fix_modify GD energy yes +fix GD bulk flow/gauss 1 0 0 #energy yes +#fix_modify GD energy yes -run ${stabil} +run ${stabil} ##################################################################### #collect data #print the applied force and total flux to ensure conservation of Jx -variable Fapp equal f_GD[1] -compute vxBulk bulk reduce sum vx -compute vyBulk bulk reduce sum vy +variable Fapp equal f_GD[1] +compute vxBulk bulk reduce sum vx +compute vyBulk bulk reduce sum vy variable invVol equal 1.0/(lx*ly) -variable jx equal c_vxBulk*${invVol} -variable jy equal c_vyBulk*${invVol} -variable curr_step equal step -fix print_vCOM all print ${dump_rate} & - "${curr_step} ${Fapp} ${jx} ${jy}" file GD.out screen no & - title "timestep Fapp Jx Jy" +variable jx equal c_vxBulk*${invVol} +variable jy equal c_vyBulk*${invVol} +variable curr_step equal step +variable p_Fapp format Fapp %.3f +variable p_jx format jx %.5g +variable p_jy format jy %.5g +fix print_vCOM all print ${dump_rate} & + "${curr_step} ${p_Fapp} ${p_jx} ${p_jy}" file GD.out screen no & + title "timestep Fapp Jx Jy" -#compute IK1 pressure profile +#compute IK1 pressure profile #see Todd, Evans, and Davis, Phys. Rev. E 52(2) 1995, p. 1627 #use profile-unbiased temperature to remove the streaming velocity #from the kinetic part of the pressure -compute spa bulk stress/atom myTp +compute spa bulk stress/atom myTp #for the pressure profile, use the same grid as the PUT -compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box +compute chunkX bulk chunk/atom bin/1d x lower ${dX} units box #output pressure profile and other profiles #the pressure profile is (-1/2V)*(c_spa[1] + c_spa[2]), where #V is the volume of a slice -fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX & - vx density/mass c_spa[1] c_spa[2] & - file x_profiles ave running overwrite +fix profiles bulk ave/chunk 1 1 ${dump_rate} chunkX & + vx density/mass c_spa[1] c_spa[2] & + file x_profiles ave running overwrite #compute velocity profile across the pipe with a finer grid -variable dYnew equal ${dY}/10 -compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box & - region pipe -fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY & - vx file Vy_profile ave running overwrite +variable dYnew equal ${dY}/10 +compute chunkY bulk chunk/atom bin/1d y center ${dYnew} units box & + region pipe +fix velYprof bulk ave/chunk 1 1 ${dump_rate} chunkY & + vx file Vy_profile ave running overwrite #full trajectory -dump 7 bulk custom ${dump_rate} bulk.lammpstrj & - id type x y z -dump_modify 7 sort id +# dump 7 bulk custom ${dump_rate} bulk.lammpstrj id type x y z +# dump_modify 7 sort id -run ${run} +run ${run} diff --git a/examples/USER/flow_gauss/log.6Jul17.GD.g++.1 b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.1 similarity index 100% rename from examples/USER/flow_gauss/log.6Jul17.GD.g++.1 rename to examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.1 diff --git a/examples/USER/flow_gauss/log.6Jul17.GD.g++.4 b/examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.4 similarity index 100% rename from examples/USER/flow_gauss/log.6Jul17.GD.g++.4 rename to examples/USER/misc/flow_gauss/log.6Jul17.GD.g++.4 diff --git a/examples/USER/flow_gauss/output-files/GD.out b/examples/USER/misc/flow_gauss/output-files/GD.out similarity index 100% rename from examples/USER/flow_gauss/output-files/GD.out rename to examples/USER/misc/flow_gauss/output-files/GD.out diff --git a/examples/USER/flow_gauss/output-files/Vy_profile b/examples/USER/misc/flow_gauss/output-files/Vy_profile similarity index 100% rename from examples/USER/flow_gauss/output-files/Vy_profile rename to examples/USER/misc/flow_gauss/output-files/Vy_profile diff --git a/examples/USER/flow_gauss/output-files/x_profiles b/examples/USER/misc/flow_gauss/output-files/x_profiles similarity index 100% rename from examples/USER/flow_gauss/output-files/x_profiles rename to examples/USER/misc/flow_gauss/output-files/x_profiles From bbb4d63db9802c7e1e29114ee6836751dff7bf3b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 14:52:08 -0400 Subject: [PATCH 087/293] use neighbor list exclusions instead of a zero cutoff --- examples/ASPHERE/poly/in.poly | 139 +++++++++++++++--------------- examples/ASPHERE/poly/in.poly.mp | 143 ++++++++++++++++--------------- 2 files changed, 142 insertions(+), 140 deletions(-) diff --git a/examples/ASPHERE/poly/in.poly b/examples/ASPHERE/poly/in.poly index 3496a774bb..8932523dbf 100644 --- a/examples/ASPHERE/poly/in.poly +++ b/examples/ASPHERE/poly/in.poly @@ -1,114 +1,115 @@ # SRD diffusion demo - poydisperse spheres -units lj -atom_style sphere -atom_modify first big -dimension 2 +units lj +atom_style sphere +atom_modify first big +dimension 2 # create big particles with 3 different types and diameters -lattice sq 0.3 -region box block 0 10 0 10 -0.5 0.5 -create_box 4 box -create_atoms 1 region box +lattice sq 0.3 +region box block 0 10 0 10 -0.5 0.5 +create_box 4 box +create_atoms 1 region box -group big type 1 -set group big type/fraction 2 0.33 394895 -set group big type/fraction 3 0.5 989894 -group big type 2 3 +group big type 1 +set group big type/fraction 2 0.33 394895 +set group big type/fraction 3 0.5 989894 +group big type 2 3 -set type 1*3 mass 1.0 -velocity big create 1.44 87287 loop geom +set type 1*3 mass 1.0 +velocity big create 1.44 87287 loop geom # equilibrate big particles, repulsive only to prevent aggregation -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.1 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes -fix 1 big nve -fix 2 all enforce2d +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 -#dump 1 all atom 10 dump.poly.equil +fix 1 big nve +fix 2 all enforce2d -run 1000 +#dump 1 all atom 10 dump.poly.equil -#undump 1 -unfix 1 -unfix 2 +run 1000 + +#undump 1 +unfix 1 +unfix 2 # add small particles as hi density lattice -region plane block INF INF INF INF -0.001 0.001 units box -lattice sq 250.0 -create_atoms 4 region plane +region plane block INF INF INF INF -0.001 0.001 units box +lattice sq 250.0 +create_atoms 4 region plane -set type 4 mass 0.1 -group small type 4 -velocity small create 1.0 593849 loop geom +set type 4 mass 0.1 +group small type 4 +velocity small create 1.0 593849 loop geom # delete overlaps # must set *-4 cutoffs to non-zero values -pair_style lj/cut 2.5 -pair_coeff 1 1 1.0 1.0 -pair_coeff 2 2 1.0 2.0 -pair_coeff 3 3 1.0 1.5 -pair_coeff 1 4 0.0 1.0 0.5 -pair_coeff 2 4 0.0 1.0 1.0 -pair_coeff 3 4 0.0 1.0 0.75 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 +pair_coeff 2 2 1.0 2.0 +pair_coeff 3 3 1.0 1.5 +pair_coeff 4 4 0.0 1.0 0.1 +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 -delete_atoms overlap 1.0 small big +delete_atoms overlap 1.0 small big # SRD run -reset_timestep 0 +reset_timestep 0 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -comm_modify mode multi group big vel yes -neigh_modify include big +comm_modify mode multi group big vel yes +neigh_modify include big # no pairwise interactions with small particles -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.1 +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 # use fix SRD to push small particles out from inside big ones # if comment out, big particles won't see SRD particles -timestep 0.001 +timestep 0.001 -fix 1 big nve -fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & +fix 1 big nve +fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & search 0.2 inside ignore -fix 3 all enforce2d +fix 3 all enforce2d # diagnostics -compute tbig big temp/sphere -variable pebig equal pe*atoms/count(big) -variable ebig equal etotal*atoms/count(big) -thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & - f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & - f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] +compute tbig big temp/sphere +variable pebig equal pe*atoms/count(big) +variable ebig equal etotal*atoms/count(big) +thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & + f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & + f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] -thermo_modify temp tbig -thermo 1000 +thermo_modify temp tbig +thermo 1000 -#dump 1 all atom 1000 dump.poly +#dump 1 all atom 1000 dump.poly -#dump 1 all image 1000 image.*.jpg type type zoom 1.6 -#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 +#dump 1 all image 1000 image.*.jpg type type zoom 1.6 +#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 -run 100000 +run 100000 diff --git a/examples/ASPHERE/poly/in.poly.mp b/examples/ASPHERE/poly/in.poly.mp index 1c6a1faee3..05ff8226e2 100644 --- a/examples/ASPHERE/poly/in.poly.mp +++ b/examples/ASPHERE/poly/in.poly.mp @@ -1,115 +1,116 @@ # SRD viscosity demo - poydisperse spheres -units lj -atom_style sphere -atom_modify first big -dimension 2 +units lj +atom_style sphere +atom_modify first big +dimension 2 # create big particles with 3 different types and diameters -lattice sq 0.3 -region box block 0 10 0 10 -0.5 0.5 -create_box 4 box -create_atoms 1 region box +lattice sq 0.3 +region box block 0 10 0 10 -0.5 0.5 +create_box 4 box +create_atoms 1 region box -group big type 1 -set group big type/fraction 2 0.33 394895 -set group big type/fraction 3 0.5 989894 -group big type 2 3 +group big type 1 +set group big type/fraction 2 0.33 394895 +set group big type/fraction 3 0.5 989894 +group big type 2 3 -set type 1*3 mass 1.0 -velocity big create 1.44 87287 loop geom +set type 1*3 mass 1.0 +velocity big create 1.44 87287 loop geom # equilibrate big particles, repulsive only to prevent aggregation -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.1 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes -fix 1 big nve -fix 2 all enforce2d +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 -#dump 1 all atom 10 dump.poly.equil +fix 1 big nve +fix 2 all enforce2d -run 1000 +#dump 1 all atom 10 dump.poly.equil -#undump 1 -unfix 1 -unfix 2 +run 1000 + +#undump 1 +unfix 1 +unfix 2 # add small particles as hi density lattice -region plane block INF INF INF INF -0.001 0.001 units box -lattice sq 250.0 -create_atoms 4 region plane +region plane block INF INF INF INF -0.001 0.001 units box +lattice sq 250.0 +create_atoms 4 region plane -set type 4 mass 0.1 -group small type 4 -velocity small create 1.0 593849 loop geom +set type 4 mass 0.1 +group small type 4 +velocity small create 1.0 593849 loop geom # delete overlaps # must set *-4 cutoffs to non-zero values -pair_style lj/cut 2.5 -pair_coeff 1 1 1.0 1.0 -pair_coeff 2 2 1.0 2.0 -pair_coeff 3 3 1.0 1.5 -pair_coeff 1 4 0.0 1.0 0.5 -pair_coeff 2 4 0.0 1.0 1.0 -pair_coeff 3 4 0.0 1.0 0.75 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 +pair_coeff 2 2 1.0 2.0 +pair_coeff 3 3 1.0 1.5 +pair_coeff 4 4 0.0 1.0 0.1 +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 -delete_atoms overlap 1.0 small big +delete_atoms overlap 1.0 small big # SRD run -reset_timestep 0 +reset_timestep 0 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -comm_modify mode multi group big vel yes -neigh_modify include big +comm_modify mode multi group big vel yes +neigh_modify include big # no pairwise interactions with small particles -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.0 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.1 +neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 # use fix SRD to push small particles out from inside big ones # if comment out, big particles won't see SRD particles -timestep 0.001 +timestep 0.001 -fix 1 big nve -fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & - search 0.2 inside ignore -fix 3 small viscosity 10 x y 50 -fix 4 all enforce2d +fix 1 big nve +fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & + search 0.2 inside ignore +fix 3 small viscosity 10 x y 50 +fix 4 all enforce2d # diagnostics -compute tbig big temp/sphere -variable pebig equal pe*atoms/count(big) -variable ebig equal etotal*atoms/count(big) -thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & - f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & - f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] +compute tbig big temp/sphere +variable pebig equal pe*atoms/count(big) +variable ebig equal etotal*atoms/count(big) +thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & + f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & + f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] -thermo_modify temp tbig -thermo 1000 +thermo_modify temp tbig +thermo 1000 -#dump 1 all atom 500 dump.poly.mp +#dump 1 all atom 500 dump.poly.mp -#dump 1 all image 500 image.*.jpg type type zoom 1.6 -#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 +#dump 1 all image 500 image.*.jpg type type zoom 1.6 +#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 -run 50000 +run 50000 From 842dc1b58c4b8f7aa68cf0c64e44d2aaffa753f9 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 14:21:21 -0600 Subject: [PATCH 088/293] cmake: collect link libs --- cmake/CMakeLists.txt | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f69d84e852..074407650e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -25,15 +25,12 @@ include(CheckCCompilerFlag) option(BUILD_SHARED_LIBS "Build shared libs" OFF) include(GNUInstallDirs) +set(LAMMPS_LINK_LIBS) option(ENABLE_MPI "Build MPI version" OFF) if(ENABLE_MPI) - find_package(MPI) + find_package(MPI REQUIRED) include_directories(${MPI_C_INCLUDE_PATH}) - set(MPI_SOURCES) -else() - file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) - include_directories(${LAMMPS_SOURCE_DIR}/STUBS) - set(MPI_CXX_LIBRARIES) + list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) endif() find_package(UnixCommands) @@ -49,16 +46,14 @@ find_package(JPEG) if(JPEG_FOUND) add_definitions(-DLAMMPS_JPEG) include_directories(${JPEG_INCLUDE_DIR}) -else() - set(JPEG_LIBRARIES) + list(APPEND LAMMPS_LINK_LIBS ${JPEG_LIBRARIES}) endif() find_package(PNG) if(PNG_FOUND) include_directories(${PNG_INCLUDE_DIR}) + list(APPEND LAMMPS_LINK_LIBS ${PNG_LIBRARIES}) add_definitions(-DLAMMPS_PNG) -else(PNG_FOUND) - set(PNG_LIBRARIES) endif(PNG_FOUND) ######################################################################## @@ -81,6 +76,7 @@ foreach(FUNC sin cos) 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}) ###################################### # Include the following subdirectory # @@ -93,6 +89,12 @@ file(GLOB LIB_SOURCES ${LAMMPS_SOURCE_DIR}/*.cpp) file(GLOB LMP_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) +if(NOT ENABLE_MPI) + file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) + list(APPEND LIB_SOURCES ${MPI_SOURCES}) + include_directories(${LAMMPS_SOURCE_DIR}/STUBS) +endif() + foreach(PKG ${PACKAGES}) if(ENABLE_${PKG}) file(GLOB ${PKG}_SOURCES ${LAMMPS_SOURCE_DIR}/${PKG}/*.cpp) @@ -112,8 +114,8 @@ include_directories(${CMAKE_SOURCE_DIR}/Headers) configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR}/cmake/package.h) include_directories(${CMAKE_BINARY_DIR}/cmake) -add_library(lammps ${LIB_SOURCES} ${MPI_SOURCES}) -target_link_libraries(lammps ${MPI_CXX_LIBRARIES} ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${MATH_LIBRARIES}) +add_library(lammps ${LIB_SOURCES}) +target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) From e4e12521522b1bdbb57758f431d9ef08b6aa7792 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 14:44:44 -0600 Subject: [PATCH 089/293] fix LAMMPS_PNG --- cmake/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 074407650e..a21c81b9cd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -50,11 +50,12 @@ if(JPEG_FOUND) endif() find_package(PNG) -if(PNG_FOUND) - include_directories(${PNG_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${PNG_LIBRARIES}) +find_package(ZLIB) +if(PNG_FOUND AND ZLIB_FOUND) + include_directories(${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) add_definitions(-DLAMMPS_PNG) -endif(PNG_FOUND) +endif() ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # From c07adac22d577c4ad4cb6546480ca6c669018fdb Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 14:49:53 -0600 Subject: [PATCH 090/293] add support for LAMMPS_GZIP --- cmake/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a21c81b9cd..9db55174fc 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -57,6 +57,11 @@ if(PNG_FOUND AND ZLIB_FOUND) add_definitions(-DLAMMPS_PNG) endif() +find_program(GZIP gzip) +if(GZIP) + add_definitions(-DLAMMPS_GZIP) +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## From d5dcb3d32930c2efcd41bd394d21b283c46c78e6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 15:55:36 -0600 Subject: [PATCH 091/293] add support for KSPACE --- cmake/CMakeLists.txt | 14 +++++++++++++- cmake/Headers/style_fix.h | 3 +++ cmake/Headers/style_kspace.h | 12 ++++++++++++ cmake/Headers/style_pair.h | 30 ++++++++++++++++++++++++++++++ cmake/Modules/FindFFTW3.cmake | 25 +++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/FindFFTW3.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9db55174fc..f0d121d834 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -5,6 +5,9 @@ set(SOVERSION 0) set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) +# Cmake modules/macros are in a subdirectory to keep this file cleaner +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules) + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) #release comes with -O3 by default set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) @@ -37,11 +40,20 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) -set(PACKAGES ASPHERE REAX) +set(PACKAGES ASPHERE KSPACE REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() +if(ENABLE_KSPACE) + find_package(FFTW3) + if(FFTW3_FOUND) + add_definitions(-DFFT_FFTW3) + include_directories(${FFTW3_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${FFTW3_LIBRARIES}) + endif() +endif() + find_package(JPEG) if(JPEG_FOUND) add_definitions(-DLAMMPS_JPEG) diff --git a/cmake/Headers/style_fix.h b/cmake/Headers/style_fix.h index 146616124d..fb68f69135 100644 --- a/cmake/Headers/style_fix.h +++ b/cmake/Headers/style_fix.h @@ -82,6 +82,9 @@ #include "fix_temp_csvr.h" #include "fix_temp_rescale.h" #include "fix_tmd.h" +#ifdef ENABLE_KSPACE +#include "fix_tune_kspace.h" +#endif #include "fix_vector.h" #include "fix_viscous.h" #include "fix_wall_harmonic.h" diff --git a/cmake/Headers/style_kspace.h b/cmake/Headers/style_kspace.h index b2b5c1f82e..64760bb422 100644 --- a/cmake/Headers/style_kspace.h +++ b/cmake/Headers/style_kspace.h @@ -1 +1,13 @@ #include "package.h" +#ifdef ENABLE_KSPACE +#include "ewald.h" +#include "ewald_disp.h" +#include "msm.h" +#include "msm_cg.h" +#include "pppm.h" +#include "pppm_cg.h" +#include "pppm_disp.h" +#include "pppm_disp_tip4p.h" +#include "pppm_stagger.h" +#include "pppm_tip4p.h" +#endif diff --git a/cmake/Headers/style_pair.h b/cmake/Headers/style_pair.h index 067e2cdb23..e7676bfabf 100644 --- a/cmake/Headers/style_pair.h +++ b/cmake/Headers/style_pair.h @@ -2,12 +2,25 @@ #include "pair_beck.h" #include "pair_born.h" #include "pair_born_coul_dsf.h" +#ifdef ENABLE_KSPACE +#include "pair_born_coul_long.h" +#include "pair_born_coul_msm.h" +#endif #include "pair_born_coul_wolf.h" #include "pair_buck.h" #include "pair_buck_coul_cut.h" +#ifdef ENABLE_KSPACE +#include "pair_buck_coul_long.h" +#include "pair_buck_coul_msm.h" +#include "pair_buck_long_coul_long.h" +#endif #include "pair_coul_cut.h" #include "pair_coul_debye.h" #include "pair_coul_dsf.h" +#ifdef ENABLE_KSPACE +#include "pair_coul_long.h" +#include "pair_coul_msm.h" +#endif #include "pair_coul_streitz.h" #include "pair_coul_wolf.h" #include "pair_dpd.h" @@ -22,14 +35,28 @@ #include "pair_line_lj.h" #endif #include "pair_lj96_cut.h" +#ifdef ENABLE_KSPACE +#include "pair_lj_charmm_coul_long.h" +#include "pair_lj_charmm_coul_msm.h" +#include "pair_lj_charmmfsw_coul_long.h" +#endif #include "pair_lj_cubic.h" #include "pair_lj_cut.h" #include "pair_lj_cut_coul_cut.h" #include "pair_lj_cut_coul_debye.h" #include "pair_lj_cut_coul_dsf.h" +#ifdef ENABLE_KSPACE +#include "pair_lj_cut_coul_long.h" +#include "pair_lj_cut_coul_msm.h" +#include "pair_lj_cut_tip4p_long.h" +#endif #include "pair_lj_expand.h" #include "pair_lj_gromacs.h" #include "pair_lj_gromacs_coul_gromacs.h" +#ifdef ENABLE_KSPACE +#include "pair_lj_long_coul_long.h" +#include "pair_lj_long_tip4p_long.h" +#endif #include "pair_lj_smooth.h" #include "pair_lj_smooth_linear.h" #include "pair_mie_cut.h" @@ -42,6 +69,9 @@ #endif #include "pair_soft.h" #include "pair_table.h" +#ifdef ENABLE_KSPACE +#include "pair_tip4p_long.h" +#endif #ifdef ENABLE_ASPHERE #include "pair_tri_lj.h" #endif diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake new file mode 100644 index 0000000000..552bcc4257 --- /dev/null +++ b/cmake/Modules/FindFFTW3.cmake @@ -0,0 +1,25 @@ +# - Find fftw3 +# Find the native FFTW3 headers and libraries. +# +# FFTW3_INCLUDE_DIRS - where to find fftw3.h, etc. +# FFTW3_LIBRARIES - List of libraries when using fftw3. +# FFTW3_FOUND - True if fftw3 found. +# + +find_package(PkgConfig) + +pkg_check_modules(PC_FFTW3 fftw3) +find_path(FFTW3_INCLUDE_DIR fftw3.h HINTS ${PC_FFTW3_INCLUDE_DIRS}) + +find_library(FFTW3_LIBRARY NAMES fftw3 HINTS ${PC_FFTW3_LIBRARY_DIRS}) + +set(FFTW3_LIBRARIES ${FFTW3_LIBRARY}) +set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR}) + +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) + +mark_as_advanced(FFTW3_INCLUDE_DIR FFTW3_LIBRARY ) From 296e572e6998214669d573562335b145c22b758a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 14 Jul 2017 16:25:16 -0600 Subject: [PATCH 092/293] better Install.py script for KIM from Ryan Elliott --- doc/src/Section_example.txt | 1 + doc/src/Section_packages.txt | 44 +++++-- doc/src/neigh_modify.txt | 7 +- examples/README | 1 + lib/Install.py | 13 +- lib/atc/Install.py | 13 +- lib/awpmd/Install.py | 13 +- lib/colvars/Install.py | 13 +- lib/gpu/Install.py | 25 ++-- lib/h5md/Install.py | 13 +- lib/kim/Install.py | 223 ++++++++++++++++++++++++++--------- lib/kim/README | 10 +- lib/linalg/Install.py | 8 +- lib/meam/Install.py | 13 +- lib/mscg/Install.py | 11 +- lib/poems/Install.py | 13 +- lib/qmmm/Install.py | 13 +- lib/reax/Install.py | 13 +- lib/smd/Install.py | 11 +- lib/voronoi/Install.py | 11 +- src/Makefile | 3 +- 21 files changed, 363 insertions(+), 109 deletions(-) diff --git a/doc/src/Section_example.txt b/doc/src/Section_example.txt index 26dc3b9698..f8b39be173 100644 --- a/doc/src/Section_example.txt +++ b/doc/src/Section_example.txt @@ -49,6 +49,7 @@ Lists of both kinds of directories are given below. Lowercase directories :h4 accelerate: run with various acceleration options (OpenMP, GPU, Phi) +airebo: polyethylene with AIREBO potential balance: dynamic load balancing, 2d system body: body particles, 2d system cmap: CMAP 5-body contributions to CHARMM force field diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt index 76f88b8ab8..a65e510654 100644 --- a/doc/src/Section_packages.txt +++ b/doc/src/Section_packages.txt @@ -492,14 +492,38 @@ Minnesota). [Install or un-install:] -Using this package requires the KIM library and its models -(interatomic potentials) to be downloaded and installed on your -system. The library can be downloaded and built in lib/kim or -elsewhere on your system. Details of the download, build, and install -process for KIM are given in the lib/kim/README file. +Before building LAMMPS with this package, you must first download and +build the KIM library and include the KIM models that you want to +use. You can do this manually if you prefer; follow the instructions +in lib/kim/README. You can also do it in one step from the lammps/src +dir, using a command like these, which simply invoke the +lib/kim/Install.py script with the specified args. -Once that process is complete, you can then install/un-install the -package and build LAMMPS in the usual manner: +make lib-kim # print help message +make lib-kim args="-b . none" # install KIM API lib with only example models +make lib-kim args="-b . Glue_Ercolessi_Adams_Al__MO_324507536345_001" # ditto plus one model +make lib-kim args="-b . OpenKIM" # install KIM API lib with all models +make lib-kim args="-a EAM_Dynamo_Ackland_W__MO_141627196590_002" # add one model or model driver :pre + +Note that in LAMMPS lingo, a KIM model driver is a pair style +(e.g. EAM or Tersoff). A KIM model is a pair style for a particular +element or alloy and set of parameters, e.g. EAM for Cu with a +specific EAM potential file. Also note that installing the KIM API +library with all its models, may take around 30 min to build. Of +course you only need to do that once. + +See the list of KIM model drivers here: +https://openkim.org/kim-items/model-drivers/alphabetical + +See the list of all KIM models here: +https://openkim.org/kim-items/models/by-model-drivers + +See the list of example KIM models included by default here: +https://openkim.org/kim-api +in the "What is in the KIM API source package?" section + +You can then install/un-install the package and build LAMMPS in the +usual manner: make yes-kim make machine :pre @@ -1414,7 +1438,7 @@ lib/linalg. In the latter case you also need to build the library in lib/linalg with a command like these: make lib-linalg # print help message -make lib-atc args="-m gfortran" # build with GNU Fortran compiler +make lib-linalg args="-m gfortran" # build with GNU Fortran compiler You can then install/un-install the package and build LAMMPS in the usual manner: @@ -2469,8 +2493,8 @@ step from the lammps/src dir, using a command like these, which simply invoke the lib/smd/Install.py script with the specified args: make lib-smd # print help message -make lib-smd args="-g -l" # download in default lib/smd/eigen-eigen-* -make lib-smd args="-h . eigen -g -l" # download in lib/smd/eigen +make lib-smd args="-g -l" # download and build in default lib/smd/eigen-eigen-* +make lib-smd args="-h . eigen -g -l" # download and build in lib/smd/eigen make lib-smd args="-h ~ eigen -g -l" # download and build in ~/eigen :pre Note that the final -l switch is to create a symbolic (soft) link diff --git a/doc/src/neigh_modify.txt b/doc/src/neigh_modify.txt index 5c149d892d..c4544cb29b 100644 --- a/doc/src/neigh_modify.txt +++ b/doc/src/neigh_modify.txt @@ -109,7 +109,8 @@ atoms in the specified group. This can be useful for models where a large portion of the simulation is particles that do not interact with other particles or with each other via pairwise interactions. The group specified with this option must also be specified via the -"atom_modify first"_atom_modify.html command. +"atom_modify first"_atom_modify.html command. Note that specifying +"all" as the group-ID effectively turns off the {include} option. The {exclude} option turns off pairwise interactions between certain pairs of atoms, by not including them in the neighbor list. These are @@ -213,5 +214,5 @@ space. [Default:] The option defaults are delay = 10, every = 1, check = yes, once = no, -cluster = no, include = all, exclude = none, page = 100000, one = -2000, and binsize = 0.0. +cluster = no, include = all (same as no include option defined), +exclude = none, page = 100000, one = 2000, and binsize = 0.0. diff --git a/examples/README b/examples/README index e4312e2598..0ec28aa2c2 100644 --- a/examples/README +++ b/examples/README @@ -58,6 +58,7 @@ These are the sample problems and their output in the various sub-directories: accelerate: use of all the various accelerator packages +airebo: polyethylene with AIREBO potential balance: dynamic load balancing, 2d system body: body particles, 2d system cmap: CMAP 5-body contributions to CHARMM force field diff --git a/lib/Install.py b/lib/Install.py index 18b426f928..29270560a6 100644 --- a/lib/Install.py +++ b/lib/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/atc/Install.py b/lib/atc/Install.py index 18b426f928..29270560a6 100644 --- a/lib/atc/Install.py +++ b/lib/atc/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py index 18b426f928..29270560a6 100644 --- a/lib/awpmd/Install.py +++ b/lib/awpmd/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index 18b426f928..29270560a6 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/gpu/Install.py b/lib/gpu/Install.py index d396be5e1a..c6cd1f3021 100644 --- a/lib/gpu/Install.py +++ b/lib/gpu/Install.py @@ -8,14 +8,17 @@ import sys,os,re,commands # help message help = """ -Syntax: python Install.py -i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix - specify one or more options, order does not matter - copies an existing Makefile.isuffix in lib/gpu to Makefile.auto - optionally edits these variables in Makefile.auto: - CUDA_HOME, CUDA_ARCH, CUDA_PRECISION, EXTRAMAKE - optionally uses Makefile.auto to build the GPU library -> libgpu.a - and to copy a Makefile.lammps.esuffix -> Makefile.lammps - optionally copies Makefile.auto to a new Makefile.osuffix +Syntax from src dir: make lib-gpu args="-i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix" +Syntax from lib dir: python Install.py -i isuffix -h hdir -a arch -p precision -e esuffix -m -o osuffix + +specify one or more options, order does not matter + +copies an existing Makefile.isuffix in lib/gpu to Makefile.auto +optionally edits these variables in Makefile.auto: + CUDA_HOME, CUDA_ARCH, CUDA_PRECISION, EXTRAMAKE +optionally uses Makefile.auto to build the GPU library -> libgpu.a + and to copy a Makefile.lammps.esuffix -> Makefile.lammps +optionally copies Makefile.auto to a new Makefile.osuffix -i = use Makefile.isuffix as starting point, copy to Makefile.auto default isuffix = linux @@ -34,6 +37,12 @@ Syntax: python Install.py -i isuffix -h hdir -a arch -p precision -e esuffix -m also copies EXTRAMAKE file -> Makefile.lammps -e can set which Makefile.lammps.esuffix file is copied -o = copy final Makefile.auto to Makefile.osuffix + +Examples: + +make lib-gpu args="-m" # build GPU lib with default Makefile.linux +make lib-gpu args="-i xk7 -p single -o xk7.single" # create new Makefile.xk7.single, altered for single-precision +make lib-gpu args="-i xk7 -p single -o xk7.single -m" # ditto, also build GPU lib """ # print error message or help diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py index 18b426f928..29270560a6 100644 --- a/lib/h5md/Install.py +++ b/lib/h5md/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/kim/Install.py b/lib/kim/Install.py index bcd22dcbb3..9f36f9fedb 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -1,25 +1,44 @@ #!/usr/bin/env python -# install.py tool to setup the kim-api library +# install.pa tool to setup the kim-api library # used to automate the steps described in the README file in this dir import sys,os,re,urllib,commands help = """ -Syntax: install.py -v version -c kim-dir -b kim-model-name -a kim-name - specify one or more options, order does not matter - -v = version of kim-api to download and work with - default = kim-api-v1.8.2 (current as of June 2017) - -c = create Makefile.KIM_DIR within lammps lib/kim to configure lammps - for use with the kim-api library installed at "kim-dir" (absolute - path). default = this dir - -b = build kim-api and kim model where kim-model-name can be a specific - openkim.org model name (such as - "EAM_Dynamo_Ackland_W__MO_141627196590_002") or the keyword - "OpenKIM" to install all compatible models from the openkim.org - site. - -a = add kim-name openkim.org item (model driver or model) to existing - kim-api instalation. +Syntax from src dir: make lib-kim args="-v version -b kim-install-dir kim-name -a kim-name" +Syntax from lib dir: python Install.py -v version -b kim-install-dir kim-name -a kim-name + +specify one or more options, order does not matter + + -v = version of KIM API library to use + default = kim-api-v1.8.2 (current as of June 2017) + -b = download and build KIM API library with KIM models + kim-dir = where to install/build the KIM API library + use "." to install in lib/kim + kim-name = none to install only the example KIM models + kim-name = KIM model name (see example below) + examples + kim-name = OpenKIM to install all models + from the openkim.org site (this can take 30 minutes or more) + -a = add single KIM model or model driver with kim-name + to existing KIM API lib (see example below) + +Examples: + +make lib-kim args="-b . none" # install KIM API lib with only example models +make lib-kim args="-b . Glue_Ercolessi_Adams_Al__MO_324507536345_001" # ditto plus one model +make lib-kim args="-b . OpenKIM" # install KIM API lib with all models +make lib-kim args="-a EAM_Dynamo_Ackland_W__MO_141627196590_002" # add one model or model driver + +See the list of KIM model drivers here: +https://openkim.org/kim-items/model-drivers/alphabetical + +See the list of all KIM models here: +https://openkim.org/kim-items/models/by-model-drivers + +See the list of example KIM models included by default here: +https://openkim.org/kim-api +in the "What is in the KIM API source package?" section """ def error(): @@ -28,32 +47,28 @@ def error(): # parse args -args = sys.argv +args = sys.argv[1:] +nargs = len(args) +if nargs == 0: error() thisdir = os.environ['PWD'] -dir = thisdir version = "kim-api-v1.8.2" -dirflag = 0 buildflag = 0 addflag = 0 -iarg = 1 +iarg = 0 while iarg < len(args): if args[iarg] == "-v": if iarg+2 > len(args): error() version = args[iarg+1] iarg += 2 - elif args[iarg] == "-c": - dirflag = 1 - if iarg+2 > len(args): error() - dir = args[iarg+1] - iarg += 2 elif args[iarg] == "-b": buildflag = 1 - if iarg+2 > len(args): error() - modelname = args[iarg+1] - iarg += 2 + if iarg+3 > len(args): error() + dir = args[iarg+1] + modelname = args[iarg+2] + iarg += 3 elif args[iarg] == "-a": addflag = 1 if iarg+2 > len(args): error() @@ -62,33 +77,59 @@ while iarg < len(args): else: error() thisdir = os.path.abspath(thisdir) -dir = os.path.abspath(dir) url = "https://s3.openkim.org/kim-api/%s.tgz" % version -# download and unpack tarball - - -if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): - open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) - open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) - print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) -else: - if dirflag == 1: - open("%s/Makefile.KIM_DIR" % thisdir, 'w').write("KIM_INSTALL_DIR=%s" % dir) - open("%s/Makefile.KIM_Config" % thisdir, 'w').write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) - print "Updated %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) - +# download KIM tarball, unpack, build KIM +# either in lib/kim or user-requested location if buildflag == 1: - # download kim-api + + # set install directory + dir = os.path.abspath(dir) + "/installed-" + version + + # check to see if an installed kim-api already exists + + if os.path.isdir(dir): + print "kim-api is already installed at %s" % dir + print "Must remove this directory in order to resintall at this location" + sys.exit() + + # configure LAMMPS to use kim-api to be installed + + mkfle = open("%s/Makefile.KIM_DIR" % thisdir, 'w') + mkfle.write("KIM_INSTALL_DIR=%s\n" % dir) + mkfle.write("\n") + mkfle.write(".DUMMY: print_dir\n") + mkfle.write("\n") + mkfle.write("print_dir:\n") + mkfle.write(" @printf $(KIM_INSTALL_DIR)\n") + mkfle.close() + open("%s/Makefile.KIM_Config" % thisdir, 'w'). \ + write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) + print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) + + # download entire kim-api tarball + # try first via urllib + # if fails (probably due to no SSL support), use wget + print "Downloading kim-api tarball ..." - urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) + + try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) + except: + cmd = "wget %s %s/%s.tgz" % (url,thisdir,version) + txt = commands.getstatusoutput(cmd) + print txt[1] + if not os.path.isfile("%s/%s.tgz" % (thisdir,version)): + print "Both urllib.urlretrieve() and wget command failed to download" + sys.exit() + print "Unpacking kim-api tarball ..." cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) txt = commands.getstatusoutput(cmd) if txt[0] != 0: error() # configure kim-api + print "Configuring kim-api ..." cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) txt = commands.getstatusoutput(cmd) @@ -96,12 +137,19 @@ if buildflag == 1: if txt[0] != 0: error() # build kim-api + print "Configuring model : %s" % modelname - cmd = "cd %s/%s; make add-%s" % (thisdir,version,modelname) + if modelname == "none": + cmd = "cd %s/%s; make add-examples" % (thisdir,version) + else: + if modelname == "OpenKIM": + print "configuring all OpenKIM models, this will take a while ..." + cmd = "cd %s/%s; make add-examples; make add-%s" % \ + (thisdir,version,modelname) txt = commands.getstatusoutput(cmd) print txt[1] if txt[0] != 0: error() - # + print "Building kim-api ..." cmd = "cd %s/%s; make" % (thisdir,version) txt = commands.getstatusoutput(cmd) @@ -109,42 +157,101 @@ if buildflag == 1: if txt[0] != 0: error() # install kim-api + print "Installing kim-api ..." cmd = "cd %s/%s; make install" % (thisdir,version) txt = commands.getstatusoutput(cmd) print txt[1] if txt[0] != 0: error() - # + cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) txt = commands.getstatusoutput(cmd) print txt[1] if txt[0] != 0: error() # remove source files + print "Removing kim-api source and build files ..." cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) txt = commands.getstatusoutput(cmd) print txt[1] if txt[0] != 0: error() +# add a single model (and possibly its driver) to existing KIM installation + if addflag == 1: - # download model - url = "https://openkim.org/download/%s.tgz" % addmodelname + + # get location of installed kim-api + + if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): + print "kim-api is not installed" + error() + else: + cmd = "cd %s; make -f Makefile.KIM_DIR print_dir" % thisdir + dir = commands.getstatusoutput(cmd)[1] + + # download single model + # try first via urllib + # if fails (probably due to no SSL support), use wget + print "Downloading item tarball ..." - urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) + + url = "https://openkim.org/download/%s.tgz" % addmodelname + + try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) + except: + cmd = "wget %s %s/%s.tgz" % (url,thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if not os.path.isfile("%s/%s.tgz" % (thisdir,addmodelname)): + print "Both urllib.urlretrieve() and wget command failed to download" + sys.exit() + print "Unpacking item tarball ..." cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) txt = commands.getstatusoutput(cmd) if txt[0] != 0: error() - # + print "Building item ..." cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() - # - print "Removing kim item source and build files ..." - cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] - if txt[0] != 0: error() + firstRunOutput = txt[1] + if txt[0] != 0: + # Error: but first, check to see if it needs a driver + + cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + if txt[1] == "ParameterizedModel": + + # Get and install driver + + cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + adddrivername = txt[1] + print "First Installing model driver: %s" % adddrivername + cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) + txt = commands.getstatusoutput(cmd) + if txt[0] != 0: + print firstRunOutput + print txt[1] + error() + else: + print txt[1] + cmd = "cd %s; python Install.py -a %s" % (thisdir,addmodelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: + error() + else: + print firstRunOutput + error() + else: + + # success + + print firstRunOutput + print "Removing kim item source and build files ..." + cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) + txt = commands.getstatusoutput(cmd) + print txt[1] + if txt[0] != 0: error() diff --git a/lib/kim/README b/lib/kim/README index 00d6ea8fad..7a4230dc25 100644 --- a/lib/kim/README +++ b/lib/kim/README @@ -8,14 +8,16 @@ James Sethna (Cornell U). Ryan Elliott is the main developer for the KIM API and he also maintains the code that implements the pair_style kim command. -To download, build, and install the KIM API on your system, follow -these steps. You can use the install.py script to automate these steps. +You can type "make lib-kim" from the src directory to see help on +how to download and build this library via make commands, or you can +do the same thing by typing "python Install.py" from within this +directory, or you can do it manually by following the instructions +below. ----------------- Instructions: - 1. Configure lammps for use with the kim-api library installed in this directory $ printf "KIM_INSTALL_DIR=${PWD}\n" > ./Makefile.KIM_DIR @@ -65,7 +67,7 @@ $ rm -rf EAM_Johnson_NearestNeighbor_Cu__MO_887933271505_001.tgz When these steps are complete you can build LAMMPS with the KIM package installed: -$ cd ../../src +$ cd lammpos/src $ make yes-kim $ make g++ (or whatever target you wish) diff --git a/lib/linalg/Install.py b/lib/linalg/Install.py index c7076ca52f..560afecec4 100644 --- a/lib/linalg/Install.py +++ b/lib/linalg/Install.py @@ -8,9 +8,15 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine +Syntax from src dir: make lib-linalg args="-m machine" +Syntax from lib dir: python Install.py -m machine + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file + +Example: + +make lib-linalg args="-m gfortran" # build with GNU Fortran compiler """ # print error message or help diff --git a/lib/meam/Install.py b/lib/meam/Install.py index 18b426f928..29270560a6 100644 --- a/lib/meam/Install.py +++ b/lib/meam/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/mscg/Install.py b/lib/mscg/Install.py index e547232614..7b10be189f 100644 --- a/lib/mscg/Install.py +++ b/lib/mscg/Install.py @@ -8,8 +8,11 @@ import sys,os,re,commands # help message help = """ -Syntax: python Install.py -h hpath hdir -g -b [suffix] -l - specify one or more options, order does not matter +Syntax from src dir: make lib-mscg args="-h hpath hdir -g -b [suffix] -l" +Syntax from lib dir: python Install.py -h hpath hdir -g -b [suffix] -l + +specify one or more options, order does not matter + -h = set home dir of MS-CG to be hpath/hdir hpath can be full path, contain '~' or '.' chars default hpath = . = lib/mscg @@ -22,6 +25,10 @@ Syntax: python Install.py -h hpath hdir -g -b [suffix] -l optional suffix specifies which src/Make/Makefile.suffix to use default suffix = g++_simple -l = create 2 softlinks (includelink,liblink) in lib/mscg to MS-CG src dir + +Example: + +make lib-mscg args="-g -b -l" # download/build in lib/mscg/MSCG-release-master """ # settings diff --git a/lib/poems/Install.py b/lib/poems/Install.py index 18b426f928..29270560a6 100644 --- a/lib/poems/Install.py +++ b/lib/poems/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py index 18b426f928..29270560a6 100644 --- a/lib/qmmm/Install.py +++ b/lib/qmmm/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/reax/Install.py b/lib/reax/Install.py index 18b426f928..29270560a6 100644 --- a/lib/reax/Install.py +++ b/lib/reax/Install.py @@ -9,12 +9,21 @@ import sys,commands,os # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-libname args="-m machine -e suffix" +Syntax from lib dir: python Install.py -m machine -e suffix + +libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examplesx: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help diff --git a/lib/smd/Install.py b/lib/smd/Install.py index dc0a3187ce..e6fe8926a4 100644 --- a/lib/smd/Install.py +++ b/lib/smd/Install.py @@ -8,8 +8,11 @@ import sys,os,re,glob,commands # help message help = """ -Syntax: python Install.py -h hpath hdir -g -l - specify one or more options, order does not matter +Syntax from src dir: make lib-smd args="-h hpath hdir -g -l" +Syntax from lib dir: python Install.py -h hpath hdir -g -l + +specify one or more options, order does not matter + -h = set home dir of Eigen to be hpath/hdir hpath can be full path, contain '~' or '.' chars default hpath = . = lib/smd @@ -19,6 +22,10 @@ Syntax: python Install.py -h hpath hdir -g -l hpath must already exist if hdir already exists, it will be deleted before unpack -l = create softlink (includelink) in lib/smd to Eigen src dir + +Example: + +make lib-smd args="-g -l" # download/build in default lib/smd/eigen-eigen-* """ # settings diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 7d847183b3..54246f113e 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -8,8 +8,11 @@ import sys,os,re,urllib,commands # help message help = """ -Syntax: python Install.py -v version -h hpath hdir -g -b -l - specify one or more options, order does not matter +Syntax from src dir: make lib-voronoi args="-v version -h hpath hdir -g -b -l" +Syntax from lib dir: python Install.py -v version -h hpath hdir -g -b -l + +specify one or more options, order does not matter + -v = version of Voro++ to download and build default version = voro++-0.4.6 (current as of Jan 2015) -h = set home dir of Voro++ to be hpath/hdir @@ -22,6 +25,10 @@ Syntax: python Install.py -v version -h hpath hdir -g -b -l if hdir already exists, it will be deleted before unpack -b = build Voro++ library in its src dir -l = create 2 softlinks (includelink,liblink) in lib/voronoi to Voro++ src dir + +Example: + +make lib-voronoi args="-g -b -l" # download/build in lib/voronoi/voro++-0.4.6 """ # settings diff --git a/src/Makefile b/src/Makefile index c7b20dcb13..3d1085e0be 100644 --- a/src/Makefile +++ b/src/Makefile @@ -116,7 +116,8 @@ help: @echo 'make package-overwrite replace package files with src files' @echo 'make package-diff (pd) diff src files against package files' @echo '' - @echo 'make lib-package download/build/install a package library' + @echo 'make lib-package help for download/build/install a package library' + @echo 'make lib-package args="..." download/build/install a package library' @echo 'make purge purge obsolete copies of source files' @echo '' @echo 'make machine build LAMMPS for machine' From 335ef11a7bf555dfcf524e35b142509fb8a572d3 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 17:49:05 -0500 Subject: [PATCH 093/293] Added style header generation with CMake --- cmake/CMakeLists.txt | 41 +++++++++++-- cmake/Headers/package.h.cmakein | 2 - cmake/Headers/style_angle.h | 3 - cmake/Headers/style_atom.h | 9 --- cmake/Headers/style_body.h | 1 - cmake/Headers/style_bond.h | 3 - cmake/Headers/style_command.h | 23 ------- cmake/Headers/style_compute.h | 66 -------------------- cmake/Headers/style_dihedral.h | 3 - cmake/Headers/style_dump.h | 9 --- cmake/Headers/style_fix.h | 92 ---------------------------- cmake/Headers/style_improper.h | 3 - cmake/Headers/style_integrate.h | 3 - cmake/Headers/style_kspace.h | 1 - cmake/Headers/style_minimize.h | 6 -- cmake/Headers/style_nbin.h | 2 - cmake/Headers/style_npair.h | 36 ----------- cmake/Headers/style_nstencil.h | 21 ------- cmake/Headers/style_ntopo.h | 13 ---- cmake/Headers/style_pair.h | 50 --------------- cmake/Headers/style_reader.h | 3 - cmake/Headers/style_region.h | 9 --- cmake/Modules/StyleHeaderUtils.cmake | 81 ++++++++++++++++++++++++ 23 files changed, 117 insertions(+), 363 deletions(-) delete mode 100644 cmake/Headers/package.h.cmakein delete mode 100644 cmake/Headers/style_angle.h delete mode 100644 cmake/Headers/style_atom.h delete mode 100644 cmake/Headers/style_body.h delete mode 100644 cmake/Headers/style_bond.h delete mode 100644 cmake/Headers/style_command.h delete mode 100644 cmake/Headers/style_compute.h delete mode 100644 cmake/Headers/style_dihedral.h delete mode 100644 cmake/Headers/style_dump.h delete mode 100644 cmake/Headers/style_fix.h delete mode 100644 cmake/Headers/style_improper.h delete mode 100644 cmake/Headers/style_integrate.h delete mode 100644 cmake/Headers/style_kspace.h delete mode 100644 cmake/Headers/style_minimize.h delete mode 100644 cmake/Headers/style_nbin.h delete mode 100644 cmake/Headers/style_npair.h delete mode 100644 cmake/Headers/style_nstencil.h delete mode 100644 cmake/Headers/style_ntopo.h delete mode 100644 cmake/Headers/style_pair.h delete mode 100644 cmake/Headers/style_reader.h delete mode 100644 cmake/Headers/style_region.h create mode 100644 cmake/Modules/StyleHeaderUtils.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9db55174fc..c69ca085e8 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -5,6 +5,8 @@ set(SOVERSION 0) set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules) + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) #release comes with -O3 by default set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) @@ -42,6 +44,11 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() +set(ACCEL_PACKAGES USER-OMP) +foreach(PKG ${ACCEL_PACKAGES}) + option(ENABLE_${PKG} "Build ${PKG} Package" OFF) +endforeach() + find_package(JPEG) if(JPEG_FOUND) add_definitions(-DLAMMPS_JPEG) @@ -101,24 +108,48 @@ if(NOT ENABLE_MPI) include_directories(${LAMMPS_SOURCE_DIR}/STUBS) endif() +include(StyleHeaderUtils) +RegisterStyles(${LAMMPS_SOURCE_DIR}) + +# packages which include entire content when enabled + foreach(PKG ${PACKAGES}) if(ENABLE_${PKG}) - file(GLOB ${PKG}_SOURCES ${LAMMPS_SOURCE_DIR}/${PKG}/*.cpp) + set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) + + # detects styles in package and adds them to global list + RegisterStyles(${${PKG}_SOURCES_DIR}) + + file(GLOB ${PKG}_SOURCES ${${PKG}_SOURCES_DIR}/*.cpp) list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) - include_directories(${LAMMPS_SOURCE_DIR}/${PKG}) + include_directories(${${PKG}_SOURCES_DIR}) endif() endforeach() +# packages which selectively include variants based on enabled styles +# e.g. accelerator packages + +# TODO + if(ENABLE_REAX) enable_language(Fortran) file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) list(APPEND LIB_SOURCES ${REAX_SOURCES}) include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) endif() + + +###################################################### +# Generate style headers based on global list of +# styles registered during package selection +###################################################### +set(LAMMPS_STYLE_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/styles) + +GenerateStyleHeaders(${LAMMPS_STYLE_HEADERS_DIR}) + include_directories(${LAMMPS_SOURCE_DIR}) -include_directories(${CMAKE_SOURCE_DIR}/Headers) -configure_file(${CMAKE_SOURCE_DIR}/Headers/package.h.cmakein ${CMAKE_BINARY_DIR}/cmake/package.h) -include_directories(${CMAKE_BINARY_DIR}/cmake) +include_directories(${LAMMPS_STYLE_HEADERS_DIR}) + add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) diff --git a/cmake/Headers/package.h.cmakein b/cmake/Headers/package.h.cmakein deleted file mode 100644 index 9c7ff403a4..0000000000 --- a/cmake/Headers/package.h.cmakein +++ /dev/null @@ -1,2 +0,0 @@ -#cmakedefine ENABLE_ASPHERE -#cmakedefine ENABLE_REAX diff --git a/cmake/Headers/style_angle.h b/cmake/Headers/style_angle.h deleted file mode 100644 index 8b395b557f..0000000000 --- a/cmake/Headers/style_angle.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "angle_hybrid.h" -#include "angle_zero.h" diff --git a/cmake/Headers/style_atom.h b/cmake/Headers/style_atom.h deleted file mode 100644 index ec4e5d7d20..0000000000 --- a/cmake/Headers/style_atom.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "package.h" -#include "atom_vec_atomic.h" -#include "atom_vec_body.h" -#include "atom_vec_charge.h" -#include "atom_vec_ellipsoid.h" -#include "atom_vec_hybrid.h" -#include "atom_vec_line.h" -#include "atom_vec_sphere.h" -#include "atom_vec_tri.h" diff --git a/cmake/Headers/style_body.h b/cmake/Headers/style_body.h deleted file mode 100644 index b2b5c1f82e..0000000000 --- a/cmake/Headers/style_body.h +++ /dev/null @@ -1 +0,0 @@ -#include "package.h" diff --git a/cmake/Headers/style_bond.h b/cmake/Headers/style_bond.h deleted file mode 100644 index d18a31ca91..0000000000 --- a/cmake/Headers/style_bond.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "bond_hybrid.h" -#include "bond_zero.h" diff --git a/cmake/Headers/style_command.h b/cmake/Headers/style_command.h deleted file mode 100644 index d795f4ba0a..0000000000 --- a/cmake/Headers/style_command.h +++ /dev/null @@ -1,23 +0,0 @@ -#include "package.h" -#include "balance.h" -#include "change_box.h" -#include "create_atoms.h" -#include "create_bonds.h" -#include "create_box.h" -#include "delete_atoms.h" -#include "delete_bonds.h" -#include "displace_atoms.h" -#include "info.h" -#include "minimize.h" -#include "read_data.h" -#include "read_dump.h" -#include "read_restart.h" -#include "replicate.h" -#include "rerun.h" -#include "run.h" -#include "set.h" -#include "velocity.h" -#include "write_coeff.h" -#include "write_data.h" -#include "write_dump.h" -#include "write_restart.h" diff --git a/cmake/Headers/style_compute.h b/cmake/Headers/style_compute.h deleted file mode 100644 index bfcd053ed6..0000000000 --- a/cmake/Headers/style_compute.h +++ /dev/null @@ -1,66 +0,0 @@ -#include "package.h" -#include "compute_angle.h" -#include "compute_angle_local.h" -#include "compute_angmom_chunk.h" -#include "compute_bond.h" -#include "compute_bond_local.h" -#include "compute_centro_atom.h" -#include "compute_chunk_atom.h" -#include "compute_cluster_atom.h" -#include "compute_cna_atom.h" -#include "compute_com.h" -#include "compute_com_chunk.h" -#include "compute_contact_atom.h" -#include "compute_coord_atom.h" -#include "compute_dihedral.h" -#include "compute_dihedral_local.h" -#include "compute_dipole_chunk.h" -#include "compute_displace_atom.h" -#ifdef ENABLE_ASPHERE -#include "compute_erotate_asphere.h" -#endif -#include "compute_erotate_sphere.h" -#include "compute_erotate_sphere_atom.h" -#include "compute_global_atom.h" -#include "compute_group_group.h" -#include "compute_gyration.h" -#include "compute_gyration_chunk.h" -#include "compute_heat_flux.h" -#include "compute_hexorder_atom.h" -#include "compute_improper.h" -#include "compute_improper_local.h" -#include "compute_inertia_chunk.h" -#include "compute_ke.h" -#include "compute_ke_atom.h" -#include "compute_msd.h" -#include "compute_msd_chunk.h" -#include "compute_omega_chunk.h" -#include "compute_orientorder_atom.h" -#include "compute_pair.h" -#include "compute_pair_local.h" -#include "compute_pe.h" -#include "compute_pe_atom.h" -#include "compute_pressure.h" -#include "compute_property_atom.h" -#include "compute_property_chunk.h" -#include "compute_property_local.h" -#include "compute_rdf.h" -#include "compute_reduce.h" -#include "compute_reduce_region.h" -#include "compute_slice.h" -#include "compute_stress_atom.h" -#include "compute_temp.h" -#ifdef ENABLE_ASPHERE -#include "compute_temp_asphere.h" -#endif -#include "compute_temp_chunk.h" -#include "compute_temp_com.h" -#include "compute_temp_deform.h" -#include "compute_temp_partial.h" -#include "compute_temp_profile.h" -#include "compute_temp_ramp.h" -#include "compute_temp_region.h" -#include "compute_temp_sphere.h" -#include "compute_torque_chunk.h" -#include "compute_vacf.h" -#include "compute_vcm_chunk.h" diff --git a/cmake/Headers/style_dihedral.h b/cmake/Headers/style_dihedral.h deleted file mode 100644 index 26cb4a815a..0000000000 --- a/cmake/Headers/style_dihedral.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "dihedral_hybrid.h" -#include "dihedral_zero.h" diff --git a/cmake/Headers/style_dump.h b/cmake/Headers/style_dump.h deleted file mode 100644 index bc8477a6bf..0000000000 --- a/cmake/Headers/style_dump.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "package.h" -#include "dump_atom.h" -#include "dump_cfg.h" -#include "dump_custom.h" -#include "dump_dcd.h" -#include "dump_image.h" -#include "dump_local.h" -#include "dump_movie.h" -#include "dump_xyz.h" diff --git a/cmake/Headers/style_fix.h b/cmake/Headers/style_fix.h deleted file mode 100644 index 146616124d..0000000000 --- a/cmake/Headers/style_fix.h +++ /dev/null @@ -1,92 +0,0 @@ -#include "package.h" -#include "fix_adapt.h" -#include "fix_addforce.h" -#include "fix_ave_atom.h" -#include "fix_ave_chunk.h" -#include "fix_ave_correlate.h" -#include "fix_ave_histo.h" -#include "fix_ave_histo_weight.h" -#include "fix_ave_time.h" -#include "fix_aveforce.h" -#include "fix_balance.h" -#include "fix_box_relax.h" -#include "fix_controller.h" -#include "fix_deform.h" -#include "fix_deprecated.h" -#include "fix_drag.h" -#include "fix_dt_reset.h" -#include "fix_enforce2d.h" -#include "fix_external.h" -#include "fix_gravity.h" -#include "fix_group.h" -#include "fix_halt.h" -#include "fix_heat.h" -#include "fix_indent.h" -#include "fix_langevin.h" -#include "fix_lineforce.h" -#include "fix_minimize.h" -#include "fix_momentum.h" -#include "fix_move.h" -#include "fix_nph.h" -#ifdef ENABLE_ASPHERE -#include "fix_nph_asphere.h" -#endif -#include "fix_nph_sphere.h" -#include "fix_npt.h" -#ifdef ENABLE_ASPHERE -#include "fix_npt_asphere.h" -#endif -#include "fix_npt_sphere.h" -#include "fix_nve.h" -#ifdef ENABLE_ASPHERE -#include "fix_nve_asphere.h" -#include "fix_nve_asphere_noforce.h" -#endif -#include "fix_nve_limit.h" -#ifdef ENABLE_ASPHERE -#include "fix_nve_line.h" -#endif -#include "fix_nve_noforce.h" -#include "fix_nve_sphere.h" -#ifdef ENABLE_ASPHERE -#include "fix_nve_tri.h" -#endif -#include "fix_nvt.h" -#ifdef ENABLE_ASPHERE -#include "fix_nvt_asphere.h" -#endif -#include "fix_nvt_sllod.h" -#include "fix_nvt_sphere.h" -#include "fix_planeforce.h" -#include "fix_press_berendsen.h" -#include "fix_print.h" -#include "fix_property_atom.h" -#include "fix_read_restart.h" -#ifdef ENABLE_REAX -#include "fix_reax_bonds.h" -#endif -#include "fix_recenter.h" -#include "fix_respa.h" -#include "fix_restrain.h" -#include "fix_setforce.h" -#include "fix_shear_history.h" -#include "fix_spring.h" -#include "fix_spring_chunk.h" -#include "fix_spring_rg.h" -#include "fix_spring_self.h" -#include "fix_store.h" -#include "fix_store_force.h" -#include "fix_store_state.h" -#include "fix_temp_berendsen.h" -#include "fix_temp_csld.h" -#include "fix_temp_csvr.h" -#include "fix_temp_rescale.h" -#include "fix_tmd.h" -#include "fix_vector.h" -#include "fix_viscous.h" -#include "fix_wall_harmonic.h" -#include "fix_wall_lj1043.h" -#include "fix_wall_lj126.h" -#include "fix_wall_lj93.h" -#include "fix_wall_reflect.h" -#include "fix_wall_region.h" diff --git a/cmake/Headers/style_improper.h b/cmake/Headers/style_improper.h deleted file mode 100644 index 3de3047d73..0000000000 --- a/cmake/Headers/style_improper.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "improper_hybrid.h" -#include "improper_zero.h" diff --git a/cmake/Headers/style_integrate.h b/cmake/Headers/style_integrate.h deleted file mode 100644 index 0a2fd00cf7..0000000000 --- a/cmake/Headers/style_integrate.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "respa.h" -#include "verlet.h" diff --git a/cmake/Headers/style_kspace.h b/cmake/Headers/style_kspace.h deleted file mode 100644 index b2b5c1f82e..0000000000 --- a/cmake/Headers/style_kspace.h +++ /dev/null @@ -1 +0,0 @@ -#include "package.h" diff --git a/cmake/Headers/style_minimize.h b/cmake/Headers/style_minimize.h deleted file mode 100644 index 35d9188e8d..0000000000 --- a/cmake/Headers/style_minimize.h +++ /dev/null @@ -1,6 +0,0 @@ -#include "package.h" -#include "min_cg.h" -#include "min_fire.h" -#include "min_hftn.h" -#include "min_quickmin.h" -#include "min_sd.h" diff --git a/cmake/Headers/style_nbin.h b/cmake/Headers/style_nbin.h deleted file mode 100644 index f0d52b05bc..0000000000 --- a/cmake/Headers/style_nbin.h +++ /dev/null @@ -1,2 +0,0 @@ -#include "package.h" -#include "nbin_standard.h" diff --git a/cmake/Headers/style_npair.h b/cmake/Headers/style_npair.h deleted file mode 100644 index bd403ebeeb..0000000000 --- a/cmake/Headers/style_npair.h +++ /dev/null @@ -1,36 +0,0 @@ -#include "package.h" -#include "npair_copy.h" -#include "npair_full_bin.h" -#include "npair_full_bin_atomonly.h" -#include "npair_full_bin_ghost.h" -#include "npair_full_multi.h" -#include "npair_full_nsq.h" -#include "npair_full_nsq_ghost.h" -#include "npair_half_bin_atomonly_newton.h" -#include "npair_half_bin_newtoff.h" -#include "npair_half_bin_newtoff_ghost.h" -#include "npair_half_bin_newton.h" -#include "npair_half_bin_newton_tri.h" -#include "npair_half_multi_newtoff.h" -#include "npair_half_multi_newton.h" -#include "npair_half_multi_newton_tri.h" -#include "npair_half_nsq_newtoff.h" -#include "npair_half_nsq_newtoff_ghost.h" -#include "npair_half_nsq_newton.h" -#include "npair_half_respa_bin_newtoff.h" -#include "npair_half_respa_bin_newton.h" -#include "npair_half_respa_bin_newton_tri.h" -#include "npair_half_respa_nsq_newtoff.h" -#include "npair_half_respa_nsq_newton.h" -#include "npair_half_size_bin_newtoff.h" -#include "npair_half_size_bin_newton.h" -#include "npair_half_size_bin_newton_tri.h" -#include "npair_half_size_nsq_newtoff.h" -#include "npair_half_size_nsq_newton.h" -#include "npair_halffull_newtoff.h" -#include "npair_halffull_newton.h" -#include "npair_skip.h" -#include "npair_skip_respa.h" -#include "npair_skip_size.h" -#include "npair_skip_size_off2on.h" -#include "npair_skip_size_off2on_oneside.h" diff --git a/cmake/Headers/style_nstencil.h b/cmake/Headers/style_nstencil.h deleted file mode 100644 index d28e4b23b1..0000000000 --- a/cmake/Headers/style_nstencil.h +++ /dev/null @@ -1,21 +0,0 @@ -#include "package.h" -#include "nstencil_full_bin_2d.h" -#include "nstencil_full_bin_3d.h" -#include "nstencil_full_ghost_bin_2d.h" -#include "nstencil_full_ghost_bin_3d.h" -#include "nstencil_full_multi_2d.h" -#include "nstencil_full_multi_3d.h" -#include "nstencil_half_bin_2d_newtoff.h" -#include "nstencil_half_bin_2d_newton.h" -#include "nstencil_half_bin_2d_newton_tri.h" -#include "nstencil_half_bin_3d_newtoff.h" -#include "nstencil_half_bin_3d_newton.h" -#include "nstencil_half_bin_3d_newton_tri.h" -#include "nstencil_half_ghost_bin_2d_newtoff.h" -#include "nstencil_half_ghost_bin_3d_newtoff.h" -#include "nstencil_half_multi_2d_newtoff.h" -#include "nstencil_half_multi_2d_newton.h" -#include "nstencil_half_multi_2d_newton_tri.h" -#include "nstencil_half_multi_3d_newtoff.h" -#include "nstencil_half_multi_3d_newton.h" -#include "nstencil_half_multi_3d_newton_tri.h" diff --git a/cmake/Headers/style_ntopo.h b/cmake/Headers/style_ntopo.h deleted file mode 100644 index 130b10200f..0000000000 --- a/cmake/Headers/style_ntopo.h +++ /dev/null @@ -1,13 +0,0 @@ -#include "package.h" -#include "ntopo_angle_all.h" -#include "ntopo_angle_partial.h" -#include "ntopo_angle_template.h" -#include "ntopo_bond_all.h" -#include "ntopo_bond_partial.h" -#include "ntopo_bond_template.h" -#include "ntopo_dihedral_all.h" -#include "ntopo_dihedral_partial.h" -#include "ntopo_dihedral_template.h" -#include "ntopo_improper_all.h" -#include "ntopo_improper_partial.h" -#include "ntopo_improper_template.h" diff --git a/cmake/Headers/style_pair.h b/cmake/Headers/style_pair.h deleted file mode 100644 index 067e2cdb23..0000000000 --- a/cmake/Headers/style_pair.h +++ /dev/null @@ -1,50 +0,0 @@ -#include "package.h" -#include "pair_beck.h" -#include "pair_born.h" -#include "pair_born_coul_dsf.h" -#include "pair_born_coul_wolf.h" -#include "pair_buck.h" -#include "pair_buck_coul_cut.h" -#include "pair_coul_cut.h" -#include "pair_coul_debye.h" -#include "pair_coul_dsf.h" -#include "pair_coul_streitz.h" -#include "pair_coul_wolf.h" -#include "pair_dpd.h" -#include "pair_dpd_tstat.h" -#include "pair_gauss.h" -#ifdef ENABLE_ASPHERE -#include "pair_gayberne.h" -#endif -#include "pair_hybrid.h" -#include "pair_hybrid_overlay.h" -#ifdef ENABLE_ASPHERE -#include "pair_line_lj.h" -#endif -#include "pair_lj96_cut.h" -#include "pair_lj_cubic.h" -#include "pair_lj_cut.h" -#include "pair_lj_cut_coul_cut.h" -#include "pair_lj_cut_coul_debye.h" -#include "pair_lj_cut_coul_dsf.h" -#include "pair_lj_expand.h" -#include "pair_lj_gromacs.h" -#include "pair_lj_gromacs_coul_gromacs.h" -#include "pair_lj_smooth.h" -#include "pair_lj_smooth_linear.h" -#include "pair_mie_cut.h" -#include "pair_morse.h" -#ifdef ENABLE_REAX -#include "pair_reax.h" -#endif -#ifdef ENABLE_ASPHERE -#include "pair_resquared.h" -#endif -#include "pair_soft.h" -#include "pair_table.h" -#ifdef ENABLE_ASPHERE -#include "pair_tri_lj.h" -#endif -#include "pair_yukawa.h" -#include "pair_zbl.h" -#include "pair_zero.h" diff --git a/cmake/Headers/style_reader.h b/cmake/Headers/style_reader.h deleted file mode 100644 index 0b8145e13d..0000000000 --- a/cmake/Headers/style_reader.h +++ /dev/null @@ -1,3 +0,0 @@ -#include "package.h" -#include "reader_native.h" -#include "reader_xyz.h" diff --git a/cmake/Headers/style_region.h b/cmake/Headers/style_region.h deleted file mode 100644 index dc467b2a3d..0000000000 --- a/cmake/Headers/style_region.h +++ /dev/null @@ -1,9 +0,0 @@ -#include "package.h" -#include "region_block.h" -#include "region_cone.h" -#include "region_cylinder.h" -#include "region_intersect.h" -#include "region_plane.h" -#include "region_prism.h" -#include "region_sphere.h" -#include "region_union.h" diff --git a/cmake/Modules/StyleHeaderUtils.cmake b/cmake/Modules/StyleHeaderUtils.cmake new file mode 100644 index 0000000000..2ee9496671 --- /dev/null +++ b/cmake/Modules/StyleHeaderUtils.cmake @@ -0,0 +1,81 @@ +function(FindStyleHeaders path style_class file_pattern headers) + file(GLOB files "${path}/${file_pattern}*.h") + get_property(hlist GLOBAL PROPERTY ${headers}) + + foreach(file_name ${files}) + file(STRINGS ${file_name} is_style LIMIT_COUNT 1 REGEX ${style_class}) + if(is_style) + list(APPEND hlist ${file_name}) + endif() + endforeach() + set_property(GLOBAL PROPERTY ${headers} "${hlist}") +endfunction(FindStyleHeaders) + +function(CreateStyleHeader path filename) + math(EXPR N "${ARGC}-2") + + set(temp "") + if(N GREATER 0) + math(EXPR ARG_END "${ARGC}-1") + + foreach(IDX RANGE 2 ${ARG_END}) + list(GET ARGV ${IDX} FNAME) + get_filename_component(FNAME ${FNAME} NAME) + set(temp "${temp}#include \"${FNAME}\"\n") + endforeach() + endif() + message("Generating ${filename}...") + file(WRITE "${path}/${filename}" "${temp}" ) +endfunction(CreateStyleHeader) + +function(GenerateStyleHeader path property style) + get_property(files GLOBAL PROPERTY ${property}) + #message("${property} = ${files}") + CreateStyleHeader("${path}" "style_${style}.h" ${files}) +endfunction(GenerateStyleHeader) + +function(RegisterStyles search_path) + FindStyleHeaders(${search_path} ANGLE_CLASS angle_ ANGLE ) # angle ) # force + FindStyleHeaders(${search_path} ATOM_CLASS atom_vec_ ATOM_VEC ) # atom ) # atom atom_vec_hybrid + FindStyleHeaders(${search_path} BODY_CLASS body_ BODY ) # body ) # atom_vec_body + FindStyleHeaders(${search_path} BOND_CLASS bond_ BOND ) # bond ) # force + FindStyleHeaders(${search_path} COMMAND_CLASS "" COMMAND ) # command ) # input + FindStyleHeaders(${search_path} COMPUTE_CLASS compute_ COMPUTE ) # compute ) # modify + FindStyleHeaders(${search_path} DIHEDRAL_CLASS dihedral_ DIHEDRAL ) # dihedral ) # force + FindStyleHeaders(${search_path} DUMP_CLASS dump_ DUMP ) # dump ) # output write_dump + FindStyleHeaders(${search_path} FIX_CLASS fix_ FIX ) # fix ) # modify + FindStyleHeaders(${search_path} IMPROPER_CLASS improper_ IMPROPER ) # improper ) # force + FindStyleHeaders(${search_path} INTEGRATE_CLASS "" INTEGRATE ) # integrate ) # update + FindStyleHeaders(${search_path} KSPACE_CLASS "" KSPACE ) # kspace ) # force + FindStyleHeaders(${search_path} MINIMIZE_CLASS min_ MINIMIZE ) # minimize ) # update + FindStyleHeaders(${search_path} NBIN_CLASS nbin_ NBIN ) # nbin ) # neighbor + FindStyleHeaders(${search_path} NPAIR_CLASS npair_ NPAIR ) # npair ) # neighbor + FindStyleHeaders(${search_path} NSTENCIL_CLASS nstencil_ NSTENCIL ) # nstencil ) # neighbor + FindStyleHeaders(${search_path} NTOPO_CLASS ntopo_ NTOPO ) # ntopo ) # neighbor + FindStyleHeaders(${search_path} PAIR_CLASS pair_ PAIR ) # pair ) # force + FindStyleHeaders(${search_path} READER_CLASS reader_ READER ) # reader ) # read_dump + FindStyleHeaders(${search_path} REGION_CLASS region_ REGION ) # region ) # domain +endfunction(RegisterStyles) + +function(GenerateStyleHeaders output_path) + GenerateStyleHeader(${output_path} ANGLE angle ) # force + GenerateStyleHeader(${output_path} ATOM_VEC atom ) # atom atom_vec_hybrid + GenerateStyleHeader(${output_path} BODY body ) # atom_vec_body + GenerateStyleHeader(${output_path} BOND bond ) # force + GenerateStyleHeader(${output_path} COMMAND command ) # input + GenerateStyleHeader(${output_path} COMPUTE compute ) # modify + GenerateStyleHeader(${output_path} DIHEDRAL dihedral ) # force + GenerateStyleHeader(${output_path} DUMP dump ) # output write_dump + GenerateStyleHeader(${output_path} FIX fix ) # modify + GenerateStyleHeader(${output_path} IMPROPER improper ) # force + GenerateStyleHeader(${output_path} INTEGRATE integrate ) # update + GenerateStyleHeader(${output_path} KSPACE kspace ) # force + GenerateStyleHeader(${output_path} MINIMIZE minimize ) # update + GenerateStyleHeader(${output_path} NBIN nbin ) # neighbor + GenerateStyleHeader(${output_path} NPAIR npair ) # neighbor + GenerateStyleHeader(${output_path} NSTENCIL nstencil ) # neighbor + GenerateStyleHeader(${output_path} NTOPO ntopo ) # neighbor + GenerateStyleHeader(${output_path} PAIR pair ) # force + GenerateStyleHeader(${output_path} READER reader ) # read_dump + GenerateStyleHeader(${output_path} REGION region ) # domain +endfunction(GenerateStyleHeaders) From b85979503ffc41a83750efa5caae14e331af9091 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 18:19:59 -0500 Subject: [PATCH 094/293] Add CMake support for more packages BODY, COLLOID, CLASS2, COMPRESS, CORESHELL, DIPOLE, GRANULAR, MC, MOLECULE, MANYBODY, RIGID --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 74785d340f..7fc2304a4c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -40,7 +40,7 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) -set(PACKAGES ASPHERE KSPACE REAX) +set(PACKAGES ASPHERE BODY COLLOID CLASS2 COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MC MOLECULE MANYBODY RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() From 0a6e9c8bf676a12ef9a6dad0c8b67eb2b10e5eff Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 17:41:13 -0600 Subject: [PATCH 095/293] added ENABLE_ALL option --- cmake/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7fc2304a4c..5cff0f0a54 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -40,9 +40,10 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) +option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY COLLOID CLASS2 COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MC MOLECULE MANYBODY RIGID REAX) foreach(PKG ${PACKAGES}) - option(ENABLE_${PKG} "Build ${PKG} Package" OFF) + option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() set(ACCEL_PACKAGES USER-OMP) @@ -169,3 +170,9 @@ install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTI add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) install(TARGETS lammps DESTINATION ${CMAKE_INSTALL_BINDIR}) + +foreach(PKG ${PACKAGES} ${ACCEL_PACKAGES}) + if(ENABLE_${PKG}) + message(STATUS "Building package: ${PKG}") + endif() +endforeach() From 54f2b02ac813f5931a8e4118395ccc86078d583b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 18:33:27 -0600 Subject: [PATCH 096/293] cmake: fix install --- cmake/CMakeLists.txt | 10 ++++++++-- cmake/Modules/StyleHeaderUtils.cmake | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 5cff0f0a54..96d1595f6b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -26,6 +26,7 @@ include(CheckCCompilerFlag) # User input options # ######################################################################## option(BUILD_SHARED_LIBS "Build shared libs" OFF) +option(INSTALL_LIB "Install lammps library and header" ON) include(GNUInstallDirs) set(LAMMPS_LINK_LIBS) @@ -165,11 +166,16 @@ include_directories(${LAMMPS_STYLE_HEADERS_DIR}) add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) -install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) +if(INSTALL_LIB) + install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) +elseif(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "Shared library has to install, use -DBUILD_SHARED_LIBS=OFF to install lammps with a a library") +endif() add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) -install(TARGETS lammps DESTINATION ${CMAKE_INSTALL_BINDIR}) +install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) foreach(PKG ${PACKAGES} ${ACCEL_PACKAGES}) if(ENABLE_${PKG}) diff --git a/cmake/Modules/StyleHeaderUtils.cmake b/cmake/Modules/StyleHeaderUtils.cmake index 2ee9496671..bbb93e6145 100644 --- a/cmake/Modules/StyleHeaderUtils.cmake +++ b/cmake/Modules/StyleHeaderUtils.cmake @@ -24,7 +24,7 @@ function(CreateStyleHeader path filename) set(temp "${temp}#include \"${FNAME}\"\n") endforeach() endif() - message("Generating ${filename}...") + message(STATUS "Generating ${filename}...") file(WRITE "${path}/${filename}" "${temp}" ) endfunction(CreateStyleHeader) From d079b2f758fe1a0235897d9f74376fda07a8ed69 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 14 Jul 2017 18:37:06 -0600 Subject: [PATCH 097/293] CreateStyleHeader: use temp file --- cmake/Modules/StyleHeaderUtils.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/Modules/StyleHeaderUtils.cmake b/cmake/Modules/StyleHeaderUtils.cmake index bbb93e6145..b0b9bd9418 100644 --- a/cmake/Modules/StyleHeaderUtils.cmake +++ b/cmake/Modules/StyleHeaderUtils.cmake @@ -25,7 +25,8 @@ function(CreateStyleHeader path filename) endforeach() endif() message(STATUS "Generating ${filename}...") - file(WRITE "${path}/${filename}" "${temp}" ) + file(WRITE "${path}/${filename}.tmp" "${temp}" ) + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${path}/${filename}.tmp" "${path}/${filename}") endfunction(CreateStyleHeader) function(GenerateStyleHeader path property style) From 3f297382ac1f4682626555e840ed243bbc0a1ec3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 22:41:59 -0400 Subject: [PATCH 098/293] Revert "do not allow pairwise cutoffs <= 0.0. avoids undefined behavior and division by zero errors" This reverts commit a04711b21f06b78270f852bb62beed12eb7e4475. --- src/pair.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pair.cpp b/src/pair.cpp index 21c8fe00e5..ce711c4f5d 100644 --- a/src/pair.cpp +++ b/src/pair.cpp @@ -242,7 +242,6 @@ void Pair::init() for (i = 1; i <= atom->ntypes; i++) for (j = i; j <= atom->ntypes; j++) { cut = init_one(i,j); - if (cut <= 0.0) error->all(FLERR,"Illegal pair style cutoff <= 0.0"); cutsq[i][j] = cutsq[j][i] = cut*cut; cutforce = MAX(cutforce,cut); if (tail_flag) { From 5e841bfe1522a4ea54baed7472d5ee74243bacfa Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Fri, 14 Jul 2017 22:07:53 -0500 Subject: [PATCH 099/293] Added USER-OMP support to CMake build --- cmake/CMakeLists.txt | 28 ++++++++++++++-- cmake/Modules/StyleHeaderUtils.cmake | 50 ++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7fc2304a4c..35c0708d36 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -45,7 +45,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() -set(ACCEL_PACKAGES USER-OMP) +set(ACCEL_PACKAGES USER_OMP) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -139,7 +139,31 @@ endforeach() # packages which selectively include variants based on enabled styles # e.g. accelerator packages -# TODO +if(ENABLE_USER_OMP) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + else() + message(FATAL_ERROR "USER-OMP requires a compiler with OpenMP support") + endif() + + set(USER_OMP_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-OMP) + set(USER_OMP_SOURCES ${USER_OMP_SOURCES_DIR}/thr_data.cpp + ${USER_OMP_SOURCES_DIR}/thr_omp.cpp + ${USER_OMP_SOURCES_DIR}/fix_nh_omp.cpp + ${USER_OMP_SOURCES_DIR}/fix_nh_sphere_omp.cpp) + set_property(GLOBAL PROPERTY "OMP_SOURCES" "${USER_OMP_SOURCES}") + + # detects styles which have USER-OMP version + RegisterStylesExt(${USER_OMP_SOURCES_DIR} omp OMP_SOURCES) + + get_property(USER_OMP_SOURCES GLOBAL PROPERTY OMP_SOURCES) + + list(APPEND LIB_SOURCES ${USER_OMP_SOURCES}) + include_directories(${USER_OMP_SOURCES_DIR}) +endif() + if(ENABLE_REAX) enable_language(Fortran) diff --git a/cmake/Modules/StyleHeaderUtils.cmake b/cmake/Modules/StyleHeaderUtils.cmake index 2ee9496671..55a6c15223 100644 --- a/cmake/Modules/StyleHeaderUtils.cmake +++ b/cmake/Modules/StyleHeaderUtils.cmake @@ -11,6 +11,33 @@ function(FindStyleHeaders path style_class file_pattern headers) set_property(GLOBAL PROPERTY ${headers} "${hlist}") endfunction(FindStyleHeaders) +function(FindStyleHeadersExt path style_class extension headers sources) + get_property(hlist GLOBAL PROPERTY ${headers}) + get_property(slist GLOBAL PROPERTY ${sources}) + set(ext_list) + get_filename_component(abs_path "${path}" ABSOLUTE) + + foreach(file_name ${hlist}) + get_filename_component(basename ${file_name} NAME_WE) + set(ext_file_name "${abs_path}/${basename}_${extension}.h") + if(EXISTS "${ext_file_name}") + file(STRINGS ${ext_file_name} is_style LIMIT_COUNT 1 REGEX ${style_class}) + if(is_style) + list(APPEND ext_list ${ext_file_name}) + + set(source_file_name "${abs_path}/${basename}_${extension}.cpp") + if(EXISTS "${source_file_name}") + list(APPEND slist ${source_file_name}) + endif() + endif() + endif() + endforeach() + + list(APPEND hlist ${ext_list}) + set_property(GLOBAL PROPERTY ${headers} "${hlist}") + set_property(GLOBAL PROPERTY ${sources} "${slist}") +endfunction(FindStyleHeadersExt) + function(CreateStyleHeader path filename) math(EXPR N "${ARGC}-2") @@ -57,6 +84,29 @@ function(RegisterStyles search_path) FindStyleHeaders(${search_path} REGION_CLASS region_ REGION ) # region ) # domain endfunction(RegisterStyles) +function(RegisterStylesExt search_path extension sources) + FindStyleHeadersExt(${search_path} ANGLE_CLASS ${extension} ANGLE ${sources}) + FindStyleHeadersExt(${search_path} ATOM_CLASS ${extension} ATOM_VEC ${sources}) + FindStyleHeadersExt(${search_path} BODY_CLASS ${extension} BODY ${sources}) + FindStyleHeadersExt(${search_path} BOND_CLASS ${extension} BOND ${sources}) + FindStyleHeadersExt(${search_path} COMMAND_CLASS ${extension} COMMAND ${sources}) + FindStyleHeadersExt(${search_path} COMPUTE_CLASS ${extension} COMPUTE ${sources}) + FindStyleHeadersExt(${search_path} DIHEDRAL_CLASS ${extension} DIHEDRAL ${sources}) + FindStyleHeadersExt(${search_path} DUMP_CLASS ${extension} DUMP ${sources}) + FindStyleHeadersExt(${search_path} FIX_CLASS ${extension} FIX ${sources}) + FindStyleHeadersExt(${search_path} IMPROPER_CLASS ${extension} IMPROPER ${sources}) + FindStyleHeadersExt(${search_path} INTEGRATE_CLASS ${extension} INTEGRATE ${sources}) + FindStyleHeadersExt(${search_path} KSPACE_CLASS ${extension} KSPACE ${sources}) + FindStyleHeadersExt(${search_path} MINIMIZE_CLASS ${extension} MINIMIZE ${sources}) + FindStyleHeadersExt(${search_path} NBIN_CLASS ${extension} NBIN ${sources}) + FindStyleHeadersExt(${search_path} NPAIR_CLASS ${extension} NPAIR ${sources}) + FindStyleHeadersExt(${search_path} NSTENCIL_CLASS ${extension} NSTENCIL ${sources}) + FindStyleHeadersExt(${search_path} NTOPO_CLASS ${extension} NTOPO ${sources}) + FindStyleHeadersExt(${search_path} PAIR_CLASS ${extension} PAIR ${sources}) + FindStyleHeadersExt(${search_path} READER_CLASS ${extension} READER ${sources}) + FindStyleHeadersExt(${search_path} REGION_CLASS ${extension} REGION ${sources}) +endfunction(RegisterStylesExt) + function(GenerateStyleHeaders output_path) GenerateStyleHeader(${output_path} ANGLE angle ) # force GenerateStyleHeader(${output_path} ATOM_VEC atom ) # atom atom_vec_hybrid From 4ec07422f07cc325435a4eeeefbdcc24d5a08559 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 14 Jul 2017 23:33:00 -0400 Subject: [PATCH 100/293] avoid division by zero when using cutoff 0.0 with pair_modify shift yes --- src/ASPHERE/pair_gayberne.cpp | 2 +- src/ASPHERE/pair_resquared.cpp | 2 +- src/CLASS2/pair_lj_class2.cpp | 2 +- src/CLASS2/pair_lj_class2_coul_cut.cpp | 2 +- src/CLASS2/pair_lj_class2_coul_long.cpp | 2 +- src/COLLOID/pair_colloid.cpp | 2 +- src/COLLOID/pair_yukawa_colloid.cpp | 2 +- src/DIPOLE/pair_lj_cut_dipole_cut.cpp | 2 +- src/DIPOLE/pair_lj_cut_dipole_long.cpp | 2 +- src/DIPOLE/pair_lj_long_dipole_long.cpp | 2 +- src/KSPACE/pair_born_coul_long.cpp | 2 +- src/KSPACE/pair_buck_coul_long.cpp | 2 +- src/KSPACE/pair_buck_long_coul_long.cpp | 2 +- src/KSPACE/pair_lj_cut_coul_long.cpp | 2 +- src/KSPACE/pair_lj_long_coul_long.cpp | 2 +- src/MISC/pair_nm_cut.cpp | 2 +- src/MISC/pair_nm_cut_coul_cut.cpp | 2 +- src/MISC/pair_nm_cut_coul_long.cpp | 2 +- src/MOLECULE/pair_lj_cut_tip4p_cut.cpp | 2 +- src/USER-CGSDK/pair_lj_sdk.cpp | 2 +- src/USER-CGSDK/pair_lj_sdk_coul_long.cpp | 2 +- .../pair_lj_charmm_coul_long_soft.cpp | 2 +- src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp | 4 +- src/USER-FEP/pair_lj_cut_coul_long_soft.cpp | 4 +- src/USER-FEP/pair_lj_cut_soft.cpp | 4 +- src/USER-MISC/pair_buck_mdf.cpp | 2 +- src/USER-MISC/pair_coul_diel.cpp | 2 +- src/USER-MISC/pair_gauss_cut.cpp | 3 + src/USER-MISC/pair_kolmogorov_crespi_z.cpp | 4 +- src/USER-MISC/pair_list.cpp | 94 +++++++++---------- src/pair_born.cpp | 2 +- src/pair_born_coul_dsf.cpp | 2 +- src/pair_born_coul_wolf.cpp | 2 +- src/pair_buck.cpp | 2 +- src/pair_buck_coul_cut.cpp | 2 +- src/pair_lj96_cut.cpp | 2 +- src/pair_lj_cut.cpp | 2 +- src/pair_lj_cut_coul_cut.cpp | 2 +- src/pair_lj_cut_coul_dsf.cpp | 2 +- src/pair_lj_expand.cpp | 2 +- src/pair_mie_cut.cpp | 2 +- src/pair_yukawa.cpp | 2 +- 42 files changed, 97 insertions(+), 88 deletions(-) diff --git a/src/ASPHERE/pair_gayberne.cpp b/src/ASPHERE/pair_gayberne.cpp index 25bdae14f1..9ff87326ed 100644 --- a/src/ASPHERE/pair_gayberne.cpp +++ b/src/ASPHERE/pair_gayberne.cpp @@ -391,7 +391,7 @@ double PairGayBerne::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/ASPHERE/pair_resquared.cpp b/src/ASPHERE/pair_resquared.cpp index ed9d9b36c4..caa031a1e8 100644 --- a/src/ASPHERE/pair_resquared.cpp +++ b/src/ASPHERE/pair_resquared.cpp @@ -391,7 +391,7 @@ double PairRESquared::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/CLASS2/pair_lj_class2.cpp b/src/CLASS2/pair_lj_class2.cpp index e79dc0c6de..0b90b2717e 100644 --- a/src/CLASS2/pair_lj_class2.cpp +++ b/src/CLASS2/pair_lj_class2.cpp @@ -235,7 +235,7 @@ double PairLJClass2::init_one(int i, int j) lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/CLASS2/pair_lj_class2_coul_cut.cpp b/src/CLASS2/pair_lj_class2_coul_cut.cpp index bec7f1da15..395953e0a9 100644 --- a/src/CLASS2/pair_lj_class2_coul_cut.cpp +++ b/src/CLASS2/pair_lj_class2_coul_cut.cpp @@ -286,7 +286,7 @@ double PairLJClass2CoulCut::init_one(int i, int j) lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/CLASS2/pair_lj_class2_coul_long.cpp b/src/CLASS2/pair_lj_class2_coul_long.cpp index 5f7d738e92..5d2ae891d0 100644 --- a/src/CLASS2/pair_lj_class2_coul_long.cpp +++ b/src/CLASS2/pair_lj_class2_coul_long.cpp @@ -329,7 +329,7 @@ double PairLJClass2CoulLong::init_one(int i, int j) lj3[i][j] = 2.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 3.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = epsilon[i][j] * (2.0*pow(ratio,9.0) - 3.0*pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/COLLOID/pair_colloid.cpp b/src/COLLOID/pair_colloid.cpp index 68150f6eff..983b973e0e 100644 --- a/src/COLLOID/pair_colloid.cpp +++ b/src/COLLOID/pair_colloid.cpp @@ -354,7 +354,7 @@ double PairColloid::init_one(int i, int j) lj4[j][i] = lj4[i][j] = 4.0 * epsilon * sigma6[i][j]; offset[j][i] = offset[i][j] = 0.0; - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double tmp; offset[j][i] = offset[i][j] = single(0,0,i,j,cut[i][j]*cut[i][j],0.0,1.0,tmp); diff --git a/src/COLLOID/pair_yukawa_colloid.cpp b/src/COLLOID/pair_yukawa_colloid.cpp index 9b8d0ecaad..87fa7f5422 100644 --- a/src/COLLOID/pair_yukawa_colloid.cpp +++ b/src/COLLOID/pair_yukawa_colloid.cpp @@ -147,7 +147,7 @@ double PairYukawaColloid::init_one(int i, int j) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } - if (offset_flag) { + if (offset_flag && (kappa != 0.0)) { double screening = exp(-kappa * (cut[i][j] - (rad[i]+rad[j]))); offset[i][j] = a[i][j]/kappa * screening; } else offset[i][j] = 0.0; diff --git a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp index addd02e505..af987bf258 100644 --- a/src/DIPOLE/pair_lj_cut_dipole_cut.cpp +++ b/src/DIPOLE/pair_lj_cut_dipole_cut.cpp @@ -387,7 +387,7 @@ double PairLJCutDipoleCut::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/DIPOLE/pair_lj_cut_dipole_long.cpp b/src/DIPOLE/pair_lj_cut_dipole_long.cpp index 78922e356f..63f48bea81 100644 --- a/src/DIPOLE/pair_lj_cut_dipole_long.cpp +++ b/src/DIPOLE/pair_lj_cut_dipole_long.cpp @@ -420,7 +420,7 @@ double PairLJCutDipoleLong::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/DIPOLE/pair_lj_long_dipole_long.cpp b/src/DIPOLE/pair_lj_long_dipole_long.cpp index 15ac2e788c..b833b250d4 100644 --- a/src/DIPOLE/pair_lj_long_dipole_long.cpp +++ b/src/DIPOLE/pair_lj_long_dipole_long.cpp @@ -314,7 +314,7 @@ double PairLJLongDipoleLong::init_one(int i, int j) //if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3]) //error->all(FLERR,"Pair cutoff < Respa interior cutoff"); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp index e588a30b55..479128ef2b 100644 --- a/src/KSPACE/pair_born_coul_long.cpp +++ b/src/KSPACE/pair_born_coul_long.cpp @@ -311,7 +311,7 @@ double PairBornCoulLong::init_one(int i, int j) born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) + d[i][j]/pow(cut_lj[i][j],8.0); diff --git a/src/KSPACE/pair_buck_coul_long.cpp b/src/KSPACE/pair_buck_coul_long.cpp index 476e3c716a..95496409b9 100644 --- a/src/KSPACE/pair_buck_coul_long.cpp +++ b/src/KSPACE/pair_buck_coul_long.cpp @@ -297,7 +297,7 @@ double PairBuckCoulLong::init_one(int i, int j) buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double rexp = exp(-cut_lj[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0); } else offset[i][j] = 0.0; diff --git a/src/KSPACE/pair_buck_long_coul_long.cpp b/src/KSPACE/pair_buck_long_coul_long.cpp index 8aa4d72083..4cfb9b7267 100644 --- a/src/KSPACE/pair_buck_long_coul_long.cpp +++ b/src/KSPACE/pair_buck_long_coul_long.cpp @@ -330,7 +330,7 @@ double PairBuckLongCoulLong::init_one(int i, int j) if (cut_respa && MIN(cut_buck[i][j],cut_coul) < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); - if (offset_flag) { + if (offset_flag && (cut_buck[i][j] > 0.0)) { double rexp = exp(-cut_buck[i][j]/buck_rho[i][j]); offset[i][j] = buck_a[i][j]*rexp - buck_c[i][j]/pow(cut_buck[i][j],6.0); } else offset[i][j] = 0.0; diff --git a/src/KSPACE/pair_lj_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp index e9799843fc..f8be9fdb79 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -743,7 +743,7 @@ double PairLJCutCoulLong::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/KSPACE/pair_lj_long_coul_long.cpp b/src/KSPACE/pair_lj_long_coul_long.cpp index 44256a9fbb..7c6adfcb41 100644 --- a/src/KSPACE/pair_lj_long_coul_long.cpp +++ b/src/KSPACE/pair_lj_long_coul_long.cpp @@ -333,7 +333,7 @@ double PairLJLongCoulLong::init_one(int i, int j) if (cut_respa && MIN(cut_lj[i][j],cut_coul) < cut_respa[3]) error->all(FLERR,"Pair cutoff < Respa interior cutoff"); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/MISC/pair_nm_cut.cpp b/src/MISC/pair_nm_cut.cpp index 0163cdcf58..b9bf6ac477 100644 --- a/src/MISC/pair_nm_cut.cpp +++ b/src/MISC/pair_nm_cut.cpp @@ -243,7 +243,7 @@ double PairNMCut::init_one(int i, int j) r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut[i][j],mm[i][j]))); diff --git a/src/MISC/pair_nm_cut_coul_cut.cpp b/src/MISC/pair_nm_cut_coul_cut.cpp index 5cb2452906..78c77a648f 100644 --- a/src/MISC/pair_nm_cut_coul_cut.cpp +++ b/src/MISC/pair_nm_cut_coul_cut.cpp @@ -291,7 +291,7 @@ double PairNMCutCoulCut::init_one(int i, int j) r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j]))); diff --git a/src/MISC/pair_nm_cut_coul_long.cpp b/src/MISC/pair_nm_cut_coul_long.cpp index 15d5d03757..8e0da40eac 100644 --- a/src/MISC/pair_nm_cut_coul_long.cpp +++ b/src/MISC/pair_nm_cut_coul_long.cpp @@ -339,7 +339,7 @@ double PairNMCutCoulLong::init_one(int i, int j) r0n[i][j] = pow(r0[i][j],nn[i][j]); r0m[i][j] = pow(r0[i][j],mm[i][j]); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { offset[i][j] = e0nm[i][j] * ((mm[i][j]*r0n[i][j] / pow(cut_lj[i][j],nn[i][j])) - (nn[i][j]*r0m[i][j] / pow(cut_lj[i][j],mm[i][j]))); diff --git a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp index e3093e4d10..c616a9fa83 100644 --- a/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp +++ b/src/MOLECULE/pair_lj_cut_tip4p_cut.cpp @@ -531,7 +531,7 @@ double PairLJCutTIP4PCut::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/USER-CGSDK/pair_lj_sdk.cpp b/src/USER-CGSDK/pair_lj_sdk.cpp index 23b0f47a6d..56e56c9605 100644 --- a/src/USER-CGSDK/pair_lj_sdk.cpp +++ b/src/USER-CGSDK/pair_lj_sdk.cpp @@ -311,7 +311,7 @@ double PairLJSDK::init_one(int i, int j) lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = lj_prefact[ljt] * epsilon[i][j] * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); } else offset[i][j] = 0.0; diff --git a/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp b/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp index 845c5822a7..4c9e42f778 100644 --- a/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp +++ b/src/USER-CGSDK/pair_lj_sdk_coul_long.cpp @@ -401,7 +401,7 @@ double PairLJSDKCoulLong::init_one(int i, int j) lj3[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow1[ljt]); lj4[i][j] = lj_prefact[ljt] * epsilon[i][j] * pow(sigma[i][j],lj_pow2[ljt]); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = lj_prefact[ljt] * epsilon[i][j] * (pow(ratio,lj_pow1[ljt]) - pow(ratio,lj_pow2[ljt])); diff --git a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp index 81b82e9774..d8bfd698be 100644 --- a/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp +++ b/src/USER-FEP/pair_lj_charmm_coul_long_soft.cpp @@ -994,7 +994,7 @@ double PairLJCharmmCoulLongSoft::single(int i, int j, int itype, int jtype, if (rsq < cut_ljsq) { philj = lj1[itype][jtype] * 4.0 * epsilon[itype][jtype] * - (1.0/(denlj*denlj) - 1.0/denlj) - offset[itype][jtype]; + (1.0/(denlj*denlj) - 1.0/denlj); if (rsq > cut_lj_innersq) { switch1 = (cut_ljsq-rsq) * (cut_ljsq-rsq) * (cut_ljsq + 2.0*rsq - 3.0*cut_lj_innersq) / denom_lj; diff --git a/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp index b2e781c57b..9e52a16a02 100644 --- a/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_coul_cut_soft.cpp @@ -236,6 +236,8 @@ void PairLJCutCoulCutSoft::coeff(int narg, char **arg) double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); + if (sigma_one <= 0.0) + error->all(FLERR,"Incorrect args for pair coefficients"); double cut_lj_one = cut_lj_global; double cut_coul_one = cut_coul_global; @@ -296,7 +298,7 @@ double PairLJCutCoulCutSoft::init_one(int i, int j) lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; diff --git a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp index 3b80729b0b..f7c4084fe2 100644 --- a/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_coul_long_soft.cpp @@ -604,6 +604,8 @@ void PairLJCutCoulLongSoft::coeff(int narg, char **arg) double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); + if (sigma_one <= 0.0) + error->all(FLERR,"Incorrect args for pair coefficients"); double cut_lj_one = cut_lj_global; if (narg == 6) cut_lj_one = force->numeric(FLERR,arg[5]); @@ -723,7 +725,7 @@ double PairLJCutCoulLongSoft::init_one(int i, int j) lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); lj4[i][j] = alphac * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double denlj = lj3[i][j] + pow(cut_lj[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; diff --git a/src/USER-FEP/pair_lj_cut_soft.cpp b/src/USER-FEP/pair_lj_cut_soft.cpp index 800fdfcde8..8b6280a61a 100644 --- a/src/USER-FEP/pair_lj_cut_soft.cpp +++ b/src/USER-FEP/pair_lj_cut_soft.cpp @@ -484,6 +484,8 @@ void PairLJCutSoft::coeff(int narg, char **arg) double epsilon_one = force->numeric(FLERR,arg[2]); double sigma_one = force->numeric(FLERR,arg[3]); double lambda_one = force->numeric(FLERR,arg[4]); + if (sigma_one <= 0.0) + error->all(FLERR,"Incorrect args for pair coefficients"); double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); @@ -584,7 +586,7 @@ double PairLJCutSoft::init_one(int i, int j) lj2[i][j] = pow(sigma[i][j], 6.0); lj3[i][j] = alphalj * (1.0 - lambda[i][j])*(1.0 - lambda[i][j]); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double denlj = lj3[i][j] + pow(cut[i][j] / sigma[i][j], 6.0); offset[i][j] = lj1[i][j] * 4.0 * epsilon[i][j] * (1.0/(denlj*denlj) - 1.0/denlj); } else offset[i][j] = 0.0; diff --git a/src/USER-MISC/pair_buck_mdf.cpp b/src/USER-MISC/pair_buck_mdf.cpp index 6c3dcbd7ee..372fbaf8c0 100644 --- a/src/USER-MISC/pair_buck_mdf.cpp +++ b/src/USER-MISC/pair_buck_mdf.cpp @@ -259,7 +259,7 @@ double PairBuckMDF::init_one(int i, int j) buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double rexp = exp(-cut[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0); } else offset[i][j] = 0.0; diff --git a/src/USER-MISC/pair_coul_diel.cpp b/src/USER-MISC/pair_coul_diel.cpp index a62362aa6f..c653e9abb2 100644 --- a/src/USER-MISC/pair_coul_diel.cpp +++ b/src/USER-MISC/pair_coul_diel.cpp @@ -235,7 +235,7 @@ double PairCoulDiel::init_one(int i, int j) double *q = atom->q; double qqrd2e = force->qqrd2e; - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double rarg = (cut[i][j]-rme[i][j])/sigmae[i][j]; double epsr=a_eps+b_eps*tanh(rarg); offset[i][j] = qqrd2e*q[i]*q[j]*((eps_s/epsr) -1.)/cut[i][j]; diff --git a/src/USER-MISC/pair_gauss_cut.cpp b/src/USER-MISC/pair_gauss_cut.cpp index 3836187a64..4408545c34 100644 --- a/src/USER-MISC/pair_gauss_cut.cpp +++ b/src/USER-MISC/pair_gauss_cut.cpp @@ -196,6 +196,9 @@ void PairGaussCut::coeff(int narg, char **arg) double hgauss_one = force->numeric(FLERR,arg[2]); double rmh_one = force->numeric(FLERR,arg[3]); double sigmah_one = force->numeric(FLERR,arg[4]); + if (sigmah_one <= 0.0) + error->all(FLERR,"Incorrect args for pair coefficients"); + double cut_one = cut_global; if (narg == 6) cut_one = force->numeric(FLERR,arg[5]); diff --git a/src/USER-MISC/pair_kolmogorov_crespi_z.cpp b/src/USER-MISC/pair_kolmogorov_crespi_z.cpp index 15a325e106..c03aee6362 100644 --- a/src/USER-MISC/pair_kolmogorov_crespi_z.cpp +++ b/src/USER-MISC/pair_kolmogorov_crespi_z.cpp @@ -53,7 +53,7 @@ PairKolmogorovCrespiZ::PairKolmogorovCrespiZ(LAMMPS *lmp) : Pair(lmp) map = NULL; // always compute energy offset - offset_flag = true; + offset_flag = 1; } /* ---------------------------------------------------------------------- */ @@ -285,7 +285,7 @@ double PairKolmogorovCrespiZ::init_one(int i, int j) { if (setflag[i][j] == 0) error->all(FLERR,"All pair coeffs are not set"); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { int iparam_ij = elem2param[map[i]][map[j]]; Param& p = params[iparam_ij]; offset[i][j] = -p.A*pow(p.z0/cut[i][j],6); diff --git a/src/USER-MISC/pair_list.cpp b/src/USER-MISC/pair_list.cpp index 3adbe8b69d..458c228d58 100644 --- a/src/USER-MISC/pair_list.cpp +++ b/src/USER-MISC/pair_list.cpp @@ -81,7 +81,7 @@ void PairList::compute(int eflag, int vflag) { if (eflag || vflag) ev_setup(eflag,vflag); else evflag = vflag_fdotr = eflag_global = - vflag_global = eflag_atom = vflag_atom = 0; + vflag_global = eflag_atom = vflag_atom = 0; const int nlocal = atom->nlocal; const int newton_pair = force->newton_pair; @@ -126,46 +126,46 @@ void PairList::compute(int eflag, int vflag) const double r2inv = 1.0/rsq; if (style[n] == HARM) { - const double r = sqrt(rsq); - const double dr = par.parm.harm.r0 - r; - fpair = 2.0*par.parm.harm.k*dr/r; + const double r = sqrt(rsq); + const double dr = par.parm.harm.r0 - r; + fpair = 2.0*par.parm.harm.k*dr/r; - if (eflag_either) - epair = par.parm.harm.k*dr*dr - par.offset; + if (eflag_either) + epair = par.parm.harm.k*dr*dr - par.offset; } else if (style[n] == MORSE) { - const double r = sqrt(rsq); - const double dr = par.parm.morse.r0 - r; - const double dexp = exp(par.parm.morse.alpha * dr); - fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha - * (dexp*dexp - dexp) / r; + const double r = sqrt(rsq); + const double dr = par.parm.morse.r0 - r; + const double dexp = exp(par.parm.morse.alpha * dr); + fpair = 2.0*par.parm.morse.d0*par.parm.morse.alpha + * (dexp*dexp - dexp) / r; - if (eflag_either) - epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset; + if (eflag_either) + epair = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp) - par.offset; } else if (style[n] == LJ126) { - const double r6inv = r2inv*r2inv*r2inv; - const double sig6 = mypow(par.parm.lj126.sigma,6); - fpair = 24.0*par.parm.lj126.epsilon*r6inv - * (2.0*sig6*sig6*r6inv - sig6) * r2inv; + const double r6inv = r2inv*r2inv*r2inv; + const double sig6 = mypow(par.parm.lj126.sigma,6); + fpair = 24.0*par.parm.lj126.epsilon*r6inv + * (2.0*sig6*sig6*r6inv - sig6) * r2inv; - if (eflag_either) - epair = 4.0*par.parm.lj126.epsilon*r6inv - * (sig6*sig6*r6inv - sig6) - par.offset; + if (eflag_either) + epair = 4.0*par.parm.lj126.epsilon*r6inv + * (sig6*sig6*r6inv - sig6) - par.offset; } if (newton_pair || i < nlocal) { - f[i].x += dx*fpair; - f[i].y += dy*fpair; - f[i].z += dz*fpair; + f[i].x += dx*fpair; + f[i].y += dy*fpair; + f[i].z += dz*fpair; } if (newton_pair || j < nlocal) { - f[j].x -= dx*fpair; - f[j].y -= dy*fpair; - f[j].z -= dz*fpair; + f[j].x -= dx*fpair; + f[j].y -= dy*fpair; + f[j].z -= dz*fpair; } if (evflag) ev_tally(i,j,nlocal,newton_pair,epair,0.0,fpair,dx,dy,dz); @@ -174,10 +174,10 @@ void PairList::compute(int eflag, int vflag) if (vflag_fdotr) virial_fdotr_compute(); if (check_flag) { - int tmp; - MPI_Allreduce(&pc,&tmp,1,MPI_INT,MPI_SUM,world); - if (tmp != 2*npairs) - error->all(FLERR,"Not all pairs processed in pair_style list"); + int tmp; + MPI_Allreduce(&pc,&tmp,1,MPI_INT,MPI_SUM,world); + if (tmp != 2*npairs) + error->all(FLERR,"Not all pairs processed in pair_style list"); } } @@ -263,12 +263,12 @@ void PairList::settings(int narg, char **arg) ptr = strtok(NULL," \t\n\r\f"); if ((ptr == NULL) || (*ptr == '#')) - error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); + error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); par.parm.harm.k = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if ((ptr == NULL) || (*ptr == '#')) - error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); + error->all(FLERR,"Incorrectly formatted harmonic pair parameters"); par.parm.harm.r0 = force->numeric(FLERR,ptr); ++nharm; @@ -279,17 +279,17 @@ void PairList::settings(int narg, char **arg) ptr = strtok(NULL," \t\n\r\f"); if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); + error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.d0 = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); + error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.alpha = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) - error->all(FLERR,"Incorrectly formatted morse pair parameters"); + error->all(FLERR,"Incorrectly formatted morse pair parameters"); par.parm.morse.r0 = force->numeric(FLERR,ptr); ++nmorse; @@ -300,12 +300,12 @@ void PairList::settings(int narg, char **arg) ptr = strtok(NULL," \t\n\r\f"); if (!ptr) - error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); + error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); par.parm.lj126.epsilon = force->numeric(FLERR,ptr); ptr = strtok(NULL," \t\n\r\f"); if (!ptr) - error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); + error->all(FLERR,"Incorrectly formatted 12-6 LJ pair parameters"); par.parm.lj126.sigma = force->numeric(FLERR,ptr); ++nlj126; @@ -332,10 +332,10 @@ void PairList::settings(int narg, char **arg) if (comm->me == 0) { if (screen) fprintf(screen,"Read %d (%d/%d/%d) interacting pairs from %s\n", - npairs, nharm, nmorse, nlj126, arg[0]); + npairs, nharm, nmorse, nlj126, arg[0]); if (logfile) fprintf(logfile,"Read %d (%d/%d/%d) interacting pairs from %s\n", - npairs, nharm, nmorse, nlj126, arg[0]); + npairs, nharm, nmorse, nlj126, arg[0]); } } @@ -380,18 +380,18 @@ void PairList::init_style() list_parm_t &par = params[n]; if (style[n] == HARM) { - const double dr = sqrt(par.cutsq) - par.parm.harm.r0; - par.offset = par.parm.harm.k*dr*dr; + const double dr = sqrt(par.cutsq) - par.parm.harm.r0; + par.offset = par.parm.harm.k*dr*dr; } else if (style[n] == MORSE) { - const double dr = par.parm.morse.r0 - sqrt(par.cutsq); - const double dexp = exp(par.parm.morse.alpha * dr); - par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp); + const double dr = par.parm.morse.r0 - sqrt(par.cutsq); + const double dexp = exp(par.parm.morse.alpha * dr); + par.offset = par.parm.morse.d0 * (dexp*dexp - 2.0*dexp); } else if (style[n] == LJ126) { - const double r6inv = par.cutsq*par.cutsq*par.cutsq; - const double sig6 = mypow(par.parm.lj126.sigma,6); - par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6); + const double r6inv = par.cutsq*par.cutsq*par.cutsq; + const double sig6 = mypow(par.parm.lj126.sigma,6); + par.offset = 4.0*par.parm.lj126.epsilon*r6inv * (sig6*sig6*r6inv - sig6); } } } diff --git a/src/pair_born.cpp b/src/pair_born.cpp index 6d420fb36b..979499488e 100644 --- a/src/pair_born.cpp +++ b/src/pair_born.cpp @@ -243,7 +243,7 @@ double PairBorn::init_one(int i, int j) born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double rexp = exp((sigma[i][j]-cut[i][j])*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0) + d[i][j]/pow(cut[i][j],8.0); diff --git a/src/pair_born_coul_dsf.cpp b/src/pair_born_coul_dsf.cpp index caec95759a..d53e9cf00e 100644 --- a/src/pair_born_coul_dsf.cpp +++ b/src/pair_born_coul_dsf.cpp @@ -306,7 +306,7 @@ double PairBornCoulDSF::init_one(int i, int j) born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) + d[i][j]/pow(cut_lj[i][j],8.0); diff --git a/src/pair_born_coul_wolf.cpp b/src/pair_born_coul_wolf.cpp index bad0c5ed3e..fbec4f3da7 100644 --- a/src/pair_born_coul_wolf.cpp +++ b/src/pair_born_coul_wolf.cpp @@ -305,7 +305,7 @@ double PairBornCoulWolf::init_one(int i, int j) born2[i][j] = 6.0*c[i][j]; born3[i][j] = 8.0*d[i][j]; - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double rexp = exp((sigma[i][j]-cut_lj[i][j])*rhoinv[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0) + d[i][j]/pow(cut_lj[i][j],8.0); diff --git a/src/pair_buck.cpp b/src/pair_buck.cpp index e4da772e0a..ac7ac0aeb5 100644 --- a/src/pair_buck.cpp +++ b/src/pair_buck.cpp @@ -230,7 +230,7 @@ double PairBuck::init_one(int i, int j) buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double rexp = exp(-cut[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut[i][j],6.0); } else offset[i][j] = 0.0; diff --git a/src/pair_buck_coul_cut.cpp b/src/pair_buck_coul_cut.cpp index c052c3100a..2764a8e4e4 100644 --- a/src/pair_buck_coul_cut.cpp +++ b/src/pair_buck_coul_cut.cpp @@ -281,7 +281,7 @@ double PairBuckCoulCut::init_one(int i, int j) buck1[i][j] = a[i][j]/rho[i][j]; buck2[i][j] = 6.0*c[i][j]; - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double rexp = exp(-cut_lj[i][j]/rho[i][j]); offset[i][j] = a[i][j]*rexp - c[i][j]/pow(cut_lj[i][j],6.0); } else offset[i][j] = 0.0; diff --git a/src/pair_lj96_cut.cpp b/src/pair_lj96_cut.cpp index f4b2747d40..83fc5bcdda 100644 --- a/src/pair_lj96_cut.cpp +++ b/src/pair_lj96_cut.cpp @@ -557,7 +557,7 @@ double PairLJ96Cut::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],9.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,9.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/pair_lj_cut.cpp b/src/pair_lj_cut.cpp index a3ebf414c9..7f838061f1 100644 --- a/src/pair_lj_cut.cpp +++ b/src/pair_lj_cut.cpp @@ -551,7 +551,7 @@ double PairLJCut::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/pair_lj_cut_coul_cut.cpp b/src/pair_lj_cut_coul_cut.cpp index 0d62c43dc3..85cf9dc97d 100644 --- a/src/pair_lj_cut_coul_cut.cpp +++ b/src/pair_lj_cut_coul_cut.cpp @@ -278,7 +278,7 @@ double PairLJCutCoulCut::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/pair_lj_cut_coul_dsf.cpp b/src/pair_lj_cut_coul_dsf.cpp index 09293a6f4c..5d95d06ed7 100644 --- a/src/pair_lj_cut_coul_dsf.cpp +++ b/src/pair_lj_cut_coul_dsf.cpp @@ -303,7 +303,7 @@ double PairLJCutCoulDSF::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/pair_lj_expand.cpp b/src/pair_lj_expand.cpp index 2fd780472a..785733dccc 100644 --- a/src/pair_lj_expand.cpp +++ b/src/pair_lj_expand.cpp @@ -240,7 +240,7 @@ double PairLJExpand::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/pair_mie_cut.cpp b/src/pair_mie_cut.cpp index 312fb7bc70..320f21248d 100644 --- a/src/pair_mie_cut.cpp +++ b/src/pair_mie_cut.cpp @@ -575,7 +575,7 @@ double PairMIECut::init_one(int i, int j) mie3[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamR[i][j]); mie4[i][j] = Cmie[i][j] * epsilon[i][j] * pow(sigma[i][j],gamA[i][j]); - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double ratio = sigma[i][j] / cut[i][j]; offset[i][j] = Cmie[i][j] * epsilon[i][j] * (pow(ratio,gamR[i][j]) - pow(ratio,gamA[i][j])); diff --git a/src/pair_yukawa.cpp b/src/pair_yukawa.cpp index 0e5fd36cd6..2ba6633d9e 100644 --- a/src/pair_yukawa.cpp +++ b/src/pair_yukawa.cpp @@ -210,7 +210,7 @@ double PairYukawa::init_one(int i, int j) cut[i][j] = mix_distance(cut[i][i],cut[j][j]); } - if (offset_flag) { + if (offset_flag && (cut[i][j] > 0.0)) { double screening = exp(-kappa * cut[i][j]); offset[i][j] = a[i][j] * screening / cut[i][j]; } else offset[i][j] = 0.0; From d7355801dff5d7ef2aed45fa0a90bb9a40016ff5 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sat, 15 Jul 2017 12:03:04 -0500 Subject: [PATCH 101/293] Make KIM Install.py Python 3 compatible --- lib/kim/Install.py | 141 ++++++++++++++++++++++----------------------- 1 file changed, 70 insertions(+), 71 deletions(-) diff --git a/lib/kim/Install.py b/lib/kim/Install.py index 9f36f9fedb..cf1b254ecd 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -2,8 +2,8 @@ # install.pa tool to setup the kim-api library # used to automate the steps described in the README file in this dir - -import sys,os,re,urllib,commands +from __future__ import print_function +import sys,os,re,urllib,subprocess help = """ Syntax from src dir: make lib-kim args="-v version -b kim-install-dir kim-name -a kim-name" @@ -42,7 +42,7 @@ in the "What is in the KIM API source package?" section """ def error(): - print help + print(help) sys.exit() # parse args @@ -54,8 +54,8 @@ if nargs == 0: error() thisdir = os.environ['PWD'] version = "kim-api-v1.8.2" -buildflag = 0 -addflag = 0 +buildflag = False +addflag = False iarg = 0 while iarg < len(args): @@ -64,13 +64,13 @@ while iarg < len(args): version = args[iarg+1] iarg += 2 elif args[iarg] == "-b": - buildflag = 1 + buildflag = True if iarg+3 > len(args): error() dir = args[iarg+1] modelname = args[iarg+2] iarg += 3 elif args[iarg] == "-a": - addflag = 1 + addflag = True if iarg+2 > len(args): error() addmodelname = args[iarg+1] iarg += 2 @@ -82,176 +82,175 @@ url = "https://s3.openkim.org/kim-api/%s.tgz" % version # download KIM tarball, unpack, build KIM # either in lib/kim or user-requested location -if buildflag == 1: +if buildflag: # set install directory - dir = os.path.abspath(dir) + "/installed-" + version + dir = os.path.join(os.path.abspath(dir), "installed-" + version) # check to see if an installed kim-api already exists if os.path.isdir(dir): - print "kim-api is already installed at %s" % dir - print "Must remove this directory in order to resintall at this location" + print("kim-api is already installed at %s" % dir) + print("Must remove this directory in order to resintall at this location") sys.exit() # configure LAMMPS to use kim-api to be installed - mkfle = open("%s/Makefile.KIM_DIR" % thisdir, 'w') - mkfle.write("KIM_INSTALL_DIR=%s\n" % dir) - mkfle.write("\n") - mkfle.write(".DUMMY: print_dir\n") - mkfle.write("\n") - mkfle.write("print_dir:\n") - mkfle.write(" @printf $(KIM_INSTALL_DIR)\n") - mkfle.close() - open("%s/Makefile.KIM_Config" % thisdir, 'w'). \ - write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) - print "Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir) + with open("%s/Makefile.KIM_DIR" % thisdir, 'w') as mkfile: + mkfle.write("KIM_INSTALL_DIR=%s\n\n" % dir) + mkfle.write(".DUMMY: print_dir\n\n") + mkfle.write("print_dir:\n") + mkfle.write(" @printf $(KIM_INSTALL_DIR)\n") + + with open("%s/Makefile.KIM_Config" % thisdir, 'w') as cfgfile: + cfgfile.write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) + + print("Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir)) # download entire kim-api tarball # try first via urllib # if fails (probably due to no SSL support), use wget - print "Downloading kim-api tarball ..." + print("Downloading kim-api tarball ...") try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) except: cmd = "wget %s %s/%s.tgz" % (url,thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if not os.path.isfile("%s/%s.tgz" % (thisdir,version)): - print "Both urllib.urlretrieve() and wget command failed to download" + print("Both urllib.urlretrieve() and wget command failed to download") sys.exit() - print "Unpacking kim-api tarball ..." + print("Unpacking kim-api tarball ...") cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) if txt[0] != 0: error() # configure kim-api - print "Configuring kim-api ..." + print("Configuring kim-api ...") cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() # build kim-api - print "Configuring model : %s" % modelname + print("Configuring model : %s" % modelname) if modelname == "none": cmd = "cd %s/%s; make add-examples" % (thisdir,version) else: if modelname == "OpenKIM": - print "configuring all OpenKIM models, this will take a while ..." + print("configuring all OpenKIM models, this will take a while ...") cmd = "cd %s/%s; make add-examples; make add-%s" % \ (thisdir,version,modelname) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() - print "Building kim-api ..." + print("Building kim-api ...") cmd = "cd %s/%s; make" % (thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() # install kim-api - print "Installing kim-api ..." + print("Installing kim-api ...") cmd = "cd %s/%s; make install" % (thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() # remove source files - print "Removing kim-api source and build files ..." + print("Removing kim-api source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() # add a single model (and possibly its driver) to existing KIM installation -if addflag == 1: +if addflag: # get location of installed kim-api if not os.path.isfile("%s/Makefile.KIM_DIR" % thisdir): - print "kim-api is not installed" + print("kim-api is not installed") error() else: cmd = "cd %s; make -f Makefile.KIM_DIR print_dir" % thisdir - dir = commands.getstatusoutput(cmd)[1] + dir = subprocess.getstatusoutput(cmd)[1] # download single model # try first via urllib # if fails (probably due to no SSL support), use wget - print "Downloading item tarball ..." + print("Downloading item tarball ...") url = "https://openkim.org/download/%s.tgz" % addmodelname try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) except: cmd = "wget %s %s/%s.tgz" % (url,thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if not os.path.isfile("%s/%s.tgz" % (thisdir,addmodelname)): - print "Both urllib.urlretrieve() and wget command failed to download" + print("Both urllib.urlretrieve() and wget command failed to download") sys.exit() - print "Unpacking item tarball ..." + print("Unpacking item tarball ...") cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) if txt[0] != 0: error() - print "Building item ..." + print("Building item ...") cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) firstRunOutput = txt[1] if txt[0] != 0: # Error: but first, check to see if it needs a driver cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) if txt[1] == "ParameterizedModel": # Get and install driver cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) adddrivername = txt[1] - print "First Installing model driver: %s" % adddrivername + print("First Installing model driver: %s" % adddrivername) cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) - txt = commands.getstatusoutput(cmd) + txt = subprocess.getstatusoutput(cmd) if txt[0] != 0: - print firstRunOutput - print txt[1] + print(firstRunOutput) + print(txt[1]) error() else: - print txt[1] + print(txt[1]) cmd = "cd %s; python Install.py -a %s" % (thisdir,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() else: - print firstRunOutput + print(firstRunOutput) error() else: # success - print firstRunOutput - print "Removing kim item source and build files ..." + print(firstRunOutput) + print("Removing kim item source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - txt = commands.getstatusoutput(cmd) - print txt[1] + txt = subprocess.getstatusoutput(cmd) + print(txt[1]) if txt[0] != 0: error() From acd315e97a7ce25fa2b1d8ef6825ecfd36ecc172 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sat, 15 Jul 2017 15:33:36 -0500 Subject: [PATCH 102/293] Add basic KOKKOS support to CMake build --- cmake/CMakeLists.txt | 59 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index eb84d0eb6a..e23cfa67ff 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -4,6 +4,7 @@ project(lammps) set(SOVERSION 0) set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) +set(LAMMPS_LIB_BINARY_DIR ${CMAKE_BINARY_DIR}/lib) # Cmake modules/macros are in a subdirectory to keep this file cleaner set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules) @@ -47,7 +48,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -set(ACCEL_PACKAGES USER_OMP) +set(ACCEL_PACKAGES USER_OMP KOKKOS) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -61,6 +62,24 @@ if(ENABLE_KSPACE) endif() endif() +if(ENABLE_KOKKOS) + # starting with CMake 3.1 this is all you have to do to enforce C++11 + set (CMAKE_CXX_STANDARD 11) + set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) + set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) + add_definitions(-DLMP_KOKKOS) + add_subdirectory(${LAMMPS_LIB_KOKKOS_SRC_DIR} ${LAMMPS_LIB_KOKKOS_BIN_DIR}) + message("KOKKOS_DIRS: ${Kokkos_INCLUDE_DIRS}") + + # TODO there probably is a better way + set(Kokkos_INCLUDE_DIRS ${LAMMPS_LIB_KOKKOS_SRC_DIR}/core/src + ${LAMMPS_LIB_KOKKOS_SRC_DIR}/containers/src + ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src + ${LAMMPS_LIB_KOKKOS_BIN_DIR}) + include_directories(${Kokkos_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${Kokkos_LIBRARIES}) +endif() + find_package(JPEG) if(JPEG_FOUND) add_definitions(-DLAMMPS_JPEG) @@ -166,6 +185,38 @@ if(ENABLE_USER_OMP) include_directories(${USER_OMP_SOURCES_DIR}) endif() +if(ENABLE_KOKKOS) + find_package(OpenMP REQUIRED) + if (OPENMP_FOUND) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + else() + message(FATAL_ERROR "USER-OMP requires a compiler with OpenMP support") + endif() + + set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) + set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/atom_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/atom_vec_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/comm_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/comm_tiled_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neighbor_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neigh_list_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neigh_bond_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/fix_nh_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/domain_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/modify_kokkos.cpp) + set_property(GLOBAL PROPERTY "KOKKOS_PKG_SOURCES" "${KOKKOS_PKG_SOURCES}") + + # detects styles which have KOKKOS version + RegisterStylesExt(${KOKKOS_PKG_SOURCES_DIR} kokkos KOKKOS_PKG_SOURCES) + + get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) + + list(APPEND LIB_SOURCES ${KOKKOS_PKG_SOURCES}) + include_directories(${KOKKOS_PKG_SOURCES_DIR}) +endif() + if(ENABLE_REAX) enable_language(Fortran) @@ -190,6 +241,11 @@ include_directories(${LAMMPS_STYLE_HEADERS_DIR}) add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) + +if(ENABLE_KOKKOS) + target_link_libraries(lammps kokkos) +endif() + if(INSTALL_LIB) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) @@ -199,6 +255,7 @@ endif() add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) + install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) foreach(PKG ${PACKAGES} ${ACCEL_PACKAGES}) From 629f1129150d2b6af7ec28ba72aea0eac95aff50 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 15 Jul 2017 16:44:03 -0600 Subject: [PATCH 103/293] add support for MEAM --- cmake/CMakeLists.txt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index eb84d0eb6a..c0153e3d6b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) -set(PACKAGES ASPHERE BODY COLLOID CLASS2 COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MC MOLECULE MANYBODY RIGID REAX) +set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MOLECULE RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -167,13 +167,22 @@ if(ENABLE_USER_OMP) endif() -if(ENABLE_REAX) +if(ENABLE_REAX OR ENABLE_MEAM) enable_language(Fortran) +endif() + +if(ENABLE_REAX) file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) list(APPEND LIB_SOURCES ${REAX_SOURCES}) include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) endif() +if(ENABLE_MEAM) + file(GLOB MEAM_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/meam/*.F ${LAMMPS_LIB_SOURCE_DIR}/meam/*.c) + list(APPEND LIB_SOURCES ${MEAM_SOURCES}) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/meam) +endif() + ###################################################### # Generate style headers based on global list of From 23540cfc94148a2388892f705491a865e93c7c40 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 15 Jul 2017 16:46:20 -0600 Subject: [PATCH 104/293] enable MISC --- cmake/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f81f8f120a..5aa8a7a358 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -43,7 +43,8 @@ find_package(UnixCommands) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) -set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MOLECULE RIGID REAX) +set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR + KSPACE MANYBODY MC MEAM MISC MOLECULE RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() From fa1f38596c08c4da5570d0d9fdd31969405a7de7 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sat, 15 Jul 2017 18:29:33 -0500 Subject: [PATCH 105/293] Add support for PYTHON in CMake build --- cmake/CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 5aa8a7a358..a16cad55eb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -44,7 +44,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE PYTHON RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -81,6 +81,17 @@ if(ENABLE_KOKKOS) list(APPEND LAMMPS_LINK_LIBS ${Kokkos_LIBRARIES}) endif() +if(ENABLE_PYTHON) + find_package(PythonLibs) + if(PYTHONLIBS_FOUND) + add_definitions(-DLMP_PYTHON) + include_directories(${PYTHON_INCLUDE_DIR}) + list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) + else() + message(FATAL_ERROR "Could not find needed Python libraries and headers") + endif() +endif() + find_package(JPEG) if(JPEG_FOUND) add_definitions(-DLAMMPS_JPEG) From 01f5136584b3faf7010f48feddb31257a7ce8803 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 08:22:19 -0600 Subject: [PATCH 106/293] cmake: clean up --- cmake/CMakeLists.txt | 89 +++++++++++++++++++------------------------- 1 file changed, 38 insertions(+), 51 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a16cad55eb..7b1aa6363a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -38,8 +38,6 @@ if(ENABLE_MPI) list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) endif() -find_package(UnixCommands) - option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) @@ -64,13 +62,10 @@ if(ENABLE_KSPACE) endif() if(ENABLE_KOKKOS) - # starting with CMake 3.1 this is all you have to do to enforce C++11 - set (CMAKE_CXX_STANDARD 11) set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) add_definitions(-DLMP_KOKKOS) add_subdirectory(${LAMMPS_LIB_KOKKOS_SRC_DIR} ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - message("KOKKOS_DIRS: ${Kokkos_INCLUDE_DIRS}") # TODO there probably is a better way set(Kokkos_INCLUDE_DIRS ${LAMMPS_LIB_KOKKOS_SRC_DIR}/core/src @@ -78,18 +73,14 @@ if(ENABLE_KOKKOS) ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src ${LAMMPS_LIB_KOKKOS_BIN_DIR}) include_directories(${Kokkos_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${Kokkos_LIBRARIES}) + list(APPEND LAMMPS_LINK_LIBS kokkos) endif() if(ENABLE_PYTHON) - find_package(PythonLibs) - if(PYTHONLIBS_FOUND) - add_definitions(-DLMP_PYTHON) - include_directories(${PYTHON_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) - else() - message(FATAL_ERROR "Could not find needed Python libraries and headers") - endif() + find_package(PythonLibs REQUIRED) + add_definitions(-DLMP_PYTHON) + include_directories(${PYTHON_INCLUDE_DIR}) + list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) endif() find_package(JPEG) @@ -169,18 +160,43 @@ foreach(PKG ${PACKAGES}) endif() endforeach() +if(ENABLE_REAX OR ENABLE_MEAM) + enable_language(Fortran) +endif() + + +if(ENABLE_KOKKOS) + # starting with CMake 3.1 this is all you have to do to enforce C++11 + set(CMAKE_CXX_STANDARD 11) # C++11... + set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... + set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 +endif() + +if(ENABLE_USER_OMP OR ENABLE_KOKKOS) + find_package(OpenMP REQUIRED) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + + +if(ENABLE_REAX) + file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) + list(APPEND LIB_SOURCES ${REAX_SOURCES}) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) +endif() + +if(ENABLE_MEAM) + file(GLOB MEAM_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/meam/*.F ${LAMMPS_LIB_SOURCE_DIR}/meam/*.c) + list(APPEND LIB_SOURCES ${MEAM_SOURCES}) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/meam) +endif() + +###################################################################### # packages which selectively include variants based on enabled styles # e.g. accelerator packages +###################################################################### if(ENABLE_USER_OMP) - find_package(OpenMP REQUIRED) - if (OPENMP_FOUND) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - else() - message(FATAL_ERROR "USER-OMP requires a compiler with OpenMP support") - endif() - set(USER_OMP_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-OMP) set(USER_OMP_SOURCES ${USER_OMP_SOURCES_DIR}/thr_data.cpp ${USER_OMP_SOURCES_DIR}/thr_omp.cpp @@ -198,14 +214,6 @@ if(ENABLE_USER_OMP) endif() if(ENABLE_KOKKOS) - find_package(OpenMP REQUIRED) - if (OPENMP_FOUND) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") - else() - message(FATAL_ERROR "USER-OMP requires a compiler with OpenMP support") - endif() - set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp ${KOKKOS_PKG_SOURCES_DIR}/atom_kokkos.cpp @@ -230,23 +238,6 @@ if(ENABLE_KOKKOS) endif() -if(ENABLE_REAX OR ENABLE_MEAM) - enable_language(Fortran) -endif() - -if(ENABLE_REAX) - file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) - list(APPEND LIB_SOURCES ${REAX_SOURCES}) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) -endif() - -if(ENABLE_MEAM) - file(GLOB MEAM_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/meam/*.F ${LAMMPS_LIB_SOURCE_DIR}/meam/*.c) - list(APPEND LIB_SOURCES ${MEAM_SOURCES}) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/meam) -endif() - - ###################################################### # Generate style headers based on global list of # styles registered during package selection @@ -263,10 +254,6 @@ add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) -if(ENABLE_KOKKOS) - target_link_libraries(lammps kokkos) -endif() - if(INSTALL_LIB) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) From f50a757dc6d34f3a6379fadfa0bdec3ea3a76d3a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 08:32:14 -0600 Subject: [PATCH 107/293] added MPIIO support --- cmake/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7b1aa6363a..493bafc3ad 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE PYTHON RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MPIIO PYTHON RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -52,6 +52,10 @@ foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() +if(ENABLE_MPIIO AND NOT ENABLE_MPI) + message(FATAL_ERROR "MPIIO package needed to LAMMPS to be build with mpi") +endif() + if(ENABLE_KSPACE) find_package(FFTW3) if(FFTW3_FOUND) From 95d9d323075b204a0663f104f4a0b2efe20b9dcd Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 10:37:24 -0600 Subject: [PATCH 108/293] add support for MSCG --- cmake/CMakeLists.txt | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 493bafc3ad..0032c8100e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MPIIO PYTHON RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PYTHON RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -169,7 +169,7 @@ if(ENABLE_REAX OR ENABLE_MEAM) endif() -if(ENABLE_KOKKOS) +if(ENABLE_KOKKOS OR ENABLE_MSCG) # starting with CMake 3.1 this is all you have to do to enforce C++11 set(CMAKE_CXX_STANDARD 11) # C++11... set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... @@ -195,6 +195,33 @@ if(ENABLE_MEAM) include_directories(${LAMMPS_LIB_SOURCE_DIR}/meam) endif() +if(ENABLE_MSCG) + find_package(GSL REQUIRED) + find_package(LAPACK REQUIRED) + set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) + set(MSCG_TARBALL ${LAMMPS_LIB_MSCG_BIN_DIR}/MS-CG-master.zip) + set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_MSCG_BIN_DIR}/MSCG-release-master/src) + if(NOT EXISTS ${LAMMPS_LIB_MSCG_BIN_DIR}) + if(NOT EXISTS ${MSCG_TARBALL}) + message(STATUS "Downloading ${MSCG_TARBALL}") + file(DOWNLOAD + https://github.com/uchicago-voth/MSCG-release/archive/master.zip + ${MSCG_TARBALL} SHOW_PROGRESS) #EXPECTED_MD5 cannot be due due to master + endif() + message(STATUS "Unpacking ${MSCG_TARBALL}") + execute_process(COMMAND ${CMAKE_COMMAND} -E tar xvf ${MSCG_TARBALL} + WORKING_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/mscg) + endif() + file(GLOB MSCG_SOURCES ${LAMMPS_LIB_MSCG_BIN_DIR}/*.cpp) + list(APPEND LIB_SOURCES ${MSCG_SOURCES}) + foreach(MSCG_SOURCE ${MSCG_SOURCES}) + set_property(SOURCE ${MSCG_SOURCE} APPEND PROPERTY COMPILE_DEFINITIONS + DIMENSION=3 _exclude_gromacs=1) + endforeach() + include_directories(${LAMMPS_LIB_MSCG_BIN_DIR} ${GSL_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES} ${LAPACK_LIBRARIES}) +endif() + ###################################################################### # packages which selectively include variants based on enabled styles # e.g. accelerator packages From 4812d4c659f6e3e7e178744f5721e0419e2da442 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 10:48:29 -0600 Subject: [PATCH 109/293] enable PERI --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0032c8100e..eb613a8089 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PYTHON RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI PYTHON RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() From 742eee1966c1c43e3df1700a08b7dfe81d431d99 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 11:07:36 -0600 Subject: [PATCH 110/293] added support for POEMS --- cmake/CMakeLists.txt | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index eb613a8089..7f825f012e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI PYTHON RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON RIGID REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -182,18 +182,15 @@ if(ENABLE_USER_OMP OR ENABLE_KOKKOS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() - -if(ENABLE_REAX) - file(GLOB REAX_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/reax/*.F) - list(APPEND LIB_SOURCES ${REAX_SOURCES}) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/reax) -endif() - -if(ENABLE_MEAM) - file(GLOB MEAM_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/meam/*.F ${LAMMPS_LIB_SOURCE_DIR}/meam/*.c) - list(APPEND LIB_SOURCES ${MEAM_SOURCES}) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/meam) -endif() +foreach(SIMPLE_LIB REAX MEAM POEMS) + if(ENABLE_${SIMPLE_LIB}) + string(TOLOWER "${SIMPLE_LIB}" INC_DIR) + file(GLOB ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F + ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.c ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.cpp) + list(APPEND LIB_SOURCES ${${SIMPLE_LIB}_SOURCES}) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}) + endif() +endforeach() if(ENABLE_MSCG) find_package(GSL REQUIRED) From 140182fb0bb01c46d50352c347c24c8cc2eb9be5 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 11:14:08 -0600 Subject: [PATCH 111/293] added support for QEQ --- cmake/CMakeLists.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7f825f012e..d6289fb37c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,8 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON RIGID REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON RIGID QEQ + REAX) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -52,9 +53,14 @@ foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() -if(ENABLE_MPIIO AND NOT ENABLE_MPI) - message(FATAL_ERROR "MPIIO package needed to LAMMPS to be build with mpi") -endif() +macro(pkg_depends PKG1 PKG2) + if(ENABLE_${PKG1} AND NOT ENABLE_${PKG2}) + message(FATAL_ERROR "${PKG1} package needed to LAMMPS to be build with ${PKG2}") + endif() +endmacro() + +pkg_depends(MPIIO MPI) +pkg_depends(QEQ MANYBODY) if(ENABLE_KSPACE) find_package(FFTW3) From c549a16a85ad022796841e0de3daf05733b7a906 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 11:29:31 -0600 Subject: [PATCH 112/293] enable REPLICA RIGID SHOCK SNAP SRD VORONOI --- cmake/CMakeLists.txt | 11 +++++++++-- cmake/Modules/FindVORO.cmake | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 cmake/Modules/FindVORO.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d6289fb37c..54864a8a48 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,8 +42,8 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON RIGID QEQ - REAX) + KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ + REAX REPLICA RIGID SHOCK SNAP SRD VORONOI) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -113,6 +113,13 @@ if(GZIP) add_definitions(-DLAMMPS_GZIP) endif() +if(ENABLE_VORONOI) + find_package(VORO REQUIRED) #some distros + include_directories(${VORO_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${VORO_LIBRARIES}) + #TODO download and build voro++ +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## diff --git a/cmake/Modules/FindVORO.cmake b/cmake/Modules/FindVORO.cmake new file mode 100644 index 0000000000..b0cccbcd1d --- /dev/null +++ b/cmake/Modules/FindVORO.cmake @@ -0,0 +1,22 @@ +# - Find voro++ +# Find the native VORO headers and libraries. +# +# VORO_INCLUDE_DIRS - where to find voro++.hh, etc. +# VORO_LIBRARIES - List of libraries when using voro++. +# VORO_FOUND - True if voro++ found. +# + +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) + +mark_as_advanced(VORO_INCLUDE_DIR VORO_LIBRARY ) From 992ce797010d5de94163e5b4a7f2f02b6f1ca537 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sun, 16 Jul 2017 14:37:30 -0400 Subject: [PATCH 113/293] add sanity checks to EAM potential file reader subroutine --- src/MANYBODY/pair_eam.cpp | 8 ++++++-- src/MANYBODY/pair_eam_alloy.cpp | 6 +++++- src/MANYBODY/pair_eam_fs.cpp | 6 +++++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/MANYBODY/pair_eam.cpp b/src/MANYBODY/pair_eam.cpp index d3ac3951bf..29a627e1d0 100644 --- a/src/MANYBODY/pair_eam.cpp +++ b/src/MANYBODY/pair_eam.cpp @@ -465,16 +465,17 @@ void PairEAM::read_file(char *filename) } } - int tmp; + int tmp,nwords; if (me == 0) { fgets(line,MAXLINE,fptr); fgets(line,MAXLINE,fptr); sscanf(line,"%d %lg",&tmp,&file->mass); fgets(line,MAXLINE,fptr); - sscanf(line,"%d %lg %d %lg %lg", + nwords = sscanf(line,"%d %lg %d %lg %lg", &file->nrho,&file->drho,&file->nr,&file->dr,&file->cut); } + MPI_Bcast(&nwords,1,MPI_INT,0,world); MPI_Bcast(&file->mass,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->nrho,1,MPI_INT,0,world); MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world); @@ -482,6 +483,9 @@ void PairEAM::read_file(char *filename) MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world); + if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0)) + error->all(FLERR,"Invalid EAM potential file"); + memory->create(file->frho,(file->nrho+1),"pair:frho"); memory->create(file->rhor,(file->nr+1),"pair:rhor"); memory->create(file->zr,(file->nr+1),"pair:zr"); diff --git a/src/MANYBODY/pair_eam_alloy.cpp b/src/MANYBODY/pair_eam_alloy.cpp index d3ed404a0b..e22b4642a8 100644 --- a/src/MANYBODY/pair_eam_alloy.cpp +++ b/src/MANYBODY/pair_eam_alloy.cpp @@ -166,16 +166,20 @@ void PairEAMAlloy::read_file(char *filename) if (me == 0) { fgets(line,MAXLINE,fptr); - sscanf(line,"%d %lg %d %lg %lg", + nwords = sscanf(line,"%d %lg %d %lg %lg", &file->nrho,&file->drho,&file->nr,&file->dr,&file->cut); } + MPI_Bcast(&nwords,1,MPI_INT,0,world); MPI_Bcast(&file->nrho,1,MPI_INT,0,world); MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->nr,1,MPI_INT,0,world); MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world); + if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0)) + error->all(FLERR,"Invalid EAM potential file"); + file->mass = new double[file->nelements]; memory->create(file->frho,file->nelements,file->nrho+1,"pair:frho"); memory->create(file->rhor,file->nelements,file->nr+1,"pair:rhor"); diff --git a/src/MANYBODY/pair_eam_fs.cpp b/src/MANYBODY/pair_eam_fs.cpp index f0f1814dc2..2817e13f8a 100644 --- a/src/MANYBODY/pair_eam_fs.cpp +++ b/src/MANYBODY/pair_eam_fs.cpp @@ -166,16 +166,20 @@ void PairEAMFS::read_file(char *filename) if (me == 0) { fgets(line,MAXLINE,fptr); - sscanf(line,"%d %lg %d %lg %lg", + nwords = sscanf(line,"%d %lg %d %lg %lg", &file->nrho,&file->drho,&file->nr,&file->dr,&file->cut); } + MPI_Bcast(&nwords,1,MPI_INT,0,world); MPI_Bcast(&file->nrho,1,MPI_INT,0,world); MPI_Bcast(&file->drho,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->nr,1,MPI_INT,0,world); MPI_Bcast(&file->dr,1,MPI_DOUBLE,0,world); MPI_Bcast(&file->cut,1,MPI_DOUBLE,0,world); + if ((nwords != 5) || (file->nrho <= 0) || (file->nr <= 0) || (file->dr <= 0.0)) + error->all(FLERR,"Invalid EAM potential file"); + file->mass = new double[file->nelements]; memory->create(file->frho,file->nelements,file->nrho+1, "pair:frho"); From c64424754d32705c6fc5dc7f867baea94e5dd204 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 16:18:58 -0600 Subject: [PATCH 114/293] added USER-ATC --- cmake/CMakeLists.txt | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 54864a8a48..46203f43dc 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -43,7 +43,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ - REAX REPLICA RIGID SHOCK SNAP SRD VORONOI) + REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -55,12 +55,13 @@ endforeach() macro(pkg_depends PKG1 PKG2) if(ENABLE_${PKG1} AND NOT ENABLE_${PKG2}) - message(FATAL_ERROR "${PKG1} package needed to LAMMPS to be build with ${PKG2}") + message(FATAL_ERROR "${PKG1} package needs LAMMPS to be build with ${PKG2}") endif() endmacro() pkg_depends(MPIIO MPI) pkg_depends(QEQ MANYBODY) +pkg_depends(USER-ATC MANYBODY) if(ENABLE_KSPACE) find_package(FFTW3) @@ -86,6 +87,11 @@ if(ENABLE_KOKKOS) list(APPEND LAMMPS_LINK_LIBS kokkos) endif() +if(ENABLE_MSCG OR ENABLE_USER-ATC) + find_package(LAPACK REQUIRED) + list(APPEND LAMMPS_LINK_LIBS ${LAPACK_LIBRARIES}) +endif() + if(ENABLE_PYTHON) find_package(PythonLibs REQUIRED) add_definitions(-DLMP_PYTHON) @@ -195,8 +201,9 @@ if(ENABLE_USER_OMP OR ENABLE_KOKKOS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() -foreach(SIMPLE_LIB REAX MEAM POEMS) +foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC) if(ENABLE_${SIMPLE_LIB}) + string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") string(TOLOWER "${SIMPLE_LIB}" INC_DIR) file(GLOB ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.c ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.cpp) @@ -207,7 +214,6 @@ endforeach() if(ENABLE_MSCG) find_package(GSL REQUIRED) - find_package(LAPACK REQUIRED) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) set(MSCG_TARBALL ${LAMMPS_LIB_MSCG_BIN_DIR}/MS-CG-master.zip) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_MSCG_BIN_DIR}/MSCG-release-master/src) @@ -229,7 +235,7 @@ if(ENABLE_MSCG) DIMENSION=3 _exclude_gromacs=1) endforeach() include_directories(${LAMMPS_LIB_MSCG_BIN_DIR} ${GSL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES} ${LAPACK_LIBRARIES}) + list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES}) endif() ###################################################################### From d50b62837b42c9390e3bdf6c2d160bee4c1fba3d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 16:45:28 -0600 Subject: [PATCH 115/293] add USER-AWPMD --- cmake/CMakeLists.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 46203f43dc..b1990b1a9c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -43,7 +43,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ - REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC) + REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -87,9 +87,10 @@ if(ENABLE_KOKKOS) list(APPEND LAMMPS_LINK_LIBS kokkos) endif() -if(ENABLE_MSCG OR ENABLE_USER-ATC) +if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD) find_package(LAPACK REQUIRED) list(APPEND LAMMPS_LINK_LIBS ${LAPACK_LIBRARIES}) + #TODO use lib/lapack endif() if(ENABLE_PYTHON) @@ -201,17 +202,22 @@ if(ENABLE_USER_OMP OR ENABLE_KOKKOS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() -foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC) +foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD) if(ENABLE_${SIMPLE_LIB}) string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") string(TOLOWER "${SIMPLE_LIB}" INC_DIR) - file(GLOB ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F + file(GLOB_RECURSE ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.c ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.cpp) list(APPEND LIB_SOURCES ${${SIMPLE_LIB}_SOURCES}) include_directories(${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}) endif() endforeach() +if(ENABLE_USER-AWPMD) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/awpmd/systems/interact + ${LAMMPS_LIB_SOURCE_DIR}/awpmd/ivutils/include) +endif() + if(ENABLE_MSCG) find_package(GSL REQUIRED) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) From bb87bd4ac74d4bc5bb1a9b9e3db2562bdacf1984 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 17:01:28 -0600 Subject: [PATCH 116/293] enable more user packages --- cmake/CMakeLists.txt | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b1990b1a9c..43d8f5decf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -43,7 +43,9 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ - REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD) + REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD USER-CGDNA + USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF + USER-FEP USER-H5MD USER-LB) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -62,6 +64,8 @@ endmacro() pkg_depends(MPIIO MPI) pkg_depends(QEQ MANYBODY) pkg_depends(USER-ATC MANYBODY) +pkg_depends(USER-H5MD MPI) +pkg_depends(USER-LB MPI) if(ENABLE_KSPACE) find_package(FFTW3) @@ -202,7 +206,7 @@ if(ENABLE_USER_OMP OR ENABLE_KOKKOS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() -foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD) +foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD) if(ENABLE_${SIMPLE_LIB}) string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") string(TOLOWER "${SIMPLE_LIB}" INC_DIR) @@ -218,6 +222,12 @@ if(ENABLE_USER-AWPMD) ${LAMMPS_LIB_SOURCE_DIR}/awpmd/ivutils/include) endif() +if(ENABLE_USER-H5MD) + find_package(HDF5 REQUIRED) + list(APPEND LAMMPS_LINK_LIBS ${HDF5_LIBRARIES}) + include_directories(${HDF5_INCLUDE_DIRS} ${LAMMPS_LIB_SOURCE_DIR}/h5md/include) +endif() + if(ENABLE_MSCG) find_package(GSL REQUIRED) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) From fc2e8b3c5ed552306daf31cba4af56eef3e67861 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 17:52:43 -0600 Subject: [PATCH 117/293] more USER packages --- cmake/CMakeLists.txt | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 43d8f5decf..ed0eeaacdd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -45,7 +45,9 @@ set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD USER-CGDNA USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF - USER-FEP USER-H5MD USER-LB) + USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC + USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD + USER-SMTBQ USER-SPH USER-TALLY) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -66,6 +68,8 @@ pkg_depends(QEQ MANYBODY) pkg_depends(USER-ATC MANYBODY) pkg_depends(USER-H5MD MPI) pkg_depends(USER-LB MPI) +pkg_depends(USER-MISC MANYBODY) +pkg_depends(USER-PHONON KSPACE) if(ENABLE_KSPACE) find_package(FFTW3) @@ -131,6 +135,22 @@ if(ENABLE_VORONOI) #TODO download and build voro++ endif() +if(ENABLE_USER-MOLFILE) + list(APPEND LAMMPS_LINK_LIBS ${CMAKE_DL_LIBS}) +endif() + +if(ENABLE_USER-NETCDF) + find_package(NetCDF REQUIRED) + include_directories(NETCDF_INCLUDE_DIR) + list(APPEND LAMMPS_LINK_LIBS ${NETCDF_LIBRARY}) + add_definitions(-DLMP_HAS_NETCDF -DNC_64BIT_DATA=0x0020) +endif() + +if(ENABLE_USER-SMD) + find_package(Eigen3 REQUIRED) + include_directories(${EIGEN3_INCLUDE_DIR}) +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## @@ -206,7 +226,8 @@ if(ENABLE_USER_OMP OR ENABLE_KOKKOS) set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() -foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD) +foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD + USER-MOLFILE) if(ENABLE_${SIMPLE_LIB}) string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") string(TOLOWER "${SIMPLE_LIB}" INC_DIR) From 9991f679ae03310064281f3c7bf37cf260845451 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sun, 16 Jul 2017 20:41:42 -0400 Subject: [PATCH 118/293] added USER-VTK --- cmake/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ed0eeaacdd..947e29cbd0 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -47,7 +47,7 @@ set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD - USER-SMTBQ USER-SPH USER-TALLY) + USER-SMTBQ USER-SPH USER-TALLY USER-VTK) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -249,6 +249,13 @@ if(ENABLE_USER-H5MD) include_directories(${HDF5_INCLUDE_DIRS} ${LAMMPS_LIB_SOURCE_DIR}/h5md/include) endif() +if(ENABLE_USER-VTK) + find_package(VTK REQUIRED NO_MODULE) + include(${VTK_USE_FILE}) + add_definitions(-DLAMMPS_VTK) + list(APPEND LAMMPS_LINK_LIBS ${VTK_LIBRARIES}) +endif() + if(ENABLE_MSCG) find_package(GSL REQUIRED) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) From 2978cce8db453c4d6e9a251fb42989ff85c3afef Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Sun, 16 Jul 2017 20:52:38 -0400 Subject: [PATCH 119/293] Added OPT --- cmake/CMakeLists.txt | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 947e29cbd0..68097d3655 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -52,7 +52,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -set(ACCEL_PACKAGES USER_OMP KOKKOS) +set(ACCEL_PACKAGES USER_OMP KOKKOS OPT) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -328,6 +328,20 @@ if(ENABLE_KOKKOS) include_directories(${KOKKOS_PKG_SOURCES_DIR}) endif() +if(ENABLE_OPT) + set(OPT_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/OPT) + set(OPT_SOURCES) + set_property(GLOBAL PROPERTY "OPT_SOURCES" "${OPT_SOURCES}") + + # detects styles which have OPT version + RegisterStylesExt(${OPT_SOURCES_DIR} opt OPT_SOURCES) + + get_property(OPT_SOURCES GLOBAL PROPERTY OPT_SOURCES) + + list(APPEND LIB_SOURCES ${OPT_SOURCES}) + include_directories(${OPT_SOURCES_DIR}) +endif() + ###################################################### # Generate style headers based on global list of From b6385d6ce21ca19048b9451cff65e7cbaaa1f441 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 20:17:41 -0600 Subject: [PATCH 120/293] add OpenKIM support --- cmake/CMakeLists.txt | 8 ++- cmake/Modules/FindKIM.cmake | 22 ++++++ cmake/Modules/FindNetCDF.cmake | 118 +++++++++++++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/FindKIM.cmake create mode 100644 cmake/Modules/FindNetCDF.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 68097d3655..1b6b426ded 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -42,7 +42,7 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ + KIM KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD USER-CGDNA USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC @@ -256,6 +256,12 @@ if(ENABLE_USER-VTK) list(APPEND LAMMPS_LINK_LIBS ${VTK_LIBRARIES}) endif() +if(ENABLE_KIM) + find_package(KIM REQUIRED) + list(APPEND LAMMPS_LINK_LIBS ${KIM_LIBRARIES}) + include_directories(${KIM_INCLUDE_DIRS}) +endif() + if(ENABLE_MSCG) find_package(GSL REQUIRED) set(LAMMPS_LIB_MSCG_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/mscg) diff --git a/cmake/Modules/FindKIM.cmake b/cmake/Modules/FindKIM.cmake new file mode 100644 index 0000000000..a01f817cf6 --- /dev/null +++ b/cmake/Modules/FindKIM.cmake @@ -0,0 +1,22 @@ +# - Find kim +# Find the native KIM headers and libraries. +# +# KIM_INCLUDE_DIRS - where to find kim.h, etc. +# KIM_LIBRARIES - List of libraries when using kim. +# KIM_FOUND - True if kim found. +# + +find_path(KIM_INCLUDE_DIR KIM_API.h PATH_SUFFIXES kim-api-v1) + +find_library(KIM_LIBRARY NAMES kim-api-v1) + +set(KIM_LIBRARIES ${KIM_LIBRARY}) +set(KIM_INCLUDE_DIRS ${KIM_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set KIM_FOUND to TRUE +# if all listed variables are TRUE + +find_package_handle_standard_args(KIM DEFAULT_MSG KIM_LIBRARY KIM_INCLUDE_DIR) + +mark_as_advanced(KIM_INCLUDE_DIR KIM_LIBRARY ) diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake new file mode 100644 index 0000000000..a28c959acf --- /dev/null +++ b/cmake/Modules/FindNetCDF.cmake @@ -0,0 +1,118 @@ +# - Find NetCDF +# Find the native NetCDF includes and library +# +# NETCDF_INCLUDE_DIR - user modifiable choice of where netcdf headers are +# NETCDF_LIBRARY - user modifiable choice of where netcdf libraries are +# +# Your package can require certain interfaces to be FOUND by setting these +# +# NETCDF_CXX - require the C++ interface and link the C++ library +# NETCDF_F77 - require the F77 interface and link the fortran library +# NETCDF_F90 - require the F90 interface and link the fortran library +# +# Or equivalently by calling FindNetCDF with a COMPONENTS argument containing one or +# more of "CXX;F77;F90". +# +# When interfaces are requested the user has access to interface specific hints: +# +# NETCDF_${LANG}_INCLUDE_DIR - where to search for interface header files +# NETCDF_${LANG}_LIBRARY - where to search for interface libraries +# +# This module returns these variables for the rest of the project to use. +# +# NETCDF_FOUND - True if NetCDF found including required interfaces (see below) +# NETCDF_LIBRARIES - All netcdf related libraries. +# NETCDF_INCLUDE_DIRS - All directories to include. +# NETCDF_HAS_INTERFACES - Whether requested interfaces were found or not. +# NETCDF_${LANG}_INCLUDE_DIRS/NETCDF_${LANG}_LIBRARIES - C/C++/F70/F90 only interface +# +# Normal usage would be: +# set (NETCDF_F90 "YES") +# find_package (NetCDF REQUIRED) +# target_link_libraries (uses_everthing ${NETCDF_LIBRARIES}) +# target_link_libraries (only_uses_f90 ${NETCDF_F90_LIBRARIES}) + +#search starting from user editable cache var +if (NETCDF_INCLUDE_DIR AND NETCDF_LIBRARY) + # Already in cache, be silent + set (NETCDF_FIND_QUIETLY TRUE) +endif () + +set(USE_DEFAULT_PATHS "NO_DEFAULT_PATH") +if(NETCDF_USE_DEFAULT_PATHS) + set(USE_DEFAULT_PATHS "") +endif() + +find_path (NETCDF_INCLUDE_DIR netcdf.h + HINTS "${NETCDF_DIR}/include") +mark_as_advanced (NETCDF_INCLUDE_DIR) +set (NETCDF_C_INCLUDE_DIRS ${NETCDF_INCLUDE_DIR}) + +find_library (NETCDF_LIBRARY NAMES netcdf + HINTS "${NETCDF_DIR}/lib") +mark_as_advanced (NETCDF_LIBRARY) + +set (NETCDF_C_LIBRARIES ${NETCDF_LIBRARY}) + +#start finding requested language components +set (NetCDF_libs "") +set (NetCDF_includes "${NETCDF_INCLUDE_DIR}") + +get_filename_component (NetCDF_lib_dirs "${NETCDF_LIBRARY}" PATH) +set (NETCDF_HAS_INTERFACES "YES") # will be set to NO if we're missing any interfaces + +macro (NetCDF_check_interface lang header libs) + if (NETCDF_${lang}) + #search starting from user modifiable cache var + find_path (NETCDF_${lang}_INCLUDE_DIR NAMES ${header} + HINTS "${NETCDF_INCLUDE_DIR}" + HINTS "${NETCDF_${lang}_ROOT}/include" + ${USE_DEFAULT_PATHS}) + + find_library (NETCDF_${lang}_LIBRARY NAMES ${libs} + HINTS "${NetCDF_lib_dirs}" + HINTS "${NETCDF_${lang}_ROOT}/lib" + ${USE_DEFAULT_PATHS}) + + mark_as_advanced (NETCDF_${lang}_INCLUDE_DIR NETCDF_${lang}_LIBRARY) + + #export to internal varS that rest of project can use directly + set (NETCDF_${lang}_LIBRARIES ${NETCDF_${lang}_LIBRARY}) + set (NETCDF_${lang}_INCLUDE_DIRS ${NETCDF_${lang}_INCLUDE_DIR}) + + if (NETCDF_${lang}_INCLUDE_DIR AND NETCDF_${lang}_LIBRARY) + list (APPEND NetCDF_libs ${NETCDF_${lang}_LIBRARY}) + list (APPEND NetCDF_includes ${NETCDF_${lang}_INCLUDE_DIR}) + else () + set (NETCDF_HAS_INTERFACES "NO") + message (STATUS "Failed to find NetCDF interface for ${lang}") + endif () + endif () +endmacro () + +list (FIND NetCDF_FIND_COMPONENTS "CXX" _nextcomp) +if (_nextcomp GREATER -1) + set (NETCDF_CXX 1) +endif () +list (FIND NetCDF_FIND_COMPONENTS "F77" _nextcomp) +if (_nextcomp GREATER -1) + set (NETCDF_F77 1) +endif () +list (FIND NetCDF_FIND_COMPONENTS "F90" _nextcomp) +if (_nextcomp GREATER -1) + set (NETCDF_F90 1) +endif () +NetCDF_check_interface (CXX netcdfcpp.h netcdf_c++) +NetCDF_check_interface (F77 netcdf.inc netcdff) +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) From d6f05ea309c8362f8c603022ccf60904551a119b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 20:19:20 -0600 Subject: [PATCH 121/293] USER_OMP -> USER-OMP --- cmake/CMakeLists.txt | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1b6b426ded..f732576513 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -52,7 +52,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -set(ACCEL_PACKAGES USER_OMP KOKKOS OPT) +set(ACCEL_PACKAGES USER-OMP KOKKOS OPT) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -220,7 +220,7 @@ if(ENABLE_KOKKOS OR ENABLE_MSCG) set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 endif() -if(ENABLE_USER_OMP OR ENABLE_KOKKOS) +if(ENABLE_USER-OMP OR ENABLE_KOKKOS) find_package(OpenMP REQUIRED) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") @@ -293,21 +293,21 @@ endif() # e.g. accelerator packages ###################################################################### -if(ENABLE_USER_OMP) - set(USER_OMP_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-OMP) - set(USER_OMP_SOURCES ${USER_OMP_SOURCES_DIR}/thr_data.cpp - ${USER_OMP_SOURCES_DIR}/thr_omp.cpp - ${USER_OMP_SOURCES_DIR}/fix_nh_omp.cpp - ${USER_OMP_SOURCES_DIR}/fix_nh_sphere_omp.cpp) - set_property(GLOBAL PROPERTY "OMP_SOURCES" "${USER_OMP_SOURCES}") +if(ENABLE_USER-OMP) + set(USER-OMP_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-OMP) + set(USER-OMP_SOURCES ${USER-OMP_SOURCES_DIR}/thr_data.cpp + ${USER-OMP_SOURCES_DIR}/thr_omp.cpp + ${USER-OMP_SOURCES_DIR}/fix_nh_omp.cpp + ${USER-OMP_SOURCES_DIR}/fix_nh_sphere_omp.cpp) + set_property(GLOBAL PROPERTY "OMP_SOURCES" "${USER-OMP_SOURCES}") # detects styles which have USER-OMP version - RegisterStylesExt(${USER_OMP_SOURCES_DIR} omp OMP_SOURCES) + RegisterStylesExt(${USER-OMP_SOURCES_DIR} omp OMP_SOURCES) - get_property(USER_OMP_SOURCES GLOBAL PROPERTY OMP_SOURCES) + get_property(USER-OMP_SOURCES GLOBAL PROPERTY OMP_SOURCES) - list(APPEND LIB_SOURCES ${USER_OMP_SOURCES}) - include_directories(${USER_OMP_SOURCES_DIR}) + list(APPEND LIB_SOURCES ${USER-OMP_SOURCES}) + include_directories(${USER-OMP_SOURCES_DIR}) endif() if(ENABLE_KOKKOS) From fa0f8a9e2ad23f2d7bb780478690e20f04cc66c8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 21:31:57 -0600 Subject: [PATCH 122/293] added USER-QUIP --- cmake/CMakeLists.txt | 44 ++++++++++++++++++++---------------- cmake/Modules/FindQUIP.cmake | 18 +++++++++++++++ 2 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 cmake/Modules/FindQUIP.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index f732576513..b9d57a3736 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -47,7 +47,7 @@ set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD - USER-SMTBQ USER-SPH USER-TALLY USER-VTK) + USER-SMTBQ USER-SPH USER-TALLY USER-VTK USER-QUIP) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -71,6 +71,23 @@ pkg_depends(USER-LB MPI) pkg_depends(USER-MISC MANYBODY) pkg_depends(USER-PHONON KSPACE) +if(ENABLE_REAX OR ENABLE_MEAM OR ENABLE_USER-QUIP) + enable_language(Fortran) +endif() + +if(ENABLE_KOKKOS OR ENABLE_MSCG) + # starting with CMake 3.1 this is all you have to do to enforce C++11 + set(CMAKE_CXX_STANDARD 11) # C++11... + set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... + set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 +endif() + +if(ENABLE_USER-OMP OR ENABLE_KOKKOS) + find_package(OpenMP REQUIRED) + set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") + set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") +endif() + if(ENABLE_KSPACE) find_package(FFTW3) if(FFTW3_FOUND) @@ -95,7 +112,7 @@ if(ENABLE_KOKKOS) list(APPEND LAMMPS_LINK_LIBS kokkos) endif() -if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD) +if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD OR ENABLE_USER-QUIP) find_package(LAPACK REQUIRED) list(APPEND LAMMPS_LINK_LIBS ${LAPACK_LIBRARIES}) #TODO use lib/lapack @@ -151,6 +168,11 @@ if(ENABLE_USER-SMD) include_directories(${EIGEN3_INCLUDE_DIR}) endif() +if(ENABLE_USER-QUIP) + find_package(QUIP REQUIRED) + list(APPEND LAMMPS_LINK_LIBS ${QUIP_LIBRARIES} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## @@ -208,24 +230,6 @@ foreach(PKG ${PACKAGES}) endif() endforeach() -if(ENABLE_REAX OR ENABLE_MEAM) - enable_language(Fortran) -endif() - - -if(ENABLE_KOKKOS OR ENABLE_MSCG) - # starting with CMake 3.1 this is all you have to do to enforce C++11 - set(CMAKE_CXX_STANDARD 11) # C++11... - set(CMAKE_CXX_STANDARD_REQUIRED ON) #...is required... - set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 -endif() - -if(ENABLE_USER-OMP OR ENABLE_KOKKOS) - find_package(OpenMP REQUIRED) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") -endif() - foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD USER-MOLFILE) if(ENABLE_${SIMPLE_LIB}) diff --git a/cmake/Modules/FindQUIP.cmake b/cmake/Modules/FindQUIP.cmake new file mode 100644 index 0000000000..4ee1baf4f8 --- /dev/null +++ b/cmake/Modules/FindQUIP.cmake @@ -0,0 +1,18 @@ +# - Find quip +# Find the native QUIP libraries. +# +# QUIP_LIBRARIES - List of libraries when using fftw3. +# QUIP_FOUND - True if fftw3 found. +# + +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) + +mark_as_advanced(QUIP_LIBRARY) From 7dd5068740ac38a385252163356fe229d8ba8f22 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 21:43:29 -0600 Subject: [PATCH 123/293] allow internal lapack --- cmake/CMakeLists.txt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b9d57a3736..7693b0f744 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -6,6 +6,10 @@ set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) set(LAMMPS_LIB_BINARY_DIR ${CMAKE_BINARY_DIR}/lib) +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_SOURCE_DIR}/Modules) @@ -113,9 +117,14 @@ if(ENABLE_KOKKOS) endif() if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD OR ENABLE_USER-QUIP) - find_package(LAPACK REQUIRED) - list(APPEND LAMMPS_LINK_LIBS ${LAPACK_LIBRARIES}) - #TODO use lib/lapack + find_package(LAPACK) + if(LAPACK_FOUND) + list(APPEND LAMMPS_LINK_LIBS ${LAPACK_LIBRARIES}) + else() + enable_language(Fortran) + file(GLOB LAPACK_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/linalg/*.f) + list(APPEND LIB_SOURCES ${LAPACK_SOURCES}) + endif() endif() if(ENABLE_PYTHON) @@ -202,10 +211,6 @@ list(APPEND LAMMPS_LINK_LIBS ${MATH_LIBRARIES}) #Do NOT go into src to not conflict with old Makefile build system #add_subdirectory(src) -file(GLOB LIB_SOURCES ${LAMMPS_SOURCE_DIR}/*.cpp) -file(GLOB LMP_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) -list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) - if(NOT ENABLE_MPI) file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) list(APPEND LIB_SOURCES ${MPI_SOURCES}) From 22ecd9b8d225819de8fe134cf44cdcc8ff1d1a71 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 22:07:21 -0600 Subject: [PATCH 124/293] started on USER-QMMM --- cmake/CMakeLists.txt | 10 ++++++++-- cmake/Modules/FindQE.cmake | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 cmake/Modules/FindQE.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7693b0f744..c40cee9252 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -51,7 +51,7 @@ set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD - USER-SMTBQ USER-SPH USER-TALLY USER-VTK USER-QUIP) + USER-SMTBQ USER-SPH USER-TALLY USER-VTK USER-QUIP USER-QMMM) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() @@ -182,6 +182,12 @@ if(ENABLE_USER-QUIP) list(APPEND LAMMPS_LINK_LIBS ${QUIP_LIBRARIES} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() +if(ENABLE_USER-QMMM) + find_package(QE REQUIRED) + include_directories(${QE_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${QE_LIBRARIES}) +endif() + ######################################################################## # Basic system tests (standard libraries, headers, functions, types) # ######################################################################## @@ -236,7 +242,7 @@ foreach(PKG ${PACKAGES}) endforeach() foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD - USER-MOLFILE) + USER-MOLFILE USER-QMMM) if(ENABLE_${SIMPLE_LIB}) string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") string(TOLOWER "${SIMPLE_LIB}" INC_DIR) diff --git a/cmake/Modules/FindQE.cmake b/cmake/Modules/FindQE.cmake new file mode 100644 index 0000000000..c46adc1689 --- /dev/null +++ b/cmake/Modules/FindQE.cmake @@ -0,0 +1,22 @@ +# - Find quantum-espresso +# Find the native QE headers and libraries. +# +# QE_INCLUDE_DIRS - where to find quantum-espresso.h, etc. +# QE_LIBRARIES - List of libraries when using quantum-espresso. +# QE_FOUND - True if quantum-espresso found. +# + +find_path(QE_INCLUDE_DIR libqecouple.h PATH_SUFFIXES COUPLE/include) + +find_library(QE_LIBRARY NAMES libqefft) + +set(QE_LIBRARIES ${QE_LIBRARY}) +set(QE_INCLUDE_DIRS ${QE_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set QE_FOUND to TRUE +# if all listed variables are TRUE + +find_package_handle_standard_args(QE DEFAULT_MSG QE_LIBRARY QE_INCLUDE_DIR) + +mark_as_advanced(QE_INCLUDE_DIR QE_LIBRARY ) From 7605f72c9a3e484515da9b1bd10d36251dee6a5c Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 22:37:51 -0600 Subject: [PATCH 125/293] finish USER-QMMM --- cmake/CMakeLists.txt | 4 ++-- cmake/Modules/FindQE.cmake | 15 +++++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c40cee9252..7727efa8c9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -75,7 +75,7 @@ pkg_depends(USER-LB MPI) pkg_depends(USER-MISC MANYBODY) pkg_depends(USER-PHONON KSPACE) -if(ENABLE_REAX OR ENABLE_MEAM OR ENABLE_USER-QUIP) +if(ENABLE_REAX OR ENABLE_MEAM OR ENABLE_USER-QUIP OR ENABLE_USER-QMMM) enable_language(Fortran) endif() @@ -185,7 +185,7 @@ endif() if(ENABLE_USER-QMMM) find_package(QE REQUIRED) include_directories(${QE_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${QE_LIBRARIES}) + list(APPEND LAMMPS_LINK_LIBS ${QE_LIBRARIES} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() ######################################################################## diff --git a/cmake/Modules/FindQE.cmake b/cmake/Modules/FindQE.cmake index c46adc1689..4484bd4db2 100644 --- a/cmake/Modules/FindQE.cmake +++ b/cmake/Modules/FindQE.cmake @@ -8,15 +8,22 @@ find_path(QE_INCLUDE_DIR libqecouple.h PATH_SUFFIXES COUPLE/include) -find_library(QE_LIBRARY NAMES libqefft) +find_library(QECOUPLE_LIBRARY NAMES qecouple) +find_library(PW_LIBRARY NAMES pw) +find_library(QEMOD_LIBRARY NAMES qemod) +find_library(QEFFT_LIBRARY NAMES qefft) +find_library(QELA_LIBRARY NAMES qela) +find_library(CLIB_LIBRARY NAMES clib) +find_library(IOTK_LIBRARY NAMES iotk) -set(QE_LIBRARIES ${QE_LIBRARY}) + +set(QE_LIBRARIES ${QECOUPLE_LIBRARY} ${PW_LIBRARY} ${QEMOD_LIBRARY} ${QEFFT_LIBRARY} ${QELA_LIBRARY} ${CLIB_LIBRARY} ${IOTK_LIBRARY}) set(QE_INCLUDE_DIRS ${QE_INCLUDE_DIR}) include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set QE_FOUND to TRUE # if all listed variables are TRUE -find_package_handle_standard_args(QE DEFAULT_MSG QE_LIBRARY QE_INCLUDE_DIR) +find_package_handle_standard_args(QE DEFAULT_MSG QECOUPLE_LIBRARY PW_LIBRARY QEMOD_LIBRARY QEFFT_LIBRARY QELA_LIBRARY CLIB_LIBRARY IOTK_LIBRARY QE_INCLUDE_DIR) -mark_as_advanced(QE_INCLUDE_DIR QE_LIBRARY ) +mark_as_advanced(QE_INCLUDE_DIR QECOUPLE_LIBRARY PW_LIBRARY QEMOD_LIBRARY QEFFT_LIBRARY QELA_LIBRARY CLIB_LIBRARY IOTK_LIBRARY) From fc1be074b2957b72911dffdf3ec7f176174904ac Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 22:52:59 -0600 Subject: [PATCH 126/293] added USER-INTEL --- cmake/CMakeLists.txt | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7727efa8c9..1d755913e6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -56,7 +56,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -set(ACCEL_PACKAGES USER-OMP KOKKOS OPT) +set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -86,7 +86,7 @@ if(ENABLE_KOKKOS OR ENABLE_MSCG) set(CMAKE_CXX_EXTENSIONS OFF) #...without compiler extensions like gnu++11 endif() -if(ENABLE_USER-OMP OR ENABLE_KOKKOS) +if(ENABLE_USER-OMP OR ENABLE_KOKKOS OR ENABLE_USER-INTEL) find_package(OpenMP REQUIRED) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") @@ -363,6 +363,29 @@ if(ENABLE_OPT) include_directories(${OPT_SOURCES_DIR}) endif() +if(ENABLE_USER-INTEL) + set(USER-INTEL_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-INTEL) + set(USER-INTEL_SOURCES ${USER-INTEL_SOURCES_DIR}/intel_preprocess.h + ${USER-INTEL_SOURCES_DIR}/intel_buffers.h + ${USER-INTEL_SOURCES_DIR}/intel_buffers.cpp + ${USER-INTEL_SOURCES_DIR}/math_extra_intel.h + ${USER-INTEL_SOURCES_DIR}/nbin_intel.h + ${USER-INTEL_SOURCES_DIR}/nbin_intel.cpp + ${USER-INTEL_SOURCES_DIR}/npair_intel.h + ${USER-INTEL_SOURCES_DIR}/npair_intel.cpp + ${USER-INTEL_SOURCES_DIR}/intel_simd.h + ${USER-INTEL_SOURCES_DIR}/intel_intrinsics.h) + + set_property(GLOBAL PROPERTY "USER-INTEL_SOURCES" "${USER-INTEL_SOURCES}") + + # detects styles which have USER-INTEL version + RegisterStylesExt(${USER-INTEL_SOURCES_DIR} opt USER-INTEL_SOURCES) + + get_property(USER-INTEL_SOURCES GLOBAL PROPERTY USER-INTEL_SOURCES) + + list(APPEND LIB_SOURCES ${USER-INTEL_SOURCES}) + include_directories(${USER-INTEL_SOURCES_DIR}) +endif() ###################################################### # Generate style headers based on global list of From 385c6f7f2ba7ee72783f5bd4b205f99e2826853f Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 22:53:53 -0600 Subject: [PATCH 127/293] cmake: clean up --- cmake/CMakeLists.txt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1d755913e6..8713c3c2db 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -40,6 +40,10 @@ if(ENABLE_MPI) find_package(MPI REQUIRED) include_directories(${MPI_C_INCLUDE_PATH}) list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) +else() + file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) + list(APPEND LIB_SOURCES ${MPI_SOURCES}) + include_directories(${LAMMPS_SOURCE_DIR}/STUBS) endif() option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) @@ -217,12 +221,6 @@ list(APPEND LAMMPS_LINK_LIBS ${MATH_LIBRARIES}) #Do NOT go into src to not conflict with old Makefile build system #add_subdirectory(src) -if(NOT ENABLE_MPI) - file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) - list(APPEND LIB_SOURCES ${MPI_SOURCES}) - include_directories(${LAMMPS_SOURCE_DIR}/STUBS) -endif() - include(StyleHeaderUtils) RegisterStyles(${LAMMPS_SOURCE_DIR}) From 80e44486146c35dcfb63ad62e01f88755da2735a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 16 Jul 2017 23:03:11 -0600 Subject: [PATCH 128/293] added GPU --- cmake/CMakeLists.txt | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8713c3c2db..e96516c1cd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -60,7 +60,7 @@ foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL) +set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL GPU) foreach(PKG ${ACCEL_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -385,6 +385,29 @@ if(ENABLE_USER-INTEL) include_directories(${USER-INTEL_SOURCES_DIR}) endif() +if(ENABLE_GPU) + find_package(CUDA REQUIRED) + + set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) + set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) + + set_property(GLOBAL PROPERTY "GPU_SOURCES" "${GPU_SOURCES}") + + # detects styles which have GPU version + RegisterStylesExt(${GPU_SOURCES_DIR} opt GPU_SOURCES) + + get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) + + + file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp + ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu + cuda_add_library(lammps_gpu ${GPU_LIB_SOURCES}) + + list(APPEND LAMMPS_LINK_LIBS lammps_gpu) + list(APPEND LIB_SOURCES ${GPU_SOURCES}) + include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu) +endif() + ###################################################### # Generate style headers based on global list of # styles registered during package selection From 1c1a1db3666989a327f360d93ed47e111aab2239 Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 17 Jul 2017 11:55:05 -0400 Subject: [PATCH 129/293] Fix typo --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index e96516c1cd..d768e10662 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -400,7 +400,7 @@ if(ENABLE_GPU) file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp - ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu + ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) cuda_add_library(lammps_gpu ${GPU_LIB_SOURCES}) list(APPEND LAMMPS_LINK_LIBS lammps_gpu) From bda07301693ae242d089a234b9f34a2ff0316fd9 Mon Sep 17 00:00:00 2001 From: Max Veit Date: Mon, 7 Nov 2016 14:59:25 +0000 Subject: [PATCH 130/293] Modified the quip/lammps interface to pass lammps atom ids --- src/USER-QUIP/pair_quip.cpp | 3 ++- src/USER-QUIP/pair_quip.h | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index e8b23c761f..0ad8066027 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -66,6 +66,7 @@ void PairQUIP::compute(int eflag, int vflag) int nghost = atom->nghost; int ntotal = nlocal + nghost; int *type = atom->type; + tagint *tag = atom->tag; double **x = atom->x; double **f = atom->f; @@ -124,7 +125,7 @@ void PairQUIP::compute(int eflag, int vflag) lattice[8] = domain->zprd; quip_lammps_wrapper - (&nlocal,&nghost,atomic_numbers, + (&nlocal,&nghost,atomic_numbers,tag, &inum,&sum_num_neigh,ilist, quip_num_neigh,quip_neigh,lattice, quip_potential,&n_quip_potential,&x[0][0], diff --git a/src/USER-QUIP/pair_quip.h b/src/USER-QUIP/pair_quip.h index f86df015ea..985a43fd7e 100644 --- a/src/USER-QUIP/pair_quip.h +++ b/src/USER-QUIP/pair_quip.h @@ -24,7 +24,7 @@ PairStyle(quip,PairQUIP) extern "C" { - void quip_lammps_wrapper(int*, int*, int*, + void quip_lammps_wrapper(int*, int*, int*, int*, int*, int*, int*, int*, int*, double*, int*, int*, double*, From 5ee2c310389d249b511ab59e27a7332a31db3e0d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 11:01:08 -0600 Subject: [PATCH 131/293] split PACKAGES, get ENABLE-ALL right --- cmake/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d768e10662..55bed88501 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -51,17 +51,17 @@ option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KIM KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ - REAX REPLICA RIGID SHOCK SNAP SRD VORONOI USER-ATC USER-AWPMD USER-CGDNA + REAX REPLICA RIGID SHOCK SNAP SRD VORONOI) +set(USER-PACKAGES USER-ATC USER-AWPMD USER-CGDNA USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD USER-SMTBQ USER-SPH USER-TALLY USER-VTK USER-QUIP USER-QMMM) +set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL GPU) foreach(PKG ${PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() - -set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL GPU) -foreach(PKG ${ACCEL_PACKAGES}) +foreach(PKG ${ACCEL_PACKAGES} ${USER-PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -226,7 +226,7 @@ RegisterStyles(${LAMMPS_SOURCE_DIR}) # packages which include entire content when enabled -foreach(PKG ${PACKAGES}) +foreach(PKG ${PACKAGES} ${USER-PACKAGES}) if(ENABLE_${PKG}) set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) From 2411192ab41dc92a3d1bebb3a5f6d80805de8124 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 11:52:06 -0600 Subject: [PATCH 132/293] cmake: add cross-configure warning --- cmake/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 55bed88501..1846d6babb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -18,6 +18,14 @@ if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) +foreach(STYLE_FILE style_angle.h style_atom.h style_body.h style_bond.h style_command.h style_compute.h style_dihedral.h style_dump.h + style_fix.h style_improper.h style_integrate.h style_kspace.h style_minimize.h style_nbin.h style_npair.h style_nstencil.h + style_ntopo.h style_pair.h style_reader.h style_region.h) + if(EXISTS ${LAMMPS_SOURCE_DIR}/${STYLE_FILE}) + message(FATAL_ERROR "There is a ${STYLE_FILE} in ${LAMMPS_SOURCE_DIR}, please clean up the source directory first") + endif() +endforeach() + enable_language(CXX) ###################################################################### From 08c920029fc78d0da2da73fc6ecf104e15d1fcf2 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 12:22:28 -0600 Subject: [PATCH 133/293] added lammps size option --- cmake/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1846d6babb..177a9b8296 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -54,6 +54,10 @@ else() include_directories(${LAMMPS_SOURCE_DIR}/STUBS) endif() +set(LAMMPS_SIZE_LIMIT "LAMMPS_SMALLBIG" CACHE STRING "Lammps size limit") +set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS LAMMPS_SMALLBIG LAMMPS_BIGBIG LAMMPS_SMALLSMALL) +add_definitions(-D${LAMMPS_SIZE_LIMIT}) + option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) From a3885b78ada825208c757cb2a2c7c3a98dfc7496 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 13:21:42 -0600 Subject: [PATCH 134/293] added support -DLAMMPS_XDR and -DPACK_* --- cmake/CMakeLists.txt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 177a9b8296..8095f3e500 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -115,6 +115,16 @@ if(ENABLE_KSPACE) include_directories(${FFTW3_INCLUDE_DIRS}) list(APPEND LAMMPS_LINK_LIBS ${FFTW3_LIBRARIES}) endif() + set(PACK_OPTIMIZATION "PACK_ARRAY" CACHE STRING "Optimization for FFT") + set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) + add_definitions(-D${PACK_OPTIMIZATION}) +endif() + +if(ENABLE_MISC) + option(LAMMPS_XDR "include XDR compatibility files for doing particle dumps in XTC format" OFF) + if(LAMMPS_XDR) + add_definitions(-DLAMMPS_XDR) + endif() endif() if(ENABLE_KOKKOS) From 99f5f82b0266f47c12ec6d5e61b4d5eb339502ba Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 13:26:46 -0600 Subject: [PATCH 135/293] added support for LAMMPS_MEMALIGN and LAMMPS_LONGLONG_TO_LONG --- cmake/CMakeLists.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8095f3e500..1d912970d2 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -48,6 +48,10 @@ if(ENABLE_MPI) find_package(MPI REQUIRED) include_directories(${MPI_C_INCLUDE_PATH}) list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) + 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) + endif() else() file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) list(APPEND LIB_SOURCES ${MPI_SOURCES}) @@ -58,6 +62,9 @@ set(LAMMPS_SIZE_LIMIT "LAMMPS_SMALLBIG" CACHE STRING "Lammps size limit") set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS LAMMPS_SMALLBIG LAMMPS_BIGBIG LAMMPS_SMALLSMALL) add_definitions(-D${LAMMPS_SIZE_LIMIT}) +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") +add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) + option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_ALL "Build all packages" OFF) From 050a82af5813b15536a509f20a62b8b1f0cde0de Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 13:28:34 -0600 Subject: [PATCH 136/293] fix LAMMPS_LONGLONG_TO_LONG description --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1d912970d2..1aeaf33c43 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -48,7 +48,7 @@ if(ENABLE_MPI) find_package(MPI REQUIRED) include_directories(${MPI_C_INCLUDE_PATH}) list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) - option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize "long long" data types" OFF) + 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) endif() From 8bc318461172d95625f0bda8db17bc59b124ff44 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 14:01:05 -0600 Subject: [PATCH 137/293] added support for LAMMPS_FFMPEG --- cmake/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 1aeaf33c43..051ff4d290 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -187,6 +187,11 @@ if(GZIP) add_definitions(-DLAMMPS_GZIP) endif() +find_program(FFMPEG ffmpeg) +if(FFMPEG) + add_definitions(-DLAMMPS_FFMPEG) +endif() + if(ENABLE_VORONOI) find_package(VORO REQUIRED) #some distros include_directories(${VORO_INCLUDE_DIRS}) From 3c3baf34c4e55970ae1845cbbc650b0c562efdc8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 17 Jul 2017 15:04:07 -0600 Subject: [PATCH 138/293] GPU: added cuda includedir --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 051ff4d290..17759cbb65 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -421,6 +421,7 @@ endif() if(ENABLE_GPU) find_package(CUDA REQUIRED) + include_directories(${CUDA_TOOLKIT_INCLUDE}) set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) From 23033404b0a4f3101a3090981329780b088d8050 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 17 Jul 2017 18:18:21 -0400 Subject: [PATCH 139/293] skip table consistency check for bitmapped tables --- src/pair_table.cpp | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/src/pair_table.cpp b/src/pair_table.cpp index b36843ff44..782fb43f9a 100644 --- a/src/pair_table.cpp +++ b/src/pair_table.cpp @@ -453,20 +453,25 @@ void PairTable::read_table(Table *tb, char *file, char *keyword) double r,e,f,rprev,rnext,eprev,enext,fleft,fright; int ferror = 0; - for (int i = 1; i < tb->ninput-1; i++) { - r = tb->rfile[i]; - rprev = tb->rfile[i-1]; - rnext = tb->rfile[i+1]; - e = tb->efile[i]; - eprev = tb->efile[i-1]; - enext = tb->efile[i+1]; - f = tb->ffile[i]; - fleft = - (e-eprev) / (r-rprev); - fright = - (enext-e) / (rnext-r); - if (f < fleft && f < fright) ferror++; - if (f > fleft && f > fright) ferror++; - //printf("Values %d: %g %g %g\n",i,r,e,f); - //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f); + + // bitmapped tables do not follow regular ordering, so we cannot check them here + + if (tb->rflag != BMP) { + for (int i = 1; i < tb->ninput-1; i++) { + r = tb->rfile[i]; + rprev = tb->rfile[i-1]; + rnext = tb->rfile[i+1]; + e = tb->efile[i]; + eprev = tb->efile[i-1]; + enext = tb->efile[i+1]; + f = tb->ffile[i]; + fleft = - (e-eprev) / (r-rprev); + fright = - (enext-e) / (rnext-r); + if (f < fleft && f < fright) ferror++; + if (f > fleft && f > fright) ferror++; + //printf("Values %d: %g %g %g\n",i,r,e,f); + //printf(" secant %d %d %g: %g %g %g\n",i,ferror,r,fleft,fright,f); + } } if (ferror) { From c3a2ed0d1b30c8afb8464e7695f8ec808462be08 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Mon, 17 Jul 2017 23:56:38 -0400 Subject: [PATCH 140/293] plug small memory leak in USER-OMP variants of pppm kspace styles --- src/USER-OMP/pppm_cg_omp.cpp | 42 +++++++++++----------- src/USER-OMP/pppm_cg_omp.h | 3 +- src/USER-OMP/pppm_disp_omp.cpp | 47 ++++++++++-------------- src/USER-OMP/pppm_disp_omp.h | 1 - src/USER-OMP/pppm_disp_tip4p_omp.cpp | 54 +++++++++++++--------------- src/USER-OMP/pppm_disp_tip4p_omp.h | 3 +- src/USER-OMP/pppm_omp.cpp | 6 ++-- src/USER-OMP/pppm_omp.h | 3 +- src/USER-OMP/pppm_tip4p_omp.cpp | 42 +++++++++++----------- src/USER-OMP/pppm_tip4p_omp.h | 3 +- src/USER-OMP/thr_data.cpp | 35 +++++++++++------- 11 files changed, 111 insertions(+), 128 deletions(-) diff --git a/src/USER-OMP/pppm_cg_omp.cpp b/src/USER-OMP/pppm_cg_omp.cpp index 021765d14b..df0e632f78 100644 --- a/src/USER-OMP/pppm_cg_omp.cpp +++ b/src/USER-OMP/pppm_cg_omp.cpp @@ -54,6 +54,26 @@ PPPMCGOMP::PPPMCGOMP(LAMMPS *lmp, int narg, char **arg) : suffix_flag |= Suffix::OMP; } +/* ---------------------------------------------------------------------- + clean up per-thread allocations +------------------------------------------------------------------------- */ + +PPPMCGOMP::~PPPMCGOMP() +{ +#if defined(_OPENMP) +#pragma omp parallel default(none) +#endif + { +#if defined(_OPENMP) + const int tid = omp_get_thread_num(); +#else + const int tid = 0; +#endif + ThrData *thr = fix->get_thr(tid); + thr->init_pppm(-order,memory); + } +} + /* ---------------------------------------------------------------------- allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ @@ -76,28 +96,6 @@ void PPPMCGOMP::allocate() } } -/* ---------------------------------------------------------------------- - free memory that depends on # of K-vectors and order -------------------------------------------------------------------------- */ - -void PPPMCGOMP::deallocate() -{ - PPPMCG::deallocate(); - -#if defined(_OPENMP) -#pragma omp parallel default(none) -#endif - { -#if defined(_OPENMP) - const int tid = omp_get_thread_num(); -#else - const int tid = 0; -#endif - ThrData *thr = fix->get_thr(tid); - thr->init_pppm(-order,memory); - } -} - /* ---------------------------------------------------------------------- pre-compute modified (Hockney-Eastwood) Coulomb Green's function ------------------------------------------------------------------------- */ diff --git a/src/USER-OMP/pppm_cg_omp.h b/src/USER-OMP/pppm_cg_omp.h index 91f09ebbfa..07763eba38 100644 --- a/src/USER-OMP/pppm_cg_omp.h +++ b/src/USER-OMP/pppm_cg_omp.h @@ -28,12 +28,11 @@ namespace LAMMPS_NS { class PPPMCGOMP : public PPPMCG, public ThrOMP { public: PPPMCGOMP(class LAMMPS *, int, char **); - virtual ~PPPMCGOMP () {}; + virtual ~PPPMCGOMP (); virtual void compute(int, int); protected: virtual void allocate(); - virtual void deallocate(); virtual void compute_gf_ik(); virtual void compute_gf_ad(); diff --git a/src/USER-OMP/pppm_disp_omp.cpp b/src/USER-OMP/pppm_disp_omp.cpp index 16d3001ddf..6cf2983761 100644 --- a/src/USER-OMP/pppm_disp_omp.cpp +++ b/src/USER-OMP/pppm_disp_omp.cpp @@ -55,7 +55,24 @@ PPPMDispOMP::PPPMDispOMP(LAMMPS *lmp, int narg, char **arg) : PPPMDispOMP::~PPPMDispOMP() { - deallocate(); +#if defined(_OPENMP) +#pragma omp parallel default(none) +#endif + { +#if defined(_OPENMP) + const int tid = omp_get_thread_num(); +#else + const int tid = 0; +#endif + if (function[0]) { + ThrData * thr = fix->get_thr(tid); + thr->init_pppm(-order,memory); + } + if (function[1] + function[2]) { + ThrData * thr = fix->get_thr(tid); + thr->init_pppm_disp(-order_6,memory); + } + } } /* ---------------------------------------------------------------------- @@ -87,34 +104,6 @@ void PPPMDispOMP::allocate() } } -/* ---------------------------------------------------------------------- - free memory that depends on # of K-vectors and order -------------------------------------------------------------------------- */ - -void PPPMDispOMP::deallocate() -{ - PPPMDisp::deallocate(); - -#if defined(_OPENMP) -#pragma omp parallel default(none) -#endif - { -#if defined(_OPENMP) - const int tid = omp_get_thread_num(); -#else - const int tid = 0; -#endif - if (function[0]) { - ThrData * thr = fix->get_thr(tid); - thr->init_pppm(-order,memory); - } - if (function[1] + function[2]) { - ThrData * thr = fix->get_thr(tid); - thr->init_pppm_disp(-order_6,memory); - } - } -} - /* ---------------------------------------------------------------------- Compute the modified (hockney-eastwood) coulomb green function ------------------------------------------------------------------------- */ diff --git a/src/USER-OMP/pppm_disp_omp.h b/src/USER-OMP/pppm_disp_omp.h index 86c213282a..b1ec2856bb 100644 --- a/src/USER-OMP/pppm_disp_omp.h +++ b/src/USER-OMP/pppm_disp_omp.h @@ -33,7 +33,6 @@ namespace LAMMPS_NS { protected: virtual void allocate(); - virtual void deallocate(); virtual void compute_gf(); virtual void compute_gf_6(); diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.cpp b/src/USER-OMP/pppm_disp_tip4p_omp.cpp index 8872c849f3..29aeeb79dc 100644 --- a/src/USER-OMP/pppm_disp_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_disp_tip4p_omp.cpp @@ -52,6 +52,31 @@ PPPMDispTIP4POMP::PPPMDispTIP4POMP(LAMMPS *lmp, int narg, char **arg) : suffix_flag |= Suffix::OMP; } +/* ---------------------------------------------------------------------- */ + +PPPMDispTIP4POMP::~PPPMDispTIP4POMP() +{ + +#if defined(_OPENMP) +#pragma omp parallel default(none) +#endif + { +#if defined(_OPENMP) + const int tid = omp_get_thread_num(); +#else + const int tid = 0; +#endif + if (function[0]) { + ThrData * thr = fix->get_thr(tid); + thr->init_pppm(-order,memory); + } + if (function[1] + function[2]) { + ThrData * thr = fix->get_thr(tid); + thr->init_pppm_disp(-order_6,memory); + } + } +} + /* ---------------------------------------------------------------------- allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ @@ -81,35 +106,6 @@ void PPPMDispTIP4POMP::allocate() } } -/* ---------------------------------------------------------------------- - free memory that depends on # of K-vectors and order -------------------------------------------------------------------------- */ - -void PPPMDispTIP4POMP::deallocate() -{ - PPPMDispTIP4P::deallocate(); - -#if defined(_OPENMP) -#pragma omp parallel default(none) -#endif - { -#if defined(_OPENMP) - const int tid = omp_get_thread_num(); -#else - const int tid = 0; -#endif - if (function[0]) { - ThrData * thr = fix->get_thr(tid); - thr->init_pppm(-order,memory); - } - if (function[1] + function[2]) { - ThrData * thr = fix->get_thr(tid); - thr->init_pppm_disp(-order_6,memory); - } - } -} - - /* ---------------------------------------------------------------------- Compute the modified (hockney-eastwood) coulomb green function ------------------------------------------------------------------------- */ diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.h b/src/USER-OMP/pppm_disp_tip4p_omp.h index e05a52ac80..296444366b 100644 --- a/src/USER-OMP/pppm_disp_tip4p_omp.h +++ b/src/USER-OMP/pppm_disp_tip4p_omp.h @@ -28,11 +28,10 @@ namespace LAMMPS_NS { class PPPMDispTIP4POMP : public PPPMDispTIP4P, public ThrOMP { public: PPPMDispTIP4POMP(class LAMMPS *, int, char **); - virtual ~PPPMDispTIP4POMP () {}; + virtual ~PPPMDispTIP4POMP (); protected: virtual void allocate(); - virtual void deallocate(); virtual void compute_gf(); virtual void compute_gf_6(); diff --git a/src/USER-OMP/pppm_omp.cpp b/src/USER-OMP/pppm_omp.cpp index a62199be56..48b91e3a7b 100644 --- a/src/USER-OMP/pppm_omp.cpp +++ b/src/USER-OMP/pppm_omp.cpp @@ -74,13 +74,11 @@ void PPPMOMP::allocate() } /* ---------------------------------------------------------------------- - free memory that depends on # of K-vectors and order + clean up per-thread allocations ------------------------------------------------------------------------- */ -void PPPMOMP::deallocate() +PPPMOMP::~PPPMOMP() { - PPPM::deallocate(); - #if defined(_OPENMP) #pragma omp parallel default(none) #endif diff --git a/src/USER-OMP/pppm_omp.h b/src/USER-OMP/pppm_omp.h index 03eb0e110b..bf8a9e0c21 100644 --- a/src/USER-OMP/pppm_omp.h +++ b/src/USER-OMP/pppm_omp.h @@ -28,12 +28,11 @@ namespace LAMMPS_NS { class PPPMOMP : public PPPM, public ThrOMP { public: PPPMOMP(class LAMMPS *, int, char **); - virtual ~PPPMOMP () {}; + virtual ~PPPMOMP (); virtual void compute(int, int); protected: virtual void allocate(); - virtual void deallocate(); virtual void compute_gf_ik(); virtual void compute_gf_ad(); diff --git a/src/USER-OMP/pppm_tip4p_omp.cpp b/src/USER-OMP/pppm_tip4p_omp.cpp index 21e3081c65..1eab140cec 100644 --- a/src/USER-OMP/pppm_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_tip4p_omp.cpp @@ -52,6 +52,26 @@ PPPMTIP4POMP::PPPMTIP4POMP(LAMMPS *lmp, int narg, char **arg) : suffix_flag |= Suffix::OMP; } +/* ---------------------------------------------------------------------- + clean up per-thread allocations +------------------------------------------------------------------------- */ + +PPPMTIP4POMP::~PPPMTIP4POMP() +{ +#if defined(_OPENMP) +#pragma omp parallel default(none) +#endif + { +#if defined(_OPENMP) + const int tid = omp_get_thread_num(); +#else + const int tid = 0; +#endif + ThrData *thr = fix->get_thr(tid); + thr->init_pppm(-order,memory); + } +} + /* ---------------------------------------------------------------------- allocate memory that depends on # of K-vectors and order ------------------------------------------------------------------------- */ @@ -74,28 +94,6 @@ void PPPMTIP4POMP::allocate() } } -/* ---------------------------------------------------------------------- - free memory that depends on # of K-vectors and order -------------------------------------------------------------------------- */ - -void PPPMTIP4POMP::deallocate() -{ - PPPMTIP4P::deallocate(); - -#if defined(_OPENMP) -#pragma omp parallel default(none) -#endif - { -#if defined(_OPENMP) - const int tid = omp_get_thread_num(); -#else - const int tid = 0; -#endif - ThrData *thr = fix->get_thr(tid); - thr->init_pppm(-order,memory); - } -} - /* ---------------------------------------------------------------------- pre-compute modified (Hockney-Eastwood) Coulomb Green's function ------------------------------------------------------------------------- */ diff --git a/src/USER-OMP/pppm_tip4p_omp.h b/src/USER-OMP/pppm_tip4p_omp.h index 0ee807651c..59559cd587 100644 --- a/src/USER-OMP/pppm_tip4p_omp.h +++ b/src/USER-OMP/pppm_tip4p_omp.h @@ -28,12 +28,11 @@ namespace LAMMPS_NS { class PPPMTIP4POMP : public PPPMTIP4P, public ThrOMP { public: PPPMTIP4POMP(class LAMMPS *, int, char **); - virtual ~PPPMTIP4POMP () {}; + virtual ~PPPMTIP4POMP (); virtual void compute(int, int); protected: virtual void allocate(); - virtual void deallocate(); virtual void compute_gf_ik(); virtual void compute_gf_ad(); diff --git a/src/USER-OMP/thr_data.cpp b/src/USER-OMP/thr_data.cpp index 28fd27f9b8..2ee68fb311 100644 --- a/src/USER-OMP/thr_data.cpp +++ b/src/USER-OMP/thr_data.cpp @@ -176,16 +176,22 @@ void ThrData::init_pppm(int order, Memory *memory) { FFT_SCALAR **rho1d, **drho1d; if (order > 0) { - memory->create2d_offset(rho1d,3,-order/2,order/2,"thr_data:rho1d"); - memory->create2d_offset(drho1d,3,-order/2,order/2,"thr_data:drho1d"); - _rho1d = static_cast(rho1d); - _drho1d = static_cast(drho1d); + rho1d = static_cast(_rho1d); + drho1d = static_cast(_drho1d); + if (rho1d) memory->destroy2d_offset(rho1d,-order/2); + if (drho1d) memory->destroy2d_offset(drho1d,-order/2); + memory->create2d_offset(rho1d,3,-order/2,order/2,"thr_data:rho1d"); + memory->create2d_offset(drho1d,3,-order/2,order/2,"thr_data:drho1d"); + _rho1d = static_cast(rho1d); + _drho1d = static_cast(drho1d); } else { order = -order; rho1d = static_cast(_rho1d); drho1d = static_cast(_drho1d); - memory->destroy2d_offset(rho1d,-order/2); - memory->destroy2d_offset(drho1d,-order/2); + if (rho1d) memory->destroy2d_offset(rho1d,-order/2); + if (drho1d) memory->destroy2d_offset(drho1d,-order/2); + _rho1d = NULL; + _drho1d = NULL; } } @@ -203,20 +209,23 @@ void ThrData::init_pppm_disp(int order_6, Memory *memory) { FFT_SCALAR **rho1d_6, **drho1d_6; if (order_6 > 0) { - memory->create2d_offset(rho1d_6,3,-order_6/2,order_6/2,"thr_data:rho1d_6"); - memory->create2d_offset(drho1d_6,3,-order_6/2,order_6/2,"thr_data:drho1d_6"); - _rho1d_6 = static_cast(rho1d_6); - _drho1d_6 = static_cast(drho1d_6); + rho1d_6 = static_cast(_rho1d_6); + drho1d_6 = static_cast(_drho1d_6); + if (rho1d_6) memory->destroy2d_offset(rho1d_6,-order_6/2); + if (drho1d_6) memory->destroy2d_offset(drho1d_6,-order_6/2); + memory->create2d_offset(rho1d_6,3,-order_6/2,order_6/2,"thr_data:rho1d_6"); + memory->create2d_offset(drho1d_6,3,-order_6/2,order_6/2,"thr_data:drho1d_6"); + _rho1d_6 = static_cast(rho1d_6); + _drho1d_6 = static_cast(drho1d_6); } else { order_6 = -order_6; rho1d_6 = static_cast(_rho1d_6); drho1d_6 = static_cast(_drho1d_6); - memory->destroy2d_offset(rho1d_6,-order_6/2); - memory->destroy2d_offset(drho1d_6,-order_6/2); + if (rho1d_6) memory->destroy2d_offset(rho1d_6,-order_6/2); + if (drho1d_6) memory->destroy2d_offset(drho1d_6,-order_6/2); } } - /* ---------------------------------------------------------------------- compute global pair virial via summing F dot r over own & ghost atoms at this point, only pairwise forces have been accumulated in atom->f From c083d5d6f3f844bba454776a7397a36856aea4de Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 00:18:03 -0400 Subject: [PATCH 141/293] fix memory leak in list of neighbor list requests --- src/neighbor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/neighbor.cpp b/src/neighbor.cpp index 487b860c92..ef150902e3 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -197,7 +197,7 @@ Neighbor::~Neighbor() delete [] slist; delete [] plist; - for (int i = 0; i < nlist; i++) + for (int i = 0; i < nrequest; i++) if (requests[i]) delete requests[i]; memory->sfree(requests); for (int i = 0; i < old_nrequest; i++) From bc5186bc30e150c01edd456f395961db44a3c7eb Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 00:44:24 -0400 Subject: [PATCH 142/293] fix unitialized pointer issue in USER-OMP with pppm/disp --- src/USER-OMP/thr_data.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/USER-OMP/thr_data.cpp b/src/USER-OMP/thr_data.cpp index 2ee68fb311..9d0b657b30 100644 --- a/src/USER-OMP/thr_data.cpp +++ b/src/USER-OMP/thr_data.cpp @@ -30,7 +30,8 @@ using namespace LAMMPS_NS; ThrData::ThrData(int tid, Timer *t) : _f(0),_torque(0),_erforce(0),_de(0),_drho(0),_mu(0),_lambda(0),_rhoB(0), - _D_values(0),_rho(0),_fp(0),_rho1d(0),_drho1d(0),_tid(tid), _timer(t) + _D_values(0),_rho(0),_fp(0),_rho1d(0),_drho1d(0),_rho1d_6(0),_drho1d_6(0), + _tid(tid), _timer(t) { _timer_active = 0; } From d9186c8fde6d764c6c9e16f51aa29e463a17e786 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 01:17:34 -0400 Subject: [PATCH 143/293] Revert "use neighbor list exclusions instead of a zero cutoff" This reverts commit bbb4d63db9802c7e1e29114ee6836751dff7bf3b. --- examples/ASPHERE/poly/in.poly | 139 +++++++++++++++--------------- examples/ASPHERE/poly/in.poly.mp | 143 +++++++++++++++---------------- 2 files changed, 140 insertions(+), 142 deletions(-) diff --git a/examples/ASPHERE/poly/in.poly b/examples/ASPHERE/poly/in.poly index 8932523dbf..3496a774bb 100644 --- a/examples/ASPHERE/poly/in.poly +++ b/examples/ASPHERE/poly/in.poly @@ -1,115 +1,114 @@ # SRD diffusion demo - poydisperse spheres -units lj -atom_style sphere -atom_modify first big -dimension 2 +units lj +atom_style sphere +atom_modify first big +dimension 2 # create big particles with 3 different types and diameters -lattice sq 0.3 -region box block 0 10 0 10 -0.5 0.5 -create_box 4 box -create_atoms 1 region box +lattice sq 0.3 +region box block 0 10 0 10 -0.5 0.5 +create_box 4 box +create_atoms 1 region box -group big type 1 -set group big type/fraction 2 0.33 394895 -set group big type/fraction 3 0.5 989894 -group big type 2 3 +group big type 1 +set group big type/fraction 2 0.33 394895 +set group big type/fraction 3 0.5 989894 +group big type 2 3 -set type 1*3 mass 1.0 -velocity big create 1.44 87287 loop geom +set type 1*3 mass 1.0 +velocity big create 1.44 87287 loop geom # equilibrate big particles, repulsive only to prevent aggregation -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.1 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.0 +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +fix 1 big nve +fix 2 all enforce2d -fix 1 big nve -fix 2 all enforce2d +#dump 1 all atom 10 dump.poly.equil -#dump 1 all atom 10 dump.poly.equil +run 1000 -run 1000 - -#undump 1 -unfix 1 -unfix 2 +#undump 1 +unfix 1 +unfix 2 # add small particles as hi density lattice -region plane block INF INF INF INF -0.001 0.001 units box -lattice sq 250.0 -create_atoms 4 region plane +region plane block INF INF INF INF -0.001 0.001 units box +lattice sq 250.0 +create_atoms 4 region plane -set type 4 mass 0.1 -group small type 4 -velocity small create 1.0 593849 loop geom +set type 4 mass 0.1 +group small type 4 +velocity small create 1.0 593849 loop geom # delete overlaps # must set *-4 cutoffs to non-zero values -pair_style lj/cut 2.5 -pair_coeff 1 1 1.0 1.0 -pair_coeff 2 2 1.0 2.0 -pair_coeff 3 3 1.0 1.5 -pair_coeff 4 4 0.0 1.0 0.1 -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 +pair_coeff 2 2 1.0 2.0 +pair_coeff 3 3 1.0 1.5 +pair_coeff 1 4 0.0 1.0 0.5 +pair_coeff 2 4 0.0 1.0 1.0 +pair_coeff 3 4 0.0 1.0 0.75 +pair_coeff 4 4 0.0 1.0 0.0 -delete_atoms overlap 1.0 small big +delete_atoms overlap 1.0 small big # SRD run -reset_timestep 0 +reset_timestep 0 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -comm_modify mode multi group big vel yes -neigh_modify include big +comm_modify mode multi group big vel yes +neigh_modify include big # no pairwise interactions with small particles -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.1 -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.0 # use fix SRD to push small particles out from inside big ones # if comment out, big particles won't see SRD particles -timestep 0.001 +timestep 0.001 -fix 1 big nve -fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & +fix 1 big nve +fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & search 0.2 inside ignore -fix 3 all enforce2d +fix 3 all enforce2d # diagnostics -compute tbig big temp/sphere -variable pebig equal pe*atoms/count(big) -variable ebig equal etotal*atoms/count(big) -thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & - f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & - f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] +compute tbig big temp/sphere +variable pebig equal pe*atoms/count(big) +variable ebig equal etotal*atoms/count(big) +thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & + f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & + f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] -thermo_modify temp tbig -thermo 1000 +thermo_modify temp tbig +thermo 1000 -#dump 1 all atom 1000 dump.poly +#dump 1 all atom 1000 dump.poly -#dump 1 all image 1000 image.*.jpg type type zoom 1.6 -#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 +#dump 1 all image 1000 image.*.jpg type type zoom 1.6 +#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 -run 100000 +run 100000 diff --git a/examples/ASPHERE/poly/in.poly.mp b/examples/ASPHERE/poly/in.poly.mp index 05ff8226e2..1c6a1faee3 100644 --- a/examples/ASPHERE/poly/in.poly.mp +++ b/examples/ASPHERE/poly/in.poly.mp @@ -1,116 +1,115 @@ # SRD viscosity demo - poydisperse spheres -units lj -atom_style sphere -atom_modify first big -dimension 2 +units lj +atom_style sphere +atom_modify first big +dimension 2 # create big particles with 3 different types and diameters -lattice sq 0.3 -region box block 0 10 0 10 -0.5 0.5 -create_box 4 box -create_atoms 1 region box +lattice sq 0.3 +region box block 0 10 0 10 -0.5 0.5 +create_box 4 box +create_atoms 1 region box -group big type 1 -set group big type/fraction 2 0.33 394895 -set group big type/fraction 3 0.5 989894 -group big type 2 3 +group big type 1 +set group big type/fraction 2 0.33 394895 +set group big type/fraction 3 0.5 989894 +group big type 2 3 -set type 1*3 mass 1.0 -velocity big create 1.44 87287 loop geom +set type 1*3 mass 1.0 +velocity big create 1.44 87287 loop geom # equilibrate big particles, repulsive only to prevent aggregation -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.1 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.0 +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +fix 1 big nve +fix 2 all enforce2d -fix 1 big nve -fix 2 all enforce2d +#dump 1 all atom 10 dump.poly.equil -#dump 1 all atom 10 dump.poly.equil +run 1000 -run 1000 - -#undump 1 -unfix 1 -unfix 2 +#undump 1 +unfix 1 +unfix 2 # add small particles as hi density lattice -region plane block INF INF INF INF -0.001 0.001 units box -lattice sq 250.0 -create_atoms 4 region plane +region plane block INF INF INF INF -0.001 0.001 units box +lattice sq 250.0 +create_atoms 4 region plane -set type 4 mass 0.1 -group small type 4 -velocity small create 1.0 593849 loop geom +set type 4 mass 0.1 +group small type 4 +velocity small create 1.0 593849 loop geom # delete overlaps # must set *-4 cutoffs to non-zero values -pair_style lj/cut 2.5 -pair_coeff 1 1 1.0 1.0 -pair_coeff 2 2 1.0 2.0 -pair_coeff 3 3 1.0 1.5 -pair_coeff 4 4 0.0 1.0 0.1 -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +pair_style lj/cut 2.5 +pair_coeff 1 1 1.0 1.0 +pair_coeff 2 2 1.0 2.0 +pair_coeff 3 3 1.0 1.5 +pair_coeff 1 4 0.0 1.0 0.5 +pair_coeff 2 4 0.0 1.0 1.0 +pair_coeff 3 4 0.0 1.0 0.75 +pair_coeff 4 4 0.0 1.0 0.0 -delete_atoms overlap 1.0 small big +delete_atoms overlap 1.0 small big # SRD run -reset_timestep 0 +reset_timestep 0 -neighbor 0.3 bin -neigh_modify delay 0 every 1 check yes +neighbor 0.3 bin +neigh_modify delay 0 every 1 check yes -comm_modify mode multi group big vel yes -neigh_modify include big +comm_modify mode multi group big vel yes +neigh_modify include big # no pairwise interactions with small particles -pair_style lj/cut 1.12 -pair_coeff 1 1 1.0 1.0 1.12 -pair_coeff 2 2 1.0 2.0 2.24 -pair_coeff 3 3 1.0 1.5 1.68 -pair_coeff 4 4 0.0 1.0 0.1 -neigh_modify exclude type 1 4 exclude type 2 4 exclude type 3 4 exclude type 4 4 +pair_style lj/cut 1.12 +pair_coeff 1 1 1.0 1.0 1.12 +pair_coeff 2 2 1.0 2.0 2.24 +pair_coeff 3 3 1.0 1.5 1.68 +pair_coeff 4 4 0.0 1.0 0.0 # use fix SRD to push small particles out from inside big ones # if comment out, big particles won't see SRD particles -timestep 0.001 +timestep 0.001 -fix 1 big nve -fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & - search 0.2 inside ignore -fix 3 small viscosity 10 x y 50 -fix 4 all enforce2d +fix 1 big nve +fix 2 small srd 20 big 1.0 0.25 49894 shift yes 54979 & + search 0.2 inside ignore +fix 3 small viscosity 10 x y 50 +fix 4 all enforce2d # diagnostics -compute tbig big temp/sphere -variable pebig equal pe*atoms/count(big) -variable ebig equal etotal*atoms/count(big) -thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & - f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & - f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] +compute tbig big temp/sphere +variable pebig equal pe*atoms/count(big) +variable ebig equal etotal*atoms/count(big) +thermo_style custom step temp f_2[8] etotal v_pebig v_ebig press & + f_2[1] f_2[2] f_2[3] f_2[4] f_2[5] & + f_2[6] f_2[7] f_2[8] f_2[9] f_2[10] f_2[11] -thermo_modify temp tbig -thermo 1000 +thermo_modify temp tbig +thermo 1000 -#dump 1 all atom 500 dump.poly.mp +#dump 1 all atom 500 dump.poly.mp -#dump 1 all image 500 image.*.jpg type type zoom 1.6 -#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 +#dump 1 all image 500 image.*.jpg type type zoom 1.6 +#dump_modify 1 pad 6 adiam 1 1 adiam 2 2.0 adiam 3 1.5 adiam 4 0.1 -run 50000 +run 50000 From 358915d16ee7841396177f4f0fc71f4b6229addc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 07:26:45 -0400 Subject: [PATCH 144/293] avoid division by zero in peri pair styles --- src/PERI/pair_peri_eps.cpp | 37 +++++++++++++++--------------- src/PERI/pair_peri_lps.cpp | 22 ++++++++++-------- src/USER-OMP/pair_peri_lps_omp.cpp | 18 +++++++++------ 3 files changed, 42 insertions(+), 35 deletions(-) diff --git a/src/PERI/pair_peri_eps.cpp b/src/PERI/pair_peri_eps.cpp index b5807c0e3c..670e1d6937 100644 --- a/src/PERI/pair_peri_eps.cpp +++ b/src/PERI/pair_peri_eps.cpp @@ -46,7 +46,7 @@ PairPeriEPS::PairPeriEPS(LAMMPS *lmp) : Pair(lmp) ifix_peri = -1; - nmax = 0; + nmax = -1; s0_new = NULL; theta = NULL; @@ -209,7 +209,7 @@ void PairPeriEPS::compute(int eflag, int vflag) for (i = 0; i < nlocal; i++) maxpartner = MAX(maxpartner,npartner[i]); - if (atom->nmax > nmax) { + if (nlocal > nmax) { memory->destroy(s0_new); memory->destroy(theta); nmax = atom->nmax; @@ -220,13 +220,13 @@ void PairPeriEPS::compute(int eflag, int vflag) // ******** temp array to store Plastic extension *********** /// // create on heap to reduce stack use and to allow for faster zeroing - double **deviatorPlasticExtTemp; - memory->create(deviatorPlasticExtTemp,nlocal,maxpartner,"pair:plastext"); - memset(&(deviatorPlasticExtTemp[0][0]),0,sizeof(double)*nlocal*maxpartner); + double **deviatorPlasticExtTemp = NULL; + if (nlocal*maxpartner > 0) { + memory->create(deviatorPlasticExtTemp,nlocal,maxpartner,"pair:plastext"); + memset(&(deviatorPlasticExtTemp[0][0]),0,sizeof(double)*nlocal*maxpartner); + } // ******** temp array to store Plastic extension *********** /// - - // compute the dilatation on each particle compute_dilatation(); @@ -280,12 +280,10 @@ void PairPeriEPS::compute(int eflag, int vflag) double fsurf = (tdnorm * tdnorm)/2 - pointwiseYieldvalue; bool elastic = true; - double alphavalue = (15 * shearmodulus[itype][itype]) /wvolume[i]; - - - if (fsurf>0) { + if (fsurf > 0) { elastic = false; - deltalambda = ((tdnorm /sqrt(2.0 * pointwiseYieldvalue)) - 1.0) / alphavalue; + deltalambda = ((tdnorm /sqrt(2.0 * pointwiseYieldvalue)) - 1.0) * wvolume[i] + / (15 * shearmodulus[itype][itype]); double templambda = lambdaValue[i]; lambdaValue[i] = templambda + deltalambda; } @@ -348,10 +346,9 @@ void PairPeriEPS::compute(int eflag, int vflag) ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * (deviatoric_extension - edpNp1); - if(elastic) { + if (elastic) { rkNew = tdtrialValue; - } - else { + } else { rkNew = (sqrt(2.0*pointwiseYieldvalue) * tdtrialValue) / tdnorm; deviatorPlasticExtTemp[i][jj] = edpNp1 + rkNew * deltalambda; } @@ -402,10 +399,12 @@ void PairPeriEPS::compute(int eflag, int vflag) memcpy(s0,s0_new,sizeof(double)*nlocal); - memcpy(&(deviatorPlasticextension[0][0]), - &(deviatorPlasticExtTemp[0][0]), - sizeof(double)*nlocal*maxpartner); - memory->destroy(deviatorPlasticExtTemp); + if (nlocal*maxpartner > 0) { + memcpy(&(deviatorPlasticextension[0][0]), + &(deviatorPlasticExtTemp[0][0]), + sizeof(double)*nlocal*maxpartner); + memory->destroy(deviatorPlasticExtTemp); + } } /* ---------------------------------------------------------------------- diff --git a/src/PERI/pair_peri_lps.cpp b/src/PERI/pair_peri_lps.cpp index cd88b41825..0fe8f29f38 100644 --- a/src/PERI/pair_peri_lps.cpp +++ b/src/PERI/pair_peri_lps.cpp @@ -33,6 +33,7 @@ #include "memory.h" #include "error.h" #include "update.h" +#include "math_const.h" using namespace LAMMPS_NS; @@ -174,7 +175,7 @@ void PairPeriLPS::compute(int eflag, int vflag) // of the bond-based theory used in PMB model double kshort = (15.0 * 18.0 * bulkmodulus[itype][itype]) / - (3.141592653589793 * cutsq[itype][jtype] * cutsq[itype][jtype]); + (MathConst::MY_PI * cutsq[itype][jtype] * cutsq[itype][jtype]); rk = (kshort * vfrac[j]) * (dr / cut[itype][jtype]); if (r > 0.0) fpair = -(rk/r); @@ -285,13 +286,14 @@ void PairPeriLPS::compute(int eflag, int vflag) omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); omega_minus = influence_function(delx0,dely0,delz0); - - rk = ( (3.0 * bulkmodulus[itype][itype]) - - (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale * - ( (omega_plus * theta[i] / wvolume[i]) + - ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj]; - rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * - ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr; + if ((wvolume[i] > 0.0) && (wvolume[j] > 0.0)) { + rk = ( (3.0 * bulkmodulus[itype][itype]) - + (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale * + ( (omega_plus * theta[i] / wvolume[i]) + + ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj]; + rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * + ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr; + } else rk = 0.0; if (r > 0.0) fbond = -(rk/r); else fbond = 0.0; @@ -305,9 +307,11 @@ void PairPeriLPS::compute(int eflag, int vflag) double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0); - if (eflag) evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * + if (eflag && (wvolume[i] > 0.0)) + evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * omega_plus*(deviatoric_extension * deviatoric_extension) * vfrac[j] * vfrac_scale; + else evdwl = 0.0; if (evflag) ev_tally(i,i,nlocal,0,0.5*evdwl,0.0, 0.5*fbond*vfrac[i],delx,dely,delz); diff --git a/src/USER-OMP/pair_peri_lps_omp.cpp b/src/USER-OMP/pair_peri_lps_omp.cpp index 4876e6b15f..a471b47750 100644 --- a/src/USER-OMP/pair_peri_lps_omp.cpp +++ b/src/USER-OMP/pair_peri_lps_omp.cpp @@ -310,12 +310,14 @@ void PairPeriLPSOMP::eval(int iifrom, int iito, ThrData * const thr) omega_plus = influence_function(-1.0*delx0,-1.0*dely0,-1.0*delz0); omega_minus = influence_function(delx0,dely0,delz0); - rk = ( (3.0 * bulkmodulus[itype][itype]) - - (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale * - ( (omega_plus * theta[i] / wvolume[i]) + - ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj]; - rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * - ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr; + if ((wvolume[i] > 0.0) && (wvolume[j] > 0.0)) { + rk = ( (3.0 * bulkmodulus[itype][itype]) - + (5.0 * shearmodulus[itype][itype]) ) * vfrac[j] * vfrac_scale * + ( (omega_plus * theta[i] / wvolume[i]) + + ( omega_minus * theta[j] / wvolume[j] ) ) * r0[i][jj]; + rk += 15.0 * ( shearmodulus[itype][itype] * vfrac[j] * vfrac_scale ) * + ( (omega_plus / wvolume[i]) + (omega_minus / wvolume[j]) ) * dr; + } else rk = 0.0; if (r > 0.0) fbond = -(rk/r); else fbond = 0.0; @@ -327,9 +329,11 @@ void PairPeriLPSOMP::eval(int iifrom, int iito, ThrData * const thr) // since I-J is double counted, set newton off & use 1/2 factor and I,I double deviatoric_extension = dr - (theta[i]* r0[i][jj] / 3.0); - if (EFLAG) evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * + if (EFLAG && (wvolume[i] > 0.0)) + evdwl = 0.5 * 15 * (shearmodulus[itype][itype]/wvolume[i]) * omega_plus*(deviatoric_extension * deviatoric_extension) * vfrac[j] * vfrac_scale; + else evdwl = 0.0; if (EVFLAG) ev_tally_thr(this,i,i,nlocal,0,0.5*evdwl,0.0, 0.5*fbond*vfrac[i],delx,dely,delz,thr); From 4ad9528999220c12c3a1a008c66e0e6c3f68e3e8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 07:37:14 -0400 Subject: [PATCH 145/293] safer handling of memory management for lists in reax/c --- src/USER-REAXC/pair_reaxc.cpp | 1 + src/USER-REAXC/reaxc_list.cpp | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/USER-REAXC/pair_reaxc.cpp b/src/USER-REAXC/pair_reaxc.cpp index 300ccbe330..0f4bd49cc8 100644 --- a/src/USER-REAXC/pair_reaxc.cpp +++ b/src/USER-REAXC/pair_reaxc.cpp @@ -84,6 +84,7 @@ PairReaxC::PairReaxC(LAMMPS *lmp) : Pair(lmp) memory->smalloc(sizeof(storage),"reax:storage"); lists = (reax_list *) memory->smalloc(LIST_N * sizeof(reax_list),"reax:lists"); + memset(lists,0,LIST_N * sizeof(reax_list)); out_control = (output_controls *) memory->smalloc(sizeof(output_controls),"reax:out_control"); mpi_data = (mpi_datatypes *) diff --git a/src/USER-REAXC/reaxc_list.cpp b/src/USER-REAXC/reaxc_list.cpp index 2755d5506e..e7fac4d418 100644 --- a/src/USER-REAXC/reaxc_list.cpp +++ b/src/USER-REAXC/reaxc_list.cpp @@ -36,6 +36,8 @@ int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm) l->n = n; l->num_intrs = num_intrs; + if (l->index) sfree(l->index, "list:index"); + if (l->end_index) sfree(l->index, "list:end_index"); l->index = (int*) smalloc( n * sizeof(int), "list:index", comm ); l->end_index = (int*) smalloc( n * sizeof(int), "list:end_index", comm ); @@ -43,36 +45,43 @@ int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm) switch(l->type) { case TYP_VOID: + if (l->select.v) sfree(l->select.v, "list:v"); l->select.v = (void*) smalloc(l->num_intrs * sizeof(void*), "list:v", comm); break; case TYP_THREE_BODY: + if (l->select.three_body_list) sfree(l->select.three_body_list,"list:three_bodies"); l->select.three_body_list = (three_body_interaction_data*) smalloc( l->num_intrs * sizeof(three_body_interaction_data), "list:three_bodies", comm ); break; case TYP_BOND: + if (l->select.bond_list) sfree(l->select.bond_list,"list:bonds"); l->select.bond_list = (bond_data*) smalloc( l->num_intrs * sizeof(bond_data), "list:bonds", comm ); break; case TYP_DBO: + if (l->select.dbo_list) sfree(l->select.dbo_list,"list:dbonds"); l->select.dbo_list = (dbond_data*) smalloc( l->num_intrs * sizeof(dbond_data), "list:dbonds", comm ); break; case TYP_DDELTA: + if (l->select.dDelta_list) sfree(l->select.dDelta_list,"list:dDeltas"); l->select.dDelta_list = (dDelta_data*) smalloc( l->num_intrs * sizeof(dDelta_data), "list:dDeltas", comm ); break; case TYP_FAR_NEIGHBOR: + if (l->select.far_nbr_list) sfree(l->select.far_nbr_list,"list:far_nbrs"); l->select.far_nbr_list = (far_neighbor_data*) smalloc(l->num_intrs * sizeof(far_neighbor_data), "list:far_nbrs", comm); break; case TYP_HBOND: + if (l->select.hbond_list) sfree(l->select.hbond_list,"list:hbonds"); l->select.hbond_list = (hbond_data*) smalloc( l->num_intrs * sizeof(hbond_data), "list:hbonds", comm ); break; @@ -94,28 +103,37 @@ void Delete_List( reax_list *l, MPI_Comm comm ) sfree( l->index, "list:index" ); sfree( l->end_index, "list:end_index" ); + l->index = NULL; + l->end_index = NULL; switch(l->type) { case TYP_VOID: sfree( l->select.v, "list:v" ); + l->select.v = NULL; break; case TYP_HBOND: sfree( l->select.hbond_list, "list:hbonds" ); + l->select.hbond_list = NULL; break; case TYP_FAR_NEIGHBOR: sfree( l->select.far_nbr_list, "list:far_nbrs" ); + l->select.far_nbr_list = NULL; break; case TYP_BOND: sfree( l->select.bond_list, "list:bonds" ); + l->select.bond_list = NULL; break; case TYP_DBO: sfree( l->select.dbo_list, "list:dbos" ); + l->select.dbo_list = NULL; break; case TYP_DDELTA: sfree( l->select.dDelta_list, "list:dDeltas" ); + l->select.dDelta_list = NULL; break; case TYP_THREE_BODY: sfree( l->select.three_body_list, "list:three_bodies" ); + l->select.three_body_list = NULL; break; default: From 085cbee1163d6cd6bd787718fb2152f37fd049c0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 11:14:59 -0400 Subject: [PATCH 146/293] protect LAMMPS from calling incompatible QUIP library with -DLAMMPS_BIGBIG --- src/USER-QUIP/pair_quip.cpp | 11 +++++++++++ src/USER-QUIP/pair_quip.h | 5 +++++ 2 files changed, 16 insertions(+) diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index 0ad8066027..ccd71235e7 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -124,12 +124,23 @@ void PairQUIP::compute(int eflag, int vflag) lattice[7] = domain->yz; lattice[8] = domain->zprd; +#if defined(LAMMPS_BIGBIG) + error->all(FLERR,"Pair style quip does not support -DLAMMPS_BIGBIG"); + // quip_lammps_longint_wrapper( + // (&nlocal,&nghost,atomic_numbers,tag, + // &inum,&sum_num_neigh,ilist, + // quip_num_neigh,quip_neigh,lattice, + // quip_potential,&n_quip_potential,&x[0][0], + // &quip_energy,quip_local_e,quip_virial,quip_local_virial,quip_force); +#else quip_lammps_wrapper (&nlocal,&nghost,atomic_numbers,tag, &inum,&sum_num_neigh,ilist, quip_num_neigh,quip_neigh,lattice, quip_potential,&n_quip_potential,&x[0][0], &quip_energy,quip_local_e,quip_virial,quip_local_virial,quip_force); +#endif + iquip = 0; for (ii = 0; ii < ntotal; ii++) { for( jj = 0; jj < 3; jj++ ) { diff --git a/src/USER-QUIP/pair_quip.h b/src/USER-QUIP/pair_quip.h index 985a43fd7e..c785792410 100644 --- a/src/USER-QUIP/pair_quip.h +++ b/src/USER-QUIP/pair_quip.h @@ -29,6 +29,11 @@ extern "C" int*, int*, double*, int*, int*, double*, double*, double*, double*, double*, double*); + // void quip_lammps_longint_wrapper(int*, int*, int*, int64_t*, + // int*, int*, int*, + // int*, int*, double*, + // int*, int*, double*, + // double*, double*, double*, double*, double*); void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*); } From a92d79253734ab7d7ef8288b35920a5bc368eec1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 12:55:55 -0400 Subject: [PATCH 147/293] update manual links that got broken when removing and renumbering a section --- doc/src/Manual.txt | 1 - doc/src/Section_accelerate.txt | 10 +- doc/src/Section_errors.txt | 2 +- doc/src/Section_howto.txt | 10 +- doc/src/Section_packages.txt | 30 +- doc/src/Section_python.txt | 6 +- doc/src/Section_start.txt | 12 +- doc/src/accelerate_gpu.txt | 10 +- doc/src/accelerate_intel.txt | 10 +- doc/src/accelerate_kokkos.txt | 24 +- doc/src/accelerate_omp.txt | 6 +- doc/src/accelerate_opt.txt | 4 +- doc/src/angle_charmm.txt | 2 +- doc/src/angle_class2.txt | 2 +- doc/src/angle_cosine.txt | 2 +- doc/src/angle_cosine_delta.txt | 2 +- doc/src/angle_cosine_periodic.txt | 2 +- doc/src/angle_cosine_shift.txt | 2 +- doc/src/angle_cosine_shift_exp.txt | 2 +- doc/src/angle_cosine_squared.txt | 2 +- doc/src/angle_fourier.txt | 2 +- doc/src/angle_fourier_simple.txt | 2 +- doc/src/angle_harmonic.txt | 2 +- doc/src/angle_quartic.txt | 2 +- doc/src/angle_table.txt | 2 +- doc/src/balance.txt | 2 +- doc/src/bond_class2.txt | 2 +- doc/src/bond_fene.txt | 2 +- doc/src/bond_fene_expand.txt | 2 +- doc/src/bond_harmonic.txt | 2 +- doc/src/bond_harmonic_shift.txt | 2 +- doc/src/bond_harmonic_shift_cut.txt | 2 +- doc/src/bond_morse.txt | 2 +- doc/src/bond_nonlinear.txt | 2 +- doc/src/bond_quartic.txt | 2 +- doc/src/bond_table.txt | 2 +- doc/src/compute_pressure.txt | 2 +- doc/src/compute_temp.txt | 2 +- doc/src/compute_temp_partial.txt | 2 +- doc/src/dihedral_charmm.txt | 2 +- doc/src/dihedral_class2.txt | 2 +- doc/src/dihedral_cosine_shift_exp.txt | 2 +- doc/src/dihedral_fourier.txt | 2 +- doc/src/dihedral_harmonic.txt | 2 +- doc/src/dihedral_helix.txt | 2 +- doc/src/dihedral_multi_harmonic.txt | 2 +- doc/src/dihedral_nharmonic.txt | 2 +- doc/src/dihedral_opls.txt | 2 +- doc/src/dihedral_quadratic.txt | 2 +- doc/src/echo.txt | 2 +- doc/src/fix_addforce.txt | 2 +- doc/src/fix_aveforce.txt | 2 +- doc/src/fix_deform.txt | 2 +- doc/src/fix_enforce2d.txt | 2 +- doc/src/fix_freeze.txt | 2 +- doc/src/fix_gravity.txt | 2 +- doc/src/fix_langevin.txt | 2 +- doc/src/fix_momentum.txt | 2 +- doc/src/fix_nh.txt | 2 +- doc/src/fix_nph_asphere.txt | 2 +- doc/src/fix_nph_body.txt | 2 +- doc/src/fix_nph_sphere.txt | 2 +- doc/src/fix_nphug.txt | 2 +- doc/src/fix_npt_asphere.txt | 2 +- doc/src/fix_npt_body.txt | 2 +- doc/src/fix_npt_sphere.txt | 2 +- doc/src/fix_nve.txt | 2 +- doc/src/fix_nve_asphere.txt | 2 +- doc/src/fix_nve_sphere.txt | 2 +- doc/src/fix_nvt_asphere.txt | 2 +- doc/src/fix_nvt_body.txt | 2 +- doc/src/fix_nvt_sllod.txt | 2 +- doc/src/fix_nvt_sphere.txt | 2 +- doc/src/fix_qeq_comb.txt | 2 +- doc/src/fix_qeq_reax.txt | 2 +- doc/src/fix_reax_bonds.txt | 2 +- doc/src/fix_reaxc_species.txt | 2 +- doc/src/fix_rigid.txt | 2 +- doc/src/fix_setforce.txt | 2 +- doc/src/fix_shake.txt | 2 +- doc/src/fix_wall_reflect.txt | 2 +- doc/src/improper_class2.txt | 2 +- doc/src/improper_cossq.txt | 2 +- doc/src/improper_cvff.txt | 2 +- doc/src/improper_fourier.txt | 2 +- doc/src/improper_harmonic.txt | 2 +- doc/src/improper_ring.txt | 2 +- doc/src/improper_umbrella.txt | 2 +- doc/src/jump.txt | 4 +- doc/src/log.txt | 2 +- doc/src/neb.txt | 2 +- doc/src/neighbor.txt | 2 +- doc/src/next.txt | 2 +- doc/src/package.txt | 28 +- doc/src/pair_adp.txt | 2 +- doc/src/pair_agni.txt | 2 +- doc/src/pair_airebo.txt | 2 +- doc/src/pair_beck.txt | 2 +- doc/src/pair_born.txt | 2 +- doc/src/pair_brownian.txt | 2 +- doc/src/pair_buck.txt | 2 +- doc/src/pair_buck_long.txt | 2 +- doc/src/pair_charmm.txt | 2 +- doc/src/pair_class2.txt | 2 +- doc/src/pair_colloid.txt | 2 +- doc/src/pair_comb.txt | 2 +- doc/src/pair_coul.txt | 2 +- doc/src/pair_dipole.txt | 2 +- doc/src/pair_dpd.txt | 2 +- doc/src/pair_eam.txt | 2 +- doc/src/pair_edip.txt | 2 +- doc/src/pair_eim.txt | 2 +- doc/src/pair_gayberne.txt | 2 +- doc/src/pair_gran.txt | 2 +- doc/src/pair_gromacs.txt | 2 +- doc/src/pair_hbond_dreiding.txt | 2 +- doc/src/pair_hybrid.txt | 2 +- doc/src/pair_lj.txt | 2 +- doc/src/pair_lj96.txt | 2 +- doc/src/pair_lj_cubic.txt | 2 +- doc/src/pair_lj_expand.txt | 2 +- doc/src/pair_lj_long.txt | 2 +- doc/src/pair_lj_smooth.txt | 2 +- doc/src/pair_lj_smooth_linear.txt | 2 +- doc/src/pair_lj_soft.txt | 2 +- doc/src/pair_lubricate.txt | 2 +- doc/src/pair_meam_spline.txt | 2 +- doc/src/pair_morse.txt | 2 +- doc/src/pair_nb3b_harmonic.txt | 2 +- doc/src/pair_nm.txt | 2 +- doc/src/pair_peri.txt | 2 +- doc/src/pair_reaxc.txt | 2 +- doc/src/pair_resquared.txt | 2 +- doc/src/pair_sdk.txt | 2 +- doc/src/pair_soft.txt | 2 +- doc/src/pair_sw.txt | 2 +- doc/src/pair_table.txt | 2 +- doc/src/pair_tersoff.txt | 2 +- doc/src/pair_tersoff_mod.txt | 2 +- doc/src/pair_tersoff_zbl.txt | 2 +- doc/src/pair_thole.txt | 2 +- doc/src/pair_vashishta.txt | 2 +- doc/src/pair_yukawa.txt | 2 +- doc/src/pair_yukawa_colloid.txt | 2 +- doc/src/pair_zbl.txt | 2 +- doc/src/partition.txt | 4 +- doc/src/prd.txt | 2 +- doc/src/processors.txt | 12 +- doc/src/read_data.txt | 2 +- doc/src/read_restart.txt | 2 +- doc/src/region.txt | 2 +- doc/src/restart.txt | 2 +- doc/src/run_style.txt | 6 +- doc/src/suffix.txt | 4 +- doc/src/temper.txt | 4 +- doc/src/thermo_style.txt | 2 +- doc/src/timer.txt | 2 +- doc/src/variable.txt | 8 +- doc/src/write_data.txt | 2 +- doc/src/write_restart.txt | 2 +- src/Make.py | 2378 ------------------------- 161 files changed, 237 insertions(+), 2616 deletions(-) delete mode 100755 src/Make.py diff --git a/doc/src/Manual.txt b/doc/src/Manual.txt index 36391731d0..359aa19edb 100644 --- a/doc/src/Manual.txt +++ b/doc/src/Manual.txt @@ -261,7 +261,6 @@ END_RST --> :link(start_6,Section_start.html#start_6) :link(start_7,Section_start.html#start_7) :link(start_8,Section_start.html#start_8) -:link(start_9,Section_start.html#start_9) :link(cmd_1,Section_commands.html#cmd_1) :link(cmd_2,Section_commands.html#cmd_2) diff --git a/doc/src/Section_accelerate.txt b/doc/src/Section_accelerate.txt index 64b80c1a55..8812358886 100644 --- a/doc/src/Section_accelerate.txt +++ b/doc/src/Section_accelerate.txt @@ -56,7 +56,7 @@ timings; you can simply extrapolate from short runs. For the set of runs, look at the timing data printed to the screen and log file at the end of each LAMMPS run. "This -section"_Section_start.html#start_8 of the manual has an overview. +section"_Section_start.html#start_7 of the manual has an overview. Running on one (or a few processors) should give a good estimate of the serial performance and what portions of the timestep are taking @@ -226,16 +226,16 @@ re-build LAMMPS | make machine | prepare and test a regular LAMMPS simulation | lmp_machine -in in.script; mpirun -np 32 lmp_machine -in in.script | -enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_7, | +enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_6, | only needed for KOKKOS package | -set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_7 or "package"_package.html command, | +set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_6 or "package"_package.html command, | only if defaults need to be changed | -use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_7 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu +use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_6 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu :tb(c=2,s=|) Note that the first 4 steps can be done as a single command, using the src/Make.py tool. This tool is discussed in "Section -2.4"_Section_start.html#start_4 of the manual, and its use is +4"_Section_packages.html of the manual, and its use is illustrated in the individual accelerator sections. Typically these steps only need to be done once, to create an executable that uses one or more accelerator packages. diff --git a/doc/src/Section_errors.txt b/doc/src/Section_errors.txt index 40e61a248e..408c01d52c 100644 --- a/doc/src/Section_errors.txt +++ b/doc/src/Section_errors.txt @@ -71,7 +71,7 @@ style", with ... being fix, compute, pair, etc, it means that you mistyped the style name or that the command is part of an optional package which was not compiled into your executable. The list of available styles in your executable can be listed by using "the -h -command-line argument"_Section_start.html#start_7. The installation +command-line argument"_Section_start.html#start_6. The installation and compilation of optional packages is explained in the "installation instructions"_Section_start.html#start_3. diff --git a/doc/src/Section_howto.txt b/doc/src/Section_howto.txt index f2f2561af8..6d699fe24b 100644 --- a/doc/src/Section_howto.txt +++ b/doc/src/Section_howto.txt @@ -54,7 +54,7 @@ restart files can be saved to disk using the "restart"_restart.html command. At a later time, these binary files can be read via a "read_restart"_read_restart.html command in a new script. Or they can be converted to text data files using the "-r command-line -switch"_Section_start.html#start_7 and read by a +switch"_Section_start.html#start_6 and read by a "read_data"_read_data.html command in a new script. Here we give examples of 2 scripts that read either a binary restart @@ -337,7 +337,7 @@ All of the above examples work whether you are running on 1 or multiple processors, but assumed you are running LAMMPS on a single partition of processors. LAMMPS can be run on multiple partitions via the "-partition" command-line switch as described in "this -section"_Section_start.html#start_7 of the manual. +section"_Section_start.html#start_6 of the manual. In the last 2 examples, if LAMMPS were run on 3 partitions, the same scripts could be used if the "index" and "loop" variables were @@ -387,7 +387,7 @@ for more info on packages. In all these cases, you must run with one or more processors per replica. The processors assigned to each replica are determined at run-time by using the "-partition command-line -switch"_Section_start.html#start_7 to launch LAMMPS on multiple +switch"_Section_start.html#start_6 to launch LAMMPS on multiple partitions, which in this context are the same as replicas. E.g. these commands: @@ -395,7 +395,7 @@ mpirun -np 16 lmp_linux -partition 8x2 -in in.temper mpirun -np 8 lmp_linux -partition 8x1 -in in.neb :pre would each run 8 replicas, on either 16 or 8 processors. Note the use -of the "-in command-line switch"_Section_start.html#start_7 to specify +of the "-in command-line switch"_Section_start.html#start_6 to specify the input script which is required when running in multi-replica mode. Also note that with MPI installed on a machine (e.g. your desktop), @@ -1872,7 +1872,7 @@ void lammps_free(void *) :pre The lammps_open() function is used to initialize LAMMPS, passing in a list of strings as if they were "command-line -arguments"_Section_start.html#start_7 when LAMMPS is run in +arguments"_Section_start.html#start_6 when LAMMPS is run in stand-alone mode from the command line, and a MPI communicator for LAMMPS to run under. It returns a ptr to the LAMMPS object that is created, and which is used in subsequent library calls. The diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt index a65e510654..c7e6e84831 100644 --- a/doc/src/Section_packages.txt +++ b/doc/src/Section_packages.txt @@ -369,7 +369,7 @@ suffix in their style name. "Section 5.3.1"_accelerate_gpu.html gives details of what hardware and Cuda software is required on your system, and details on how to build and use this package. Its styles can be invoked at run time via the "-sf gpu" or "-suffix gpu" "command-line -switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS +switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS package, which has GPU-enabled styles. [Authors:] Mike Brown (Intel) while at Sandia and ORNL and Trung Nguyen @@ -427,8 +427,8 @@ src/GPU/README lib/gpu/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.1"_accelerate_gpu.html -"Section 2.7 -sf gpu"_Section_start.html#start_7 -"Section 2.7 -pk gpu"_Section_start.html#start_7 +"Section 2.6 -sf gpu"_Section_start.html#start_6 +"Section 2.6 -pk gpu"_Section_start.html#start_6 "package gpu"_package.html Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (g) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -553,7 +553,7 @@ style name. "Section 5.3.3"_accelerate_kokkos.html gives details of what hardware and software is required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf kk" or "-suffix kk" "command-line -switches"_Section_start.html#start_7. Also see the "GPU"_#GPU, +switches"_Section_start.html#start_6. Also see the "GPU"_#GPU, "OPT"_#OPT, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs, KNLs, and GPUs. @@ -621,9 +621,9 @@ src/KOKKOS/README lib/kokkos/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.3"_accelerate_kokkos.html -"Section 2.7 -k on ..."_Section_start.html#start_7 -"Section 2.7 -sf kk"_Section_start.html#start_7 -"Section 2.7 -pk kokkos"_Section_start.html#start_7 +"Section 2.6 -k on ..."_Section_start.html#start_6 +"Section 2.6 -sf kk"_Section_start.html#start_6 +"Section 2.6 -pk kokkos"_Section_start.html#start_6 "package kokkos"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (k) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -950,7 +950,7 @@ CHARMM, and Morse potentials. The styles have an "opt" suffix in their style name. "Section 5.3.5"_accelerate_opt.html gives details of how to build and use this package. Its styles can be invoked at run time via the "-sf opt" or "-suffix opt" "command-line -switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS, +switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPU performance. @@ -977,7 +977,7 @@ CCFLAGS: add -restrict :ul src/OPT: filenames -> commands "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.5"_accelerate_opt.html -"Section 2.7 -sf opt"_Section_start.html#start_7 +"Section 2.6 -sf opt"_Section_start.html#start_6 Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (t) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -1887,7 +1887,7 @@ All of them have an "intel" in their style name. "Section 5.3.2"_accelerate_intel.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf intel" or -"-suffix intel" "command-line switches"_Section_start.html#start_7. +"-suffix intel" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs and KNLs. @@ -1943,8 +1943,8 @@ src/USER-INTEL: filenames -> commands src/USER-INTEL/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.2"_accelerate_gpu.html -"Section 2.7 -sf intel"_Section_start.html#start_7 -"Section 2.7 -pk intel"_Section_start.html#start_7 +"Section 2.6 -sf intel"_Section_start.html#start_6 +"Section 2.6 -pk intel"_Section_start.html#start_6 "package intel"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (i) src/USER-INTEL/TEST @@ -2217,7 +2217,7 @@ via OpenMP directives. All of them have an "omp" in their style name. "Section 5.3.4"_accelerate_omp.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf omp" or -"-suffix omp" "command-line switches"_Section_start.html#start_7. +"-suffix omp" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-INTEL"_#USER-INTEL packages, which have styles optimized for CPUs. @@ -2250,8 +2250,8 @@ src/USER-OMP: filenames -> commands src/USER-OMP/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.4"_accelerate_omp.html -"Section 2.7 -sf omp"_Section_start.html#start_7 -"Section 2.7 -pk omp"_Section_start.html#start_7 +"Section 2.6 -sf omp"_Section_start.html#start_6 +"Section 2.6 -pk omp"_Section_start.html#start_6 "package omp"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (o) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul diff --git a/doc/src/Section_python.txt b/doc/src/Section_python.txt index 1e67fca321..f4b6bdad97 100644 --- a/doc/src/Section_python.txt +++ b/doc/src/Section_python.txt @@ -198,7 +198,7 @@ file and the shared library. 11.3 Building LAMMPS as a shared library :link(py_3),h4 Instructions on how to build LAMMPS as a shared library are given in -"Section 2.5"_Section_start.html#start_5. A shared library is one +"Section 2.4"_Section_start.html#start_4. A shared library is one that is dynamically loadable, which is what Python requires to wrap LAMMPS. On Linux this is a library file that ends in ".so", not ".a". @@ -217,7 +217,7 @@ NOTE: If you are building LAMMPS with an MPI or FFT library or other auxiliary libraries (used by various packages), then all of these extra libraries must also be shared libraries. If the LAMMPS shared-library build fails with an error complaining about this, see -"Section 2.5"_Section_start.html#start_5 for more details. +"Section 2.4"_Section_start.html#start_4 for more details. :line @@ -439,7 +439,7 @@ first importing from the lammps.py file: >>> CDLL("liblammps.so") :pre If an error occurs, carefully go thru the steps in "Section -2.5"_Section_start.html#start_5 and above about building a shared +2.4"_Section_start.html#start_4 and above about building a shared library and about insuring Python can find the necessary two files it needs. diff --git a/doc/src/Section_start.txt b/doc/src/Section_start.txt index b7a471c3fa..c798005f5e 100644 --- a/doc/src/Section_start.txt +++ b/doc/src/Section_start.txt @@ -14,11 +14,11 @@ experienced users. 2.1 "What's in the LAMMPS distribution"_#start_1 2.2 "Making LAMMPS"_#start_2 2.3 "Making LAMMPS with optional packages"_#start_3 -2.5 "Building LAMMPS as a library"_#start_4 -2.6 "Running LAMMPS"_#start_5 -2.7 "Command-line options"_#start_6 -2.8 "Screen output"_#start_7 -2.9 "Tips for users of previous versions"_#start_8 :all(b) +2.4 "Building LAMMPS as a library"_#start_4 +2.5 "Running LAMMPS"_#start_5 +2.6 "Command-line options"_#start_6 +2.7 "Screen output"_#start_7 +2.8 "Tips for users of previous versions"_#start_8 :all(b) :line @@ -714,7 +714,7 @@ type lmp_machine -h :pre to run your executable with the optional "-h command-line -switch"_#start_7 for "help", which will list the styles and commands +switch"_#start_6 for "help", which will list the styles and commands known to your executable, and immediately exit. :line diff --git a/doc/src/accelerate_gpu.txt b/doc/src/accelerate_gpu.txt index 2ac7d62f6c..68e9fa477a 100644 --- a/doc/src/accelerate_gpu.txt +++ b/doc/src/accelerate_gpu.txt @@ -54,7 +54,7 @@ specify the # of GPUs per node use GPU styles in your input script :ul The latter two steps can be done using the "-pk gpu" and "-sf gpu" -"command-line switches"_Section_start.html#start_7 respectively. Or +"command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package gpu"_package.html or "suffix gpu"_suffix.html commands respectively to your input script. @@ -75,7 +75,7 @@ This requires two steps (a,b): build the GPU library, then build LAMMPS with the GPU package. You can do both these steps in one line, using the src/Make.py script, -described in "Section 2.4"_Section_start.html#start_4 of the manual. +described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. If run from the src directory, this command will create src/lmp_gpu using src/MAKE/Makefile.mpi as the starting Makefile.machine: @@ -151,9 +151,9 @@ automatically if you create more MPI tasks/node than there are GPUs/mode. E.g. with 8 MPI tasks/node and 2 GPUs, each GPU will be shared by 4 MPI tasks. -Use the "-sf gpu" "command-line switch"_Section_start.html#start_7, +Use the "-sf gpu" "command-line switch"_Section_start.html#start_6, which will automatically append "gpu" to styles that support it. Use -the "-pk gpu Ng" "command-line switch"_Section_start.html#start_7 to +the "-pk gpu Ng" "command-line switch"_Section_start.html#start_6 to set Ng = # of GPUs/node to use. lmp_machine -sf gpu -pk gpu 1 -in in.script # 1 MPI task uses 1 GPU @@ -188,7 +188,7 @@ pair_style lj/cut/gpu 2.5 :pre You must also use the "package gpu"_package.html command to enable the GPU package, unless the "-sf gpu" or "-pk gpu" "command-line -switches"_Section_start.html#start_7 were used. It specifies the +switches"_Section_start.html#start_6 were used. It specifies the number of GPUs/node to use, as well as other options. [Speed-ups to expect:] diff --git a/doc/src/accelerate_intel.txt b/doc/src/accelerate_intel.txt index 155e29e367..74ae9d9a42 100644 --- a/doc/src/accelerate_intel.txt +++ b/doc/src/accelerate_intel.txt @@ -226,7 +226,7 @@ source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh make intel_cpu_intelmpi :pre Alternatively, the build can be accomplished with the src/Make.py -script, described in "Section 2.4"_Section_start.html#start_4 of the +script, described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. For an example: Make.py -v -p intel omp -intel cpu -a file intel_cpu_intelmpi :pre @@ -301,7 +301,7 @@ Hyper-Threading technology disabled. To enable USER-INTEL optimizations for all available styles used in the input script, the "-sf intel" -"command-line switch"_Section_start.html#start_7 can be used without +"command-line switch"_Section_start.html#start_6 can be used without any requirement for editing the input script. This switch will automatically append "intel" to styles that support it. It also invokes a default command: "package intel 1"_package.html. This @@ -314,7 +314,7 @@ support, that 1 coprocessor per node will be used with automatic balancing of work between the CPU and the coprocessor. You can specify different options for the USER-INTEL package by using -the "-pk intel Nphi" "command-line switch"_Section_start.html#start_7 +the "-pk intel Nphi" "command-line switch"_Section_start.html#start_6 with keyword/value pairs as specified in the documentation. Here, Nphi = # of Xeon Phi coprocessors/node (ignored without offload support). Common options to the USER-INTEL package include {omp} to @@ -387,7 +387,7 @@ can performed automatically by using "-sf hybrid intel opt" or and "omp" suffixes can be appended manually in the input script. For the latter, the "package omp"_package.html command must be in the input script or the "-pk omp Nt" "command-line -switch"_Section_start.html#start_7 must be used where Nt is the +switch"_Section_start.html#start_6 must be used where Nt is the number of OpenMP threads. The number of OpenMP threads should not be set differently for the different packages. Note that the "suffix hybrid intel omp"_suffix.html command can also be used within the @@ -486,7 +486,7 @@ sorting"_atom_modify.html is changed to 1 so that the per-atom data is effectively sorted at every rebuild of the neighbor lists. All the available coprocessor threads on each Phi will be divided among MPI tasks, unless the {tptask} option of the "-pk intel" "command-line -switch"_Section_start.html#start_7 is used to limit the coprocessor +switch"_Section_start.html#start_6 is used to limit the coprocessor threads per MPI task. [Restrictions:] diff --git a/doc/src/accelerate_kokkos.txt b/doc/src/accelerate_kokkos.txt index 602c3191f6..6ccd695841 100644 --- a/doc/src/accelerate_kokkos.txt +++ b/doc/src/accelerate_kokkos.txt @@ -136,7 +136,7 @@ You must choose at build time whether to build for CPUs (OpenMP), GPUs, or Phi. You can do any of these in one line, using the src/Make.py script, -described in "Section 2.4"_Section_start.html#start_4 of the manual. +described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. If run from the src directory, these commands will create src/lmp_kokkos_omp, lmp_kokkos_cuda, and lmp_kokkos_phi. Note that the OMP and PHI options use @@ -144,7 +144,7 @@ src/MAKE/Makefile.mpi as the starting Makefile.machine. The CUDA option uses src/MAKE/OPTIONS/Makefile.kokkos_cuda. The latter two steps can be done using the "-k on", "-pk kokkos" and -"-sf kk" "command-line switches"_Section_start.html#start_7 +"-sf kk" "command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package kokkos"_package.html or "suffix kk"_suffix.html commands respectively to your input script. @@ -280,10 +280,10 @@ specify how many Phi coprocessors there are per node; each coprocessors is simply treated as running some number of MPI tasks. You must use the "-k on" "command-line -switch"_Section_start.html#start_7 to enable the KOKKOS package. It +switch"_Section_start.html#start_6 to enable the KOKKOS package. It takes additional arguments for hardware settings appropriate to your system. Those arguments are "documented -here"_Section_start.html#start_7. The two most commonly used +here"_Section_start.html#start_6. The two most commonly used options are: -k on t Nt g Ng :pre @@ -304,12 +304,12 @@ The "-k on" switch also issues a "package kokkos" command (with no additional arguments) which sets various KOKKOS options to default values, as discussed on the "package"_package.html command doc page. -Use the "-sf kk" "command-line switch"_Section_start.html#start_7, +Use the "-sf kk" "command-line switch"_Section_start.html#start_6, which will automatically append "kk" to styles that support it. Use -the "-pk kokkos" "command-line switch"_Section_start.html#start_7 if +the "-pk kokkos" "command-line switch"_Section_start.html#start_6 if you wish to change any of the default "package kokkos"_package.html optionns set by the "-k on" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. @@ -323,7 +323,7 @@ However, when running in MPI-only mode with 1 thread per MPI task, it will typically be faster to use "half" neighbor lists and set the Newton flag to "on", just as is the case for non-accelerated pair styles. You can do this with the "-pk" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. [Or run with the KOKKOS package by editing an input script:] @@ -332,7 +332,7 @@ appropriate thread and GPU values for host=OMP or host=MIC or device=CUDA are the same. You must still use the "-k on" "command-line -switch"_Section_start.html#start_7 to enable the KOKKOS package, and +switch"_Section_start.html#start_6 to enable the KOKKOS package, and specify its additional arguments for hardware options appropriate to your system, as documented above. @@ -343,7 +343,7 @@ pair_style lj/cut/kk 2.5 :pre You only need to use the "package kokkos"_package.html command if you wish to change any of its option defaults, as set by the "-k on" -"command-line switch"_Section_start.html#start_7. +"command-line switch"_Section_start.html#start_6. [Speed-ups to expect:] @@ -389,7 +389,7 @@ If N is the number of physical cores/node, then the number of MPI tasks/node * number of threads/task should not exceed N, and should typically equal N. Note that the default threads/task is 1, as set by the "t" keyword of the "-k" "command-line -switch"_Section_start.html#start_7. If you do not change this, no +switch"_Section_start.html#start_6. If you do not change this, no additional parallelism (beyond MPI) will be invoked on the host CPU(s). @@ -429,7 +429,7 @@ details). The -np setting of the mpirun command should set the number of MPI tasks/node to be equal to the # of physical GPUs on the node. -Use the "-k" "command-line switch"_Section_commands.html#start_7 to +Use the "-k" "command-line switch"_Section_commands.html#start_6 to specify the number of GPUs per node, and the number of threads per MPI task. As above for multi-core CPUs (and no GPU), if N is the number of physical cores/node, then the number of MPI tasks/node * number of diff --git a/doc/src/accelerate_omp.txt b/doc/src/accelerate_omp.txt index c8dd343861..81b7a5adc2 100644 --- a/doc/src/accelerate_omp.txt +++ b/doc/src/accelerate_omp.txt @@ -41,7 +41,7 @@ each MPI task running on a CPU. The lines above illustrate how to include/build with the USER-OMP package in two steps, using the "make" command. Or how to do it with one command via the src/Make.py script, described in "Section -2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for +4"_Section_packages.html of the manual. Type "Make.py -h" for help. Note that the CCFLAGS and LINKFLAGS settings in Makefile.machine must @@ -62,14 +62,14 @@ threads/task should not exceed the physical number of cores (on a node), otherwise performance will suffer. As in the lines above, use the "-sf omp" "command-line -switch"_Section_start.html#start_7, which will automatically append +switch"_Section_start.html#start_6, which will automatically append "omp" to styles that support it. The "-sf omp" switch also issues a default "package omp 0"_package.html command, which will set the number of threads per MPI task via the OMP_NUM_THREADS environment variable. You can also use the "-pk omp Nt" "command-line -switch"_Section_start.html#start_7, to explicitly set Nt = # of OpenMP +switch"_Section_start.html#start_6, to explicitly set Nt = # of OpenMP threads per MPI task to use, as well as additional options. Its syntax is the same as the "package omp"_package.html command whose doc page gives details, including the default values used if it is not diff --git a/doc/src/accelerate_opt.txt b/doc/src/accelerate_opt.txt index 704321ca07..5a2a5eac0a 100644 --- a/doc/src/accelerate_opt.txt +++ b/doc/src/accelerate_opt.txt @@ -36,7 +36,7 @@ None. The lines above illustrate how to build LAMMPS with the OPT package in two steps, using the "make" command. Or how to do it with one command via the src/Make.py script, described in "Section -2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for +4"_Section_packages.html of the manual. Type "Make.py -h" for help. Note that if you use an Intel compiler to build with the OPT package, @@ -46,7 +46,7 @@ The Make.py command will add this automatically. [Run with the OPT package from the command line:] As in the lines above, use the "-sf opt" "command-line -switch"_Section_start.html#start_7, which will automatically append +switch"_Section_start.html#start_6, which will automatically append "opt" to styles that support it. [Or run with the OPT package by editing an input script:] diff --git a/doc/src/angle_charmm.txt b/doc/src/angle_charmm.txt index a02e604258..7ff7ef8fd4 100644 --- a/doc/src/angle_charmm.txt +++ b/doc/src/angle_charmm.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_class2.txt b/doc/src/angle_class2.txt index 74f2544cd4..71a508d691 100644 --- a/doc/src/angle_class2.txt +++ b/doc/src/angle_class2.txt @@ -94,7 +94,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine.txt b/doc/src/angle_cosine.txt index 4fb2ccaf7c..c0ce3c9301 100644 --- a/doc/src/angle_cosine.txt +++ b/doc/src/angle_cosine.txt @@ -50,7 +50,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_delta.txt b/doc/src/angle_cosine_delta.txt index 6ab214508c..830fd6db58 100644 --- a/doc/src/angle_cosine_delta.txt +++ b/doc/src/angle_cosine_delta.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_periodic.txt b/doc/src/angle_cosine_periodic.txt index c6cd57e419..b5c53b1b0f 100644 --- a/doc/src/angle_cosine_periodic.txt +++ b/doc/src/angle_cosine_periodic.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_shift.txt b/doc/src/angle_cosine_shift.txt index dc1a29a86b..6ed9fe2150 100644 --- a/doc/src/angle_cosine_shift.txt +++ b/doc/src/angle_cosine_shift.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_shift_exp.txt b/doc/src/angle_cosine_shift_exp.txt index 48af5ba76a..44a68c1087 100644 --- a/doc/src/angle_cosine_shift_exp.txt +++ b/doc/src/angle_cosine_shift_exp.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_squared.txt b/doc/src/angle_cosine_squared.txt index 23e1b150a8..065cdad542 100644 --- a/doc/src/angle_cosine_squared.txt +++ b/doc/src/angle_cosine_squared.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_fourier.txt b/doc/src/angle_fourier.txt index f58ae8e4f4..da39e7cf32 100644 --- a/doc/src/angle_fourier.txt +++ b/doc/src/angle_fourier.txt @@ -51,7 +51,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_fourier_simple.txt b/doc/src/angle_fourier_simple.txt index 9da8ffed28..5adda6cb32 100644 --- a/doc/src/angle_fourier_simple.txt +++ b/doc/src/angle_fourier_simple.txt @@ -50,7 +50,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_harmonic.txt b/doc/src/angle_harmonic.txt index 12ee805218..4c74763964 100644 --- a/doc/src/angle_harmonic.txt +++ b/doc/src/angle_harmonic.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_quartic.txt b/doc/src/angle_quartic.txt index fea2eb9e03..f7640bdfbc 100644 --- a/doc/src/angle_quartic.txt +++ b/doc/src/angle_quartic.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_table.txt b/doc/src/angle_table.txt index 61dd7b041e..bd6e167bd8 100644 --- a/doc/src/angle_table.txt +++ b/doc/src/angle_table.txt @@ -136,7 +136,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/balance.txt b/doc/src/balance.txt index 79728d6569..da6f59900d 100644 --- a/doc/src/balance.txt +++ b/doc/src/balance.txt @@ -394,7 +394,7 @@ weights. It assigns the same weight to each particle owned by a processor based on the total computational time spent by that processor. See details below on what time window is used. It uses the same timing information as is used for the "MPI task timing -breakdown"_Section_start.html#start_8, namely, for sections {Pair}, +breakdown"_Section_start.html#start_7, namely, for sections {Pair}, {Bond}, {Kspace}, and {Neigh}. The time spent in those portions of the timestep are measured for each MPI rank, summed, then divided by the number of particles owned by that processor. I.e. the weight is diff --git a/doc/src/bond_class2.txt b/doc/src/bond_class2.txt index aa05412387..9687a63168 100644 --- a/doc/src/bond_class2.txt +++ b/doc/src/bond_class2.txt @@ -56,7 +56,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_fene.txt b/doc/src/bond_fene.txt index 80d2a805c5..9050c3bf5c 100644 --- a/doc/src/bond_fene.txt +++ b/doc/src/bond_fene.txt @@ -59,7 +59,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_fene_expand.txt b/doc/src/bond_fene_expand.txt index 3908c16a7e..ff687444a9 100644 --- a/doc/src/bond_fene_expand.txt +++ b/doc/src/bond_fene_expand.txt @@ -62,7 +62,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic.txt b/doc/src/bond_harmonic.txt index 1cbd897dac..c18a7e0fd4 100644 --- a/doc/src/bond_harmonic.txt +++ b/doc/src/bond_harmonic.txt @@ -54,7 +54,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic_shift.txt b/doc/src/bond_harmonic_shift.txt index 8cb2d2ce7d..bf3b3c115a 100644 --- a/doc/src/bond_harmonic_shift.txt +++ b/doc/src/bond_harmonic_shift.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic_shift_cut.txt b/doc/src/bond_harmonic_shift_cut.txt index 836d6afda4..1918ce00b6 100644 --- a/doc/src/bond_harmonic_shift_cut.txt +++ b/doc/src/bond_harmonic_shift_cut.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_morse.txt b/doc/src/bond_morse.txt index 12e51f9bef..4f6a32e341 100644 --- a/doc/src/bond_morse.txt +++ b/doc/src/bond_morse.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_nonlinear.txt b/doc/src/bond_nonlinear.txt index ac9f3369c2..434af62506 100644 --- a/doc/src/bond_nonlinear.txt +++ b/doc/src/bond_nonlinear.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_quartic.txt b/doc/src/bond_quartic.txt index e61f4f0343..4dc7ad4a36 100644 --- a/doc/src/bond_quartic.txt +++ b/doc/src/bond_quartic.txt @@ -88,7 +88,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_table.txt b/doc/src/bond_table.txt index cb096fba11..906d3e5d76 100644 --- a/doc/src/bond_table.txt +++ b/doc/src/bond_table.txt @@ -133,7 +133,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_pressure.txt b/doc/src/compute_pressure.txt index 292e779f72..f0691ad207 100644 --- a/doc/src/compute_pressure.txt +++ b/doc/src/compute_pressure.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_temp.txt b/doc/src/compute_temp.txt index 0bd2d4b121..b88be79e20 100644 --- a/doc/src/compute_temp.txt +++ b/doc/src/compute_temp.txt @@ -79,7 +79,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_temp_partial.txt b/doc/src/compute_temp_partial.txt index 163a00af52..fe2420b4e4 100644 --- a/doc/src/compute_temp_partial.txt +++ b/doc/src/compute_temp_partial.txt @@ -86,7 +86,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_charmm.txt b/doc/src/dihedral_charmm.txt index 73dc67cdef..06abe054e4 100644 --- a/doc/src/dihedral_charmm.txt +++ b/doc/src/dihedral_charmm.txt @@ -128,7 +128,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_class2.txt b/doc/src/dihedral_class2.txt index 91ab6f3738..cb9fc72c22 100644 --- a/doc/src/dihedral_class2.txt +++ b/doc/src/dihedral_class2.txt @@ -153,7 +153,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_cosine_shift_exp.txt b/doc/src/dihedral_cosine_shift_exp.txt index 89614a3fdb..715682affc 100644 --- a/doc/src/dihedral_cosine_shift_exp.txt +++ b/doc/src/dihedral_cosine_shift_exp.txt @@ -64,7 +64,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_fourier.txt b/doc/src/dihedral_fourier.txt index 5682309b83..da892b59da 100644 --- a/doc/src/dihedral_fourier.txt +++ b/doc/src/dihedral_fourier.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_harmonic.txt b/doc/src/dihedral_harmonic.txt index c763dcce22..d9a48ff384 100644 --- a/doc/src/dihedral_harmonic.txt +++ b/doc/src/dihedral_harmonic.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_helix.txt b/doc/src/dihedral_helix.txt index fced983db0..1e907557b2 100644 --- a/doc/src/dihedral_helix.txt +++ b/doc/src/dihedral_helix.txt @@ -58,7 +58,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_multi_harmonic.txt b/doc/src/dihedral_multi_harmonic.txt index 5774a67685..7d3c2ea083 100644 --- a/doc/src/dihedral_multi_harmonic.txt +++ b/doc/src/dihedral_multi_harmonic.txt @@ -52,7 +52,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_nharmonic.txt b/doc/src/dihedral_nharmonic.txt index 0df28a05d4..8392d83899 100644 --- a/doc/src/dihedral_nharmonic.txt +++ b/doc/src/dihedral_nharmonic.txt @@ -52,7 +52,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_opls.txt b/doc/src/dihedral_opls.txt index afcc5d3514..d1a6ba3ff2 100644 --- a/doc/src/dihedral_opls.txt +++ b/doc/src/dihedral_opls.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_quadratic.txt b/doc/src/dihedral_quadratic.txt index 526b469f63..ca2f5aed40 100644 --- a/doc/src/dihedral_quadratic.txt +++ b/doc/src/dihedral_quadratic.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/echo.txt b/doc/src/echo.txt index 8ef8ad05f8..3141c7a719 100644 --- a/doc/src/echo.txt +++ b/doc/src/echo.txt @@ -26,7 +26,7 @@ command to the screen and/or log file as it is read and processed. If an input script has errors, it can be useful to look at echoed output to see the last command processed. -The "command-line switch"_Section_start.html#start_5 -echo can be used +The "command-line switch"_Section_start.html#start_6 -echo can be used in place of this command. [Restrictions:] none diff --git a/doc/src/fix_addforce.txt b/doc/src/fix_addforce.txt index da9f98a6da..1cc0a15332 100644 --- a/doc/src/fix_addforce.txt +++ b/doc/src/fix_addforce.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_aveforce.txt b/doc/src/fix_aveforce.txt index d980e9a211..5d7dec3e6a 100644 --- a/doc/src/fix_aveforce.txt +++ b/doc/src/fix_aveforce.txt @@ -77,7 +77,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_deform.txt b/doc/src/fix_deform.txt index d3254eece6..63d872eded 100644 --- a/doc/src/fix_deform.txt +++ b/doc/src/fix_deform.txt @@ -557,7 +557,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_enforce2d.txt b/doc/src/fix_enforce2d.txt index 1dce620033..5d04e96677 100644 --- a/doc/src/fix_enforce2d.txt +++ b/doc/src/fix_enforce2d.txt @@ -41,7 +41,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_freeze.txt b/doc/src/fix_freeze.txt index 6a4f6c2fcf..a63ee4cb32 100644 --- a/doc/src/fix_freeze.txt +++ b/doc/src/fix_freeze.txt @@ -45,7 +45,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_gravity.txt b/doc/src/fix_gravity.txt index 2cf1665c30..dae8ac5ed0 100644 --- a/doc/src/fix_gravity.txt +++ b/doc/src/fix_gravity.txt @@ -102,7 +102,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_langevin.txt b/doc/src/fix_langevin.txt index 534d83f6a9..93c73f5a5d 100644 --- a/doc/src/fix_langevin.txt +++ b/doc/src/fix_langevin.txt @@ -276,7 +276,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_momentum.txt b/doc/src/fix_momentum.txt index 4f94e2a857..bcf4465fb8 100644 --- a/doc/src/fix_momentum.txt +++ b/doc/src/fix_momentum.txt @@ -73,7 +73,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nh.txt b/doc/src/fix_nh.txt index c1cc3e560a..8fa30ac222 100644 --- a/doc/src/fix_nh.txt +++ b/doc/src/fix_nh.txt @@ -492,7 +492,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_asphere.txt b/doc/src/fix_nph_asphere.txt index 3d151a724b..8c35b6a1a7 100644 --- a/doc/src/fix_nph_asphere.txt +++ b/doc/src/fix_nph_asphere.txt @@ -93,7 +93,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_body.txt b/doc/src/fix_nph_body.txt index 3a273be595..1e590f1cb3 100644 --- a/doc/src/fix_nph_body.txt +++ b/doc/src/fix_nph_body.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_sphere.txt b/doc/src/fix_nph_sphere.txt index 9258f40c76..62b45edfd7 100644 --- a/doc/src/fix_nph_sphere.txt +++ b/doc/src/fix_nph_sphere.txt @@ -102,7 +102,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nphug.txt b/doc/src/fix_nphug.txt index ef3ffc4955..292e46f94a 100644 --- a/doc/src/fix_nphug.txt +++ b/doc/src/fix_nphug.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_asphere.txt b/doc/src/fix_npt_asphere.txt index 8fe98f1818..5f3979e36e 100644 --- a/doc/src/fix_npt_asphere.txt +++ b/doc/src/fix_npt_asphere.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_body.txt b/doc/src/fix_npt_body.txt index 772920df61..d89bf19db2 100644 --- a/doc/src/fix_npt_body.txt +++ b/doc/src/fix_npt_body.txt @@ -116,7 +116,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_sphere.txt b/doc/src/fix_npt_sphere.txt index 24a8fede57..c4cf2cb08d 100644 --- a/doc/src/fix_npt_sphere.txt +++ b/doc/src/fix_npt_sphere.txt @@ -127,7 +127,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve.txt b/doc/src/fix_nve.txt index 7ad8301877..c04c17858e 100644 --- a/doc/src/fix_nve.txt +++ b/doc/src/fix_nve.txt @@ -46,7 +46,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve_asphere.txt b/doc/src/fix_nve_asphere.txt index 03846a2558..1f31fb9679 100644 --- a/doc/src/fix_nve_asphere.txt +++ b/doc/src/fix_nve_asphere.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve_sphere.txt b/doc/src/fix_nve_sphere.txt index f91a41f515..21dc6cba8a 100644 --- a/doc/src/fix_nve_sphere.txt +++ b/doc/src/fix_nve_sphere.txt @@ -77,7 +77,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_asphere.txt b/doc/src/fix_nvt_asphere.txt index 77de1dea40..21b900f16a 100644 --- a/doc/src/fix_nvt_asphere.txt +++ b/doc/src/fix_nvt_asphere.txt @@ -98,7 +98,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_body.txt b/doc/src/fix_nvt_body.txt index 1f04b85c8b..6a5e09ba7f 100644 --- a/doc/src/fix_nvt_body.txt +++ b/doc/src/fix_nvt_body.txt @@ -97,7 +97,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_sllod.txt b/doc/src/fix_nvt_sllod.txt index 82631f22e3..392dbc281c 100644 --- a/doc/src/fix_nvt_sllod.txt +++ b/doc/src/fix_nvt_sllod.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_sphere.txt b/doc/src/fix_nvt_sphere.txt index fa1c97bcce..ecf0922b79 100644 --- a/doc/src/fix_nvt_sphere.txt +++ b/doc/src/fix_nvt_sphere.txt @@ -108,7 +108,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_qeq_comb.txt b/doc/src/fix_qeq_comb.txt index 30c5003e72..7f82404127 100644 --- a/doc/src/fix_qeq_comb.txt +++ b/doc/src/fix_qeq_comb.txt @@ -74,7 +74,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_qeq_reax.txt b/doc/src/fix_qeq_reax.txt index a1a19b7368..18450c7cd5 100644 --- a/doc/src/fix_qeq_reax.txt +++ b/doc/src/fix_qeq_reax.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_reax_bonds.txt b/doc/src/fix_reax_bonds.txt index aadb0a9cbc..54aa7faef8 100644 --- a/doc/src/fix_reax_bonds.txt +++ b/doc/src/fix_reax_bonds.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section_accelerate"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_reaxc_species.txt b/doc/src/fix_reaxc_species.txt index 9a588356e0..7c920791f7 100644 --- a/doc/src/fix_reaxc_species.txt +++ b/doc/src/fix_reaxc_species.txt @@ -151,7 +151,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section_accelerate"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_rigid.txt b/doc/src/fix_rigid.txt index 87021b8551..62969112f7 100644 --- a/doc/src/fix_rigid.txt +++ b/doc/src/fix_rigid.txt @@ -676,7 +676,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_setforce.txt b/doc/src/fix_setforce.txt index 90766fc5bc..f5be0f93a5 100644 --- a/doc/src/fix_setforce.txt +++ b/doc/src/fix_setforce.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_shake.txt b/doc/src/fix_shake.txt index 8b26aaa874..c187b17c6c 100644 --- a/doc/src/fix_shake.txt +++ b/doc/src/fix_shake.txt @@ -159,7 +159,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_wall_reflect.txt b/doc/src/fix_wall_reflect.txt index 5b425316e0..954ec65bf6 100644 --- a/doc/src/fix_wall_reflect.txt +++ b/doc/src/fix_wall_reflect.txt @@ -142,7 +142,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_class2.txt b/doc/src/improper_class2.txt index 0b41afe2db..14ec6258de 100644 --- a/doc/src/improper_class2.txt +++ b/doc/src/improper_class2.txt @@ -99,7 +99,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_cossq.txt b/doc/src/improper_cossq.txt index e238063a8f..138a6a1650 100644 --- a/doc/src/improper_cossq.txt +++ b/doc/src/improper_cossq.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_cvff.txt b/doc/src/improper_cvff.txt index 72f346ba04..5f69eccc60 100644 --- a/doc/src/improper_cvff.txt +++ b/doc/src/improper_cvff.txt @@ -66,7 +66,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_fourier.txt b/doc/src/improper_fourier.txt index 3a5354b1fe..f9062da207 100644 --- a/doc/src/improper_fourier.txt +++ b/doc/src/improper_fourier.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_harmonic.txt b/doc/src/improper_harmonic.txt index b47b0ca41f..bb17e5a641 100644 --- a/doc/src/improper_harmonic.txt +++ b/doc/src/improper_harmonic.txt @@ -70,7 +70,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_ring.txt b/doc/src/improper_ring.txt index cba59399e7..c02d392474 100644 --- a/doc/src/improper_ring.txt +++ b/doc/src/improper_ring.txt @@ -69,7 +69,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_umbrella.txt b/doc/src/improper_umbrella.txt index fafa2e7e4c..d6df9ee6cc 100644 --- a/doc/src/improper_umbrella.txt +++ b/doc/src/improper_umbrella.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/jump.txt b/doc/src/jump.txt index 1b1a209511..4e3799f7b1 100644 --- a/doc/src/jump.txt +++ b/doc/src/jump.txt @@ -40,12 +40,12 @@ lmp_g++ < in.script :pre since the SELF option invokes the C-library rewind() call, which may not be supported for stdin on some systems or by some MPI implementations. This can be worked around by using the "-in -command-line argument"_Section_start.html#start_7, e.g. +command-line argument"_Section_start.html#start_6, e.g. lmp_g++ -in in.script :pre or by using the "-var command-line -argument"_Section_start.html#start_7 to pass the script name as a +argument"_Section_start.html#start_6 to pass the script name as a variable to the input script. In the latter case, a "variable"_variable.html called "fname" could be used in place of SELF, e.g. diff --git a/doc/src/log.txt b/doc/src/log.txt index 460482ea1e..92bb12e6db 100644 --- a/doc/src/log.txt +++ b/doc/src/log.txt @@ -34,7 +34,7 @@ the same log file. The file "log.lammps" is the default log file for a LAMMPS run. The name of the initial log file can also be set by the command-line -switch -log. See "Section 2.7"_Section_start.html#start_7 for +switch -log. See "Section 2.6"_Section_start.html#start_6 for details. [Restrictions:] none diff --git a/doc/src/neb.txt b/doc/src/neb.txt index d2e8be3f03..144fe8bdef 100644 --- a/doc/src/neb.txt +++ b/doc/src/neb.txt @@ -51,7 +51,7 @@ follows the discussion in these 4 papers: "(HenkelmanA)"_#HenkelmanA, Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the manual. +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on just one or two diff --git a/doc/src/neighbor.txt b/doc/src/neighbor.txt index 7b8f499ba8..062f79a5bb 100644 --- a/doc/src/neighbor.txt +++ b/doc/src/neighbor.txt @@ -66,7 +66,7 @@ stored in the list. When a run is finished, counts of the number of neighbors stored in the pairwise list and the number of times neighbor lists were built are printed to the screen and log file. See "this -section"_Section_start.html#start_8 for details. +section"_Section_start.html#start_7 for details. [Restrictions:] none diff --git a/doc/src/next.txt b/doc/src/next.txt index fe9dc97542..08f73b896c 100644 --- a/doc/src/next.txt +++ b/doc/src/next.txt @@ -71,7 +71,7 @@ next value (for each variable) is assigned to whichever processor partition executes the command first. All processors in the partition are assigned the same value(s). Running LAMMPS on multiple partitions of processors via the "-partition" command-line switch is described in -"this section"_Section_start.html#start_7 of the manual. {Universe}- +"this section"_Section_start.html#start_6 of the manual. {Universe}- and {uloop}-style variables are incremented using the files "tmp.lammps.variable" and "tmp.lammps.variable.lock" which you will see in your directory during and after such a LAMMPS run. diff --git a/doc/src/package.txt b/doc/src/package.txt index 18a26bd55c..1b9092644f 100644 --- a/doc/src/package.txt +++ b/doc/src/package.txt @@ -115,7 +115,7 @@ their initialization, before a simulation is defined. This command can also be specified from the command-line when launching LAMMPS, using the "-pk" "command-line -switch"_Section_start.html#start_7. The syntax is exactly the same as +switch"_Section_start.html#start_6. The syntax is exactly the same as when used in an input script. Note that all of the accelerator packages require the package command @@ -126,18 +126,18 @@ a default version of the command is typically invoked by other accelerator settings. The KOKKOS package requires a "-k on" "command-line -switch"_Section_start.html#start_7 respectively, which invokes a +switch"_Section_start.html#start_6 respectively, which invokes a "package kokkos" command with default settings. For the GPU, USER-INTEL, and USER-OMP packages, if a "-sf gpu" or "-sf -intel" or "-sf omp" "command-line switch"_Section_start.html#start_7 +intel" or "-sf omp" "command-line switch"_Section_start.html#start_6 is used to auto-append accelerator suffixes to various styles in the input script, then those switches also invoke a "package gpu", "package intel", or "package omp" command with default settings. NOTE: A package command for a particular style can be invoked multiple times when a simulation is setup, e.g. by the "-c on", "-k on", "-sf", -and "-pk" "command-line switches"_Section_start.html#start_7, and by +and "-pk" "command-line switches"_Section_start.html#start_6, and by using this command in an input script. Each time it is used all of the style options are set, either to default values or to specified settings. I.e. settings from previous invocations do not persist @@ -305,7 +305,7 @@ value via their package commands, but there is only a single global invoked, you should insure the two values are consistent. If they are not, the last one invoked will take precedence, for both packages. Also note that if the "-sf hybrid intel omp" "command-line -switch"_"_Section_start.html#start_7 is used, it invokes a "package +switch"_"_Section_start.html#start_6 is used, it invokes a "package intel" command, followed by a "package omp" command, both with a setting of {Nthreads} = 0. @@ -550,7 +550,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. [Related commands:] "suffix"_suffix.html, "-pk" "command-line -setting"_Section_start.html#start_7 +setting"_Section_start.html#start_6 [Default:] @@ -558,9 +558,9 @@ For the GPU package, the default is Ngpu = 1 and the option defaults are neigh = yes, newton = off, binsize = 0.0, split = 1.0, gpuID = 0 to Ngpu-1, tpa = 1, and device = not used. These settings are made automatically if the "-sf gpu" "command-line -switch"_Section_start.html#start_7 is used. If it is not used, you +switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package gpu command in your input script or via the -"-pk gpu" "command-line switch"_Section_start.html#start_7. +"-pk gpu" "command-line switch"_Section_start.html#start_6. For the USER-INTEL package, the default is Nphi = 1 and the option defaults are omp = 0, mode = mixed, lrt = no, balance = -1, tpc = 4, @@ -569,21 +569,21 @@ style being used. This value is output to the screen in the offload report at the end of each run. Note that all of these settings, except "omp" and "mode", are ignored if LAMMPS was not built with Xeon Phi coprocessor support. These settings are made automatically -if the "-sf intel" "command-line switch"_Section_start.html#start_7 +if the "-sf intel" "command-line switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package intel command in your input script or or via the "-pk intel" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. For the KOKKOS package, the option defaults neigh = full, neigh/qeq = full, newton = off, binsize = 0.0, and comm = device. These settings are made automatically by the required "-k on" "command-line -switch"_Section_start.html#start_7. You can change them bu using the +switch"_Section_start.html#start_6. You can change them bu using the package kokkos command in your input script or via the "-pk kokkos" -"command-line switch"_Section_start.html#start_7. +"command-line switch"_Section_start.html#start_6. For the OMP package, the default is Nthreads = 0 and the option defaults are neigh = yes. These settings are made automatically if -the "-sf omp" "command-line switch"_Section_start.html#start_7 is +the "-sf omp" "command-line switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package omp command in your input script or via the "-pk omp" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. diff --git a/doc/src/pair_adp.txt b/doc/src/pair_adp.txt index 457a797d95..9d2a48dcbc 100644 --- a/doc/src/pair_adp.txt +++ b/doc/src/pair_adp.txt @@ -137,7 +137,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_agni.txt b/doc/src/pair_agni.txt index 06dcccb9d9..402e537dad 100644 --- a/doc/src/pair_agni.txt +++ b/doc/src/pair_agni.txt @@ -70,7 +70,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated style explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_airebo.txt b/doc/src/pair_airebo.txt index 0c03eb3267..e66ecb637f 100644 --- a/doc/src/pair_airebo.txt +++ b/doc/src/pair_airebo.txt @@ -185,7 +185,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_beck.txt b/doc/src/pair_beck.txt index 4e792754b8..e160f09b3d 100644 --- a/doc/src/pair_beck.txt +++ b/doc/src/pair_beck.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_born.txt b/doc/src/pair_born.txt index d38d9e3191..a3cc744a22 100644 --- a/doc/src/pair_born.txt +++ b/doc/src/pair_born.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_brownian.txt b/doc/src/pair_brownian.txt index 33eed77629..79b71e91c7 100644 --- a/doc/src/pair_brownian.txt +++ b/doc/src/pair_brownian.txt @@ -85,7 +85,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "this section"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_buck.txt b/doc/src/pair_buck.txt index e705e735fb..d18b39d5d9 100644 --- a/doc/src/pair_buck.txt +++ b/doc/src/pair_buck.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_buck_long.txt b/doc/src/pair_buck_long.txt index ba18738e4d..05e760e1b2 100644 --- a/doc/src/pair_buck_long.txt +++ b/doc/src/pair_buck_long.txt @@ -114,7 +114,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_charmm.txt b/doc/src/pair_charmm.txt index 1e78607c08..ef4ef41c95 100644 --- a/doc/src/pair_charmm.txt +++ b/doc/src/pair_charmm.txt @@ -195,7 +195,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_class2.txt b/doc/src/pair_class2.txt index 23b90aae2d..36fae5068b 100644 --- a/doc/src/pair_class2.txt +++ b/doc/src/pair_class2.txt @@ -114,7 +114,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_colloid.txt b/doc/src/pair_colloid.txt index a0df1d464e..83b15b358b 100644 --- a/doc/src/pair_colloid.txt +++ b/doc/src/pair_colloid.txt @@ -139,7 +139,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_comb.txt b/doc/src/pair_comb.txt index 3a2f380bfa..f5461b1cbc 100644 --- a/doc/src/pair_comb.txt +++ b/doc/src/pair_comb.txt @@ -124,7 +124,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_coul.txt b/doc/src/pair_coul.txt index 4a601e90c0..29e5beed3c 100644 --- a/doc/src/pair_coul.txt +++ b/doc/src/pair_coul.txt @@ -274,7 +274,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_dipole.txt b/doc/src/pair_dipole.txt index 985581cac8..2516e5eae4 100644 --- a/doc/src/pair_dipole.txt +++ b/doc/src/pair_dipole.txt @@ -198,7 +198,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_dpd.txt b/doc/src/pair_dpd.txt index 62a5faffed..9dd204ad2d 100644 --- a/doc/src/pair_dpd.txt +++ b/doc/src/pair_dpd.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_eam.txt b/doc/src/pair_eam.txt index 4d3c2b2dea..ce8495affd 100644 --- a/doc/src/pair_eam.txt +++ b/doc/src/pair_eam.txt @@ -381,7 +381,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_edip.txt b/doc/src/pair_edip.txt index 86453859d3..e5b1420b59 100644 --- a/doc/src/pair_edip.txt +++ b/doc/src/pair_edip.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_eim.txt b/doc/src/pair_eim.txt index 3f068d4040..75ad2d4683 100644 --- a/doc/src/pair_eim.txt +++ b/doc/src/pair_eim.txt @@ -148,7 +148,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gayberne.txt b/doc/src/pair_gayberne.txt index 8639f220a4..c923578586 100644 --- a/doc/src/pair_gayberne.txt +++ b/doc/src/pair_gayberne.txt @@ -145,7 +145,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gran.txt b/doc/src/pair_gran.txt index 62a58b3504..d7e87af013 100644 --- a/doc/src/pair_gran.txt +++ b/doc/src/pair_gran.txt @@ -191,7 +191,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gromacs.txt b/doc/src/pair_gromacs.txt index 3aca8c3cd3..ec84a2d57a 100644 --- a/doc/src/pair_gromacs.txt +++ b/doc/src/pair_gromacs.txt @@ -103,7 +103,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_hbond_dreiding.txt b/doc/src/pair_hbond_dreiding.txt index 9641e294fa..d3cf90ec14 100644 --- a/doc/src/pair_hbond_dreiding.txt +++ b/doc/src/pair_hbond_dreiding.txt @@ -178,7 +178,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_hybrid.txt b/doc/src/pair_hybrid.txt index 5166fe1f84..fc1824cf62 100644 --- a/doc/src/pair_hybrid.txt +++ b/doc/src/pair_hybrid.txt @@ -330,7 +330,7 @@ LAMMPS was built with those packages. See the You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj.txt b/doc/src/pair_lj.txt index 5c8e31ac42..058d54fb59 100644 --- a/doc/src/pair_lj.txt +++ b/doc/src/pair_lj.txt @@ -253,7 +253,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj96.txt b/doc/src/pair_lj96.txt index 6e7c3cbaec..83f6ec063d 100644 --- a/doc/src/pair_lj96.txt +++ b/doc/src/pair_lj96.txt @@ -61,7 +61,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_cubic.txt b/doc/src/pair_lj_cubic.txt index d33e3ec09b..4ca8c3c141 100644 --- a/doc/src/pair_lj_cubic.txt +++ b/doc/src/pair_lj_cubic.txt @@ -75,7 +75,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_expand.txt b/doc/src/pair_lj_expand.txt index c5f0c88a75..e0838426f6 100644 --- a/doc/src/pair_lj_expand.txt +++ b/doc/src/pair_lj_expand.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_long.txt b/doc/src/pair_lj_long.txt index da9f37b9c3..6be4562d18 100644 --- a/doc/src/pair_lj_long.txt +++ b/doc/src/pair_lj_long.txt @@ -168,7 +168,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_smooth.txt b/doc/src/pair_lj_smooth.txt index 133773abd0..b1678cad58 100644 --- a/doc/src/pair_lj_smooth.txt +++ b/doc/src/pair_lj_smooth.txt @@ -74,7 +74,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_smooth_linear.txt b/doc/src/pair_lj_smooth_linear.txt index a48c441f54..5f7c226cee 100644 --- a/doc/src/pair_lj_smooth_linear.txt +++ b/doc/src/pair_lj_smooth_linear.txt @@ -61,7 +61,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_soft.txt b/doc/src/pair_lj_soft.txt index e372092cf0..2ef133da55 100644 --- a/doc/src/pair_lj_soft.txt +++ b/doc/src/pair_lj_soft.txt @@ -219,7 +219,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lubricate.txt b/doc/src/pair_lubricate.txt index 501a043801..b39c7545c7 100644 --- a/doc/src/pair_lubricate.txt +++ b/doc/src/pair_lubricate.txt @@ -154,7 +154,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "this section"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_meam_spline.txt b/doc/src/pair_meam_spline.txt index 2295a6640b..6653b397a0 100644 --- a/doc/src/pair_meam_spline.txt +++ b/doc/src/pair_meam_spline.txt @@ -118,7 +118,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_morse.txt b/doc/src/pair_morse.txt index 5fbb6d5c0a..3eb5ac5afe 100644 --- a/doc/src/pair_morse.txt +++ b/doc/src/pair_morse.txt @@ -113,7 +113,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_nb3b_harmonic.txt b/doc/src/pair_nb3b_harmonic.txt index 3f7066c826..2395707fb4 100644 --- a/doc/src/pair_nb3b_harmonic.txt +++ b/doc/src/pair_nb3b_harmonic.txt @@ -104,7 +104,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_nm.txt b/doc/src/pair_nm.txt index 9096bdc523..81cea1a38d 100644 --- a/doc/src/pair_nm.txt +++ b/doc/src/pair_nm.txt @@ -145,7 +145,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_peri.txt b/doc/src/pair_peri.txt index 6ffd8122aa..6fef445595 100644 --- a/doc/src/pair_peri.txt +++ b/doc/src/pair_peri.txt @@ -151,7 +151,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_reaxc.txt b/doc/src/pair_reaxc.txt index cfa88673d7..b9dc6e0ed8 100644 --- a/doc/src/pair_reaxc.txt +++ b/doc/src/pair_reaxc.txt @@ -311,7 +311,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_resquared.txt b/doc/src/pair_resquared.txt index 2e0034ed3b..9ad95eb5fc 100644 --- a/doc/src/pair_resquared.txt +++ b/doc/src/pair_resquared.txt @@ -157,7 +157,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_sdk.txt b/doc/src/pair_sdk.txt index 1c348eaaf7..360136a4ea 100644 --- a/doc/src/pair_sdk.txt +++ b/doc/src/pair_sdk.txt @@ -97,7 +97,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_soft.txt b/doc/src/pair_soft.txt index ec1c06729a..08fa88c477 100644 --- a/doc/src/pair_soft.txt +++ b/doc/src/pair_soft.txt @@ -94,7 +94,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_sw.txt b/doc/src/pair_sw.txt index 6025b9b11b..6ed8f00236 100644 --- a/doc/src/pair_sw.txt +++ b/doc/src/pair_sw.txt @@ -156,7 +156,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. When using the USER-INTEL package with this style, there is an diff --git a/doc/src/pair_table.txt b/doc/src/pair_table.txt index 01c577cd98..b99491b477 100644 --- a/doc/src/pair_table.txt +++ b/doc/src/pair_table.txt @@ -229,7 +229,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff.txt b/doc/src/pair_tersoff.txt index 23a20ad0fd..918e889924 100644 --- a/doc/src/pair_tersoff.txt +++ b/doc/src/pair_tersoff.txt @@ -191,7 +191,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff_mod.txt b/doc/src/pair_tersoff_mod.txt index ff703063b3..e0c2b5a5cb 100644 --- a/doc/src/pair_tersoff_mod.txt +++ b/doc/src/pair_tersoff_mod.txt @@ -143,7 +143,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff_zbl.txt b/doc/src/pair_tersoff_zbl.txt index 18e54749aa..21d57e4e88 100644 --- a/doc/src/pair_tersoff_zbl.txt +++ b/doc/src/pair_tersoff_zbl.txt @@ -201,7 +201,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_thole.txt b/doc/src/pair_thole.txt index 61ca0b5c35..41a4059cee 100644 --- a/doc/src/pair_thole.txt +++ b/doc/src/pair_thole.txt @@ -142,7 +142,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_vashishta.txt b/doc/src/pair_vashishta.txt index 9c275a61d3..d9c66d45c0 100644 --- a/doc/src/pair_vashishta.txt +++ b/doc/src/pair_vashishta.txt @@ -183,7 +183,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_yukawa.txt b/doc/src/pair_yukawa.txt index 26acdb2ccb..61d6bde6a9 100644 --- a/doc/src/pair_yukawa.txt +++ b/doc/src/pair_yukawa.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_yukawa_colloid.txt b/doc/src/pair_yukawa_colloid.txt index ecdc1496ab..2037a9451f 100644 --- a/doc/src/pair_yukawa_colloid.txt +++ b/doc/src/pair_yukawa_colloid.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_zbl.txt b/doc/src/pair_zbl.txt index 154fdc1c13..5ab672171b 100644 --- a/doc/src/pair_zbl.txt +++ b/doc/src/pair_zbl.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/partition.txt b/doc/src/partition.txt index 9c1d560c83..610eee99b3 100644 --- a/doc/src/partition.txt +++ b/doc/src/partition.txt @@ -27,7 +27,7 @@ partition yes 6* fix all nvt temp 1.0 1.0 0.1 :pre This command invokes the specified command on a subset of the partitions of processors you have defined via the -partition -command-line switch. See "Section 2.6"_Section_start.html#start_7 +command-line switch. See "Section 2.6"_Section_start.html#start_6 for an explanation of the switch. Normally, every input script command in your script is invoked by @@ -49,7 +49,7 @@ argument. Partitions are numbered from 1 to Np, where Np is the number of partitions specified by the "-partition command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. {N} can be specified in one of two ways. An explicit numeric value can be used, as in the 1st example above. Or a wild-card asterisk can diff --git a/doc/src/prd.txt b/doc/src/prd.txt index 247d422b1c..3c0305e316 100644 --- a/doc/src/prd.txt +++ b/doc/src/prd.txt @@ -63,7 +63,7 @@ event to occur. Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the manual. +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on one or two diff --git a/doc/src/processors.txt b/doc/src/processors.txt index 781049af9c..e54b2cede3 100644 --- a/doc/src/processors.txt +++ b/doc/src/processors.txt @@ -82,7 +82,7 @@ sub-domain. Also note that if multiple partitions are being used then P is the number of processors in this partition; see "this -section"_Section_start.html#start_7 for an explanation of the +section"_Section_start.html#start_6 for an explanation of the -partition command-line switch. Also note that you can prefix the processors command with the "partition"_partition.html command to easily specify different Px,Py,Pz values for different partitions. @@ -249,7 +249,7 @@ partition {Precv} which is enforced when each is setting up their own mapping of their processors to the simulation box. Each of {Psend} and {Precv} must be integers from 1 to Np, where Np is the number of partitions you have defined via the "-partition command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. A "dependency" means that the sending partition will create its regular 3d grid as Px by Py by Pz and after it has done this, it will @@ -286,7 +286,7 @@ processors and their mapping to the 3d grid to the specified file processors in the manner you desired, which can be tricky to figure out, especially when running on multiple partitions or on, a multicore machine or when the processor ranks were reordered by use of the -"-reorder command-line switch"_Section_start.html#start_7 or due to +"-reorder command-line switch"_Section_start.html#start_6 or due to use of MPI-specific launch options such as a config file. If you have multiple partitions you should insure that each one writes @@ -300,9 +300,9 @@ The IDs are the processor's rank in this simulation (the world), the universe (of multiple simulations), and the original MPI communicator used to instantiate LAMMPS, respectively. The world and universe IDs will only be different if you are running on more than one partition; -see the "-partition command-line switch"_Section_start.html#start_7. +see the "-partition command-line switch"_Section_start.html#start_6. The universe and original IDs will only be different if you used the -"-reorder command-line switch"_Section_start.html#start_7 to reorder +"-reorder command-line switch"_Section_start.html#start_6 to reorder the processors differently than their rank in the original communicator LAMMPS was instantiated with. @@ -332,7 +332,7 @@ The {part} keyword (for the receiving partition) only works with the [Related commands:] -"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_7 +"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_6 [Default:] diff --git a/doc/src/read_data.txt b/doc/src/read_data.txt index 6785eb1066..a8aca53693 100644 --- a/doc/src/read_data.txt +++ b/doc/src/read_data.txt @@ -62,7 +62,7 @@ simulation. The file can be ASCII text or a gzipped text file atom coordinates; see the "read_restart"_read_restart.html and "create_atoms"_create_atoms.html commands for alternative methods. Also see the explanation of the "-restart command-line -switch"_Section_start.html#start_7 which can convert a restart file to +switch"_Section_start.html#start_6 which can convert a restart file to a data file. This command can be used multiple times to add new atoms and their diff --git a/doc/src/read_restart.txt b/doc/src/read_restart.txt index d0f4b16175..d1091542b8 100644 --- a/doc/src/read_restart.txt +++ b/doc/src/read_restart.txt @@ -81,7 +81,7 @@ wrong. Because restart files are binary, they may not be portable to other machines. In this case, you can use the "-restart command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. Similar to how restart files are written (see the diff --git a/doc/src/region.txt b/doc/src/region.txt index 885e5e45f8..5039e4a516 100644 --- a/doc/src/region.txt +++ b/doc/src/region.txt @@ -375,7 +375,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/restart.txt b/doc/src/restart.txt index 5e0c2a9ea5..7c39ae1404 100644 --- a/doc/src/restart.txt +++ b/doc/src/restart.txt @@ -125,7 +125,7 @@ Restart files can be read by a "read_restart"_read_restart.html command to restart a simulation from a particular state. Because the file is binary (to enable exact restarts), it may not be readable on another machine. In this case, you can use the "-r command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. NOTE: Although the purpose of restart files is to enable restarting a diff --git a/doc/src/run_style.txt b/doc/src/run_style.txt index a67899420b..ba836a07dd 100644 --- a/doc/src/run_style.txt +++ b/doc/src/run_style.txt @@ -69,7 +69,7 @@ The {verlet} style is a standard velocity-Verlet integrator. The {verlet/split} style is also a velocity-Verlet integrator, but it splits the force calculation within each timestep over 2 partitions of -processors. See "Section 2.7"_Section_start.html#start_7 for an +processors. See "Section 2.6"_Section_start.html#start_6 for an explanation of the -partition command-line switch. Specifically, this style performs all computation except the @@ -115,7 +115,7 @@ When you run in 2-partition mode with the {verlet/split} style, the thermodynamic data for the entire simulation will be output to the log and screen file of the 1st partition, which are log.lammps.0 and screen.0 by default; see the "-plog and -pscreen command-line -switches"_Section_start.html#start_7 to change this. The log and +switches"_Section_start.html#start_6 to change this. The log and screen file for the 2nd partition will not contain thermodynamic output beyond the 1st timestep of the run. @@ -259,7 +259,7 @@ Accelerated styles take the same arguments and should produce the same results, except for round-off and precision issues. You can specify {respa/omp} explicitly in your input script, or -you can use the "-suffix command-line switch"_Section_start.html#start_7 +you can use the "-suffix command-line switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. diff --git a/doc/src/suffix.txt b/doc/src/suffix.txt index 127719cdb5..7a4adb50b6 100644 --- a/doc/src/suffix.txt +++ b/doc/src/suffix.txt @@ -28,7 +28,7 @@ suffix kk :pre This command allows you to use variants of various styles if they exist. In that respect it operates the same as the "-suffix -command-line switch"_Section_start.html#start_7. It also has options +command-line switch"_Section_start.html#start_6. It also has options to turn off or back on any suffix setting made via the command line. The specified style can be {gpu}, {intel}, {kk}, {omp}, {opt} or @@ -105,6 +105,6 @@ input script. [Related commands:] -"Command-line switch -suffix"_Section_start.html#start_7 +"Command-line switch -suffix"_Section_start.html#start_6 [Default:] none diff --git a/doc/src/temper.txt b/doc/src/temper.txt index be7edfba43..b1c47c8076 100644 --- a/doc/src/temper.txt +++ b/doc/src/temper.txt @@ -32,7 +32,7 @@ replicas (ensembles) of a system. Two or more replicas must be used. Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on one or @@ -70,7 +70,7 @@ As a tempering run proceeds, multiple log files and screen output files are created, one per replica. By default these files are named log.lammps.M and screen.M where M is the replica number from 0 to N-1, with N = # of replicas. See the "section on command-line -switches"_Section_start.html#start_7 for info on how to change these +switches"_Section_start.html#start_6 for info on how to change these names. The main screen and log file (log.lammps) will list information about diff --git a/doc/src/thermo_style.txt b/doc/src/thermo_style.txt index 36ec7bf12e..6102169ee3 100644 --- a/doc/src/thermo_style.txt +++ b/doc/src/thermo_style.txt @@ -255,7 +255,7 @@ The {part} keyword is useful for multi-replica or multi-partition simulations to indicate which partition this output and this file corresponds to, or for use in a "variable"_variable.html to append to a filename for output specific to this partition. See "Section -2.7"_Section_start.html#start_7 of the manual for details on running +2.6"_Section_start.html#start_6 of the manual for details on running in multi-partition mode. The {timeremain} keyword returns the remaining seconds when a diff --git a/doc/src/timer.txt b/doc/src/timer.txt index 39a6c542b7..768c3e1353 100644 --- a/doc/src/timer.txt +++ b/doc/src/timer.txt @@ -40,7 +40,7 @@ time is spent in different sections of the code and thus can provide information for determining performance and load imbalance problems. This can be done at different levels of detail and accuracy. For more information about the timing output, see this "discussion of screen -output in Section 2.8"_Section_start.html#start_8. +output in Section 2.7"_Section_start.html#start_7. The {off} setting will turn all time measurements off. The {loop} setting will only measure the total time for a run and not collect any diff --git a/doc/src/variable.txt b/doc/src/variable.txt index e32e82ef4d..e3b7c5de0d 100644 --- a/doc/src/variable.txt +++ b/doc/src/variable.txt @@ -178,7 +178,7 @@ This means variables can NOT be re-defined in an input script (with two exceptions, read further). This is to allow an input script to be processed multiple times without resetting the variables; see the "jump"_jump.html or "include"_include.html commands. It also means -that using the "command-line switch"_Section_start.html#start_7 -var +that using the "command-line switch"_Section_start.html#start_6 -var will override a corresponding index variable setting in the input script. @@ -248,7 +248,7 @@ variable. {Index} style variables with a single string value can also be set by using the command-line switch -var; see "this -section"_Section_start.html#start_7 for details. +section"_Section_start.html#start_6 for details. The {loop} style is identical to the {index} style except that the strings are the integers from 1 to N inclusive, if only one argument N @@ -264,7 +264,7 @@ N1 <= N2 and N2 >= 0 is required. For the {world} style, one or more strings are specified. There must be one string for each processor partition or "world". See "this -section"_Section_start.html#start_7 of the manual for information on +section"_Section_start.html#start_6 of the manual for information on running LAMMPS with multiple partitions via the "-partition" command-line switch. This variable command assigns one string to each world. All processors in the world are assigned the same string. The @@ -277,7 +277,7 @@ different partitions. For the {universe} style, one or more strings are specified. There must be at least as many strings as there are processor partitions or -"worlds". See "this page"_Section_start.html#start_7 for information +"worlds". See "this page"_Section_start.html#start_6 for information on running LAMMPS with multiple partitions via the "-partition" command-line switch. This variable command initially assigns one string to each world. When a "next"_next.html command is encountered diff --git a/doc/src/write_data.txt b/doc/src/write_data.txt index 033199e98b..39e5a7f811 100644 --- a/doc/src/write_data.txt +++ b/doc/src/write_data.txt @@ -59,7 +59,7 @@ If you want to do more exact restarts, using binary files, see the "restart"_restart.html, "write_restart"_write_restart.html, and "read_restart"_read_restart.html commands. You can also convert binary restart files to text data files, after a simulation has run, -using the "-r command-line switch"_Section_start.html#start_7. +using the "-r command-line switch"_Section_start.html#start_6. NOTE: Only limited information about a simulation is stored in a data file. For example, no information about atom "groups"_group.html and diff --git a/doc/src/write_restart.txt b/doc/src/write_restart.txt index 8160eec3df..ff3b652dba 100644 --- a/doc/src/write_restart.txt +++ b/doc/src/write_restart.txt @@ -66,7 +66,7 @@ Restart files can be read by a "read_restart"_read_restart.html command to restart a simulation from a particular state. Because the file is binary (to enable exact restarts), it may not be readable on another machine. In this case, you can use the "-r command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. NOTE: Although the purpose of restart files is to enable restarting a diff --git a/src/Make.py b/src/Make.py deleted file mode 100755 index 3030183e1a..0000000000 --- a/src/Make.py +++ /dev/null @@ -1,2378 +0,0 @@ -#!/usr/bin/env python2 - -# Make.py tool for managing packages and their auxiliary libs, -# auto-editing machine Makefiles, and building LAMMPS -# Syntax: Make.py -h (for help) -# Notes: should be compatible with python 2.7 and 3.x thanks to 'futurize' - -from __future__ import print_function -import sys,os,re,copy,subprocess,platform - -# switch abbrevs -# switch classes = created class for each switch -# lib classes = auxiliary package libs -# build classes = build options with defaults -# make classes = makefile options with no defaults -# setargs = makefile settings -# actionargs = allowed actions (also lib-dir and machine) -# lib build flags are set if lib is built, for use with zoutput - -abbrevs = "adhjmoprsvz" - -switchclasses = ("actions","dir","help","jmake","makefile", - "output","packages","redo","settings","verbose","zoutput") -libclasses = ("atc","awpmd","colvars","cuda","gpu","h5md", - "meam","poems","python","qmmm","reax","voronoi") -buildclasses = ("intel","kokkos") -makeclasses = ("cc","flags","mpi","fft","jpg","png") - -setargs = ("gzip","#gzip","ffmpeg","#ffmpeg","smallbig","bigbig", - "smallsmall","exceptions","#exceptions") -actionargs = ("lib-all","file","clean","exe") - -gpubuildflag = 0 - -# ---------------------------------------------------------------- -# functions -# ---------------------------------------------------------------- - -# if flag = 1, print txt and exit -# if flag = 0, print txt as warning and do not exit - -def error(txt,flag=1): - if flag: - print("ERROR:",txt) - sys.exit() - else: - print("WARNING:",txt) - -# store command-line args as sw = dict of key/value -# key = switch word, value = list of following args -# order = list of switches in order specified -# enforce no switch more than once - -def parse_args(args): - narg = len(args) - sw = {} - order = [] - iarg = 0 - while iarg < narg: - if args[iarg][0] != '-': error("Arg %s is not a switch" % args[iarg]) - switch = args[iarg][1:] - if switch in sw: error("Duplicate switch %s" % args[iarg]) - order.append(switch) - first = iarg+1 - last = first - while last < narg and args[last][0] != '-': last += 1 - sw[switch] = args[first:last] - iarg = last - return sw,order - -# convert info in switches dict back to a string, in switch_order - -def switch2str(switches,switch_order): - txt = "" - for switch in switch_order: - if txt: txt += ' ' - txt += "-%s" % switch - txt += ' ' + ' '.join(switches[switch]) - return txt - -# check if compiler works with ccflags on dummy one-line tmpauto.cpp file -# return 1 if successful, else 0 -# warn = 1 = print warning if not successful, warn = 0 = no warning -# NOTE: unrecognized -override-limits can leave verride-limits file - -def compile_check(compiler,ccflags,warn): - open("tmpauto.cpp",'w').write("int main(int, char **) {}\n") - tmp = "%s %s -c tmpauto.cpp" % (compiler,ccflags) - try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT, - shell=True).decode() - except subprocess.CalledProcessError as e: txt = e.output - flag = 1 - if txt or not os.path.isfile("tmpauto.o"): - flag = 0 - if warn: - print(tmp) - if txt: print(txt) - else: print("compile produced no output") - os.remove("tmpauto.cpp") - if os.path.isfile("tmpauto.o"): os.remove("tmpauto.o") - return flag - -# check if linker works with linkflags and libs on tmpauto.o file -# return 1 if successful, else 0 -# warn = 1 = print warning if not successful, warn = 0 = no warning - -def link_check(linker,linkflags,libs,warn): - open("tmpauto.cpp",'w').write("int main(int, char **) {}\n") - tmp = "%s %s -o tmpauto tmpauto.cpp %s" % (linker,linkflags,libs) - try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT, - shell=True).decode() - except subprocess.CalledProcessError as e: txt = e.output - flag = 1 - if txt or not os.path.isfile("tmpauto"): - flag = 0 - if warn: - print(tmp) - if txt: print(txt) - else: print("link produced no output") - os.remove("tmpauto.cpp") - if os.path.isfile("tmpauto"): os.remove("tmpauto") - return flag - -# ---------------------------------------------------------------- -# switch classes, one per single-letter switch -# ---------------------------------------------------------------- - -# actions - -class Actions(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --a action1 action2 ... - possible actions = lib-all, lib-dir, file, clean, exe or machine - machine is a Makefile.machine suffix - actions can be specified in any order - each action can appear only once - lib-dir can appear multiple times for different dirs - some actions depend on installed packages - installed packages = currently installed + result of -p switch - actions are invoked in this order, independent of specified order - (1) lib-all or lib-dir = build auxiliary libraries - lib-all builds all auxiliary libs needed by installed packages - lib-dir builds a specific lib whether package installed or not - dir is any dir in lib directory (atc, cuda, meam, etc) except linalg - (2) file = create a new src/MAKE/MINE/Makefile.auto - if file not specified, existing Makefile.auto is NOT changed - except by -m switch, which will copy Makefile.machine to Makefile.auto - note that exe action can add an -m switch, as described below - if file is specified, new Makefile.auto is created - if "-m machine" specified (or added by exe), - start with existing Makefile.machine, else existing Makefile.auto - if "-m none" specified, start Makefile.auto from scratch - must use -cc and -mpi switches to specify compiler and MPI - settings for these switches will alter Makefile.auto - -s, -intel, -kokkos, -cc, -mpi, -fft, -jpg, -png - if these accelerator packages are installed, they induce settings - that will alter Makefile.auto: opt, user-omp, user-intel, kokkos - use -z switch to copy final Makefile.auto to new filename - (3) clean = invoke "make clean-auto" to insure clean build on current files - useful if compiler flags have changed - (4) exe or machine = build LAMMPS - machine can be any existing Makefile.machine suffix - machine is converted to "exe" action, and additionally: - "-m machine" is added if -m switch is not specified - "-o machine" is added if -o switch is not specified - if either "-m" or "-o" are specified, they are not overridden - does not invoke any lib builds, since libs could be previously built - exe ALWAYS builds using src/MAKE/MINE/Makefile.auto - if file action also specified, it creates a new Makefile.auto - else if -m switch specified, - existing Makefile.machine is copied to create Makefile.auto - else Makefile.auto must already exist and is not changed - build produces src/lmp_auto, or error message if unsuccessful - use -o switch to copy src/lmp_auto to new filename - use -z switch to copy src/MAKE/MINE/Makefile.auto to new filename -""" - - def check(self): - if not self.inlist: error("-a args are invalid") - libs = [] - cleans = [] - files = [] - exes = [] - for one in self.inlist: - if one.startswith("lib-"): - lib = one[4:] - if lib != "all" and lib not in libclasses: error("Actions are invalid") - libs.append(one) - elif one == "file": - files.append(one) - elif one == "clean": - cleans.append(one) - elif one == "exe": - exes.append(one) - # one action can be unknown, must be a machine (checked in setup) - else: - exes.append(one) - if len(set(libs)) != len(libs) or \ - len(cleans) > 1 or len(files) > 1 or len(exes) > 1: - error("Actions are invalid") - self.alist = [action for actions in [libs,cleans,files,exes] \ - for action in actions] - - # dedup list of actions concatenated from two lists - # current self.inlist = specified -a switch + redo command -a switch - # specified exe/machine action replaces redo exe/machine action - # operates on and replaces self.inlist - - def dedup(self): - alist = [] - exemachine = 0 - for one in self.inlist: - if one == "exe" or (one not in actionargs and not one.startswith("lib-")): - if exemachine: continue - exemachine = 1 - if one not in alist: alist.append(one) - self.inlist = alist - - # if last action is unknown, assume machine and convert to exe - # only done if action is a suffix for an existing Makefile.machine - # return machine if conversion done, else None - - def setup(self): - machine = self.alist[-1] - if machine in actionargs or machine.startswith("lib-"): return None - make = MakeReader(machine,2) - self.alist[-1] = "exe" - return machine - - # build one or more auxiliary package libraries - - def lib(self,suffix): - if suffix != "all": - print("building",suffix,"library ...") - txt = "%s.build()" % suffix - exec(txt) - else: - final = packages.final - for one in packages.lib: - if final[one]: - if "user" in one: pkg = one[5:] - else: pkg = one - print("building",pkg,"library ...") - txt = "%s.build()" % pkg - exec(txt) - - # read Makefile.machine - # if caller = "file", edit via switches - # if caller = "exe", just read - # write out new Makefile.auto - - def file(self,caller): - - # if caller="file", create from mpi or read from Makefile.machine or auto - # if caller="exe" and "file" action already invoked, read from auto - # if caller="exe" and no "file" action, read from Makefile.machine or auto - - if caller == "file": - if makefile and makefile.machine == "none": - if cc and mpi: machine = "mpi" - else: error("Cannot create makefile unless -cc and -mpi are used") - elif makefile: machine = makefile.machine - else: machine = "auto" - elif caller == "exe" and "file" in self.alist: - machine = "auto" - elif caller == "exe" and "file" not in self.alist: - if makefile and makefile.machine == "none": - error("Cannot build with makefile = none") - elif makefile: machine = makefile.machine - else: machine = "auto" - - make = MakeReader(machine,1) - - # change makefile settings to user specifications - - precompiler = "" - if caller == "file": - - # add compiler/linker and default CCFLAGS,LINKFLAGS - # if cc.wrap, add wrapper setting for mpi = ompi/mpich - # precompiler = env variable setting for OpenMPI wrapper compiler - - if cc: - make.setvar("CC",cc.compiler) - make.setvar("LINK",cc.compiler) - if cc.wrap: - if cc.wrap == "nvcc": - wrapper = os.path.abspath("../lib/kokkos/config/nvcc_wrapper") - else: wrapper = cc.wrap - abbrev = cc.abbrev - if abbrev == "mpi": - if cc.parent == "mpich": - make.addvar("CC","-cxx=%s" % wrapper) - make.addvar("LINK","-cxx=%s" % wrapper) - elif cc.parent == "openmpi": - make.addvar("export OMPI_CXX",wrapper,"cc") - precompiler = "env OMPI_CXX=%s " % wrapper - else: error("Could not add MPI wrapper compiler, " + - "did not recognize OpenMPI or MPICH") - make.setvar("CCFLAGS","-g") - make.addvar("CCFLAGS","-O3") - make.setvar("LINKFLAGS","-g") - make.addvar("LINKFLAGS","-O") - - # add MPI settings - - if mpi: - make.delvar("MPI_INC","*") - make.delvar("MPI_PATH","*") - make.delvar("MPI_LIB","*") - if mpi.style == "mpi": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - elif mpi.style == "mpich": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir) - if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir) - make.addvar("MPI_LIB","-lmpich") - make.addvar("MPI_LIB","-lmpl") - make.addvar("MPI_LIB","-lpthread") - elif mpi.style == "ompi": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir) - if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir) - make.addvar("MPI_LIB","-lmpi") - make.addvar("MPI_LIB","-lmpi_cxx") - elif mpi.style == "serial": - make.addvar("MPI_INC","-I../STUBS") - make.addvar("MPI_PATH","-L../STUBS") - make.addvar("MPI_LIB","-lmpi_stubs") - - # add accelerator package CCFLAGS and LINKFLAGS and variables - - compiler = precompiler + ' '.join(make.getvar("CC")) - linker = precompiler + ' '.join(make.getvar("LINK")) - - final = packages.final - if final["opt"]: - if compile_check(compiler,"-restrict",0): - make.addvar("CCFLAGS","-restrict") - - if final["user-omp"]: - if compile_check(compiler,"-fopenmp",1): - make.addvar("CCFLAGS","-fopenmp") - make.addvar("LINKFLAGS","-fopenmp") - if compile_check(compiler,"-restrict",0): - make.addvar("CCFLAGS","-restrict") - - if final["user-intel"]: - if intel.mode == "cpu": - make.delvar("CCFLAGS","-O*") - make.addvar("CCFLAGS","-O2") - if compile_check(compiler,"-openmp",1): - make.addvar("CCFLAGS","-openmp") - if compile_check(compiler,"-restrict",1): - make.addvar("CCFLAGS","-restrict") - if compile_check(compiler,"-no-offload",1): - make.addvar("CCFLAGS","-no-offload") - if compile_check(compiler,"-fno-alias",1): - make.addvar("CCFLAGS","-fno-alias") - if compile_check(compiler,"-ansi-alias",1): - make.addvar("CCFLAGS","-ansi-alias") - if compile_check(compiler,"-xAVX",1): - make.addvar("CCFLAGS","-xAVX") - if compile_check(compiler,"-fp-model fast=2",1): - make.addvar("CCFLAGS","-fp-model fast=2") - if compile_check(compiler,"-no-prec-div",1): - make.addvar("CCFLAGS","-no-prec-div") - if compile_check(compiler,"-override-limits",1): - make.addvar("CCFLAGS","-override-limits") - make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64") - make.delvar("CCFLAGS","-DLMP_INTEL_OFFLOAD") - - make.delvar("LINKFLAGS","-O*") - make.addvar("LINKFLAGS","-O2") - if link_check(linker,"-openmp","",1): - make.addvar("LINKFLAGS","-openmp") - if link_check(linker,"-xAVX","",1): - make.addvar("LINKFLAGS","-xAVX") - if link_check(linker,"-fpmodel fast=2","",1): - make.addvar("LINKFLAGS","-fpmodel fast=2") - if link_check(linker,"-no-prec-div","",1): - make.addvar("LINKFLAGS","-no-prec-div") - if link_check(linker,"-override-limits","",1): - make.addvar("LINKFLAGS","-override-limits") - make.delvar("LINKFLAGS","-offload") - - if link_check(linker,"","-ltbbmalloc",1): - make.addvar("LIB","-ltbbmalloc") - if link_check(linker,"","-ltbbmalloc_proxy",1): - make.addvar("LIB","-ltbbmalloc_proxy") - - elif intel.mode == "phi": - if compile_check(compiler,"-fopenmp",1): - make.addvar("CCFLAGS","-fopenmp") - make.addvar("LINKFLAGS","-fopenmp") - make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64") - if compile_check(compiler,"-restrict",1): - make.addvar("CCFLAGS","-restrict") - if compile_check(compiler,"-xHost",1): - make.addvar("CCFLAGS","-xHost") - make.addvar("CCFLAGS","-DLMP_INTEL_OFFLOAD") - if compile_check(compiler,"-fno-alias",1): - make.addvar("CCFLAGS","-fno-alias") - if compile_check(compiler,"-ansi-alias",1): - make.addvar("CCFLAGS","-ansi-alias") - if compile_check(compiler,"-override-limits",1): - make.addvar("CCFLAGS","-override-limits") - if compile_check(compiler,'-offload-option,mic,compiler,' + - '"-fp-model fast=2 -mGLOB_default_function_attrs=' + - '\\"gather_scatter_loop_unroll=4\\""',1): - make.addvar("CCFLAGS",'-offload-option,mic,compiler,' + - '"-fp-model fast=2 -mGLOB_default_function_attrs=' + - '\\"gather_scatter_loop_unroll=4\\""') - if link_check(linker,"-offload","",1): - make.addvar("LINKFLAGS","-offload") - - if final["kokkos"]: - if kokkos.mode == "omp": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","OpenMP","lmp") - if kokkos.archcpu: - make.addvar("KOKKOS_ARCH",kokkos.archcpu,"lmp") - elif kokkos.mode == "cuda": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","Cuda, OpenMP","lmp") - if kokkos.archgpu: - if kokkos.archgpu[0] == "3": value = "Kepler" + kokkos.archgpu - elif kokkos.archgpu[0] == "2": value = "Fermi" + kokkos.archgpu - else: error("Unrecognized Kokkos archgpu setting") - if kokkos.archcpu: value += ", %s" % kokkos.archcpu - make.addvar("KOKKOS_ARCH",value,"lmp") - elif kokkos.mode == "phi": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","OpenMP","lmp") - make.addvar("KOKKOS_ARCH","KNC","lmp") - - # add LMP_INC ifdef settings - - if settings: - list = settings.inlist - for one in list: - if one == "gzip": make.addvar("LMP_INC","-DLAMMPS_GZIP") - elif one == "#gzip": make.delvar("LMP_INC","-DLAMMPS_GZIP") - elif one == "ffmpeg": make.addvar("LMP_INC","-DLAMMPS_FFMPEG") - elif one == "#ffmpeg": make.delvar("LMP_INC","-DLAMMPS_FFMPEG") - elif one == "smallbig": - make.delvar("LMP_INC","-DLAMMPS_BIGBIG") - make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL") - elif one == "bigbig": - make.delvar("LMP_INC","-DLAMMPS_SMALLBIG") - make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL") - make.addvar("LMP_INC","-DLAMMPS_BIGBIG") - elif one == "smallsmall": - make.delvar("LMP_INC","-DLAMMPS_SMALLBIG") - make.delvar("LMP_INC","-DLAMMPS_BIGBIG") - make.addvar("LMP_INC","-DLAMMPS_SMALLSMALL") - elif one == "exceptions": make.addvar("LMP_INC","-DLAMMPS_EXCEPTIONS") - elif one == "#exception": make.delvar("LMP_INC","-DLAMMPS_EXCEPTIONS") - - # add FFT, JPG, PNG settings - - if fft: - make.delvar("FFT_INC","*") - make.delvar("FFT_PATH","*") - make.delvar("FFT_LIB","*") - if fft.mode == "none": make.addvar("FFT_INC","-DFFT_NONE") - else: - make.addvar("FFT_INC","-DFFT_%s" % fft.mode.upper()) - make.addvar("FFT_LIB",fft.lib) - if fft.dir: - make.addvar("FFT_INC","-I%s/include" % fft.dir) - make.addvar("FFT_PATH","-L%s/lib" % fft.dir) - else: - if fft.incdir: make.addvar("FFT_INC","-I%s" % fft.incdir) - if fft.libdir: make.addvar("FFT_PATH","-L%s" % fft.libdir) - - if jpg: - if jpg.on == 0: - make.delvar("LMP_INC","-DLAMMPS_JPEG") - make.delvar("JPG_LIB","-ljpeg") - else: - make.addvar("LMP_INC","-DLAMMPS_JPEG") - make.addvar("JPG_LIB","-ljpeg") - if jpg.dir: - make.addvar("JPG_INC","-I%s/include" % jpg.dir) - make.addvar("JPG_PATH","-L%s/lib" % jpg.dir) - else: - if jpg.incdir: make.addvar("JPG_INC","-I%s" % jpg.incdir) - if jpg.libdir: make.addvar("JPG_PATH","-L%s" % jpg.libdir) - - if png: - if png.on == 0: - make.delvar("LMP_INC","-DLAMMPS_PNG") - make.delvar("JPG_LIB","-lpng") - else: - make.addvar("LMP_INC","-DLAMMPS_PNG") - make.addvar("JPG_LIB","-lpng") - if png.dir: - make.addvar("JPG_INC","-I%s/include" % png.dir) - make.addvar("JPG_PATH","-L%s/lib" % png.dir) - else: - if png.incdir: make.addvar("JPG_INC","-I%s" % png.incdir) - if png.libdir: make.addvar("JPG_PATH","-L%s" % png.libdir) - - # finally after all other settings, add explicit flags - - if flags: - for var,action,flist in flags.flags: - values = make.getvar(var) - if values == None: - error("Flags for a non-existent Makefile.auto variable") - for flag in flist: - flag = "-" + flag - if action == "add": make.addvar(var,flag) - elif action == "del": make.delvar(var,flag) - - # set self.stubs if Makefile.auto uses STUBS lib in MPI settings - - if make.getvar("MPI_LIB") and "-lmpi_stubs" in make.getvar("MPI_LIB"): - self.stubs = 1 - else: self.stubs = 0 - - # write out Makefile.auto - # unless caller = "exe" and "file" action already invoked - - if caller == "file" or "file" not in self.alist: - # make certain that 'MAKE/MINE' folder exists. - subprocess.check_output("mkdir -p %s/MAKE/MINE" % dir.src, - stderr=subprocess.STDOUT,shell=True) - make.write("%s/MAKE/MINE/Makefile.auto" % dir.src,1) - print("Created src/MAKE/MINE/Makefile.auto") - - # test full compile and link - # unless caller = "file" and "exe" action will be invoked later - - if caller == "file" and "exe" in self.alist: return - compiler = precompiler + ' '.join(make.getvar("CC")) - ccflags = ' '.join(make.getvar("CCFLAGS")) - linker = precompiler + ' '.join(make.getvar("LINK")) - linkflags = ' '.join(make.getvar("LINKFLAGS")) - libs = ' '.join(make.getvar("LIB")) - if not compile_check(compiler,ccflags,1): - error("Test of compilation failed") - if not link_check(linker,linkflags,libs,1): error("Test of link failed") - - # invoke "make clean-auto" to force clean before build - - def clean(self): - txt = "cd %s; make clean-auto" % dir.src - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Performed make clean-auto") - - # build LAMMPS using Makefile.auto and -j setting - # invoke self.file() first, to test makefile compile/link - # delete existing lmp_auto, so can detect if build fails - # build STUBS lib (if unbuilt) if Makefile.auto MPI settings need it - - def exe(self): - self.file("exe") - subprocess.check_output("cd %s; rm -f lmp_auto" % dir.src,stderr=subprocess.STDOUT,shell=True) - if self.stubs and not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src): - print("building serial STUBS library ...") - tmp = "cd %s/STUBS; make clean; make" % dir.src - txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode() - if not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src): - print(txt) - error('Unsuccessful "make stubs"') - print("Created src/STUBS/libmpi_stubs.a") - - # special hack for shannon GPU cluster - # must use "srun make" if on it and building w/ GPU package, else just make - # this is b/c Cuda libs are not all available on host - - make = "make" - if "shannon" == platform.node() and packages.final["gpu"]: - make = "srun make" - - if jmake: tmp = "cd %s; %s -j %d auto" % (dir.src,make,jmake.n) - else: tmp = "cd %s; %s auto" % (dir.src,make) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(tmp,shell=True) - else: - print(tmp) - try: subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/lmp_auto" % dir.src): - error('Unsuccessful "make auto"') - elif not output: print("Created src/lmp_auto") - -# dir switch - -class Dir(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --d dir - dir = LAMMPS home dir - if -d not specified, working dir must be lammps/src -""" - - def check(self): - if self.inlist != None and len(self.inlist) != 1: - error("-d args are invalid") - - # if inlist = None, check that cwd = lammps/src - # store cwd and lammps dir - # derive src,make,lib dirs from lammps dir - # check that they all exist - - def setup(self): - self.cwd = os.getcwd() - if self.inlist == None: self.lammps = ".." - else: self.lammps = self.inlist[0] - self.lammps = os.path.realpath(self.lammps) - self.src = self.lammps + "/src" - self.make = self.lammps + "/src/MAKE" - self.lib = self.lammps + "/lib" - if not os.path.isdir(self.lammps): error("LAMMPS home dir is invalid") - if not os.path.isdir(self.src): error("LAMMPS src dir is invalid") - if not os.path.isdir(self.lib): error("LAMMPS lib dir is invalid") - -# help switch - -class Help(object): - def __init__(self,list): pass - - def help(self): - return """ -Syntax: Make.py switch args ... - switches can be listed in any order - help switch: - -h prints help and syntax for all other specified switches - switch for actions: - -a lib-all, lib-dir, clean, file, exe or machine - list one or more actions, in any order - machine is a Makefile.machine suffix - one-letter switches: - -d (dir), -j (jmake), -m (makefile), -o (output), -p (packages), - -r (redo), -s (settings), -v (verbose), -z (makefile output) - switches for libs: - -atc, -awpmd, -colvars, -cuda, -gpu, -h5md, - -meam, -poems, -python, -qmmm, -reax, -voronoi - switches for build and makefile options: - -intel, -kokkos, -cc, -flags, -mpi, -fft, -jpg, -png -""" - -# jmake switch - -class Jmake(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --j N - use N procs for performing parallel make commands - used when building a lib or LAMMPS itself - if -j not specified, serial make commands run on single core -""" - - def check(self): - if len(self.inlist) != 1: error("-j args are invalid") - if not self.inlist[0].isdigit(): error("-j args are invalid") - n = int(self.inlist[0]) - if n <= 0: error("-j args are invalid") - self.n = n - -# makefile switch - -class Makefile(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --m machine - use Makefile.machine under src/MAKE as starting point to create Makefile.auto - if machine = "none", file action will create Makefile.auto from scratch - must use -cc and -mpi switches to specify compiler and MPI - if -m not specified, file/exe actions alter existing Makefile.auto -""" - - def check(self): - if len(self.inlist) != 1: error("-m args are invalid") - self.machine = self.inlist[0] - -# output switch - -class Output(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --o machine - copy final src/lmp_auto to lmp_machine in working dir - if -o not specified, exe action only produces src/lmp_auto -""" - - def check(self): - if len(self.inlist) != 1: error("-o args are invalid") - self.machine = self.inlist[0] - -# packages switch - -class Packages(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --p = package1 package2 ... - list of packages to install or uninstall in order specified - operates on set of packages currently installed - valid package names: - any LAMMPS standard or user package (type "make package" to see list) - prefix by yes/no to install/uninstall (see abbrevs) - yes-molecule, yes-user-atc, no-molecule, no-user-atc - can use LAMMPS categories (type "make package" to see list) - all = all standard and user packages (also none = no-all) - std (or standard) = all standard packages - user = all user packages - lib = all standard and user packages with auxiliary libs - can abbreviate package names and yes/no - omp = user-omp = yes-user-omp - ^omp = ^user-omp = no-user-omp - user = yes-user, ^user = no-user - all = yes-all, ^all = none = no-all - when action performed, list is processed in order, - as if typed "make yes/no" for each - if "orig" or "original" is last package in list, - set of installed packages will be restored to original (current) list - after "build" action is performed - if -p not specified, currently installed packages are not changed -""" - - def check(self): - if self.inlist != None and not self.inlist: error("-p args are invalid") - - def setup(self): - - # extract package lists from src/Makefile - # remove names from lib that there are not Make.py lib-classes for - # most don't actually have libs, so nothing to control from Make.py - - make = MakeReader("%s/Makefile" % dir.src) - std = make.getvar("PACKAGE") - user = make.getvar("PACKUSER") - lib = make.getvar("PACKLIB") - lib.remove("kim") - lib.remove("kokkos") - lib.remove("user-molfile") - lib.remove("python") - lib.remove("user-quip") - all = std + user - - # plist = command line args expanded to yes-package or no-package - - plist = [] - if self.inlist: - for one in self.inlist: - if one in std: - plist.append("yes-%s" % one) - elif one in user: - plist.append("yes-%s" % one) - elif "user-"+one in user: - plist.append("yes-user-%s" % one) - elif one == "std" or one == "standard" or one == "user" or \ - one == "lib" or one == "all": plist.append("yes-%s" % one) - elif one.startswith("yes-"): - if one[4:] in std: plist.append("yes-%s" % one[4:]) - elif one[4:] in user: plist.append("yes-%s" % one[4:]) - elif "user-"+one[4:] in user: plist.append("yes-user-%s" % one[4:]) - elif one == "yes-std" or one == "yes-standard" or \ - one == "yes-user" or one == "yes-lib" or one == "yes-all": - plist.append("yes-%s" % one[4:]) - else: error("Invalid package name %s" % one) - elif one.startswith("no-"): - if one[3:] in std: plist.append("no-%s" % one[3:]) - elif one[3:] in user: plist.append("no-%s" % one[3:]) - elif "user-"+one[3:] in user: plist.append("no-user-%s" % one[3:]) - elif one == "no-std" or one == "no-standard" or one == "no-user" or \ - one == "no-lib" or one == "no-all": - plist.append("no-%s" % one[3:]) - else: error("Invalid package name %s" % one) - elif one.startswith('^'): - if one[1:] in std: plist.append("no-%s" % one[1:]) - elif one[1:] in user: plist.append("no-%s" % one[1:]) - elif "user-"+one[1:] in user: plist.append("no-user-%s" % one[1:]) - elif one == "^std" or one == "^standard" or one == "^user" or \ - one == "^lib" or one == "^all": plist.append("no-%s" % one[1:]) - else: error("Invalid package name %s" % one) - elif one == "none": plist.append("no-all") - elif one == "orig": plist.append(one) - else: error("Invalid package name %s" % one) - if "orig" in plist and plist.index("orig") != len(plist)-1: - error('-p orig arg must be last') - if plist.count("orig") > 1: error('-p orig arg must be last') - - # original = dict of all packages - # key = package name, value = 1 if currently installed, else 0 - - original = {} - tmp = "cd %s; make ps" % dir.src - output = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode().split('\n') - pattern = "Installed\s+(\w+): package (\S+)" - for line in output: - m = re.search(pattern,line) - if not m: continue - pkg = m.group(2).lower() - if pkg not in all: error('Package list does not match "make ps" results') - if m.group(1) == "NO": original[pkg] = 0 - elif m.group(1) == "YES": original[pkg] = 1 - - # final = dict of all packages after plist applied to original - # key = package name, value = 1 if installed, else 0 - - final = copy.deepcopy(original) - for i,one in enumerate(plist): - if "yes" in one: - pkg = one[4:] - yes = 1 - else: - pkg = one[3:] - yes = 0 - if pkg in all: - final[pkg] = yes - elif pkg == "std" or pkg == "standard": - for pkg in std: final[pkg] = yes - elif pkg == "user": - for pkg in user: final[pkg] = yes - elif pkg == "lib": - for pkg in lib: final[pkg] = yes - elif pkg == "all": - for pkg in all: final[pkg] = yes - - self.std = std - self.user = user - self.lib = lib - self.all = all - self.plist = plist - self.original = original - self.final = final - - # install packages in plist - - def install(self): - if self.plist: print("Installing packages ...") - for one in self.plist: - if one == "orig": continue - subprocess.check_output("cd %s; make %s" % (dir.src,one), - stderr=subprocess.STDOUT,shell=True) - if self.plist and verbose: - txt = subprocess.check_output("cd %s; make ps" % dir.src, - stderr=subprocess.STDOUT, - shell=True).decode() - print("Package status after installation:") - print(txt) - - # restore packages to original list if requested - # order of re-install should not matter matter b/c of Depend.sh - - def uninstall(self): - if not self.plist or self.plist[-1] != "orig": return - print("Restoring packages to original state ...") - subprocess.check_output("cd %s; make no-all" % dir.src, - stderr=subprocess.STDOUT,shell=True) - for one in self.all: - if self.original[one]: - subprocess.check_output("cd %s; make yes-%s" % (dir.src,one), - stderr=subprocess.STDOUT,shell=True) - if verbose: - txt = subprocess.check_output("cd %s; make ps" % dir.src, - stderr=subprocess.STDOUT, - shell=True).decode() - print("Restored package status:") - print(txt) - -# redo switch - -class Redo(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --r file label1 label2 ... - all args are optional - invoke Make.py commands from a file - other specified switches are merged with file commands (see below) - redo file format: - blank lines and lines starting with "#" are skipped - other lines are treated as commands - each command is a list of Make.py args, as if typed at command-line - commands can have leading label, followed by ":" - commands cannot contain a "-r" switch - if no args, execute previous command, which is stored in src/Make.py.last - if one arg, execute all commands from specified file - unlabeled or labeled commands are all executed - if multiple args, execute only matching labeled commands from file - if other switches are specified, - if file command does not have the switch, it is added - if file command has the switch, the specified switch replaces it - except if -a (action) switch is both specified and in the file command, - two sets of actions are merged and duplicates removed - if both switches have "exe or machine" action, - the specified exe/machine overrides the file exe/machine -""" - - def check(self): - if len(self.inlist) == 0: - self.dir = 1 - self.file = "Make.py.last" - self.labels = [] - else: - self.dir = 0 - self.file = self.inlist[0] - self.labels = self.inlist[1:] - - # read redo file - # self.commands = list of commands to execute - - def setup(self): - file = self.file - if not os.path.isfile(file): error("Redo file %s does not exist" % file) - lines = open(file,'r').readlines() - - cmdlines = [] - for line in lines: - line = line.strip() - if not line or line[0] == '#' : continue - cmdlines.append(line) - - # if no labels, add all file commands to command list - # if labels, make a dict with key = label, value = command - # and discard unlabeled commands - - dict = {} - commands = [] - for line in cmdlines: - words = line.split() - if "-r" in words: error("Redo command cannot contain -r switch") - if words[0][-1] == ':': label = words[0][:-1] - else: label = None - if not self.labels: - if label: subprocess.append(' '.join(words[1:])) - else: subprocess.append(line) - else: - if not label: continue - dict[label] = ' '.join(words[1:]) - - # extract labeled commands from dict and add to command list - - for label in self.labels: - if label not in dict: error("Redo label not in redo file") - subprocess.append(dict[label]) - - self.commands = commands - -# settings switch - -class Settings(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --s set1 set2 ... - possible settings = gzip #gzip ffmpeg #ffmpeg - smallbig bigbig smallsmall exceptions #exceptions - alter LAMMPS ifdef settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - gzip and #gzip turn on/off LAMMPS_GZIP setting - ffmpeg and #ffmpeg turn on/off LAMMPS_FFMPEG setting - smallbig, bigbig, smallsmall turn on LAMMPS_SMALLBIG, etc - and turn off other two - exceptions and #exceptions turn on/off LAMMPS_EXCEPTIONS setting -""" - - def check(self): - if not self.inlist: error("-s args are invalid") - for one in self.inlist: - if one not in setargs: error("-s args are invalid") - -# verbose switch - -class Verbose(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --v (no arguments) - produce verbose output as Make.py executes - if -v not specified, minimal output is produced -""" - - def check(self): - if len(self.inlist): error("-v args are invalid") - -# zoutput switch for making copy of final Makefile.auto - -class Zoutput(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --z machine - copy created/used src/MAKE/MINE/Makefile.auto to Makefile.machine in same dir - copy created/used lib/*/Makefile.auto and lib/*/Makefile.lammps to - Makefile_lib.machine and Makefile_lib_lammps.machine in same dir - this can be used to preserve the machine Makefile and lib Makefiles -""" - - def check(self): - if len(self.inlist) != 1: error("-z args are invalid") - self.machine = self.inlist[0] - -# ---------------------------------------------------------------- -# lib classes, one per LAMMPS auxiliary lib -# ---------------------------------------------------------------- - -# ATC lib - -class ATC(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --atc make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-atc args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-atc args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-atc args are invalid") - - def build(self): - libdir = dir.lib + "/atc" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libatc.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/atc library") - else: print("Created lib/atc library") - -# AWPMD lib - -class AWPMD(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "mpicc" - self.lammpsflag = 0 - - def help(self): - return """ --awpmd make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = mpicc) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-awpmd args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-awpmd args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-awpmd args are invalid") - - def build(self): - libdir = dir.lib + "/awpmd" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libawpmd.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/awpmd library") - else: print("Created lib/awpmd library") - -# COLVARS lib - -class COLVARS(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --colvars make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-colvars args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-colvars args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-colvars args are invalid") - - def build(self): - libdir = dir.lib + "/colvars" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libcolvars.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/colvars library") - else: print("Created lib/colvars library") - -# CUDA lib - -class CUDA(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "double" - self.arch = "35" - - def help(self): - return """ --cuda mode=double arch=35 - all args are optional and can be in any order - mode = double or mixed or single (def = double) - arch = M (def = 35) - M = 31,35,37,etc for Kepler - M = 20 for CC2.0 (GF100/110, e.g. C2050,GTX580,GTX470) - M = 21 for CC2.1 (GF104/114, e.g. GTX560, GTX460, GTX450) - M = 13 for CC1.3 (GF200, e.g. C1060, GTX285) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-cuda args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-cuda args are invalid") - if words[0] == "mode": self.mode = words[1] - elif words[0] == "arch": self.arch = words[1] - else: error("-cuda args are invalid") - if self.mode != "double" and self.mode != "mixed" and \ - self.mode != "single": - error("-cuda args are invalid") - if not self.arch.isdigit(): error("-cuda args are invalid") - - def build(self): - libdir = dir.lib + "/cuda" - subprocess.check_output("cd %s; make clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - if self.mode == "double": n = 2 - elif self.mode == "mixed": n = 3 - elif self.mode == "single": n = 1 - if jmake: txt = "cd %s; make -j %d precision=%d arch=%s" % \ - (libdir,jmake.n,n,self.arch) - else: txt = "cd %s; make precision=%d arch=%s" % \ - (libdir,n,self.arch) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/liblammpscuda.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/cuda library") - else: print("Created lib/cuda library") - -# GPU lib - -class GPU(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "linux.double" - self.lammpsflag = self.modeflag = self.archflag = self.homeflag = 0 - - def help(self): - return """ --gpu make=suffix lammps=suffix2 mode=double arch=N home=path - all args are optional and can be in any order - make = use Makefile.suffix (def = linux.double) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) - mode = double or mixed or single (def = CUDA_PREC in makefile) - arch = 3x (x = digit for Kepler) or 2x (x = digit for Fermi) - (def = CUDA_ARCH in makefile) - home = path to Cuda, e.g. /usr/local/cuda (def = CUDA_HOME in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-gpu args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-gpu args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - elif words[0] == "mode": - self.mode = words[1] - self.modeflag = 1 - elif words[0] == "arch": - self.arch = words[1] - self.archflag = 1 - elif words[0] == "home": - self.home = words[1] - self.homeflag = 1 - else: error("-gpu args are invalid") - if self.modeflag and (self.mode != "double" and - self.mode != "mixed" and - self.mode != "single"): - error("-gpu args are invalid") - if self.archflag and not self.arch.isdigit(): - error("-gpu args are invalid") - - def build(self): - global gpubuildflag - gpubuildflag = 1 - libdir = dir.lib + "/gpu" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.modeflag: - if self.mode == "double": - make.setvar("CUDA_PRECISION","-D_DOUBLE_DOUBLE") - elif self.mode == "mixed": - make.setvar("CUDA_PRECISION","-D_SINGLE_DOUBLE") - elif self.mode == "single": - make.setvar("CUDA_PRECISION","-D_SINGLE_SINGLE") - if self.archflag: - make.setvar("CUDA_ARCH","-arch=sm_%s" % self.arch) - if self.homeflag: - make.setvar("CUDA_HOME",self.home) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - # special hack for shannon GPU cluster - # must use "srun make" if on it, else just make - # this is b/c Cuda libs are not all available on host - - make = "make" - if "shannon" == platform.node(): make = "srun make" - - subprocess.check_output("cd %s; %s -f Makefile.auto clean" % - (libdir,make),stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; %s -j %d -f Makefile.auto" % (libdir,make,jmake.n) - else: txt = "cd %s; %s -f Makefile.auto" % (libdir,make) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libgpu.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/gpu library") - else: print("Created lib/gpu library") - -# H5MD lib - -class H5MD(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "h5cc" - self.lammpsflag = 0 - - def help(self): - return """ --h5md make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = h5cc) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-h5md args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-h5md args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-h5md args are invalid") - - def build(self): - libdir = dir.lib + "/h5md" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - txt = "cd %s; make" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libch5md.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/h5md library") - else: print("Created lib/h5md library") - -# MEAM lib - -class MEAM(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --meam make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-meam args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-meam args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-meam args are invalid") - - def build(self): - libdir = dir.lib + "/meam" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - # do not use -j for MEAM build, parallel build does not work - txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libmeam.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/meam library") - else: print("Created lib/meam library") - -# POEMS lib - -class POEMS(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --poems make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-poems args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-poems args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-poems args are invalid") - - def build(self): - libdir = dir.lib + "/poems" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libpoems.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/poems library") - else: print("Created lib/poems library") - -# PYTHON lib - -class PYTHON(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --python lammps=suffix - arg is optional, use Makefile.lammps if not specified - lammps = use Makefile.lammps.suffix -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-python args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-python args are invalid") - if words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-python args are invalid") - - def build(self): - libdir = dir.lib + "/python" - if self.lammpsflag: - subprocess.check_output("cd %s; cp Makefile.lammps.%s Makefile.lammps" % - (libdir,self.lammps)) - if not os.path.isfile("%s/Makefile.lammps.%s" % (libdir,self.lammps)): - error("Unsuccessful creation of lib/python/Makefile.lammps.%s file" % - self.lammps) - else: print("Created lib/python/Makefile.lammps file") - -# QMMM lib - -class QMMM(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --qmmm make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-qmmm args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-qmmm args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-qmmm args are invalid") - - def build(self): - libdir = dir.lib + "/qmmm" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libqmmm.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/qmmm library") - else: print("Created lib/qmmm library") - -# REAX lib - -class REAX(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --reax make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-reax args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-reax args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-reax args are invalid") - - def build(self): - libdir = dir.lib + "/reax" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - cmd = "cd %s; make -f Makefile.auto clean" % libdir - subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libreax.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/reax library") - else: print("Created lib/reax library") - -# VORONOI lib - -class VORONOI(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.install = "" - - def help(self): - return """ --voronoi install="-d dir -v version -g -b -i installdir -l incdir libdir" - arg is optional, only needed if want to run install.py script - install = args to use with lib/voronoi/install.py script - must enclose in quotes since install.py args have switches - install.py can download, build, install, setup links to the Voro++ library - see lib/voronoi/README for details on Voro++ and using install.py -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-voronoi args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-voronoi args are invalid") - if words[0] == "install": self.install = words[1] - else: error("-voronoi args are invalid") - - def build(self): - if not self.install: return - libdir = dir.lib + "/voronoi" - cmd = "cd %s; python install.py %s" % (libdir,self.install) - txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT, - shell=True).decode() - if verbose: print(txt) - print("Created lib/voronoi library") - -# ---------------------------------------------------------------- -# build classes for intel, kokkos build options -# ---------------------------------------------------------------- - -# Intel class - -class Intel(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "cpu" - - def help(self): - return """ --intel mode - mode = cpu or phi (def = cpu) - build Intel package for CPU or Xeon Phi -""" - - def check(self): - if self.inlist == None: return - if len(self.inlist) != 1: error("-intel args are invalid") - self.mode = self.inlist[0] - if self.mode != "cpu" and self.mode != "phi": - error("-intel args are invalid") - -# Kokkos class - -class Kokkos(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "" - self.archgpu = None - self.archcpu = None - - def help(self): - return """ --kokkos mode archgpu=N archcpu=SNB - mode is not optional, arch is optional - mode = omp or cuda or phi (def = KOKKOS_DEVICES setting in Makefile ) - build Kokkos package for omp or cuda or phi - sets KOKKOS_DEVICES to "OpenMP" (omp, phi) or "Cuda, OpenMP" (cuda) - archgpu = number like 35 (Kepler) or 21 (Fermi) (def = none) - sets KOKKOS_ARCH for GPU to appropriate value - archcpu = SNB or HSW or BGQ or Power7 or Power8 (def = none) - for CPU = SandyBridge, Haswell, BGQ, Power7, Power8 - sets KOKKOS_ARCH for GPU to appropriate value -""" - - def check(self): - print(self.inlist) - if self.inlist != None and len(self.inlist) == 0: - error("-kokkos args are invalid") - - if self.inlist == None: return - if len(self.inlist) < 1: error("-kokkos args are invalid") - self.mode = self.inlist[0] - if self.mode != "omp" and self.mode != "cuda" and self.mode != "phi": - error("-kokkos args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-kokkos args are invalid") - if words[0] == "archgpu": self.archgpu = words[1] - elif words[0] == "archcpu": self.archcpu = words[1] - else: error("-kokkos args are invalid") - -# ---------------------------------------------------------------- -# makefile classes for CC, FLAGS, MPI, JPG, PNG, FFT settings -# ---------------------------------------------------------------- - -# Cc class - -class Cc(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.compiler = self.abbrev = "" - self.wrap = "" - self.parent = "" - - def help(self): - return """ --cc compiler wrap=wcompiler,parent - alter CC setting in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - compiler is required, all other args are optional - compiler = any string with g++ or icc or icpc - or mpi (or mpicxx, mpiCC, mpiicpc, etc) - can be compiler name or full path to compiler - mpi by itself is changed to mpicxx - wcompiler = compiler for mpi wrapper to use - use nvcc for building for Kokkos/cuda with provided nvcc_wrapper - parent = openmpi or mpich - parent style determines syntax for setting low-level compiler -""" - - def check(self): - if len(self.inlist) < 1: error("-cc args are invalid") - self.compiler = self.inlist[0] - if self.compiler == "mpi": - self.compiler = "mpicxx" - self.abbrev = "mpi" - elif self.compiler.startswith("mpi"): - self.abbrev = "mpi" - elif self.compiler == "g++" or self.compiler == "icc" or \ - self.compiler == "icpc": - self.abbrev = self.compiler - elif "mpi" in self.compiler: self.abbrev = "mpi" - elif "g++" in self.compiler: self.abbrev = "g++" - elif "icc" in self.compiler: self.abbrev = "icc" - elif "icpc" in self.compiler: self.abbrev = "icpc" - else: error("-cc args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-cc args are invalid") - args = words[1].split(',') - if len(args) != 2: error("-cc args are invalid") - if words[0] == "wrap": - if self.abbrev != "mpi": error("-cc compiler is not a wrapper") - self.wrap = args[0] - self.parent = args[1] - else: error("-cc args are invalid") - -# Flags class - -class Flags(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.flags = [] - - def help(self): - return """ --flags var action N f1 f2 ... var action N f1 f2 ... - alter variable settings (flags) in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - var = CCFLAGS, LINKFLAGS, LIB, etc - any variable in Makefile.auto, must already exist - action = add or del - N = # of flags to follow - f1,f2,etc = flag to add or delete - "-" char will be prepended to each flag - for example: add 4 g O3 xHost "fp-model fast=2" - will add: -g -O3 -xHost -fp-model fast=2 - for add: if flag already exists, no change is made - for delete: flag of form "-O*", will delete any wildcard match - for -O,-O2,-O3,etc: existing -O* will first be removed -""" - - def check(self): - if len(self.inlist) < 1: error("-flags args are invalid") - narg = len(self.inlist) - i = 0 - while i < narg: - if i+3 > narg: error("-flags args are invalid") - var = self.inlist[i] - action = self.inlist[i+1] - if action != "add" and action != "del": error("-flags args are invalid") - nflag = int(self.inlist[i+2]) - i += 3 - if i+nflag > narg: error("-flags args are invalid") - flags = self.inlist[i:i+nflag] - self.flags.append([var,action,flags]) - i += nflag - -# Mpi class - -class Mpi(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.style = self.dir = "" - - def help(self): - return """ --mpi style dir=path - alter MPI settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - style is required, all other args are optional - style = mpi or mpich or ompi or serial - mpi = no MPI settings (assume compiler is MPI wrapper) - mpich = use explicit settings for MPICH - ompi = use explicit settings for OpenMPI - serial = use settings for src/STUBS library - dir = path for MPICH or OpenMPI directory - add -I and -L settings for include and lib sub-dirs -""" - - def check(self): - if len(self.inlist) < 1: error("-mpi args are invalid") - self.style = self.inlist[0] - if self.style != "mpi" and self.style != "mpich" and \ - self.style != "ompi" and self.style != "serial": - error("-mpi args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-mpi args are invalid") - if words[0] == "dir": self.dir = words[1] - else: error("-mpi args are invalid") - -# Fft class - -class Fft(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --fft mode lib=libname dir=homedir idir=incdir ldir=libdir - alter FFT settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - mode is required, all other args are optional - first removes all current FFT variable settings - mode = none or fftw or fftw3 or ... - adds -DFFT_MODE setting - lib = name of FFT library to link with (def is libname = mode) - adds -llib{libname} setting, e.g. -llibfftw3 - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - if not len(self.inlist): error("-fft args are invalid") - self.mode = self.inlist[0] - self.lib = "-l%s" % self.mode - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-fft args are invalid") - if words[0] == "lib": self.lib = "-l%s" % words[1] - elif words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-fft args are invalid") - -# Jpg class - -class Jpg(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.on = 1 - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --jpg flag dir=homedir idir=incdir ldir=libdir - alter JPG settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - change JPG settings in makefile - all args are optional, flag must come first if specified - flag = yes or no (def = yes) - include or exclude JPEG support - adds/removes -DLAMMPS_JPEG and -ljpeg settings - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - for i,one in enumerate(self.inlist): - if one == "no" and i == 0: self.on = 0 - elif one == "yes" and i == 0: self.on = 1 - else: - words = one.split('=') - if len(words) != 2: error("-jpeg args are invalid") - if words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-jpeg args are invalid") - -# Png class - -class Png(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.on = 1 - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --png flag dir=homedir idir=incdir ldir=libdir - alter PNG settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - all args are optional, flag must come first if specified - flag = yes or no (def = yes) - include or exclude PNG support - adds/removes -DLAMMPS_PNG and -lpng settings - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - for i,one in enumerate(self.inlist): - if one == "no" and i == 0: self.on = 0 - elif one == "yes" and i == 0: self.on = 1 - else: - words = one.split('=') - if len(words) != 2: error("-png args are invalid") - if words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-png args are invalid") - -# ---------------------------------------------------------------- -# auxiliary classes -# ---------------------------------------------------------------- - -# read, tweak, and write a Makefile - -class MakeReader(object): - - # read a makefile - # flag = 0 if file is full path name - # flag = 1,2 if file is suffix for any Makefile.machine under src/MAKE - # look for this file in same order that src/Makefile does - # if flag = 1, read the file - # if flag = 2, just check if file exists - - def __init__(self,file,flag=0): - if flag == 0: - if not os.path.isfile(file): error("Makefile %s does not exist" % file) - lines = open(file,'r').readlines() - else: - mfile = "%s/MAKE/MINE/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/OPTIONS/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/MACHINES/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - error("Makefile.%s does not exist" % file) - if flag == 1: lines = open(mfile,'r').readlines() - else: return - - # scan lines of makefile - # if not a variable line, just copy to newlines - # if a variable line, concatenate any continuation lines - # convert variable to var dict entry: key = name, value = list of words - # discard any portion of value string with a comment char - # varinfo = list of variable info: (name, name with whitespace for print) - # add index into varinfo to newlines - # ccindex = index of "CC =" line, to add OMPI var before it - # lmpindex = index of "LAMMPS-specific settings" - # line to add KOKKOS vars before it - - var = {} - varinfo = [] - newlines = [] - pattern = "(\S+\s+=\s+)(.*)" - conditional = 0 - multiline = 0 - self.ccindex = self.lmpindex = 0 - - for line in lines: - line = line[:-1] - if "CC =" in line: self.ccindex = len(newlines) - if "LAMMPS-specific settings" in line: self.lmpindex = len(newlines) - if "ifeq" in line: - conditional = 1 - continue - if conditional: - if "endif" in line: - conditional = 0 - continue - if multiline: - if '#' in line: line = line[:line.find('#')] - morevalues = line.split() - values = values[:-1] + morevalues - if values[-1] != '\\': - var[name] = values - multiline = 0 - newlines.append(str(len(varinfo))) - varinfo.append((name,namewhite)) - continue - varflag = 1 - if len(line.strip()) == 0: varflag = 0 - elif line.lstrip()[0] == '#': varflag = 0 - else: - m = re.match(pattern,line) - if not m: varflag = 0 - if varflag: - namewhite = m.group(1) - name = namewhite.split()[0] - if name in var: - error("Makefile variable %s appears more than once" % name) - remainder = m.group(2) - if '#' in remainder: remainder = remainder[:remainder.find('#')] - values = remainder.split() - if values and values[-1] == '\\': multiline = 1 - else: - var[name] = values - newlines.append(str(len(varinfo))) - varinfo.append((name,namewhite)) - else: - newlines.append(line) - - self.var = var - self.varinfo = varinfo - self.lines = newlines - - # return list of values associated with var - # return None if var not defined - - def getvar(self,var): - if var in self.var: return self.var[var] - else: return None - - # set var to single value - # if var not defined, error - - def setvar(self,var,value): - if var not in self.var: error("Variable %s not in makefile" % var) - self.var[var] = [value] - - # add value to var - # do not add if value already defined by var - # if var not defined, - # create new variable using "where" - # where="cc", line before "CC =" line, use ":=" - # where="lmp", 2 lines before "LAMMPS-specific settings" line, use "=" - - def addvar(self,var,value,where=""): - if var in self.var: - if value not in self.var[var]: self.var[var].append(value) - else: - if not where: - error("Variable %s with value %s is not in makefile" % (var,value)) - if where == "cc": - if not self.ccindex: error("No 'CC =' line in makefile to add variable") - index = self.ccindex - varwhite = "%s :=\t\t" % var - elif where == "lmp": - if not self.lmpindex: error("No 'LAMMPS-specific settings line' " + - "in makefile to add variable") - index = self.lmpindex - 2 - varwhite = "%s =\t\t" % var - self.var[var] = [value] - varwhite = "%s =\t\t" % var - self.lines.insert(index,str(len(self.varinfo))) - self.varinfo.append((var,varwhite)) - - # if value = None, remove entire var - # no need to update lines or varinfo, write() will ignore deleted vars - # else remove value from var - # value can have trailing '*' to remove wildcard match - # if var or value not defined, ignore it - - def delvar(self,var,value=None): - #if var == "KOKKOS_DEVICES": - # print self.var,value - if var not in self.var: return - if not value: - del self.var[var] - #print "AGAIN",self.var - elif value and value[-1] != '*': - if value not in self.var[var]: return - self.var[var].remove(value) - else: - value = value[:-1] - values = self.var[var] - dellist = [] - for i,one in enumerate(values): - if one.startswith(value): dellist.append(i) - while dellist: values.pop(dellist.pop()) - self.var[var] = values - - # write stored makefile lines to file, using vars that may have been updated - # do not write var if not in dict, since has been deleted - # wrap var values into multiple lines if needed - # file = 1 if this is Makefile.auto, change 1st line to use "auto" - - def write(self,file,flag=0): - fp = open(file,'w') - for i,line in enumerate(self.lines): - if not line.isdigit(): - if flag and i == 0: - line = "# auto = makefile auto-generated by Make.py" - print(line, file=fp) - else: - index = int(line) - name = self.varinfo[index][0] - txt = self.varinfo[index][1] - if name not in self.var: continue - values = self.var[name] - print("%s%s" % (txt,' '.join(values)), file=fp) - -# ---------------------------------------------------------------- -# main program -# ---------------------------------------------------------------- - -# parse command-line args -# switches dict: key = switch letter, value = list of args -# switch_order = list of switches in order -# will possibly be merged with redo file args below - -cmd_switches,cmd_switch_order = parse_args(sys.argv[1:]) - -if "v" in cmd_switches: - # debug - #print "Command-line parsing:" - #for switch in cmd_switch_order: - # print " %s: %s" % (switch,' '.join(cmd_switches[switch])) - pass - -# check for redo switch, process redo file -# redolist = list of commands to execute - -redoflag = 0 -redolist = [] - -if 'r' in cmd_switches and 'h' not in cmd_switches: - redoflag = 1 - redo = Redo(cmd_switches['r']) - redo.check() - redo.setup() - redolist = redo.commands - redoindex = 0 - del redo - if not redolist: error("No commands to execute from redo file") - -# loop over Make.py commands -# if no redo switch, loop once for command-line command -# if redo, loop over one or more commands from redo file - -while 1: - - # if redo: - # parse next command from redo file - # use command-line switches to add/replace file command switches - # do not add -r, since already processed - # and don't want -r swtich to appear in Make.py.last file - # if -a in both: concatenate, de-dup, - # specified exe/machine action replaces file exe/machine action - # print resulting new command - # else just use command-line switches - - if redoflag: - if redoindex == len(redolist): break - args = redolist[redoindex].split() - switches,switch_order = parse_args(args) - redoindex += 1 - - for switch in cmd_switches: - if switch == 'r': continue - if switch == 'a' and switch in switches: - tmp = Actions(cmd_switches[switch] + switches[switch]) - tmp.dedup() - switches[switch] = tmp.inlist - continue - if switch not in switches: switch_order.append(switch) - switches[switch] = cmd_switches[switch] - - argstr = switch2str(switches,switch_order) - print("Redo command: Make.py",argstr) - else: - switches = cmd_switches - switch_order = cmd_switch_order - - # initialize all class variables to None - - for one in switchclasses: exec("%s = None" % one) - for one in libclasses: exec("%s = None" % one) - for one in buildclasses: exec("%s = None" % one) - for one in makeclasses: exec("%s = None" % one) - - # classes = dictionary of created classes - # key = switch, value = class instance - - classes = {} - for switch in switches: - if len(switch) == 1 and switch in abbrevs: - i = abbrevs.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (switchclasses[i],switch,switchclasses[i].capitalize(),switch) - exec(txt) - elif switch in libclasses: - i = libclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (libclasses[i],switch,libclasses[i].upper(),switch) - exec(txt) - elif switch in buildclasses: - i = buildclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (buildclasses[i],switch,buildclasses[i].capitalize(),switch) - exec(txt) - elif switch in makeclasses: - i = makeclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (makeclasses[i],switch,makeclasses[i].capitalize(),switch) - exec(txt) - else: error("Unknown command-line switch -%s" % switch) - - # print help messages and exit - - if help or (actions and "-h" in actions.inlist) or not switches: - if not help: help = Help(None) - print(help.help()) - for switch in switch_order: - if switch == "h": continue - print(classes[switch].help()[1:]) - sys.exit() - - # create needed default classes if not specified with switch - # dir and packages plus lib and build classes so defaults are set - - if not dir: dir = Dir(None) - if not packages: packages = Packages(None) - - for one in libclasses: - txt = "if not %s: %s = %s(None)" % (one,one,one.upper()) - exec(txt) - - for one in buildclasses: - txt = "if not %s: %s = %s(None)" % (one,one,one.capitalize()) - exec(txt) - - # error check on args for all classes - - for switch in classes: classes[switch].check() - - # prep for action - # actions.setup() detects if last action = machine - # if yes, induce addition of "-m" and "-o" switches - - dir.setup() - packages.setup() - - if actions: - machine = actions.setup() - if machine: - switches['a'][-1] = "exe" - if 'm' not in switches: - switches['m'] = [machine] - switch_order.insert(-1,'m') - makefile = classes['m'] = Makefile(switches['m']) - makefile.check() - if 'o' not in switches: - switches['o'] = [machine] - switch_order.insert(-1,'o') - output = classes['o'] = Output(switches['o']) - output.check() - - # perform actions - - packages.install() - - if actions: - for action in actions.alist: - print("Action %s ..." % action) - if action.startswith("lib-"): actions.lib(action[4:]) - elif action == "file": actions.file("file") - elif action == "clean": actions.clean() - elif action == "exe": actions.exe() - - packages.uninstall() - - # create copy of executable if requested, and exe action performed - - if output and actions and "exe" in actions.alist: - txt = "cp %s/lmp_auto %s/lmp_%s" % (dir.src,dir.cwd,output.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created lmp_%s in %s" % (output.machine,dir.cwd)) - - # create copy of Makefile.auto if requested, and file or exe action performed - # ditto for library Makefile.auto and Makefile.lammps files - - if zoutput and actions and \ - ("file" in actions.alist or "exe" in actions.alist): - txt = "cp %s/MAKE/MINE/Makefile.auto %s/MAKE/MINE/Makefile.%s" % \ - (dir.src,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile.%s in %s/MAKE/MINE" % (zoutput.machine,dir.src)) - if gpubuildflag: - txt = "cp %s/gpu/Makefile.auto %s/MAKE/MINE/Makefile_gpu.%s" % \ - (dir.lib,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile_gpu.%s in %s/MAKE/MINE" % \ - (zoutput.machine,dir.src)) - txt = "cp %s/gpu/Makefile.lammps %s/MAKE/MINE/Makefile_gpu_lammps.%s" % \ - (dir.lib,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile_gpu_lammps.%s in %s/MAKE/MINE" % \ - (zoutput.machine,dir.src)) - - # write current Make.py command to src/Make.py.last - - fp = open("%s/Make.py.last" % dir.src,'w') - print("# last invoked Make.py command", file=fp) - print(switch2str(switches,switch_order), file=fp) - fp.close() - - # if not redoflag, done - - if not redoflag: break From 49e6c2eb7d4a2a04f590b866e7fbb9e2c9cfe8cc Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 13:14:03 -0400 Subject: [PATCH 148/293] remove references to Make.py from the manual and instead refer to section 4 --- doc/src/Section_accelerate.txt | 4 ++-- doc/src/accelerate_gpu.txt | 9 ++------- doc/src/accelerate_intel.txt | 11 ++++------- doc/src/accelerate_kokkos.txt | 15 ++++++--------- doc/src/accelerate_omp.txt | 10 +++------- doc/src/accelerate_opt.txt | 8 ++------ 6 files changed, 19 insertions(+), 38 deletions(-) diff --git a/doc/src/Section_accelerate.txt b/doc/src/Section_accelerate.txt index 8812358886..bb0c93b8aa 100644 --- a/doc/src/Section_accelerate.txt +++ b/doc/src/Section_accelerate.txt @@ -233,8 +233,8 @@ set any needed options for the package via "-pk" "command-line switch"_Section_s use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_6 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu :tb(c=2,s=|) -Note that the first 4 steps can be done as a single command, using the -src/Make.py tool. This tool is discussed in "Section +Note that the first 4 steps can be done as a single command with +suitable make command invocations. This is discussed in "Section 4"_Section_packages.html of the manual, and its use is illustrated in the individual accelerator sections. Typically these steps only need to be done once, to create an executable that uses one diff --git a/doc/src/accelerate_gpu.txt b/doc/src/accelerate_gpu.txt index 68e9fa477a..2723b6e971 100644 --- a/doc/src/accelerate_gpu.txt +++ b/doc/src/accelerate_gpu.txt @@ -74,13 +74,8 @@ Run lammps/lib/gpu/nvc_get_devices (after building the GPU library, see below) t This requires two steps (a,b): build the GPU library, then build LAMMPS with the GPU package. -You can do both these steps in one line, using the src/Make.py script, -described in "Section 4"_Section_packages.html of the manual. -Type "Make.py -h" for help. If run from the src directory, this -command will create src/lmp_gpu using src/MAKE/Makefile.mpi as the -starting Makefile.machine: - -Make.py -p gpu -gpu mode=single arch=31 -o gpu -a lib-gpu file mpi :pre +You can do both these steps in one line as described in +"Section 4"_Section_packages.html of the manual. Or you can follow these two (a,b) steps: diff --git a/doc/src/accelerate_intel.txt b/doc/src/accelerate_intel.txt index 74ae9d9a42..9eb295e0d0 100644 --- a/doc/src/accelerate_intel.txt +++ b/doc/src/accelerate_intel.txt @@ -225,11 +225,9 @@ source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh # or psxevars.csh for C-shell make intel_cpu_intelmpi :pre -Alternatively, the build can be accomplished with the src/Make.py -script, described in "Section 4"_Section_packages.html of the -manual. Type "Make.py -h" for help. For an example: - -Make.py -v -p intel omp -intel cpu -a file intel_cpu_intelmpi :pre +Alternatively this can be done as a single command with +suitable make command invocations. This is discussed in "Section +4"_Section_packages.html of the manual. Note that if you build with support for a Phi coprocessor, the same binary can be used on nodes with or without coprocessors installed. @@ -244,8 +242,7 @@ highly recommended for CCFLAGS and LINKFLAGS. LIB should include is required for CCFLAGS and "-qoffload" is required for LINKFLAGS. Other recommended CCFLAG options for best performance are "-O2 -fno-alias -ansi-alias -qoverride-limits fp-model fast=2 --no-prec-div". The Make.py command will add all of these -automatically. +-no-prec-div". NOTE: The vectorization and math capabilities can differ depending on the CPU. For Intel compilers, the "-x" flag specifies the type of diff --git a/doc/src/accelerate_kokkos.txt b/doc/src/accelerate_kokkos.txt index 6ccd695841..712a05300c 100644 --- a/doc/src/accelerate_kokkos.txt +++ b/doc/src/accelerate_kokkos.txt @@ -60,8 +60,7 @@ More details follow. use a C++11 compatible compiler make yes-kokkos make mpi KOKKOS_DEVICES=OpenMP # build with the KOKKOS package -make kokkos_omp # or Makefile.kokkos_omp already has variable set -Make.py -v -p kokkos -kokkos omp -o mpi -a file mpi # or one-line build via Make.py :pre +make kokkos_omp # or Makefile.kokkos_omp already has variable set :pre mpirun -np 16 lmp_mpi -k on -sf kk -in in.lj # 1 node, 16 MPI tasks/node, no threads mpirun -np 2 -ppn 1 lmp_mpi -k on t 16 -sf kk -in in.lj # 2 nodes, 1 MPI task/node, 16 threads/task @@ -82,8 +81,7 @@ use a C++11 compatible compiler KOKKOS_DEVICES = Cuda, OpenMP KOKKOS_ARCH = Kepler35 make yes-kokkos -make machine -Make.py -p kokkos -kokkos cuda arch=31 -o kokkos_cuda -a file kokkos_cuda :pre +make machine :pre mpirun -np 1 lmp_cuda -k on t 6 -sf kk -in in.lj # one MPI task, 6 threads on CPU mpirun -np 4 -ppn 1 lmp_cuda -k on t 6 -sf kk -in in.lj # ditto on 4 nodes :pre @@ -98,8 +96,7 @@ use a C++11 compatible compiler KOKKOS_DEVICES = OpenMP KOKKOS_ARCH = KNC make yes-kokkos -make machine -Make.py -p kokkos -kokkos phi -o kokkos_phi -a file mpi :pre +make machine :pre host=MIC, Intel Phi with 61 cores (240 threads/phi via 4x hardware threading): mpirun -np 1 lmp_g++ -k on t 240 -sf kk -in in.lj # 1 MPI task on 1 Phi, 1*240 = 240 @@ -135,9 +132,9 @@ mode like the USER-INTEL package supports. You must choose at build time whether to build for CPUs (OpenMP), GPUs, or Phi. -You can do any of these in one line, using the src/Make.py script, -described in "Section 4"_Section_packages.html of the manual. -Type "Make.py -h" for help. If run from the src directory, these +You can do any of these in one line, using the suitable make command +line flags as described in "Section 4"_Section_packages.html of the +manual. If run from the src directory, these commands will create src/lmp_kokkos_omp, lmp_kokkos_cuda, and lmp_kokkos_phi. Note that the OMP and PHI options use src/MAKE/Makefile.mpi as the starting Makefile.machine. The CUDA diff --git a/doc/src/accelerate_omp.txt b/doc/src/accelerate_omp.txt index 81b7a5adc2..fa7bef1a52 100644 --- a/doc/src/accelerate_omp.txt +++ b/doc/src/accelerate_omp.txt @@ -23,8 +23,7 @@ one or more 16-core nodes. More details follow. use -fopenmp with CCFLAGS and LINKFLAGS in Makefile.machine make yes-user-omp make mpi # build with USER-OMP package, if settings added to Makefile.mpi -make omp # or Makefile.omp already has settings -Make.py -v -p omp -o mpi -a file mpi # or one-line build via Make.py :pre +make omp # or Makefile.omp already has settings :pre lmp_mpi -sf omp -pk omp 16 < in.script # 1 MPI task, 16 threads mpirun -np 4 lmp_mpi -sf omp -pk omp 4 -in in.script # 4 MPI tasks, 4 threads/task @@ -40,14 +39,11 @@ each MPI task running on a CPU. The lines above illustrate how to include/build with the USER-OMP package in two steps, using the "make" command. Or how to do it with -one command via the src/Make.py script, described in "Section -4"_Section_packages.html of the manual. Type "Make.py -h" for -help. +one command as described in "Section 4"_Section_packages.html of the manual. Note that the CCFLAGS and LINKFLAGS settings in Makefile.machine must include "-fopenmp". Likewise, if you use an Intel compiler, the -CCFLAGS setting must include "-restrict". The Make.py command will -add these automatically. +CCFLAGS setting must include "-restrict". [Run with the USER-OMP package from the command line:] diff --git a/doc/src/accelerate_opt.txt b/doc/src/accelerate_opt.txt index 5a2a5eac0a..845264b522 100644 --- a/doc/src/accelerate_opt.txt +++ b/doc/src/accelerate_opt.txt @@ -21,8 +21,7 @@ Here is a quick overview of how to use the OPT package. More details follow. make yes-opt -make mpi # build with the OPT package -Make.py -v -p opt -o mpi -a file mpi # or one-line build via Make.py :pre +make mpi # build with the OPT package :pre lmp_mpi -sf opt -in in.script # run in serial mpirun -np 4 lmp_mpi -sf opt -in in.script # run in parallel :pre @@ -35,13 +34,10 @@ None. The lines above illustrate how to build LAMMPS with the OPT package in two steps, using the "make" command. Or how to do it with one command -via the src/Make.py script, described in "Section -4"_Section_packages.html of the manual. Type "Make.py -h" for -help. +as described in "Section 4"_Section_packages.html of the manual. Note that if you use an Intel compiler to build with the OPT package, the CCFLAGS setting in your Makefile.machine must include "-restrict". -The Make.py command will add this automatically. [Run with the OPT package from the command line:] From 49b4cf9a770cd407ff8c32426c537998bf9f1eb6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 13:24:32 -0400 Subject: [PATCH 149/293] remove references to Make.py and USER-CUDA --- bench/FERMI/README | 66 ++++---------------------------------- bench/README | 46 +++++++++----------------- examples/README | 11 +------ examples/accelerate/README | 64 ++++-------------------------------- 4 files changed, 29 insertions(+), 158 deletions(-) diff --git a/bench/FERMI/README b/bench/FERMI/README index db3f527bdc..b66e560775 100644 --- a/bench/FERMI/README +++ b/bench/FERMI/README @@ -1,55 +1,21 @@ These are input scripts used to run versions of several of the -benchmarks in the top-level bench directory using the GPU and -USER-CUDA accelerator packages. The results of running these scripts -on two different machines (a desktop with 2 Tesla GPUs and the ORNL -Titan supercomputer) are shown on the "GPU (Fermi)" section of the -Benchmark page of the LAMMPS WWW site: lammps.sandia.gov/bench. +benchmarks in the top-level bench directory using the GPU accelerator +package. The results of running these scripts on two different machines +(a desktop with 2 Tesla GPUs and the ORNL Titan supercomputer) are shown +on the "GPU (Fermi)" section of the Benchmark page of the LAMMPS WWW +site: lammps.sandia.gov/bench. Examples are shown below of how to run these scripts. This assumes -you have built 3 executables with both the GPU and USER-CUDA packages +you have built 3 executables with the GPU package installed, e.g. lmp_linux_single lmp_linux_mixed lmp_linux_double -The precision (single, mixed, double) refers to the GPU and USER-CUDA -package precision. See the README files in the lib/gpu and lib/cuda -directories for instructions on how to build the packages with -different precisions. The GPU and USER-CUDA sub-sections of the -doc/Section_accelerate.html file also describes this process. - -Make.py -d ~/lammps -j 16 -p #all orig -m linux -o cpu -a exe -Make.py -d ~/lammps -j 16 -p #all opt orig -m linux -o opt -a exe -Make.py -d ~/lammps -j 16 -p #all omp orig -m linux -o omp -a exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=double arch=20 -o gpu_double -a libs exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=mixed arch=20 -o gpu_mixed -a libs exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=single arch=20 -o gpu_single -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=double arch=20 -o cuda_double -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=mixed arch=20 -o cuda_mixed -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=single arch=20 -o cuda_single -a libs exe -Make.py -d ~/lammps -j 16 -p #all intel orig -m linux -o intel_cpu -a exe -Make.py -d ~/lammps -j 16 -p #all kokkos orig -m linux -o kokkos_omp -a exe -Make.py -d ~/lammps -j 16 -p #all kokkos orig -kokkos cuda arch=20 \ - -m cuda -o kokkos_cuda -a exe - -Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \ - -gpu mode=double arch=20 -cuda mode=double arch=20 -m linux \ - -o all -a libs exe - -Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \ - -kokkos cuda arch=20 -gpu mode=double arch=20 \ - -cuda mode=double arch=20 -m cuda -o all_cuda -a libs exe - ------------------------------------------------------------------------ -To run on just CPUs (without using the GPU or USER-CUDA styles), +To run on just CPUs (without using the GPU styles), do something like the following: mpirun -np 1 lmp_linux_double -v x 8 -v y 8 -v z 8 -v t 100 < in.lj @@ -81,23 +47,5 @@ node via a "-ppn" setting. ------------------------------------------------------------------------ -To run with the USER-CUDA package, do something like the following: - -mpirun -np 1 lmp_linux_single -c on -sf cuda -v x 16 -v y 16 -v z 16 -v t 100 < in.lj -mpirun -np 2 lmp_linux_double -c on -sf cuda -pk cuda 2 -v x 32 -v y 64 -v z 64 -v t 100 < in.eam - -The "xyz" settings determine the problem size. The "t" setting -determines the number of timesteps. The "np" setting determines how -many MPI tasks (per node) the problem will run on. The numeric -argument to the "-pk" setting is the number of GPUs (per node); 1 GPU -is the default. Note that the number of MPI tasks must equal the -number of GPUs (both per node) with the USER-CUDA package. - -These mpirun commands run on a single node. To run on multiple nodes, -scale up the "-np" setting, and control the number of MPI tasks per -node via a "-ppn" setting. - ------------------------------------------------------------------------- - If the script has "titan" in its name, it was run on the Titan supercomputer at ORNL. diff --git a/bench/README b/bench/README index 85d71cbb5d..0806fcded6 100644 --- a/bench/README +++ b/bench/README @@ -71,49 +71,33 @@ integration ---------------------------------------------------------------------- -Here is a src/Make.py command which will perform a parallel build of a -LAMMPS executable "lmp_mpi" with all the packages needed by all the -examples. This assumes you have an MPI installed on your machine so -that "mpicxx" can be used as the wrapper compiler. It also assumes -you have an Intel compiler to use as the base compiler. You can leave -off the "-cc mpi wrap=icc" switch if that is not the case. You can -also leave off the "-fft fftw3" switch if you do not have the FFTW -(v3) installed as an FFT package, in which case the default KISS FFT -library will be used. - -cd src -Make.py -j 16 -p none molecule manybody kspace granular rigid orig \ - -cc mpi wrap=icc -fft fftw3 -a file mpi - ----------------------------------------------------------------------- - Here is how to run each problem, assuming the LAMMPS executable is named lmp_mpi, and you are using the mpirun command to launch parallel runs: Serial (one processor runs): -lmp_mpi < in.lj -lmp_mpi < in.chain -lmp_mpi < in.eam -lmp_mpi < in.chute -lmp_mpi < in.rhodo +lmp_mpi -in in.lj +lmp_mpi -in in.chain +lmp_mpi -in in.eam +lmp_mpi -in in.chute +lmp_mpi -in in.rhodo Parallel fixed-size runs (on 8 procs in this case): -mpirun -np 8 lmp_mpi < in.lj -mpirun -np 8 lmp_mpi < in.chain -mpirun -np 8 lmp_mpi < in.eam -mpirun -np 8 lmp_mpi < in.chute -mpirun -np 8 lmp_mpi < in.rhodo +mpirun -np 8 lmp_mpi -in in.lj +mpirun -np 8 lmp_mpi -in in.chain +mpirun -np 8 lmp_mpi -in in.eam +mpirun -np 8 lmp_mpi -in in.chute +mpirun -np 8 lmp_mpi -in in.rhodo Parallel scaled-size runs (on 16 procs in this case): -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.lj -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.chain.scaled -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.eam -mpirun -np 16 lmp_mpi -var x 4 -var y 4 < in.chute.scaled -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.rhodo.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.lj +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.chain.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.eam +mpirun -np 16 lmp_mpi -var x 4 -var y 4 -in in.chute.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.rhodo.scaled For each of the scaled-size runs you must set 3 variables as -var command line switches. The variables x,y,z are used in the input diff --git a/examples/README b/examples/README index 0ec28aa2c2..dc622ef7c4 100644 --- a/examples/README +++ b/examples/README @@ -106,20 +106,11 @@ tad: temperature-accelerated dynamics of vacancy diffusion in bulk Si vashishta: models using the Vashishta potential voronoi: Voronoi tesselation via compute voronoi/atom command -Here is a src/Make.py command which will perform a parallel build of a -LAMMPS executable "lmp_mpi" with all the packages needed by all the -examples, with the exception of the accelerate sub-directory. See the -accelerate/README for Make.py commands suitable for its example -scripts. - -cd src -Make.py -j 16 -p none std no-lib reax meam poems reaxc orig -a lib-all mpi - Here is how you might run and visualize one of the sample problems: cd indent cp ../../src/lmp_mpi . # copy LAMMPS executable to this dir -lmp_mpi < in.indent # run the problem +lmp_mpi -in in.indent # run the problem Running the simulation produces the files {dump.indent} and {log.lammps}. You can visualize the dump file as follows: diff --git a/examples/accelerate/README b/examples/accelerate/README index 1fab296a53..c4eb5dcc8d 100644 --- a/examples/accelerate/README +++ b/examples/accelerate/README @@ -1,14 +1,11 @@ These are example scripts that can be run with any of the acclerator packages in LAMMPS: -USER-CUDA, GPU, USER-INTEL, KOKKOS, USER-OMP, OPT +GPU, USER-INTEL, KOKKOS, USER-OMP, OPT The easiest way to build LAMMPS with these packages -is via the src/Make.py tool described in Section 2.4 -of the manual. You can also type "Make.py -h" to see -its options. The easiest way to run these scripts -is by using the appropriate - +is via the flags described in Section 4 of the manual. +The easiest way to run these scripts is by using the appropriate Details on the individual accelerator packages can be found in doc/Section_accelerate.html. @@ -16,21 +13,6 @@ can be found in doc/Section_accelerate.html. Build LAMMPS with one or more of the accelerator packages -The following command will invoke the src/Make.py tool with one of the -command-lines from the Make.list file: - -../../src/Make.py -r Make.list target - -target = one or more of the following: - cpu, omp, opt - cuda_double, cuda_mixed, cuda_single - gpu_double, gpu_mixed, gpu_single - intel_cpu, intel_phi - kokkos_omp, kokkos_cuda, kokkos_phi - -If successful, the build will produce the file lmp_target in this -directory. - Note that in addition to any accelerator packages, these packages also need to be installed to run all of the example scripts: ASPHERE, MOLECULE, KSPACE, RIGID. @@ -38,39 +20,11 @@ MOLECULE, KSPACE, RIGID. These two targets will build a single LAMMPS executable with all the CPU accelerator packages installed (USER-INTEL for CPU, KOKKOS for OMP, USER-OMP, OPT) or all the GPU accelerator packages installed -(USER-CUDA, GPU, KOKKOS for CUDA): +(GPU, KOKKOS for CUDA): -target = all_cpu, all_gpu - -Note that the Make.py commands in Make.list assume an MPI environment -exists on your machine and use mpicxx as the wrapper compiler with -whatever underlying compiler it wraps by default. If you add "-cc mpi -wrap=g++" or "-cc mpi wrap=icc" after the target, you can choose the -underlying compiler for mpicxx to invoke. E.g. - -../../src/Make.py -r Make.list intel_cpu -cc mpi wrap=icc - -You should do this for any build that includes the USER-INTEL -package, since it will perform best with the Intel compilers. - -Note that for kokkos_cuda, it needs to be "-cc nvcc" instead of "mpi", -since a KOKKOS for CUDA build requires NVIDIA nvcc as the wrapper -compiler. - -Also note that the Make.py commands in Make.list use the default -FFT support which is via the KISS library. If you want to -build with another FFT library, e.g. FFTW3, then you can add -"-fft fftw3" after the target, e.g. - -../../src/Make.py -r Make.list gpu -fft fftw3 - -For any build with USER-CUDA, GPU, or KOKKOS for CUDA, be sure to set +For any build with GPU, or KOKKOS for CUDA, be sure to set the arch=XX setting to the appropriate value for the GPUs and Cuda -environment on your system. What is defined in the Make.list file is -arch=21 for older Fermi GPUs. This can be overridden as follows, -e.g. for Kepler GPUs: - -../../src/Make.py -r Make.list gpu_double -gpu mode=double arch=35 +environment on your system. --------------------- @@ -118,12 +72,6 @@ Note that when running in.lj.5.0 (which has a long cutoff) with the GPU package, the "-pk tpa" setting should be > 1 (e.g. 8) for best performance. -** USER-CUDA package - -lmp_machine -c on -sf cuda < in.lj -mpirun -np 1 lmp_machine -c on -sf cuda < in.lj # 1 MPI, 1 MPI/GPU -mpirun -np 2 lmp_machine -c on -sf cuda -pk cuda 2 < in.lj # 2 MPI, 1 MPI/GPU - ** KOKKOS package for OMP lmp_kokkos_omp -k on t 1 -sf kk -pk kokkos neigh half < in.lj From 02572a4099a6dfc6dc7ddae2c908446a54a491b3 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 14:41:38 -0400 Subject: [PATCH 150/293] add workaround that allows pair style quip to work with -DLAMMPS_BIGBIG, assuming tags are still only 32-bit signed integer --- src/USER-QUIP/pair_quip.cpp | 47 +++++++++++++++++++++++-------------- src/USER-QUIP/pair_quip.h | 5 ---- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index ccd71235e7..fa946641a5 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -125,26 +125,37 @@ void PairQUIP::compute(int eflag, int vflag) lattice[8] = domain->zprd; #if defined(LAMMPS_BIGBIG) - error->all(FLERR,"Pair style quip does not support -DLAMMPS_BIGBIG"); - // quip_lammps_longint_wrapper( - // (&nlocal,&nghost,atomic_numbers,tag, - // &inum,&sum_num_neigh,ilist, - // quip_num_neigh,quip_neigh,lattice, - // quip_potential,&n_quip_potential,&x[0][0], - // &quip_energy,quip_local_e,quip_virial,quip_local_virial,quip_force); + int *tmptag = new int[ntotal]; + int tmplarge = 0, toolarge = 0; + for (ii = 0; ii < ntotal; ++ii) { + tmptag[ii] = tag[ii]; + if (tag[ii] > MAXSMALLINT) tmplarge=1; + } + MPI_Allreduce(&tmplarge,&toolarge,1,MPI_INT,MPI_MAX,comm); + if (toolarge > 0) + error->all(FLERR,"Pair style quip does not support 64-bit atom IDs"); + + quip_lammps_wrapper(&nlocal,&nghost,atomic_numbers,tmptag, + &inum,&sum_num_neigh,ilist, + quip_num_neigh,quip_neigh,lattice, + quip_potential,&n_quip_potential,&x[0][0], + &quip_energy,quip_local_e,quip_virial, + quip_local_virial,quip_force); + + delete[] tmptag; #else - quip_lammps_wrapper - (&nlocal,&nghost,atomic_numbers,tag, - &inum,&sum_num_neigh,ilist, - quip_num_neigh,quip_neigh,lattice, - quip_potential,&n_quip_potential,&x[0][0], - &quip_energy,quip_local_e,quip_virial,quip_local_virial,quip_force); + quip_lammps_wrapper(&nlocal,&nghost,atomic_numbers,tag, + &inum,&sum_num_neigh,ilist, + quip_num_neigh,quip_neigh,lattice, + quip_potential,&n_quip_potential,&x[0][0], + &quip_energy,quip_local_e,quip_virial, + quip_local_virial,quip_force); #endif iquip = 0; for (ii = 0; ii < ntotal; ii++) { for( jj = 0; jj < 3; jj++ ) { - f[ii][jj] = quip_force[iquip]; + f[ii][jj] += quip_force[iquip]; iquip++; } } @@ -175,11 +186,11 @@ void PairQUIP::compute(int eflag, int vflag) vatom[ii][1] += quip_local_virial[iatom+4]; vatom[ii][2] += quip_local_virial[iatom+8]; vatom[ii][3] += (quip_local_virial[iatom+3] + - quip_local_virial[iatom+1])*0.5; + quip_local_virial[iatom+1])*0.5; vatom[ii][4] += (quip_local_virial[iatom+2] + - quip_local_virial[iatom+6])*0.5; + quip_local_virial[iatom+6])*0.5; vatom[ii][5] += (quip_local_virial[iatom+5] + - quip_local_virial[iatom+7])*0.5; + quip_local_virial[iatom+7])*0.5; iatom += 9; } } @@ -202,6 +213,8 @@ void PairQUIP::compute(int eflag, int vflag) void PairQUIP::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR,"Illegal pair_style command"); + if (strncmp(force->pair->style,"hybrid",6) == 0) + error->all(FLERR,"Pair style quip is not compatible with hybrid styles"); } /* ---------------------------------------------------------------------- diff --git a/src/USER-QUIP/pair_quip.h b/src/USER-QUIP/pair_quip.h index c785792410..985a43fd7e 100644 --- a/src/USER-QUIP/pair_quip.h +++ b/src/USER-QUIP/pair_quip.h @@ -29,11 +29,6 @@ extern "C" int*, int*, double*, int*, int*, double*, double*, double*, double*, double*, double*); - // void quip_lammps_longint_wrapper(int*, int*, int*, int64_t*, - // int*, int*, int*, - // int*, int*, double*, - // int*, int*, double*, - // double*, double*, double*, double*, double*); void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*); } From 5cbaf7ca1d3218d6c0cbb9529ae7b0c01fd804ce Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 14:47:54 -0400 Subject: [PATCH 151/293] correct commands table format issue --- doc/src/Section_commands.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/Section_commands.txt b/doc/src/Section_commands.txt index 7dc3d27b6a..f1eb225fe5 100644 --- a/doc/src/Section_commands.txt +++ b/doc/src/Section_commands.txt @@ -734,8 +734,8 @@ package"_Section_start.html#start_3. "smd/wall/surface"_fix_smd_wall_surface.html, "temp/rescale/eff"_fix_temp_rescale_eff.html, "ti/spring"_fix_ti_spring.html, -"ttm/mod"_fix_ttm.html -"wall/ees"_fix_wall_ees.html +"ttm/mod"_fix_ttm.html, +"wall/ees"_fix_wall_ees.html, "wall/region/ees"_fix_wall_ees.html :tb(c=6,ea=c) :line From a9eaeb4d95a896e5ccb60b424152913e250d43d6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 13:47:03 -0600 Subject: [PATCH 152/293] working on GPU build --- cmake/CMakeLists.txt | 29 ++++++++++++++++++++++++++--- lib/gpu/lal_pppm.cu | 5 +++++ 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 17759cbb65..0212e3906d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -421,7 +421,16 @@ endif() if(ENABLE_GPU) find_package(CUDA REQUIRED) + find_program(BIN2C bin2c) + if(NOT BIN2C) + message(FATAL_ERROR "Couldn't find bin2c") + endif() include_directories(${CUDA_TOOLKIT_INCLUDE}) + set(CUDA_BUILD_CUBIN ON) + set(GPU_PREC "SINGLE_DOUBLE" CACHE STRING "Lammps gpu precision size") + set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) + add_definitions(-D_${GPU_PREC}) + add_definitions(-DNV_KERNEL -DUSE_CUDPP -DUCL_CUDADR -DCMAKE_GPU) set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) @@ -432,15 +441,29 @@ if(ENABLE_GPU) RegisterStylesExt(${GPU_SOURCES_DIR} opt GPU_SOURCES) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) - file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) cuda_add_library(lammps_gpu ${GPU_LIB_SOURCES}) - + #add_custom_target(cubin_headers) + #file(GLOB_RECURSE GPU_LIB_CUBIN ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cubin) + #file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) + #foreach(CUBIN ${GPU_LIB_CUBIN}) + # get_filename_component(CUBIN_NAME NAME_WE ${CUBIN}) + # message("XXX ${CUBIN_NAME}_cubin.h") + # add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR/gpu/${CUBIN_NAME}_cubin.h + # COMMAND ${BIN2C} -c -n ${CUBIN_NAME} ${CUBIN} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CUBIN_NAME}_cubin.h + # DEPENDS ${CUBIN} + # COMMENT "Generating ${CUBIN_NAME}_cubin.h") + # add_custom_target(${CUBIN_NAME}_cubin DEPENDS ${LAMMPS_LIB_BINARY_DIR/gpu/${CUBIN_NAME}_cubin.h) + # add_dependencies(cubin_headers ${CUBIN_NAME}_cubin) + #endforeach() + #add_dependencies(lammps_gpu cubin_headers) + list(APPEND LAMMPS_LINK_LIBS lammps_gpu) list(APPEND LIB_SOURCES ${GPU_SOURCES}) - include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu) + include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu + ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) endif() ###################################################### diff --git a/lib/gpu/lal_pppm.cu b/lib/gpu/lal_pppm.cu index 24636b9a93..fede2180cf 100644 --- a/lib/gpu/lal_pppm.cu +++ b/lib/gpu/lal_pppm.cu @@ -13,6 +13,11 @@ // email : brownw@ornl.gov // ***************************************************************************/ +#ifdef CMAKE_GPU +#define grdtyp float +#define grdtyp4 float4 +#endif + #ifdef NV_KERNEL #include "lal_preprocessor.h" From f96b9e0dcf555319b94e4397f103cf197cd4c988 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 15:48:18 -0400 Subject: [PATCH 153/293] add various checks and improvements to identify incompatible uses and warn or exit with error message --- src/USER-QUIP/pair_quip.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index fa946641a5..7e178c7a64 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -42,6 +42,7 @@ PairQUIP::PairQUIP(LAMMPS *lmp) : Pair(lmp) single_enable = 0; one_coeff = 1; no_virial_fdotr_compute = 1; + manybody_flag = 1; } PairQUIP::~PairQUIP() @@ -99,7 +100,7 @@ void PairQUIP::compute(int eflag, int vflag) jnum = numneigh[i]; for (jj = 0; jj < jnum; jj++) { - quip_neigh[iquip] = jlist[jj]+1; + quip_neigh[iquip] = (jlist[jj] & NEIGHMASK) + 1; iquip++; } } @@ -131,7 +132,7 @@ void PairQUIP::compute(int eflag, int vflag) tmptag[ii] = tag[ii]; if (tag[ii] > MAXSMALLINT) tmplarge=1; } - MPI_Allreduce(&tmplarge,&toolarge,1,MPI_INT,MPI_MAX,comm); + MPI_Allreduce(&tmplarge,&toolarge,1,MPI_INT,MPI_MAX,world); if (toolarge > 0) error->all(FLERR,"Pair style quip does not support 64-bit atom IDs"); @@ -213,7 +214,7 @@ void PairQUIP::compute(int eflag, int vflag) void PairQUIP::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR,"Illegal pair_style command"); - if (strncmp(force->pair->style,"hybrid",6) == 0) + if (strncmp(force->pair_style,"hybrid",6) == 0) error->all(FLERR,"Pair style quip is not compatible with hybrid styles"); } From 17aff29fe2e70bbb68d44b0b92ecb105124bdd86 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 15:48:31 -0400 Subject: [PATCH 154/293] fix off-by-one bug when copying strings --- src/USER-QUIP/pair_quip.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index 7e178c7a64..c6ab8b259b 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -255,11 +255,11 @@ void PairQUIP::coeff(int narg, char **arg) error->all(FLERR,"Incorrect args for pair coefficients"); n_quip_file = strlen(arg[2]); - quip_file = new char[n_quip_file]; + quip_file = new char[n_quip_file+1]; strcpy(quip_file,arg[2]); n_quip_string = strlen(arg[3]); - quip_string = new char[n_quip_string]; + quip_string = new char[n_quip_string+1]; strcpy(quip_string,arg[3]); for (int i = 4; i < narg; i++) { From 148364949e21685af899a9a94f9c13c5fc201806 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 16:11:49 -0400 Subject: [PATCH 155/293] fix memory corruption issue in fix reax/c/species --- src/USER-REAXC/fix_reaxc_species.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/USER-REAXC/fix_reaxc_species.cpp b/src/USER-REAXC/fix_reaxc_species.cpp index 62b3bff93e..181c9bcd31 100644 --- a/src/USER-REAXC/fix_reaxc_species.cpp +++ b/src/USER-REAXC/fix_reaxc_species.cpp @@ -195,8 +195,10 @@ FixReaxCSpecies::FixReaxCSpecies(LAMMPS *lmp, int narg, char **arg) : if (iarg+ntypes+1 > narg) error->all(FLERR,"Illegal fix reax/c/species command"); eletype = (char**) malloc(ntypes*sizeof(char*)); + int len; for (int i = 0; i < ntypes; i ++) { - eletype[i] = (char*) malloc(2*sizeof(char)); + len = strlen(arg[iarg+1+i])+1; + eletype[i] = (char*) malloc(len*sizeof(char)); strcpy(eletype[i],arg[iarg+1+i]); } eleflag = 1; From 03cd4c5255573463cfc5448a87cdc870364b5ed7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 17:16:10 -0400 Subject: [PATCH 156/293] ported lib/voronoi/Install.py to python 3.x and tested with 2.7 --- lib/voronoi/Install.py | 57 +++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 26 deletions(-) diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 54246f113e..64122c9d5b 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -2,8 +2,10 @@ # Install.py tool to download, unpack, build, and link to the Voro++ library # used to automate the steps described in the README file in this dir - -import sys,os,re,urllib,commands +from __future__ import print_function +import sys,os,re,subprocess +try: from urllib.request import urlretrieve as geturl +except: from urllib import urlretrieve as geturl # help message @@ -39,8 +41,8 @@ url = "http://math.lbl.gov/voro++/download/dir/%s.tar.gz" % version # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # expand to full path name @@ -58,9 +60,9 @@ if nargs == 0: error() homepath = "." homedir = version -grabflag = 0 -buildflag = 0 -linkflag = 0 +grabflag = False +buildflag = False +linkflag = False iarg = 0 while iarg < nargs: @@ -74,13 +76,13 @@ while iarg < nargs: homedir = args[iarg+2] iarg += 3 elif args[iarg] == "-g": - grabflag = 1 + grabflag = True iarg += 1 elif args[iarg] == "-b": - buildflag = 1 + buildflag = True iarg += 1 elif args[iarg] == "-l": - linkflag = 1 + linkflag = True iarg += 1 else: error() @@ -91,35 +93,38 @@ homedir = "%s/%s" % (homepath,homedir) # download and unpack Voro++ tarball if grabflag: - print "Downloading Voro++ ..." - urllib.urlretrieve(url,"%s/%s.tar.gz" % (homepath,version)) + print("Downloading Voro++ ...") + geturl(url,"%s/%s.tar.gz" % (homepath,version)) - print "Unpacking Voro++ tarball ..." + print("Unpacking Voro++ tarball ...") if os.path.exists("%s/%s" % (homepath,version)): - commands.getoutput("rm -rf %s/%s" % (homepath,version)) - cmd = "cd %s; tar zxvf %s.tar.gz" % (homepath,version) - commands.getoutput(cmd) + cmd = ['rm -rf "%s/%s"' % (homepath,version)] + subprocess.check_output(cmd,shell=True) + cmd = ['cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version)] + subprocess.check_output(cmd,shell=True) if os.path.basename(homedir) != version: - if os.path.exists(homedir): commands.getoutput("rm -rf %s" % homedir) + if os.path.exists(homedir): + cmd = ['rm -rf "%s"' % homedir] + subprocess.check_output(cmd,shell=True) os.rename("%s/%s" % (homepath,version),homedir) # build Voro++ if buildflag: - print "Building Voro++ ..." - cmd = "cd %s; make" % homedir - txt = commands.getoutput(cmd) - print txt + print("Building Voro++ ...") + cmd = ['cd "%s"; make' % homedir] + txt = subprocess.check_output(cmd,shell=True) + print(txt) # create 2 links in lib/voronoi to Voro++ src dir if linkflag: - print "Creating links to Voro++ include and lib files" + print("Creating links to Voro++ include and lib files") if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") if os.path.isfile("liblink") or os.path.islink("liblink"): os.remove("liblink") - cmd = "ln -s %s/src includelink" % homedir - commands.getoutput(cmd) - cmd = "ln -s %s/src liblink" % homedir - commands.getoutput(cmd) + cmd = ['ln -s "%s/src" includelink' % homedir, 'includelink'] + subprocess.check_output(cmd,shell=True) + cmd = ['ln -s "%s/src" liblink' % homedir] + subprocess.check_output(cmd,shell=True) From 7ccb0d37cdd65ad1c523a104a90aea69162f26a6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 17:37:48 -0400 Subject: [PATCH 157/293] port USER-SMD folder. make voronoi consistent with it --- lib/smd/Install.py | 34 +++++++++++++++++++--------------- lib/voronoi/Install.py | 8 ++++---- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/lib/smd/Install.py b/lib/smd/Install.py index e6fe8926a4..0fa05375db 100644 --- a/lib/smd/Install.py +++ b/lib/smd/Install.py @@ -3,7 +3,10 @@ # Install.py tool to download, unpack, and point to the Eigen library # used to automate the steps described in the README file in this dir -import sys,os,re,glob,commands +from __future__ import print_function +import sys,os,re,glob,subprocess +try: from urllib.request import urlretrieve as geturl +except: from urllib import urlretrieve as geturl # help message @@ -30,14 +33,15 @@ make lib-smd args="-g -l" # download/build in default lib/smd/eigen-eigen-* # settings -url = "http://bitbucket.org/eigen/eigen/get/3.3.3.tar.gz" +version = '3.3.4' +url = "http://bitbucket.org/eigen/eigen/get/%s.tar.gz" % version tarball = "eigen.tar.gz" # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # expand to full path name @@ -80,26 +84,26 @@ if not os.path.isdir(homepath): error("Eigen path does not exist") # glob to find name of dir it unpacks to if grabflag: - print "Downloading Eigen ..." - cmd = "curl -L %s > %s/%s" % (url,homepath,tarball) - print cmd - print commands.getoutput(cmd) + print("Downloading Eigen ...") + geturl(url,"%s/%s" % (homepath,tarball)) - print "Unpacking Eigen tarball ..." + print("Unpacking Eigen tarball ...") edir = glob.glob("%s/eigen-eigen-*" % homepath) for one in edir: - if os.path.isdir(one): commands.getoutput("rm -rf %s" % one) - cmd = "cd %s; tar zxvf %s" % (homepath,tarball) - commands.getoutput(cmd) + if os.path.isdir(one): + subprocess.check_output("rm -rf %s" % one,shell=True) + cmd = 'cd "%s"; tar -xzvf %s' % (homepath,tarball) + subprocess.check_output(cmd,shell=True) if homedir != "ee": - if os.path.exists(homedir): commands.getoutput("rm -rf %s" % homedir) + if os.path.exists(homedir): + subprocess.check_output("rm -rf %s" % homedir,shell=True) edir = glob.glob("%s/eigen-eigen-*" % homepath) os.rename(edir[0],"%s/%s" % (homepath,homedir)) # create link in lib/smd to Eigen src dir if linkflag: - print "Creating link to Eigen files" + print("Creating link to Eigen files") if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") if homedir == "ee": @@ -107,4 +111,4 @@ if linkflag: linkdir = edir[0] else: linkdir = "%s/%s" % (homepath,homedir) cmd = "ln -s %s includelink" % linkdir - commands.getoutput(cmd) + subprocess.check_output(cmd,shell=True) diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 64122c9d5b..1c4bc5cb6d 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -98,13 +98,13 @@ if grabflag: print("Unpacking Voro++ tarball ...") if os.path.exists("%s/%s" % (homepath,version)): - cmd = ['rm -rf "%s/%s"' % (homepath,version)] + cmd = 'rm -rf "%s/%s"' % (homepath,version) subprocess.check_output(cmd,shell=True) - cmd = ['cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version)] + cmd = 'cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version) subprocess.check_output(cmd,shell=True) if os.path.basename(homedir) != version: if os.path.exists(homedir): - cmd = ['rm -rf "%s"' % homedir] + cmd = 'rm -rf "%s"' % homedir subprocess.check_output(cmd,shell=True) os.rename("%s/%s" % (homepath,version),homedir) @@ -112,7 +112,7 @@ if grabflag: if buildflag: print("Building Voro++ ...") - cmd = ['cd "%s"; make' % homedir] + cmd = 'cd "%s"; make' % homedir txt = subprocess.check_output(cmd,shell=True) print(txt) From c3d9786616c62c40d6d03347436855dd67a4e718 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 16:01:35 -0600 Subject: [PATCH 158/293] GPU compiles --- cmake/CMakeLists.txt | 43 ++++++++++++++++++++++++------------------- lib/gpu/lal_pppm.cu | 5 ----- lib/gpu/lal_pppm_d.cu | 6 ++++++ lib/gpu/lal_pppm_f.cu | 6 ++++++ 4 files changed, 36 insertions(+), 24 deletions(-) create mode 100644 lib/gpu/lal_pppm_d.cu create mode 100644 lib/gpu/lal_pppm_f.cu diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0212e3906d..ff92c370d6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -427,6 +427,7 @@ if(ENABLE_GPU) endif() include_directories(${CUDA_TOOLKIT_INCLUDE}) set(CUDA_BUILD_CUBIN ON) + set(CUDA_GENERATED_OUTPUT_DIR ${LAMMPS_LIB_BINARY_DIR}/gpu) set(GPU_PREC "SINGLE_DOUBLE" CACHE STRING "Lammps gpu precision size") set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) add_definitions(-D_${GPU_PREC}) @@ -442,28 +443,29 @@ if(ENABLE_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) - file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp - ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) - cuda_add_library(lammps_gpu ${GPU_LIB_SOURCES}) - #add_custom_target(cubin_headers) - #file(GLOB_RECURSE GPU_LIB_CUBIN ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cubin) - #file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) - #foreach(CUBIN ${GPU_LIB_CUBIN}) - # get_filename_component(CUBIN_NAME NAME_WE ${CUBIN}) - # message("XXX ${CUBIN_NAME}_cubin.h") - # add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR/gpu/${CUBIN_NAME}_cubin.h - # COMMAND ${BIN2C} -c -n ${CUBIN_NAME} ${CUBIN} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CUBIN_NAME}_cubin.h - # DEPENDS ${CUBIN} - # COMMENT "Generating ${CUBIN_NAME}_cubin.h") - # add_custom_target(${CUBIN_NAME}_cubin DEPENDS ${LAMMPS_LIB_BINARY_DIR/gpu/${CUBIN_NAME}_cubin.h) - # add_dependencies(cubin_headers ${CUBIN_NAME}_cubin) - #endforeach() - #add_dependencies(lammps_gpu cubin_headers) - + file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp) + file(GLOB_RECURSE GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) + file(GLOB_RECURSE GPU_NOT_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/lal_pppm.cu) + list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) + cuda_add_library(lammps_gpu ${GPU_LIB_CU}) + file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) + add_custom_target(cubin_headers) + foreach(CU ${GPU_LIB_CU}) + get_filename_component(CU_NAME ${CU} NAME_WE) + set(CU_OBJ ${CUDA_GENERATED_OUTPUT_DIR}/lammps_gpu_generated_${CU_NAME}.cu.o.cubin.txt) + string(REGEX REPLACE "^lal_" "" CU_HEADER "${CU_NAME}") + add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h + COMMAND ${BIN2C} -c -n ${CU_HEADER} ${CU_OBJ} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h + DEPENDS ${CU_OBJ} + COMMENT "Generating ${CU_HEADER}_cubin.h") + add_custom_target(${CU_HEADER}_cubin DEPENDS ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h) + add_dependencies(cubin_headers ${CU_HEADER}_cubin) + endforeach() list(APPEND LAMMPS_LINK_LIBS lammps_gpu) - list(APPEND LIB_SOURCES ${GPU_SOURCES}) + list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES}) include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu") endif() ###################################################### @@ -479,6 +481,9 @@ include_directories(${LAMMPS_STYLE_HEADERS_DIR}) add_library(lammps ${LIB_SOURCES}) +if(ENABLE_GPU) + add_dependencies(lammps cubin_headers) +endif() target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) diff --git a/lib/gpu/lal_pppm.cu b/lib/gpu/lal_pppm.cu index fede2180cf..24636b9a93 100644 --- a/lib/gpu/lal_pppm.cu +++ b/lib/gpu/lal_pppm.cu @@ -13,11 +13,6 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef CMAKE_GPU -#define grdtyp float -#define grdtyp4 float4 -#endif - #ifdef NV_KERNEL #include "lal_preprocessor.h" diff --git a/lib/gpu/lal_pppm_d.cu b/lib/gpu/lal_pppm_d.cu new file mode 100644 index 0000000000..e00ad50496 --- /dev/null +++ b/lib/gpu/lal_pppm_d.cu @@ -0,0 +1,6 @@ +#ifdef CMAKE_GPU +#define grdtyp double +#define grdtyp4 double4 +#endif + +#include "lal_pppm.cu" diff --git a/lib/gpu/lal_pppm_f.cu b/lib/gpu/lal_pppm_f.cu new file mode 100644 index 0000000000..8c8ca88167 --- /dev/null +++ b/lib/gpu/lal_pppm_f.cu @@ -0,0 +1,6 @@ +#ifdef CMAKE_GPU +#define grdtyp float +#define grdtyp4 float4 +#endif + +#include "lal_pppm.cu" From 81f342aafa231587f748190b87423911eab9c1b0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 18:06:18 -0400 Subject: [PATCH 159/293] fix variable name bug and synchronize with other ported Install.py files --- lib/kim/Install.py | 70 +++++++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 42 deletions(-) diff --git a/lib/kim/Install.py b/lib/kim/Install.py index cf1b254ecd..f9348a2696 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -3,7 +3,9 @@ # install.pa tool to setup the kim-api library # used to automate the steps described in the README file in this dir from __future__ import print_function -import sys,os,re,urllib,subprocess +import sys,os,re,subprocess +try: from urllib.request import urlretrieve as geturl +except: from urllib import urlretrieve as geturl help = """ Syntax from src dir: make lib-kim args="-v version -b kim-install-dir kim-name -a kim-name" @@ -97,10 +99,10 @@ if buildflag: # configure LAMMPS to use kim-api to be installed with open("%s/Makefile.KIM_DIR" % thisdir, 'w') as mkfile: - mkfle.write("KIM_INSTALL_DIR=%s\n\n" % dir) - mkfle.write(".DUMMY: print_dir\n\n") - mkfle.write("print_dir:\n") - mkfle.write(" @printf $(KIM_INSTALL_DIR)\n") + mkfile.write("KIM_INSTALL_DIR=%s\n\n" % dir) + mkfile.write(".DUMMY: print_dir\n\n") + mkfile.write("print_dir:\n") + mkfile.write(" @printf $(KIM_INSTALL_DIR)\n") with open("%s/Makefile.KIM_Config" % thisdir, 'w') as cfgfile: cfgfile.write("include %s/lib/kim-api/Makefile.KIM_Config" % dir) @@ -113,27 +115,23 @@ if buildflag: print("Downloading kim-api tarball ...") - try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,version)) + try: geturl(url,"%s/%s.tgz" % (thisdir,version)) except: cmd = "wget %s %s/%s.tgz" % (url,thisdir,version) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) + subprocess.check_output(cmd,shell=True) if not os.path.isfile("%s/%s.tgz" % (thisdir,version)): - print("Both urllib.urlretrieve() and wget command failed to download") + print("Both urllib and wget command failed to download") sys.exit() print("Unpacking kim-api tarball ...") cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) - txt = subprocess.getstatusoutput(cmd) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) # configure kim-api print("Configuring kim-api ...") cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) # build kim-api @@ -145,36 +143,26 @@ if buildflag: print("configuring all OpenKIM models, this will take a while ...") cmd = "cd %s/%s; make add-examples; make add-%s" % \ (thisdir,version,modelname) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) print("Building kim-api ...") cmd = "cd %s/%s; make" % (thisdir,version) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) # install kim-api print("Installing kim-api ...") cmd = "cd %s/%s; make install" % (thisdir,version) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) # remove source files print("Removing kim-api source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) # add a single model (and possibly its driver) to existing KIM installation @@ -187,7 +175,7 @@ if addflag: error() else: cmd = "cd %s; make -f Makefile.KIM_DIR print_dir" % thisdir - dir = subprocess.getstatusoutput(cmd)[1] + dir = subprocess.check_output(cmd,shell=True)[1] # download single model # try first via urllib @@ -197,10 +185,10 @@ if addflag: url = "https://openkim.org/download/%s.tgz" % addmodelname - try: urllib.urlretrieve(url,"%s/%s.tgz" % (thisdir,addmodelname)) + try: geturl(url,"%s/%s.tgz" % (thisdir,addmodelname)) except: cmd = "wget %s %s/%s.tgz" % (url,thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) + txt = subprocess.check_output(cmd,shell=True) print(txt[1]) if not os.path.isfile("%s/%s.tgz" % (thisdir,addmodelname)): print("Both urllib.urlretrieve() and wget command failed to download") @@ -208,28 +196,27 @@ if addflag: print("Unpacking item tarball ...") cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) print("Building item ...") cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) + subprocess.check_output(cmd,shell=True) firstRunOutput = txt[1] if txt[0] != 0: # Error: but first, check to see if it needs a driver cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) + txt = subprocess.check_output(cmd,shell=True) if txt[1] == "ParameterizedModel": # Get and install driver cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) + txt = subprocess.check_output(cmd,shell=True) adddrivername = txt[1] print("First Installing model driver: %s" % adddrivername) cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) - txt = subprocess.getstatusoutput(cmd) + txt = subprocess.check_output(cmd,shell=True) if txt[0] != 0: print(firstRunOutput) print(txt[1]) @@ -237,7 +224,7 @@ if addflag: else: print(txt[1]) cmd = "cd %s; python Install.py -a %s" % (thisdir,addmodelname) - txt = subprocess.getstatusoutput(cmd) + txt = subprocess.check_output(cmd,shell=True) print(txt[1]) if txt[0] != 0: error() @@ -251,6 +238,5 @@ if addflag: print(firstRunOutput) print("Removing kim item source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - txt = subprocess.getstatusoutput(cmd) - print(txt[1]) - if txt[0] != 0: error() + subprocess.check_output(cmd,shell=True) + From 4d65c327f54a02d0f1a90de792609baae47fa456 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 16:06:29 -0600 Subject: [PATCH 160/293] added minimal README --- cmake/README | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 cmake/README diff --git a/cmake/README b/cmake/README new file mode 100644 index 0000000000..cc67cceb52 --- /dev/null +++ b/cmake/README @@ -0,0 +1,19 @@ +cmake-buildsystem +----------------- + +To use the cmake build system instead of the make-driven one, do: +``` +cmake /path/to/lammps/source/cmake +``` +(please note the cmake directory as the very end) + +To enable package, e.g. GPU do +``` +cmake /path/to/lammps/source/cmake -DENABLE_GPU=ON +``` + +cmake has many many options, do get an overview use the curses-based cmake interface, ccmake: +``` +ccmake /path/to/lammps/source/cmake +``` +(Don't forget to press "g" for generate once you are done with configuring) From 864fd9cd8788af46e1e055fa4786a074c1e7d6e6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 18:20:23 -0600 Subject: [PATCH 161/293] remove cubin_headers hack --- cmake/CMakeLists.txt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ff92c370d6..224de45a09 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -449,7 +449,6 @@ if(ENABLE_GPU) list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) cuda_add_library(lammps_gpu ${GPU_LIB_CU}) file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) - add_custom_target(cubin_headers) foreach(CU ${GPU_LIB_CU}) get_filename_component(CU_NAME ${CU} NAME_WE) set(CU_OBJ ${CUDA_GENERATED_OUTPUT_DIR}/lammps_gpu_generated_${CU_NAME}.cu.o.cubin.txt) @@ -458,8 +457,7 @@ if(ENABLE_GPU) COMMAND ${BIN2C} -c -n ${CU_HEADER} ${CU_OBJ} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h DEPENDS ${CU_OBJ} COMMENT "Generating ${CU_HEADER}_cubin.h") - add_custom_target(${CU_HEADER}_cubin DEPENDS ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h) - add_dependencies(cubin_headers ${CU_HEADER}_cubin) + list(APPEND LIB_SOURCES ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h) endforeach() list(APPEND LAMMPS_LINK_LIBS lammps_gpu) list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES}) @@ -481,9 +479,6 @@ include_directories(${LAMMPS_STYLE_HEADERS_DIR}) add_library(lammps ${LIB_SOURCES}) -if(ENABLE_GPU) - add_dependencies(lammps cubin_headers) -endif() target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) From e6f5f77edfacadfd4c4f55c167533279a3f0c6af Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 18:38:36 -0600 Subject: [PATCH 162/293] GPU: clean up --- cmake/CMakeLists.txt | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 224de45a09..c5c8326080 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -447,23 +447,22 @@ if(ENABLE_GPU) file(GLOB_RECURSE GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) file(GLOB_RECURSE GPU_NOT_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/lal_pppm.cu) list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) - cuda_add_library(lammps_gpu ${GPU_LIB_CU}) + add_custom_target(gpu_objs) + cuda_wrap_srcs(gpu_objs OBJ GPU_OBJS ${GPU_LIB_CU}) file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) - foreach(CU ${GPU_LIB_CU}) - get_filename_component(CU_NAME ${CU} NAME_WE) - set(CU_OBJ ${CUDA_GENERATED_OUTPUT_DIR}/lammps_gpu_generated_${CU_NAME}.cu.o.cubin.txt) - string(REGEX REPLACE "^lal_" "" CU_HEADER "${CU_NAME}") - add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h - COMMAND ${BIN2C} -c -n ${CU_HEADER} ${CU_OBJ} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h + foreach(CU_OBJ ${GPU_OBJS}) + get_filename_component(CU_NAME ${CU_OBJ} NAME_WE) + string(REGEX REPLACE "^.*_lal_" "" CU_NAME "${CU_NAME}") + add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h + COMMAND ${BIN2C} -c -n ${CU_NAME} ${CU_OBJ}.cubin.txt > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h DEPENDS ${CU_OBJ} - COMMENT "Generating ${CU_HEADER}_cubin.h") - list(APPEND LIB_SOURCES ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_HEADER}_cubin.h) + COMMENT "Generating ${CU_NAME}_cubin.h") + list(APPEND LIB_SOURCES ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h) endforeach() - list(APPEND LAMMPS_LINK_LIBS lammps_gpu) - list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES}) + list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES} ${GPU_OBJS}) include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu") + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu/*_cubin.h") endif() ###################################################### From acbc60319f6eb3ad15007ed568b876f1b8575785 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 18:43:51 -0600 Subject: [PATCH 163/293] GPU: clean up part 2 --- cmake/CMakeLists.txt | 5 ++--- {lib => cmake}/gpu/lal_pppm_d.cu | 2 -- {lib => cmake}/gpu/lal_pppm_f.cu | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) rename {lib => cmake}/gpu/lal_pppm_d.cu (74%) rename {lib => cmake}/gpu/lal_pppm_f.cu (73%) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c5c8326080..99208ff65b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -427,11 +427,10 @@ if(ENABLE_GPU) endif() include_directories(${CUDA_TOOLKIT_INCLUDE}) set(CUDA_BUILD_CUBIN ON) - set(CUDA_GENERATED_OUTPUT_DIR ${LAMMPS_LIB_BINARY_DIR}/gpu) set(GPU_PREC "SINGLE_DOUBLE" CACHE STRING "Lammps gpu precision size") set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) add_definitions(-D_${GPU_PREC}) - add_definitions(-DNV_KERNEL -DUSE_CUDPP -DUCL_CUDADR -DCMAKE_GPU) + add_definitions(-DNV_KERNEL -DUSE_CUDPP -DUCL_CUDADR) set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) @@ -444,7 +443,7 @@ if(ENABLE_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp) - file(GLOB_RECURSE GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu) + file(GLOB_RECURSE GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu ${CMAKE_SOURCE_DIR}/gpu/*.cu) file(GLOB_RECURSE GPU_NOT_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/lal_pppm.cu) list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) add_custom_target(gpu_objs) diff --git a/lib/gpu/lal_pppm_d.cu b/cmake/gpu/lal_pppm_d.cu similarity index 74% rename from lib/gpu/lal_pppm_d.cu rename to cmake/gpu/lal_pppm_d.cu index e00ad50496..a49a535013 100644 --- a/lib/gpu/lal_pppm_d.cu +++ b/cmake/gpu/lal_pppm_d.cu @@ -1,6 +1,4 @@ -#ifdef CMAKE_GPU #define grdtyp double #define grdtyp4 double4 -#endif #include "lal_pppm.cu" diff --git a/lib/gpu/lal_pppm_f.cu b/cmake/gpu/lal_pppm_f.cu similarity index 73% rename from lib/gpu/lal_pppm_f.cu rename to cmake/gpu/lal_pppm_f.cu index 8c8ca88167..e7f5116fa0 100644 --- a/lib/gpu/lal_pppm_f.cu +++ b/cmake/gpu/lal_pppm_f.cu @@ -1,6 +1,4 @@ -#ifdef CMAKE_GPU #define grdtyp float #define grdtyp4 float4 -#endif #include "lal_pppm.cu" From e2ad4fa74579c8432bb0a286385f329421c7bb2a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 18 Jul 2017 19:29:40 -0600 Subject: [PATCH 164/293] GPU: cubin not needed --- cmake/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 99208ff65b..5764700ebd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -426,7 +426,6 @@ if(ENABLE_GPU) message(FATAL_ERROR "Couldn't find bin2c") endif() include_directories(${CUDA_TOOLKIT_INCLUDE}) - set(CUDA_BUILD_CUBIN ON) set(GPU_PREC "SINGLE_DOUBLE" CACHE STRING "Lammps gpu precision size") set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) add_definitions(-D_${GPU_PREC}) @@ -453,7 +452,7 @@ if(ENABLE_GPU) get_filename_component(CU_NAME ${CU_OBJ} NAME_WE) string(REGEX REPLACE "^.*_lal_" "" CU_NAME "${CU_NAME}") add_custom_command(OUTPUT ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h - COMMAND ${BIN2C} -c -n ${CU_NAME} ${CU_OBJ}.cubin.txt > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h + COMMAND ${BIN2C} -c -n ${CU_NAME} ${CU_OBJ} > ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h DEPENDS ${CU_OBJ} COMMENT "Generating ${CU_NAME}_cubin.h") list(APPEND LIB_SOURCES ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h) From 2961ba7ebb0d27accaf9b33957597e592bb56f9e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 10:35:48 -0600 Subject: [PATCH 165/293] added MKL support --- cmake/CMakeLists.txt | 9 ++++++++- cmake/Modules/FindMKL.cmake | 22 ++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 cmake/Modules/FindMKL.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 5764700ebd..9d8b93e12d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -117,14 +117,21 @@ endif() if(ENABLE_KSPACE) find_package(FFTW3) + find_package(MKL) if(FFTW3_FOUND) add_definitions(-DFFT_FFTW3) include_directories(${FFTW3_INCLUDE_DIRS}) list(APPEND LAMMPS_LINK_LIBS ${FFTW3_LIBRARIES}) + elseif(MKL_FOUND) + add_definitions(-DFFT_MKL) + include_directories(${MKL_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) endif() set(PACK_OPTIMIZATION "PACK_ARRAY" CACHE STRING "Optimization for FFT") set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) - add_definitions(-D${PACK_OPTIMIZATION}) + if(NOT PACK_OPTIMIZATION STREQUAL "PACK_ARRAY") + add_definitions(-D${PACK_OPTIMIZATION}) + endif() endif() if(ENABLE_MISC) diff --git a/cmake/Modules/FindMKL.cmake b/cmake/Modules/FindMKL.cmake new file mode 100644 index 0000000000..4246062103 --- /dev/null +++ b/cmake/Modules/FindMKL.cmake @@ -0,0 +1,22 @@ +# - Find mkl +# Find the native MKL headers and libraries. +# +# MKL_INCLUDE_DIRS - where to find mkl.h, etc. +# MKL_LIBRARIES - List of libraries when using mkl. +# MKL_FOUND - True if mkl found. +# + +find_path(MKL_INCLUDE_DIR mkl_dfti.h HINTS $ENV{MKLROOT}/include) + +find_library(MKL_LIBRARY NAMES mkl_rt HINTS $ENV{MKLROOT}/lib $ENV{MKLROOT}/lib/intel64) + +set(MKL_LIBRARIES ${MKL_LIBRARY}) +set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE +# if all listed variables are TRUE + +find_package_handle_standard_args(MKL DEFAULT_MSG MKL_LIBRARY MKL_INCLUDE_DIR) + +mark_as_advanced(MKL_INCLUDE_DIR MKL_LIBRARY ) From fcf9607a666616f53cd2d03445e76fb619dae85c Mon Sep 17 00:00:00 2001 From: Max Veit Date: Wed, 19 Jul 2017 17:47:21 +0100 Subject: [PATCH 166/293] Update USER_QUIP docs to clarify use of "special_bonds" --- doc/src/pair_quip.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/doc/src/pair_quip.txt b/doc/src/pair_quip.txt index 12dcd244e2..fbc87d61ac 100644 --- a/doc/src/pair_quip.txt +++ b/doc/src/pair_quip.txt @@ -80,6 +80,14 @@ LAMMPS"_Section_start.html#start_3 section for more info. QUIP potentials are parametrized in electron-volts and Angstroms and therefore should be used with LAMMPS metal "units"_units.html. +QUIP potentials are generally not designed to work with the scaling +factors set by the "special_bonds"_special_bonds.html command. The +recommended setting in molecular systems is to include all +interactions, i.e. to use {special_bonds lj 1.0 1.0 1.0}. The only +exception to this rule is if you know that your QUIP potential needs +to exclude bonded, 1-3, or 1-4 interactions and does not already do +this exclusion within QUIP. + [Related commands:] "pair_coeff"_pair_coeff.html From 52a1c54d500e8255eab06290beaaf99ed225f9ca Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jul 2017 13:17:35 -0400 Subject: [PATCH 167/293] support QUIP wrapper API version query, relax hybrid restriction to allow hybrid/overlay, update docs --- doc/src/pair_quip.txt | 16 ++++++++++++---- src/USER-QUIP/pair_quip.cpp | 10 ++++++++-- src/USER-QUIP/pair_quip.h | 5 +++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/doc/src/pair_quip.txt b/doc/src/pair_quip.txt index fbc87d61ac..9436b0c4ed 100644 --- a/doc/src/pair_quip.txt +++ b/doc/src/pair_quip.txt @@ -83,10 +83,18 @@ therefore should be used with LAMMPS metal "units"_units.html. QUIP potentials are generally not designed to work with the scaling factors set by the "special_bonds"_special_bonds.html command. The recommended setting in molecular systems is to include all -interactions, i.e. to use {special_bonds lj 1.0 1.0 1.0}. The only -exception to this rule is if you know that your QUIP potential needs -to exclude bonded, 1-3, or 1-4 interactions and does not already do -this exclusion within QUIP. +interactions, i.e. to use {special_bonds lj/coul 1.0 1.0 1.0}. Scaling +factors > 0.0 will be ignored and treated as 1.0. The only exception +to this rule is if you know that your QUIP potential needs to exclude +bonded, 1-3, or 1-4 interactions and does not already do this exclusion +within QUIP. Then a factor 0.0 needs to be used which will remove such +pairs from the neighbor list. This needs to be very carefully tested, +because it may remove pairs from the neighbor list that are still +required. + +Pair style {quip} cannot be used with pair style {hybrid}, only +with {hybrid/overlay} and only the {quip} substyle is applied to +all atom types. [Related commands:] diff --git a/src/USER-QUIP/pair_quip.cpp b/src/USER-QUIP/pair_quip.cpp index c6ab8b259b..6bbbcdb8e6 100644 --- a/src/USER-QUIP/pair_quip.cpp +++ b/src/USER-QUIP/pair_quip.cpp @@ -214,8 +214,14 @@ void PairQUIP::compute(int eflag, int vflag) void PairQUIP::settings(int narg, char **arg) { if (narg != 0) error->all(FLERR,"Illegal pair_style command"); - if (strncmp(force->pair_style,"hybrid",6) == 0) - error->all(FLERR,"Pair style quip is not compatible with hybrid styles"); + if (strcmp(force->pair_style,"hybrid") == 0) + error->all(FLERR,"Pair style quip is only compatible with hybrid/overlay"); + + // check if linked to the correct QUIP library API version + // as of 2017-07-19 this is API_VERSION 1 + if (quip_lammps_api_version() != 1) + error->all(FLERR,"QUIP LAMMPS wrapper API version is not compatible " + "with this version of LAMMPS"); } /* ---------------------------------------------------------------------- diff --git a/src/USER-QUIP/pair_quip.h b/src/USER-QUIP/pair_quip.h index 985a43fd7e..debdc2cb83 100644 --- a/src/USER-QUIP/pair_quip.h +++ b/src/USER-QUIP/pair_quip.h @@ -24,12 +24,13 @@ PairStyle(quip,PairQUIP) extern "C" { - void quip_lammps_wrapper(int*, int*, int*, int*, + int quip_lammps_api_version(); + void quip_lammps_wrapper(int*, int*, int*, int*, int*, int*, int*, int*, int*, double*, int*, int*, double*, double*, double*, double*, double*, double*); - void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*); + void quip_lammps_potential_initialise(int*, int*, double*, char*, int*, char*, int*); } namespace LAMMPS_NS { From f181a0bfabbbdae09e440714b2e4a27c23f5efd4 Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Wed, 19 Jul 2017 12:54:33 -0500 Subject: [PATCH 168/293] Update lib/kim/Install.py for phthon 2.7 conversion --- lib/kim/Install.py | 61 ++++++++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 26 deletions(-) diff --git a/lib/kim/Install.py b/lib/kim/Install.py index f9348a2696..cb089e41e2 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -200,43 +200,52 @@ if addflag: print("Building item ...") cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) - subprocess.check_output(cmd,shell=True) - firstRunOutput = txt[1] - if txt[0] != 0: + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + # Error: but first, check to see if it needs a driver + firstRunOutput = e.output + cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) - txt = subprocess.check_output(cmd,shell=True) - if txt[1] == "ParameterizedModel": + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if txt == "ParameterizedModel": # Get and install driver cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) - txt = subprocess.check_output(cmd,shell=True) - adddrivername = txt[1] + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + adddrivername = txt print("First Installing model driver: %s" % adddrivername) cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) - txt = subprocess.check_output(cmd,shell=True) - if txt[0] != 0: - print(firstRunOutput) - print(txt[1]) - error() - else: - print(txt[1]) + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + print(e.output) + sys.exit() + + print(txt) + + # now install the model that needed the driver + cmd = "cd %s; python Install.py -a %s" % (thisdir,addmodelname) - txt = subprocess.check_output(cmd,shell=True) - print(txt[1]) - if txt[0] != 0: - error() + try: + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + except subprocess.CalledProcessError as e: + print(e.output) + sys.exit() + print(txt) + sys.exit() else: print(firstRunOutput) - error() - else: + print("Error, unable to build and install OpenKIM item: %s" \ + % addmodelname) + sys.exit() - # success - - print(firstRunOutput) - print("Removing kim item source and build files ...") - cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - subprocess.check_output(cmd,shell=True) + # success the first time + print(txt) + print("Removing kim item source and build files ...") + cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) + subprocess.check_output(cmd,shell=True) From ee6cac826e656d6280c1dff1478a5c4040ce7010 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Wed, 19 Jul 2017 14:10:43 -0400 Subject: [PATCH 169/293] Update Colvars to version 2017-07-15 and support automated builds for it --- doc/src/PDF/colvars-refman-lammps.pdf | Bin 566757 -> 570332 bytes lib/colvars/Install.py | 104 ++- lib/colvars/Makefile.colvars | 119 --- lib/colvars/Makefile.common | 65 ++ lib/colvars/Makefile.deps | 78 ++ lib/colvars/Makefile.fermi | 120 --- lib/colvars/Makefile.g++ | 118 +-- lib/colvars/Makefile.g++-debug | 5 + lib/colvars/Makefile.lammps | 5 + lib/colvars/Makefile.lammps.debug | 2 +- lib/colvars/Makefile.lammps.empty | 2 +- lib/colvars/Makefile.mingw32-cross | 124 +-- lib/colvars/Makefile.mingw64-cross | 124 +-- lib/colvars/README | 105 ++- lib/colvars/colvar.cpp | 432 +++++++-- lib/colvars/colvar.h | 47 +- lib/colvars/colvaratoms.cpp | 216 +++-- lib/colvars/colvaratoms.h | 39 +- lib/colvars/colvarbias.cpp | 24 +- lib/colvars/colvarbias.h | 2 +- lib/colvars/colvarbias_abf.cpp | 130 +-- lib/colvars/colvarbias_alb.cpp | 60 +- lib/colvars/colvarbias_histogram.cpp | 28 +- lib/colvars/colvarbias_meta.cpp | 149 +-- lib/colvars/colvarbias_meta.h | 7 +- lib/colvars/colvarbias_restraint.cpp | 54 +- lib/colvars/colvarcomp.cpp | 238 ++--- lib/colvars/colvarcomp.h | 75 +- lib/colvars/colvarcomp_angles.cpp | 203 +++- lib/colvars/colvarcomp_coordnums.cpp | 47 +- lib/colvars/colvarcomp_distances.cpp | 101 +- lib/colvars/colvarcomp_protein.cpp | 84 +- lib/colvars/colvarcomp_rotations.cpp | 14 +- lib/colvars/colvardeps.cpp | 347 +++++-- lib/colvars/colvardeps.h | 124 ++- lib/colvars/colvargrid.cpp | 3 +- lib/colvars/colvargrid.h | 6 +- lib/colvars/colvarmodule.cpp | 178 ++-- lib/colvars/colvarmodule.h | 66 +- lib/colvars/colvarparse.cpp | 53 +- lib/colvars/colvarparse.h | 25 +- lib/colvars/colvarproxy.cpp | 492 ++++++++++ lib/colvars/colvarproxy.h | 868 ++++++++---------- lib/colvars/colvars_version.h | 8 + lib/colvars/colvarscript.cpp | 150 +-- lib/colvars/colvarscript.h | 20 +- lib/colvars/colvartypes.h | 5 + lib/colvars/colvarvalue.cpp | 275 ++++++ lib/colvars/colvarvalue.h | 324 +------ src/USER-COLVARS/colvarproxy_lammps.cpp | 4 - src/USER-COLVARS/colvarproxy_lammps.h | 7 +- src/USER-COLVARS/colvarproxy_lammps_version.h | 10 + 52 files changed, 3473 insertions(+), 2413 deletions(-) delete mode 100644 lib/colvars/Makefile.colvars create mode 100644 lib/colvars/Makefile.common create mode 100644 lib/colvars/Makefile.deps delete mode 100644 lib/colvars/Makefile.fermi create mode 100644 lib/colvars/Makefile.g++-debug create mode 100644 lib/colvars/Makefile.lammps create mode 100644 lib/colvars/colvarproxy.cpp create mode 100644 lib/colvars/colvars_version.h create mode 100644 src/USER-COLVARS/colvarproxy_lammps_version.h diff --git a/doc/src/PDF/colvars-refman-lammps.pdf b/doc/src/PDF/colvars-refman-lammps.pdf index 37201275fe4b4efa0da77afbb72e6c55a127c042..a14d93cd69e7a2aced22919a7755d66714405d47 100644 GIT binary patch delta 185481 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�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 z

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

{&Ph{?q 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]{thFb?^4B~Irk{z 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 delta 182418 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 a*xA+7+1vtwlZ%~=ixYv0NC diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index 18b426f928..a367b8eeed 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -1,27 +1,34 @@ #!/usr/bin/env python -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README +# Install.py tool to do automate build of Colvars -import sys,commands,os +from __future__ import print_function +import sys,os,subprocess # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-colvars args="-m machine -e suffix" +Syntax from lib/colvars dir: python Install.py -m machine -e suffix + +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file + machine = suffix of a lib/colvars/Makefile.* or of a + src/MAKE/MACHINES/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examples: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler """ # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR"),str sys.exit() # parse args @@ -31,17 +38,17 @@ nargs = len(args) if nargs == 0: error() machine = None -extraflag = 0 +extraflag = False iarg = 0 while iarg < nargs: if args[iarg] == "-m": - if iarg+2 > nargs: error() + if iarg+2 > len(args): error() machine = args[iarg+1] iarg += 2 elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 + if iarg+2 > len(args): error() + extraflag = True suffix = args[iarg+1] iarg += 2 else: error() @@ -51,32 +58,79 @@ while iarg < nargs: cwd = os.getcwd() lib = os.path.basename(cwd) -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - +def get_lammps_machine_flags(machine): + """Parse Makefile.machine from LAMMPS, return dictionary of compiler flags""" + if not os.path.exists("../../src/MAKE/MACHINES/Makefile.%s" % machine): + error("Cannot locate src/MAKE/MACHINES/Makefile.%s" % machine) + lines = open("../../src/MAKE/MACHINES/Makefile.%s" % machine, + 'r').readlines() + machine_flags = {} + for line in lines: + line = line.partition('#')[0] + line = line.rstrip() + words = line.split() + if (len(words) > 2): + if ((words[0] == 'CC') or (words[0] == 'CCFLAGS') or + (words[0] == 'SHFLAGS') or (words[0] == 'ARCHIVE') or + (words[0] == 'ARFLAGS') or (words[0] == 'SHELL')): + machine_flags[words[0]] = ' '.join(words[2:]) + return machine_flags + +def gen_colvars_makefile_machine(machine, machine_flags): + """Generate Makefile.machine for Colvars given the compiler flags""" + machine_makefile = open("Makefile.%s" % machine, 'w') + machine_makefile.write('''# -*- makefile -*- to build Colvars module with %s + +COLVARS_LIB = libcolvars.a +COLVARS_OBJ_DIR = + +CXX = %s +CXXFLAGS = %s %s +AR = %s +ARFLAGS = %s +SHELL = %s + +include Makefile.common + +.PHONY: default clean + +default: $(COLVARS_LIB) Makefile.lammps + +clean: + -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) +''' % (machine, machine_flags['CC'], + machine_flags['CCFLAGS'], machine_flags['SHFLAGS'] , + machine_flags['ARCHIVE'], machine_flags['ARFLAGS'], + machine_flags['SHELL'])) + +if not os.path.exists("Makefile.%s" % machine): + machine_flags = get_lammps_machine_flags(machine) + gen_colvars_makefile_machine(machine, machine_flags) if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) +# create Makefile.auto as copy of Makefile.machine +# reset EXTRAMAKE if requested + lines = open("Makefile.%s" % machine,'r').readlines() fp = open("Makefile.auto",'w') - for line in lines: words = line.split() if len(words) == 3 and extraflag and \ words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - + fp.write(line) fp.close() # make the library via Makefile.auto -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt +print("Building lib%s.a ..." % lib) +cmd = ["make -f Makefile.auto clean"] +print(subprocess.check_output(cmd, shell=True)) +cmd = ["make -f Makefile.auto -j12"] +print(subprocess.check_output(cmd, shell=True)) -if os.path.exists("lib%s.a" % lib): print "Build was successful" +if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib + print("lib/%s/Makefile.lammps was NOT created" % lib) diff --git a/lib/colvars/Makefile.colvars b/lib/colvars/Makefile.colvars deleted file mode 100644 index d1a2044038..0000000000 --- a/lib/colvars/Makefile.colvars +++ /dev/null @@ -1,119 +0,0 @@ -# library build -*- makefile -*- for colvars module - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.empty - -# ------ SETTINGS ------ - -CXX = g++ -CXXFLAGS = -O2 -g -Wall -fPIC -funroll-loops # -DCOLVARS_DEBUG -ARCHIVE = ar -ARCHFLAG = -rscv -SHELL = /bin/sh - -# ------ DEFINITIONS ------ - -SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \ - colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \ - colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \ - colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \ - colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \ - colvarscript.cpp colvartypes.cpp colvarvalue.cpp - -LIB = libcolvars.a -OBJ = $(SRC:.cpp=.o) -EXE = #colvars_standalone - -# ------ MAKE PROCEDURE ------ - -default: $(LIB) $(EXE) Makefile.lammps - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - -colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB) - $(CXX) -o $@ $(CXXFLAGS) $^ - -# ------ MAKE FLAGS ------ - -.SUFFIXES: -.SUFFIXES: .cpp .o - -.PHONY: default clean - -# ------ COMPILE RULES ------ - -.cpp.o: - $(CXX) $(CXXFLAGS) -c $< - -# ------ DEPENDENCIES ------ -# -colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h -colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarbias_abf.h colvarbias.h colvargrid.h -colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_restraint.h colvarbias.h -colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h -colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvarbias_meta.h colvarbias.h colvargrid.h -colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \ - colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarcomp.h colvaratoms.h -colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvaratoms.h colvar.h colvarcomp.h -colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ - colvaratoms.h -colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarcomp.h colvaratoms.h -colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvarscript.h colvarbias.h -colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h -colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvargrid.h -colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \ - colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \ - colvarscript.h -colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \ - colvarparse.h colvardeps.h -colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h - -# ------ CLEAN ------ - -clean: - -rm *.o *~ $(LIB) - diff --git a/lib/colvars/Makefile.common b/lib/colvars/Makefile.common new file mode 100644 index 0000000000..818373abe1 --- /dev/null +++ b/lib/colvars/Makefile.common @@ -0,0 +1,65 @@ +# Shared -*- makefile -*- for multiple architectures + +# Detect settings from PYTHON package (if defined) +include ../../src/Makefile.package.settings +ifeq ($(python_SYSINC),) +COLVARS_PYTHON_INCFLAGS = +else +COLVARS_PYTHON_INCFLAGS = -DCOLVARS_PYTHON $(python_SYSINC) +endif + +# Detect debug settings +ifeq ($(COLVARS_DEBUG),) +COLVARS_DEBUG_INCFLAGS = +else +COLVARS_DEBUG_INCFLAGS= -DCOLVARS_DEBUG +endif + +COLVARS_INCFLAGS = $(COLVARS_DEBUG_INCFLAGS) $(COLVARS_PYTHON_INCFLAGS) + + +.SUFFIXES: +.SUFFIXES: .cpp .o + +COLVARS_SRCS = \ + colvaratoms.cpp \ + colvarbias_abf.cpp \ + colvarbias_alb.cpp \ + colvarbias.cpp \ + colvarbias_histogram.cpp \ + colvarbias_meta.cpp \ + colvarbias_restraint.cpp \ + colvarcomp_angles.cpp \ + colvarcomp_coordnums.cpp \ + colvarcomp.cpp \ + colvarcomp_distances.cpp \ + colvarcomp_protein.cpp \ + colvarcomp_rotations.cpp \ + colvar.cpp \ + colvardeps.cpp \ + colvargrid.cpp \ + colvarmodule.cpp \ + colvarparse.cpp \ + colvarproxy.cpp \ + colvarscript.cpp \ + colvartypes.cpp \ + colvarvalue.cpp + +COLVARS_OBJS = $(COLVARS_SRCS:.cpp=.o) + +.cpp.o: + $(CXX) $(CXXFLAGS) $(COLVARS_INCFLAGS) -c $< + +$(COLVARS_LIB): Makefile.deps $(COLVARS_OBJS) + $(AR) $(ARFLAGS) $(COLVARS_LIB) $(COLVARS_OBJS) + + +Makefile.deps: $(COLVARS_SRCS) + @echo > $@ + @for src in $^ ; do \ + obj=`basename $$src .cpp`.o ; \ + $(CXX) -MM $(COLVARS_INCFLAGS) \ + -MT '$$(COLVARS_OBJ_DIR)'$$obj $$src >> $@ ; \ + done + +include Makefile.deps diff --git a/lib/colvars/Makefile.deps b/lib/colvars/Makefile.deps new file mode 100644 index 0000000000..f463da5f86 --- /dev/null +++ b/lib/colvars/Makefile.deps @@ -0,0 +1,78 @@ + +$(COLVARS_OBJ_DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarparse.h colvaratoms.h colvardeps.h +$(COLVARS_OBJ_DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvar.h \ + colvarparse.h colvardeps.h colvarbias_abf.h colvarbias.h colvargrid.h +$(COLVARS_OBJ_DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarbias_alb.h colvar.h colvarparse.h colvardeps.h colvarbias.h +$(COLVARS_OBJ_DIR)colvarbias.o: colvarbias.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h \ + colvar.h colvarparse.h colvardeps.h +$(COLVARS_OBJ_DIR)colvarbias_histogram.o: colvarbias_histogram.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarbias_histogram.h \ + colvarbias.h colvargrid.h +$(COLVARS_OBJ_DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h colvardeps.h colvarbias_meta.h colvarbias.h \ + colvargrid.h +$(COLVARS_OBJ_DIR)colvarbias_restraint.o: colvarbias_restraint.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarbias_restraint.h colvarbias.h colvar.h colvarparse.h \ + colvardeps.h +$(COLVARS_OBJ_DIR)colvarcomp_angles.o: colvarcomp_angles.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ + colvaratoms.h +$(COLVARS_OBJ_DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h colvaratoms.h colvardeps.h colvar.h \ + colvarcomp.h +$(COLVARS_OBJ_DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h colvar.h \ + colvarparse.h colvardeps.h colvarcomp.h colvaratoms.h +$(COLVARS_OBJ_DIR)colvarcomp_distances.o: colvarcomp_distances.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \ + colvaratoms.h +$(COLVARS_OBJ_DIR)colvarcomp_protein.o: colvarcomp_protein.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \ + colvaratoms.h +$(COLVARS_OBJ_DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h colvar.h colvardeps.h colvarcomp.h \ + colvaratoms.h +$(COLVARS_OBJ_DIR)colvar.o: colvar.cpp colvarmodule.h colvars_version.h \ + colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvar.h \ + colvardeps.h colvarcomp.h colvaratoms.h colvarscript.h colvarbias.h +$(COLVARS_OBJ_DIR)colvardeps.o: colvardeps.cpp colvardeps.h \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarparse.h +$(COLVARS_OBJ_DIR)colvargrid.o: colvargrid.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarparse.h colvar.h colvardeps.h colvarcomp.h colvaratoms.h \ + colvargrid.h +$(COLVARS_OBJ_DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarparse.h colvar.h colvardeps.h colvarbias.h colvarbias_abf.h \ + colvargrid.h colvarbias_alb.h colvarbias_histogram.h colvarbias_meta.h \ + colvarbias_restraint.h colvarscript.h colvaratoms.h +$(COLVARS_OBJ_DIR)colvarparse.o: colvarparse.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarparse.h +$(COLVARS_OBJ_DIR)colvarproxy.o: colvarproxy.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarscript.h colvarbias.h colvar.h colvarparse.h colvardeps.h \ + colvaratoms.h +$(COLVARS_OBJ_DIR)colvarscript.o: colvarscript.cpp colvarscript.h \ + colvarmodule.h colvars_version.h colvartypes.h colvarproxy.h \ + colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h +$(COLVARS_OBJ_DIR)colvartypes.o: colvartypes.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h \ + colvarparse.h +$(COLVARS_OBJ_DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h \ + colvars_version.h colvartypes.h colvarproxy.h colvarvalue.h diff --git a/lib/colvars/Makefile.fermi b/lib/colvars/Makefile.fermi deleted file mode 100644 index 906675ae12..0000000000 --- a/lib/colvars/Makefile.fermi +++ /dev/null @@ -1,120 +0,0 @@ -# library build -*- makefile -*- for colvars module - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.empty - -# ------ SETTINGS ------ - -CXX = g++ -CXXFLAGS = -O2 -mpc64 -g -fPIC \ - -Wall -Wno-sign-compare # -DCOLVARS_DEBUG -ARCHIVE = ar -ARCHFLAG = -rscv -SHELL = /bin/sh - -# ------ DEFINITIONS ------ - -SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \ - colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \ - colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \ - colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \ - colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \ - colvarscript.cpp colvartypes.cpp colvarvalue.cpp - -LIB = libcolvars.a -OBJ = $(SRC:.cpp=.o) -EXE = #colvars_standalone - -# ------ MAKE PROCEDURE ------ - -default: $(LIB) $(EXE) Makefile.lammps - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - -colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB) - $(CXX) -o $@ $(CXXFLAGS) $^ - -# ------ MAKE FLAGS ------ - -.SUFFIXES: -.SUFFIXES: .cpp .o - -.PHONY: default clean - -# ------ COMPILE RULES ------ - -.cpp.o: - $(CXX) $(CXXFLAGS) -c $< - -# ------ DEPENDENCIES ------ -# -colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h -colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarbias_abf.h colvarbias.h colvargrid.h -colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_restraint.h colvarbias.h -colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h -colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvarbias_meta.h colvarbias.h colvargrid.h -colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \ - colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarcomp.h colvaratoms.h -colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvaratoms.h colvar.h colvarcomp.h -colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ - colvaratoms.h -colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarcomp.h colvaratoms.h -colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvarscript.h colvarbias.h -colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h -colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvargrid.h -colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \ - colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \ - colvarscript.h -colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \ - colvarparse.h colvardeps.h -colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h - -# ------ CLEAN ------ - -clean: - -rm *.o *~ $(LIB) - diff --git a/lib/colvars/Makefile.g++ b/lib/colvars/Makefile.g++ index c80fa1065e..cd7f72a833 100644 --- a/lib/colvars/Makefile.g++ +++ b/lib/colvars/Makefile.g++ @@ -1,119 +1,25 @@ -# library build -*- makefile -*- for colvars module - -# which file will be copied to Makefile.lammps +# -*- makefile -*- to build Colvars module with GNU compiler EXTRAMAKE = Makefile.lammps.empty -# ------ SETTINGS ------ +COLVARS_LIB = libcolvars.a +COLVARS_OBJ_DIR = CXX = g++ -CXXFLAGS = -O2 -g -fPIC -funroll-loops # -DCOLVARS_DEBUG -ARCHIVE = ar -ARCHFLAG = -rscv +CXXFLAGS = -O2 -g -Wall -fPIC -funroll-loops +AR = ar +ARFLAGS = -rscv SHELL = /bin/sh -# ------ DEFINITIONS ------ - -SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \ - colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \ - colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \ - colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \ - colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \ - colvarscript.cpp colvartypes.cpp colvarvalue.cpp - -LIB = libcolvars.a -OBJ = $(SRC:.cpp=.o) -EXE = #colvars_standalone - -# ------ MAKE PROCEDURE ------ - -default: $(LIB) $(EXE) Makefile.lammps - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - -colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB) - $(CXX) -o $@ $(CXXFLAGS) $^ - -# ------ MAKE FLAGS ------ - -.SUFFIXES: -.SUFFIXES: .cpp .o +include Makefile.common .PHONY: default clean -# ------ COMPILE RULES ------ - -.cpp.o: - $(CXX) $(CXXFLAGS) -c $< - -# ------ DEPENDENCIES ------ -# -colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h -colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarbias_abf.h colvarbias.h colvargrid.h -colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_restraint.h colvarbias.h -colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h -colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvarbias_meta.h colvarbias.h colvargrid.h -colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \ - colvarbias.h colvar.h colvarparse.h colvardeps.h -colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarcomp.h colvaratoms.h -colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvaratoms.h colvar.h colvarcomp.h -colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ - colvaratoms.h -colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarcomp.h colvaratoms.h -colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvarscript.h colvarbias.h -colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h -colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvargrid.h -colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \ - colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \ - colvarscript.h -colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \ - colvarparse.h colvardeps.h -colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h - -# ------ CLEAN ------ +default: $(COLVARS_LIB) Makefile.lammps clean: - -rm *.o *~ $(LIB) + -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) + +Makefile.lammps: + -cp $(EXTRAMAKE) Makefile.lammps diff --git a/lib/colvars/Makefile.g++-debug b/lib/colvars/Makefile.g++-debug new file mode 100644 index 0000000000..a6ca2f8124 --- /dev/null +++ b/lib/colvars/Makefile.g++-debug @@ -0,0 +1,5 @@ +# -*- makefile -*- to build Colvars module with GNU compiler + +COLVARS_DEBUG = "YES" + +include Makefile.g++ diff --git a/lib/colvars/Makefile.lammps b/lib/colvars/Makefile.lammps new file mode 100644 index 0000000000..99f57b050b --- /dev/null +++ b/lib/colvars/Makefile.lammps @@ -0,0 +1,5 @@ +# Settings that the LAMMPS build will import when this package library is used + +colvars_SYSINC = +colvars_SYSLIB = +colvars_SYSPATH = diff --git a/lib/colvars/Makefile.lammps.debug b/lib/colvars/Makefile.lammps.debug index 1ef229d58a..1c4399a2cd 100644 --- a/lib/colvars/Makefile.lammps.debug +++ b/lib/colvars/Makefile.lammps.debug @@ -1,5 +1,5 @@ # Settings that the LAMMPS build will import when this package library is used -colvars_SYSINC = # -DCOLVARS_DEBUG +colvars_SYSINC = -DCOLVARS_DEBUG colvars_SYSLIB = colvars_SYSPATH = diff --git a/lib/colvars/Makefile.lammps.empty b/lib/colvars/Makefile.lammps.empty index 1ef229d58a..99f57b050b 100644 --- a/lib/colvars/Makefile.lammps.empty +++ b/lib/colvars/Makefile.lammps.empty @@ -1,5 +1,5 @@ # Settings that the LAMMPS build will import when this package library is used -colvars_SYSINC = # -DCOLVARS_DEBUG +colvars_SYSINC = colvars_SYSLIB = colvars_SYSPATH = diff --git a/lib/colvars/Makefile.mingw32-cross b/lib/colvars/Makefile.mingw32-cross index eba83c555f..e2873ecdad 100644 --- a/lib/colvars/Makefile.mingw32-cross +++ b/lib/colvars/Makefile.mingw32-cross @@ -1,127 +1,31 @@ -# library build -*- makefile -*- for colvars module - -# which file will be copied to Makefile.lammps +# -*- makefile -*- to build Colvars module with MinGW 32-bit EXTRAMAKE = Makefile.lammps.empty -# ------ SETTINGS ------ +COLVARS_LIB = libcolvars.a +COLVARS_OBJ_DIR = Obj_mingw64/ CXX = i686-w64-mingw32-g++ CXXFLAGS = -O2 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ -fno-rtti -fno-exceptions -finline-functions \ -ffast-math -funroll-loops -fstrict-aliasing \ -Wall -W -Wno-uninitialized -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rscv +AR = i686-w64-mingw32-ar +ARFLAGS = -rscv SHELL = /bin/sh -# ------ DEFINITIONS ------ - -SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \ - colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \ - colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \ - colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \ - colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \ - colvarscript.cpp colvartypes.cpp colvarvalue.cpp - -DIR = Obj_mingw32/ -LIB = $(DIR)libcolvars.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) -EXE = #colvars_standalone - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) $(EXE) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(DIR) $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -$(DIR)colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB) - $(CXX) -o $@ $(CXXFLAGS) $^ - -# ------ MAKE FLAGS ------ - -.SUFFIXES: -.SUFFIXES: .cpp .o +include Makefile.common .PHONY: default clean -# ------ COMPILE RULES ------ +default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps -$(DIR)%.o: %.cpp - $(CXX) $(CXXFLAGS) -c $< -o $@ - -# ------ DEPENDENCIES ------ -# -$(DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h -$(DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarbias_abf.h colvarbias.h colvargrid.h -$(DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_restraint.h colvarbias.h -$(DIR)colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h -$(DIR)colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h -$(DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvarbias_meta.h colvarbias.h colvargrid.h -$(DIR)colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \ - colvarbias.h colvar.h colvarparse.h colvardeps.h -$(DIR)colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvaratoms.h colvar.h colvarcomp.h -$(DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ - colvaratoms.h -$(DIR)colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -$(DIR)colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvarscript.h colvarbias.h -$(DIR)colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h -$(DIR)colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvargrid.h -$(DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \ - colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \ - colvarscript.h -$(DIR)colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -$(DIR)colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \ - colvarparse.h colvardeps.h -$(DIR)colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -$(DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h - -# ------ CLEAN ------ +$(COLVARS_OBJ_DIR): + mkdir $(COLVARS_OBJ_DIR) clean: - -rm $(DIR)*.o *~ $(LIB) - -rmdir $(DIR) + -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) + -rmdir $(COLVARS_OBJ_DIR) + +Makefile.lammps: + -cp $(EXTRAMAKE) Makefile.lammps diff --git a/lib/colvars/Makefile.mingw64-cross b/lib/colvars/Makefile.mingw64-cross index 1d83b6a0a8..09d6bd4fa9 100644 --- a/lib/colvars/Makefile.mingw64-cross +++ b/lib/colvars/Makefile.mingw64-cross @@ -1,127 +1,31 @@ -# library build -*- makefile -*- for colvars module - -# which file will be copied to Makefile.lammps +# -*- makefile -*- to build Colvars module with MinGW 32-bit EXTRAMAKE = Makefile.lammps.empty -# ------ SETTINGS ------ +COLVARS_LIB = libcolvars.a +COLVARS_OBJ_DIR = Obj_mingw32/ CXX = x86_64-w64-mingw32-g++ CXXFLAGS = -O2 -march=core2 -mtune=core2 -mpc64 -msse2 \ -fno-rtti -fno-exceptions -finline-functions \ -ffast-math -funroll-loops -fstrict-aliasing \ -Wall -W -Wno-uninitialized -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rscv +AR = x86_64-w64-mingw32-ar +ARFLAGS = -rscv SHELL = /bin/sh -# ------ DEFINITIONS ------ - -SRC = colvaratoms.cpp colvarbias_abf.cpp colvarbias_alb.cpp colvarbias.cpp \ - colvarbias_histogram.cpp colvarbias_meta.cpp colvarbias_restraint.cpp \ - colvarcomp_angles.cpp colvarcomp_coordnums.cpp colvarcomp.cpp \ - colvarcomp_distances.cpp colvarcomp_protein.cpp colvarcomp_rotations.cpp \ - colvardeps.cpp colvar.cpp colvargrid.cpp colvarmodule.cpp colvarparse.cpp \ - colvarscript.cpp colvartypes.cpp colvarvalue.cpp - -DIR = Obj_mingw64/ -LIB = $(DIR)libcolvars.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) -EXE = #colvars_standalone - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) $(EXE) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(DIR) $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -$(DIR)colvars_standalone: colvars_main.o colvarproxy_standalone.o $(LIB) - $(CXX) -o $@ $(CXXFLAGS) $^ - -# ------ MAKE FLAGS ------ - -.SUFFIXES: -.SUFFIXES: .cpp .o +include Makefile.common .PHONY: default clean -# ------ COMPILE RULES ------ +default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps -$(DIR)%.o: %.cpp - $(CXX) $(CXXFLAGS) -c $< -o $@ - -# ------ DEPENDENCIES ------ -# -$(DIR)colvaratoms.o: colvaratoms.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvaratoms.h -$(DIR)colvarbias_abf.o: colvarbias_abf.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarbias_abf.h colvarbias.h colvargrid.h -$(DIR)colvarbias_alb.o: colvarbias_alb.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarbias_alb.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_restraint.h colvarbias.h -$(DIR)colvarbias.o: colvarbias.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarbias.h colvar.h colvarparse.h colvardeps.h -$(DIR)colvarbias_histogram.o: colvarbias_histogram.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvar.h colvarparse.h \ - colvardeps.h colvarbias_histogram.h colvarbias.h colvargrid.h -$(DIR)colvarbias_meta.o: colvarbias_meta.cpp colvar.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvarbias_meta.h colvarbias.h colvargrid.h -$(DIR)colvarbias_restraint.o: colvarbias_restraint.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias_restraint.h \ - colvarbias.h colvar.h colvarparse.h colvardeps.h -$(DIR)colvarcomp_angles.o: colvarcomp_angles.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvar.h colvarparse.h colvardeps.h \ - colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_coordnums.o: colvarcomp_coordnums.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvaratoms.h colvar.h colvarcomp.h -$(DIR)colvarcomp.o: colvarcomp.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvar.h colvarparse.h colvardeps.h colvarcomp.h \ - colvaratoms.h -$(DIR)colvarcomp_distances.o: colvarcomp_distances.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_protein.o: colvarcomp_protein.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarcomp.h colvaratoms.h -$(DIR)colvarcomp_rotations.o: colvarcomp_rotations.cpp colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h \ - colvar.h colvarcomp.h colvaratoms.h -$(DIR)colvar.o: colvar.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvarscript.h colvarbias.h -$(DIR)colvardeps.o: colvardeps.cpp colvardeps.h colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h -$(DIR)colvargrid.o: colvargrid.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h colvardeps.h colvar.h colvarcomp.h \ - colvaratoms.h colvargrid.h -$(DIR)colvarmodule.o: colvarmodule.cpp colvarmodule.h colvartypes.h \ - colvarproxy.h colvarvalue.h colvarparse.h colvardeps.h colvar.h \ - colvarbias.h colvarbias_abf.h colvargrid.h colvarbias_alb.h \ - colvarbias_restraint.h colvarbias_histogram.h colvarbias_meta.h \ - colvarscript.h -$(DIR)colvarparse.o: colvarparse.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -$(DIR)colvarscript.o: colvarscript.cpp colvarscript.h colvarmodule.h \ - colvartypes.h colvarproxy.h colvarvalue.h colvarbias.h colvar.h \ - colvarparse.h colvardeps.h -$(DIR)colvartypes.o: colvartypes.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h colvarparse.h -$(DIR)colvarvalue.o: colvarvalue.cpp colvarmodule.h colvartypes.h colvarproxy.h \ - colvarvalue.h - -# ------ CLEAN ------ +$(COLVARS_OBJ_DIR): + mkdir $(COLVARS_OBJ_DIR) clean: - -rm $(DIR)*.o *~ $(LIB) - -rmdir $(DIR) + -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) + -rmdir $(COLVARS_OBJ_DIR) + +Makefile.lammps: + -cp $(EXTRAMAKE) Makefile.lammps diff --git a/lib/colvars/README b/lib/colvars/README index a5e5938b20..a4f04221b3 100644 --- a/lib/colvars/README +++ b/lib/colvars/README @@ -1,49 +1,35 @@ -This library is the portable "colvars" module, originally interfaced -with the NAMD MD code, to provide an extensible software framework, -that allows enhanced sampling in molecular dynamics simulations. -The module is written to maximize performance, portability, -flexibility of usage for the user, and extensibility for the developer. +## Collective variables module (Colvars) -The development of the colvars library is now hosted on github at: -http://colvars.github.io/ -You can use this site to get access to the latest development sources -and the up-to-date documentation. +A software module for molecular simulation and analysis that provides a +high-performance implementation of sampling algorithms defined on a reduced +space of continuously differentiable functions (aka collective variables). -Copy of the specific documentation is also in - doc/PDF/colvars-refman-lammps.pdf +The module itself implements a variety of functions and algorithms, including +free-energy estimators based on thermodynamic forces, non-equilibrium work and +probability distributions. -Please report bugs and request new features at: -https://github.com/colvars/colvars/issues +For a brief description see: + http://colvars.github.io/ + https://github.com/colvars/colvars/ -The following publications describe the principles of -the implementation of this library: - Using collective variables to drive molecular dynamics simulations, - Giacomo Fiorin , Michael L. Klein & Jérôme Hénin (2013): - Molecular Physics DOI:10.1080/00268976.2013.813594 - - Exploring Multidimensional Free Energy Landscapes Using - Time-Dependent Biases on Collective Variables, - J. Hénin, G. Fiorin, C. Chipot, and M. L. Klein, - J. Chem. Theory Comput., 6, 35-47 (2010). - -------------------------------------------------- +## How to build This directory has source files to build a library that LAMMPS links against when using the USER-COLVARS package. -This library must be built with a C++ compiler, before LAMMPS is -built, so LAMMPS can link against it. +This library must be built with a C++ compiler, *before* LAMMPS is built, so +that LAMMPS can link against it. You can use the provided Makefile.* files or +create your own, specific to your compiler and system. For example: -You can type "make lib-colvars" from the src directory to see help on -how to build this library via make commands, or you can do the same -thing by typing "python Install.py" from within this directory, or you -can do it manually by following the instructions below. + make -f Makefile.g++ -Build the library using one of the provided Makefile.* files or create -your own, specific to your compiler and system. For example: +will use the GNU C++ compiler and is a good template to start. -make -f Makefile.g++ +**Optional**: if you use the Install.py script provided in this folder, you +can give the machine name as the '-m' argument. This can be the suffix of one +of the files from either this folder, or from src/MAKE. +*This is only supported by the Install.py within the lib/colvars folder*. When you are done building this library, two files should exist in this directory: @@ -51,23 +37,42 @@ exist in this directory: libcolvars.a the library LAMMPS will link against Makefile.lammps settings the LAMMPS Makefile will import -Makefile.lammps is created by the make command, by copying one of the -Makefile.lammps.* files. See the EXTRAMAKE setting at the top of the -Makefile.* files. - IMPORTANT: You must examine the final Makefile.lammps to insure it is correct for your system, else the LAMMPS build will likely fail. -Makefile.lammps has settings for 3 variables: - -user-colvars_SYSINC = leave blank for this package unless debugging -user-colvars_SYSLIB = leave blank for this package -user-colvars_SYSPATH = leave blank for this package - -You have several choices for these settings: - -Since they do not normally need to be set, the settings in -Makefile.lammps.empty should work. - If you want to set a debug flag recognized by the library, the -settings in Makefile.lammps.debug should work. +settings in Makefile.common should work. + + +## Documentation + +For the reference manual see: + http://colvars.github.io/colvars-refman-lammps + +A copy of reference manual is also in: + doc/PDF/colvars-refman-lammps.pdf + +Also included is a Doxygen-based developer documentation: + http://colvars.github.io/doxygen/html/ + +The reference article is: + G. Fiorin, M. L. Klein, and J. Henin, + Molecular Physics 111, 3345 (2013). + http://dx.doi.org/10.1080/00268976.2013.813594 + + +## Updating to the latest version + +To recompile LAMMPS with the most recent version of this module, the `master` +branch of this repository from GitHub, or clone it via git: + + git clone https://github.com/colvars/colvars.git + +and run the provided `update-colvars-code.sh` script against the unpacked +LAMMPS source tree: + + ./update-colvars-code.sh /path/to/lammps/folder + +Please report bugs and request new features at: +https://github.com/colvars/colvars/issues + diff --git a/lib/colvars/colvar.cpp b/lib/colvars/colvar.cpp index e8c7e88324..d23bd852aa 100644 --- a/lib/colvars/colvar.cpp +++ b/lib/colvars/colvar.cpp @@ -1,5 +1,5 @@ - // -*- c++ -*- + // This file is part of the Collective Variables module (Colvars). // The original version of Colvars and its updates are located at: // https://github.com/colvars/colvars @@ -7,13 +7,14 @@ // If you wish to distribute your changes, please submit them to the // Colvars repository at GitHub. - #include "colvarmodule.h" #include "colvarvalue.h" #include "colvarparse.h" #include "colvar.h" #include "colvarcomp.h" #include "colvarscript.h" + +// used in build_atom_list() #include @@ -25,8 +26,10 @@ bool compare(colvar::cvc *i, colvar::cvc *j) { colvar::colvar() + : prev_timestep(-1) { // Initialize static array once and for all + runave_os = NULL; init_cv_requires(); } @@ -66,6 +69,13 @@ int colvar::init(std::string const &conf) size_t i; +#ifdef LEPTON + error_code |= init_custom_function(conf); + if (error_code != COLVARS_OK) { + return cvm::get_error(); + } +#endif + // Setup colvar as scripted function of components if (get_keyval(conf, "scriptedFunction", scripted_function, "", colvarparse::parse_silent)) { @@ -122,7 +132,7 @@ int colvar::init(std::string const &conf) } } - if (!is_enabled(f_cv_scripted)) { + if (!(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function))) { colvarvalue const &cvc_value = (cvcs[0])->value(); if (cvm::debug()) cvm::log ("This collective variable is a "+ @@ -141,7 +151,7 @@ int colvar::init(std::string const &conf) // check for linear combinations { - bool lin = !is_enabled(f_cv_scripted); + bool lin = !(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function)); for (i = 0; i < cvcs.size(); i++) { // FIXME this is a reverse dependency, ie. cv feature depends on cvc flag @@ -206,7 +216,7 @@ int colvar::init(std::string const &conf) for (i = 0; i < cvcs.size(); i++) { // components may have different types only for scripted functions - if (!is_enabled(f_cv_scripted) && (colvarvalue::check_types(cvcs[i]->value(), + if (!(is_enabled(f_cv_scripted) || is_enabled(f_cv_custom_function)) && (colvarvalue::check_types(cvcs[i]->value(), cvcs[0]->value())) ) { cvm::error("ERROR: you are definining this collective variable " "by using components of different types. " @@ -223,7 +233,6 @@ int colvar::init(std::string const &conf) // at this point, the colvar's type is defined f.type(value()); - f_accumulated.type(value()); x_old.type(value()); v_fdiff.type(value()); @@ -239,18 +248,23 @@ int colvar::init(std::string const &conf) reset_bias_force(); + get_keyval(conf, "timeStepFactor", time_step_factor, 1); + if (time_step_factor < 0) { + cvm::error("Error: timeStepFactor must be positive.\n"); + return COLVARS_ERROR; + } + if (time_step_factor != 1) { + enable(f_cv_multiple_ts); + } + // TODO use here information from the CVCs' own natural boundaries error_code |= init_grid_parameters(conf); - get_keyval(conf, "timeStepFactor", time_step_factor, 1); - error_code |= init_extended_Lagrangian(conf); error_code |= init_output_flags(conf); - // Start in active state by default + // Now that the children are defined we can solve dependencies enable(f_cv_active); - // Make sure dependency side-effects are correct - refresh_deps(); if (cvm::b_analysis) parse_analysis(conf); @@ -262,6 +276,158 @@ int colvar::init(std::string const &conf) } +#ifdef LEPTON +int colvar::init_custom_function(std::string const &conf) +{ + std::string expr; + std::vector pexprs; + Lepton::ParsedExpression pexpr; + size_t pos = 0; // current position in config string + double *ref; + + if (!key_lookup(conf, "customFunction", &expr, &pos)) { + return COLVARS_OK; + } + + enable(f_cv_custom_function); + cvm::log("This colvar uses a custom function.\n"); + + do { + if (cvm::debug()) + cvm::log("Parsing expression \"" + expr + "\".\n"); + try { + pexpr = Lepton::Parser::parse(expr); + pexprs.push_back(pexpr); + } + catch (...) { + cvm::error("Error parsing expression \"" + expr + "\".\n", INPUT_ERROR); + return INPUT_ERROR; + } + + try { + value_evaluators.push_back( + new Lepton::CompiledExpression(pexpr.createCompiledExpression())); + // Define variables for cvc values + // Stored in order: expr1, cvc1, cvc2, expr2, cvc1... + for (size_t i = 0; i < cvcs.size(); i++) { + for (size_t j = 0; j < cvcs[i]->value().size(); j++) { + std::string vn = cvcs[i]->name + + (cvcs[i]->value().size() > 1 ? cvm::to_str(j+1) : ""); + try { + ref =&value_evaluators.back()->getVariableReference(vn); + } + catch (...) { // Variable is absent from expression + // To keep the same workflow, we use a pointer to a double here + // that will receive CVC values - even though none was allocated by Lepton + ref = &dev_null; + if (cvm::debug()) + cvm::log("Variable " + vn + " is absent from expression \"" + expr + "\".\n"); + } + value_eval_var_refs.push_back(ref); + } + } + } + catch (...) { + cvm::error("Error compiling expression \"" + expr + "\".\n", INPUT_ERROR); + return INPUT_ERROR; + } + } while (key_lookup(conf, "customFunction", &expr, &pos)); + + + // Now define derivative with respect to each scalar sub-component + for (size_t i = 0; i < cvcs.size(); i++) { + for (size_t j = 0; j < cvcs[i]->value().size(); j++) { + std::string vn = cvcs[i]->name + + (cvcs[i]->value().size() > 1 ? cvm::to_str(j+1) : ""); + // Element ordering: we want the + // gradient vector of derivatives of all elements of the colvar + // wrt to a given element of a cvc ([i][j]) + for (size_t c = 0; c < pexprs.size(); c++) { + gradient_evaluators.push_back( + new Lepton::CompiledExpression(pexprs[c].differentiate(vn).createCompiledExpression())); + // and record the refs to each variable in those expressions + for (size_t k = 0; k < cvcs.size(); k++) { + for (size_t l = 0; l < cvcs[k]->value().size(); l++) { + std::string vvn = cvcs[k]->name + + (cvcs[k]->value().size() > 1 ? cvm::to_str(l+1) : ""); + try { + ref = &gradient_evaluators.back()->getVariableReference(vvn); + } + catch (...) { // Variable is absent from derivative + // To keep the same workflow, we use a pointer to a double here + // that will receive CVC values - even though none was allocated by Lepton + if (cvm::debug()) + cvm::log("Variable " + vvn + " is absent from derivative of \"" + expr + "\" wrt " + vn + ".\n"); + ref = &dev_null; + } + grad_eval_var_refs.push_back(ref); + } + } + } + } + } + + + if (value_evaluators.size() == 0) { + cvm::error("Error: no custom function defined.\n", INPUT_ERROR); + return INPUT_ERROR; + } + + std::string type_str; + bool b_type_specified = get_keyval(conf, "customFunctionType", + type_str, "scalar", parse_silent); + x.type(colvarvalue::type_notset); + int t; + for (t = 0; t < colvarvalue::type_all; t++) { + if (type_str == colvarvalue::type_keyword(colvarvalue::Type(t))) { + x.type(colvarvalue::Type(t)); + break; + } + } + if (x.type() == colvarvalue::type_notset) { + cvm::error("Could not parse custom colvar type.", INPUT_ERROR); + return INPUT_ERROR; + } + + // Guess type based on number of expressions + if (!b_type_specified) { + if (value_evaluators.size() == 1) { + x.type(colvarvalue::type_scalar); + } else { + x.type(colvarvalue::type_vector); + } + } + + if (x.type() == colvarvalue::type_vector) { + x.vector1d_value.resize(value_evaluators.size()); + } + + x_reported.type(x); + cvm::log(std::string("Expecting colvar value of type ") + + colvarvalue::type_desc(x.type()) + + (x.type()==colvarvalue::type_vector ? " of size " + cvm::to_str(x.size()) : "") + + ".\n"); + + if (x.size() != value_evaluators.size()) { + cvm::error("Error: based on custom function type, expected " + + cvm::to_str(x.size()) + " scalar expressions, but " + + cvm::to_str(value_evaluators.size() + " were found.\n")); + return INPUT_ERROR; + } + + return COLVARS_OK; +} + +#else + +int colvar::init_custom_function(std::string const &conf) +{ + return COLVARS_OK; +} + +#endif // #ifdef LEPTON + + int colvar::init_grid_parameters(std::string const &conf) { colvarmodule *cv = cvm::main(); @@ -326,7 +492,8 @@ int colvar::init_grid_parameters(std::string const &conf) std::string const walls_conf("\n\ harmonicWalls {\n\ name "+this->name+"w\n\ - colvars "+this->name+"\n"+lw_conf+uw_conf+ + colvars "+this->name+"\n"+lw_conf+uw_conf+"\ + timeStepFactor "+cvm::to_str(time_step_factor)+"\n"+ "}\n"); cv->append_new_config(walls_conf); } @@ -372,17 +539,14 @@ harmonicWalls {\n\ int colvar::init_extended_Lagrangian(std::string const &conf) { - bool b_extended_Lagrangian; - get_keyval(conf, "extendedLagrangian", b_extended_Lagrangian, false); + get_keyval_feature(this, conf, "extendedLagrangian", f_cv_extended_Lagrangian, false); - if (b_extended_Lagrangian) { + if (is_enabled(f_cv_extended_Lagrangian)) { cvm::real temp, tolerance, period; cvm::log("Enabling the extended Lagrangian term for colvar \""+ this->name+"\".\n"); - enable(f_cv_extended_Lagrangian); - xr.type(value()); vr.type(value()); fr.type(value()); @@ -404,7 +568,7 @@ int colvar::init_extended_Lagrangian(std::string const &conf) return INPUT_ERROR; } ext_force_k = cvm::boltzmann() * temp / (tolerance * tolerance); - cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " kcal/mol/U^2"); + cvm::log("Computed extended system force constant: " + cvm::to_str(ext_force_k) + " [E]/U^2"); get_keyval(conf, "extendedTimeConstant", period, 200.0); if (period <= 0.0) { @@ -412,7 +576,7 @@ int colvar::init_extended_Lagrangian(std::string const &conf) } ext_mass = (cvm::boltzmann() * temp * period * period) / (4.0 * PI * PI * tolerance * tolerance); - cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " kcal/mol/(U/fs)^2 (U: colvar unit)"); + cvm::log("Computed fictitious mass: " + cvm::to_str(ext_mass) + " [E]/(U/fs)^2 (U: colvar unit)"); { bool b_output_energy; @@ -429,8 +593,9 @@ int colvar::init_extended_Lagrangian(std::string const &conf) } if (ext_gamma != 0.0) { enable(f_cv_Langevin); - ext_gamma *= 1.0e-3; // convert from ps-1 to fs-1 - ext_sigma = std::sqrt(2.0 * cvm::boltzmann() * temp * ext_gamma * ext_mass / cvm::dt()); + ext_gamma *= 1.0e-3; // correct as long as input is required in ps-1 and cvm::dt() is in fs + // Adjust Langevin sigma for slow time step if time_step_factor != 1 + ext_sigma = std::sqrt(2.0 * cvm::boltzmann() * temp * ext_gamma * ext_mass / (cvm::dt() * cvm::real(time_step_factor))); } } @@ -486,8 +651,8 @@ template int colvar::init_components_type(std::string c size_t pos = 0; while ( this->key_lookup(conf, def_config_key, - def_conf, - pos) ) { + &def_conf, + &pos) ) { if (!def_conf.size()) continue; cvm::log("Initializing " "a new \""+std::string(def_config_key)+"\" component"+ @@ -514,6 +679,7 @@ template int colvar::init_components_type(std::string c if ( (cvcp->period != 0.0) || (cvcp->wrap_center != 0.0) ) { if ( (cvcp->function_type != std::string("distance_z")) && (cvcp->function_type != std::string("dihedral")) && + (cvcp->function_type != std::string("polar_phi")) && (cvcp->function_type != std::string("spin_angle")) ) { cvm::error("Error: invalid use of period and/or " "wrapAround in a \""+ @@ -566,6 +732,10 @@ int colvar::init_components(std::string const &conf) "on an axis", "distanceZ"); error_code |= init_components_type(conf, "distance projection " "on a plane", "distanceXY"); + error_code |= init_components_type(conf, "spherical polar angle theta", + "polarTheta"); + error_code |= init_components_type(conf, "spherical azimuthal angle phi", + "polarPhi"); error_code |= init_components_type(conf, "average distance " "weighted by inverse power", "distanceInv"); error_code |= init_components_type(conf, "N1xN2-long vector " @@ -618,16 +788,18 @@ int colvar::init_components(std::string const &conf) } -int colvar::refresh_deps() +void colvar::do_feature_side_effects(int id) { - // If enabled features are changed upstream, the features below should be refreshed - if (is_enabled(f_cv_total_force_calc)) { - cvm::request_total_force(); + switch (id) { + case f_cv_total_force_calc: + cvm::request_total_force(); + break; + case f_cv_collect_gradient: + if (atom_ids.size() == 0) { + build_atom_list(); + } + break; } - if (is_enabled(f_cv_collect_gradient) && atom_ids.size() == 0) { - build_atom_list(); - } - return COLVARS_OK; } @@ -688,20 +860,19 @@ int colvar::parse_analysis(std::string const &conf) cvm::error("Error: runAveStride must be commensurate with the restart frequency.\n", INPUT_ERROR); } - std::string runave_outfile; get_keyval(conf, "runAveOutputFile", runave_outfile, std::string(cvm::output_prefix()+"."+ this->name+".runave.traj")); size_t const this_cv_width = x.output_width(cvm::cv_width); - cvm::backup_file(runave_outfile.c_str()); - runave_os.open(runave_outfile.c_str()); - runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2) - << " " - << cvm::wrap_string("running average", this_cv_width) - << " " - << cvm::wrap_string("running stddev", this_cv_width) - << "\n"; + cvm::proxy->backup_file(runave_outfile); + runave_os = cvm::proxy->output_stream(runave_outfile); + *runave_os << "# " << cvm::wrap_string("step", cvm::it_width-2) + << " " + << cvm::wrap_string("running average", this_cv_width) + << " " + << cvm::wrap_string("running stddev", this_cv_width) + << "\n"; } acf_length = 0; @@ -768,6 +939,10 @@ void colvar::setup() { colvar::~colvar() { + // There is no need to call free_children_deps() here + // because the children are cvcs and will be deleted + // just below + // Clear references to this colvar's cvcs as children // for dependency purposes remove_all_children(); @@ -792,6 +967,22 @@ colvar::~colvar() break; } } + +#ifdef LEPTON + for (std::vector::iterator cei = value_evaluators.begin(); + cei != value_evaluators.end(); + ++cei) { + if (*cei != NULL) delete (*cei); + } + value_evaluators.clear(); + + for (std::vector::iterator gei = gradient_evaluators.begin(); + gei != gradient_evaluators.end(); + ++gei) { + if (*gei != NULL) delete (*gei); + } + gradient_evaluators.clear(); +#endif } @@ -911,7 +1102,6 @@ int colvar::calc_cvc_values(int first_cvc, size_t num_cvcs) int colvar::collect_cvc_values() { x.reset(); - size_t i; // combine them appropriately, using either a scripted function or a polynomial if (is_enabled(f_cv_scripted)) { @@ -925,9 +1115,26 @@ int colvar::collect_cvc_values() cvm::error("Error running scripted colvar"); return COLVARS_OK; } + +#ifdef LEPTON + } else if (is_enabled(f_cv_custom_function)) { + + size_t l = 0; // index in the vector of variable references + + for (size_t i = 0; i < x.size(); i++) { + // Fill Lepton evaluator variables with CVC values, serialized into scalars + for (size_t j = 0; j < cvcs.size(); j++) { + for (size_t k = 0; k < cvcs[j]->value().size(); k++) { + *(value_eval_var_refs[l++]) = cvcs[j]->value()[k]; + } + } + x[i] = value_evaluators[i]->evaluate(); + } +#endif + } else if (x.type() == colvarvalue::type_scalar) { // polynomial combination allowed - for (i = 0; i < cvcs.size(); i++) { + for (size_t i = 0; i < cvcs.size(); i++) { if (!cvcs[i]->is_enabled()) continue; x += (cvcs[i])->sup_coeff * ( ((cvcs[i])->sup_np != 1) ? @@ -935,7 +1142,7 @@ int colvar::collect_cvc_values() (cvcs[i])->value().real_value ); } } else { - for (i = 0; i < cvcs.size(); i++) { + for (size_t i = 0; i < cvcs.size(); i++) { if (!cvcs[i]->is_enabled()) continue; x += (cvcs[i])->sup_coeff * (cvcs[i])->value(); } @@ -984,16 +1191,9 @@ int colvar::calc_cvc_gradients(int first_cvc, size_t num_cvcs) (cvcs[i])->calc_gradients(); // if requested, propagate (via chain rule) the gradients above // to the atoms used to define the roto-translation - // This could be integrated in the CVC base class - for (size_t ig = 0; ig < cvcs[i]->atom_groups.size(); ig++) { - if (cvcs[i]->atom_groups[ig]->b_fit_gradients) - cvcs[i]->atom_groups[ig]->calc_fit_gradients(); - - if (cvcs[i]->is_enabled(f_cvc_debug_gradient)) { - cvm::log("Debugging gradients for " + cvcs[i]->description); - cvcs[i]->debug_gradients(cvcs[i]->atom_groups[ig]); - } - } + (cvcs[i])->calc_fit_gradients(); + if ((cvcs[i])->is_enabled(f_cvc_debug_gradient)) + (cvcs[i])->debug_gradients(); } cvm::decrease_depth(); @@ -1011,13 +1211,6 @@ int colvar::collect_cvc_gradients() size_t i; if (is_enabled(f_cv_collect_gradient)) { - - if (is_enabled(f_cv_scripted)) { - cvm::error("Collecting atomic gradients is not implemented for " - "scripted colvars.", COLVARS_NOT_IMPLEMENTED); - return COLVARS_NOT_IMPLEMENTED; - } - // Collect the atomic gradients inside colvar object for (unsigned int a = 0; a < atomic_gradients.size(); a++) { atomic_gradients[a].reset(); @@ -1214,6 +1407,11 @@ cvm::real colvar::update_forces_energy() // set to zero the applied force f.type(value()); f.reset(); + fr.reset(); + + // If we are not active at this timestep, that's all we have to do + // return with energy == zero + if (!is_enabled(f_cv_active)) return 0.; // add the biases' force, which at this point should already have // been summed over each bias using this colvar @@ -1236,7 +1434,24 @@ cvm::real colvar::update_forces_energy() cvm::log("Updating extended-Lagrangian degree of freedom.\n"); } - cvm::real dt = cvm::dt(); + if (prev_timestep > -1) { + // Keep track of slow timestep to integrate MTS colvars + // the colvar checks the interval after waking up twice + int n_timesteps = cvm::step_relative() - prev_timestep; + if (n_timesteps != 0 && n_timesteps != time_step_factor) { + cvm::error("Error: extended-Lagrangian " + description + " has timeStepFactor " + + cvm::to_str(time_step_factor) + ", but was activated after " + cvm::to_str(n_timesteps) + + " steps at timestep " + cvm::to_str(cvm::step_absolute()) + " (relative step: " + + cvm::to_str(cvm::step_relative()) + ").\n" + + "Make sure that this colvar is requested by biases at multiples of timeStepFactor.\n"); + return 0.; + } + } + prev_timestep = cvm::step_relative(); + + // Integrate with slow timestep (if time_step_factor != 1) + cvm::real dt = cvm::dt() * cvm::real(time_step_factor); + colvarvalue f_ext(fr.type()); // force acting on the extended variable f_ext.reset(); @@ -1248,18 +1463,17 @@ cvm::real colvar::update_forces_energy() // - after this code block, colvar force to be applied to atomic coordinates // ie. spring force (fb_actual will be added just below) fr = f; - f_ext = f + (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x); - f = (-0.5 * ext_force_k) * this->dist2_rgrad(xr, x); + // External force has been scaled for a 1-timestep impulse, scale it back because we will + // integrate it with the colvar's own timestep factor + f_ext = f / cvm::real(time_step_factor); + f_ext += (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x); + f = (-0.5 * ext_force_k) * this->dist2_rgrad(xr, x); + // Coupling force is a slow force, to be applied to atomic coords impulse-style + f *= cvm::real(time_step_factor); - if (is_enabled(f_cv_subtract_applied_force)) { - // Report a "system" force without the biases on this colvar - // that is, just the spring force - ft_reported = (-0.5 * ext_force_k) * this->dist2_lgrad(xr, x); - } else { - // The total force acting on the extended variable is f_ext - // This will be used in the next timestep - ft_reported = f_ext; - } + // The total force acting on the extended variable is f_ext + // This will be used in the next timestep + ft_reported = f_ext; // leapfrog: starting from x_i, f_i, v_(i-1/2) vr += (0.5 * dt) * f_ext / ext_mass; @@ -1279,13 +1493,10 @@ cvm::real colvar::update_forces_energy() if (this->is_enabled(f_cv_periodic)) this->wrap(xr); } - // Now adding the force on the actual colvar (for those biases who + // Now adding the force on the actual colvar (for those biases that // bypass the extended Lagrangian mass) f += fb_actual; - // Store force to be applied, possibly summed over several timesteps - f_accumulated += f; - if (is_enabled(f_cv_fdiff_velocity)) { // set it for the next step x_old = x; @@ -1306,7 +1517,7 @@ void colvar::communicate_forces() size_t i; if (cvm::debug()) { cvm::log("Communicating forces from colvar \""+this->name+"\".\n"); - cvm::log("Force to be applied: " + cvm::to_str(f_accumulated) + "\n"); + cvm::log("Force to be applied: " + cvm::to_str(f) + "\n"); } if (is_enabled(f_cv_scripted)) { @@ -1333,14 +1544,42 @@ void colvar::communicate_forces() if (!cvcs[i]->is_enabled()) continue; // cvc force is colvar force times colvar/cvc Jacobian // (vector-matrix product) - (cvcs[i])->apply_force(colvarvalue(f_accumulated.as_vector() * func_grads[grad_index++], + (cvcs[i])->apply_force(colvarvalue(f.as_vector() * func_grads[grad_index++], cvcs[i]->value().type())); } + +#ifdef LEPTON + } else if (is_enabled(f_cv_custom_function)) { + + size_t r = 0; // index in the vector of variable references + size_t e = 0; // index of the gradient evaluator + + for (size_t i = 0; i < cvcs.size(); i++) { // gradient with respect to cvc i + cvm::matrix2d jacobian (x.size(), cvcs[i]->value().size()); + for (size_t j = 0; j < cvcs[i]->value().size(); j++) { // j-th element + for (size_t c = 0; c < x.size(); c++) { // derivative of scalar element c of the colvarvalue + + // Feed cvc values to the evaluator + for (size_t k = 0; k < cvcs.size(); k++) { // + for (size_t l = 0; l < cvcs[k]->value().size(); l++) { + *(grad_eval_var_refs[r++]) = cvcs[k]->value()[l]; + } + } + jacobian[c][j] = gradient_evaluators[e++]->evaluate(); + } + } + // cvc force is colvar force times colvar/cvc Jacobian + // (vector-matrix product) + (cvcs[i])->apply_force(colvarvalue(f.as_vector() * jacobian, + cvcs[i]->value().type())); + } +#endif + } else if (x.type() == colvarvalue::type_scalar) { for (i = 0; i < cvcs.size(); i++) { if (!cvcs[i]->is_enabled()) continue; - (cvcs[i])->apply_force(f_accumulated * (cvcs[i])->sup_coeff * + (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff * cvm::real((cvcs[i])->sup_np) * (std::pow((cvcs[i])->value().real_value, (cvcs[i])->sup_np-1)) ); @@ -1350,14 +1589,10 @@ void colvar::communicate_forces() for (i = 0; i < cvcs.size(); i++) { if (!cvcs[i]->is_enabled()) continue; - (cvcs[i])->apply_force(f_accumulated * (cvcs[i])->sup_coeff); + (cvcs[i])->apply_force(f * (cvcs[i])->sup_coeff); } } - // Accumulated forces have been applied, impulse-style - // Reset to start accumulating again - f_accumulated.reset(); - if (cvm::debug()) cvm::log("Done communicating forces from colvar \""+this->name+"\".\n"); } @@ -1394,7 +1629,7 @@ int colvar::update_cvc_flags() cvm::error("ERROR: All CVCs are disabled for colvar " + this->name +"\n"); return COLVARS_ERROR; } - cvc_flags.resize(0); + cvc_flags.clear(); } return COLVARS_OK; @@ -1744,16 +1979,15 @@ int colvar::write_output_files() cvm::log("Writing acf to file \""+acf_outfile+"\".\n"); cvm::backup_file(acf_outfile.c_str()); - cvm::ofstream acf_os(acf_outfile.c_str()); - if (! acf_os.is_open()) { - cvm::error("Cannot open file \""+acf_outfile+"\".\n", FILE_ERROR); - } - write_acf(acf_os); - acf_os.close(); + std::ostream *acf_os = cvm::proxy->output_stream(acf_outfile); + if (!acf_os) return cvm::get_error(); + write_acf(*acf_os); + cvm::proxy->close_output_stream(acf_outfile); } - if (runave_os.is_open()) { - runave_os.close(); + if (runave_os) { + cvm::proxy->close_output_stream(runave_outfile); + runave_os = NULL; } } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -2031,12 +2265,12 @@ void colvar::calc_runave() } runave_variance *= 1.0 / cvm::real(runave_length-1); - runave_os << std::setw(cvm::it_width) << cvm::step_relative() - << " " - << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) - << runave << " " - << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) - << std::sqrt(runave_variance) << "\n"; + *runave_os << std::setw(cvm::it_width) << cvm::step_relative() + << " " + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) + << runave << " " + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) + << std::sqrt(runave_variance) << "\n"; } history_add_value(runave_length, *x_history_p, x); diff --git a/lib/colvars/colvar.h b/lib/colvars/colvar.h index 0cbda450b8..6113e1678b 100644 --- a/lib/colvars/colvar.h +++ b/lib/colvars/colvar.h @@ -19,6 +19,9 @@ #include "colvarparse.h" #include "colvardeps.h" +#ifdef LEPTON +#include "Lepton.h" // for runtime custom expressions +#endif /// \brief A collective variable (main class); to be defined, it needs /// at least one object of a derived class of colvar::cvc; it @@ -89,7 +92,10 @@ public: return cv_features; } - int refresh_deps(); + /// Implements possible actions to be carried out + /// when a given feature is enabled + /// This overloads the base function in colvardeps + void do_feature_side_effects(int id); /// List of biases that depend on this colvar std::vector biases; @@ -235,6 +241,9 @@ public: /// Parse the CVC configuration and allocate their data int init_components(std::string const &conf); + /// Parse parameters for custom function with Lepton + int init_custom_function(std::string const &conf); + /// Init defaults for grid options int init_grid_parameters(std::string const &conf); @@ -334,24 +343,13 @@ protected: /// Sum of square coefficients for active cvcs cvm::real active_cvc_square_norm; - /// Time step multiplier (for coarse-time-step colvars) - /// Colvar will only be calculated at those times; biases may ignore the information and - /// always update their own forces (which is typically inexpensive) especially if - /// they rely on other colvars. In this case, the colvar will accumulate forces applied between - /// colvar updates. Alternately they may use it to calculate "impulse" biasing - /// forces at longer intervals. Impulse forces must be multiplied by the timestep factor. - int time_step_factor; - - /// Biasing force collected between updates, to be applied at next update for coarse-time-step colvars - colvarvalue f_accumulated; + /// \brief Absolute timestep number when this colvar was last updated + int prev_timestep; public: /// \brief Return the number of CVC objects with an active flag (as set by update_cvc_flags) inline size_t num_active_cvcs() const { return n_active_cvcs; } - /// \brief returns time_step_factor - inline int get_time_step_factor() const {return time_step_factor;} - /// \brief Use the internal metrics (as from \link cvc /// \endlink objects) to calculate square distances and gradients /// @@ -484,7 +482,9 @@ protected: /// Timesteps to skip between two values in the running average series size_t runave_stride; /// Name of the file to write the running average - cvm::ofstream runave_os; + std::string runave_outfile; + /// File to write the running average + std::ostream *runave_os; /// Current value of the running average colvarvalue runave; /// Current value of the square deviation from the running average @@ -508,6 +508,8 @@ public: class distance; class distance_z; class distance_xy; + class polar_theta; + class polar_phi; class distance_inv; class distance_pairs; class angle; @@ -556,6 +558,21 @@ private: /// when using scriptedFunction std::vector sorted_cvc_values; +#ifdef LEPTON + /// Vector of evaluators for custom functions using Lepton + std::vector value_evaluators; + + /// Vector of evaluators for gradients of custom functions + std::vector gradient_evaluators; + + /// Vector of references to cvc values to be passed to Lepton evaluators + std::vector value_eval_var_refs; + std::vector grad_eval_var_refs; + + /// Unused value that is written to when a variable simplifies out of a Lepton expression + double dev_null; +#endif + public: /// \brief Sorted array of (zero-based) IDs for all atoms involved std::vector atom_ids; diff --git a/lib/colvars/colvaratoms.cpp b/lib/colvars/colvaratoms.cpp index 32cfadf3b6..9b4a922e3f 100644 --- a/lib/colvars/colvaratoms.cpp +++ b/lib/colvars/colvaratoms.cpp @@ -67,18 +67,16 @@ cvm::atom::~atom() -// TODO change this arrangement -// Note: "conf" is the configuration of the cvc who is using this atom group; -// "key" is the name of the atom group (e.g. "atoms", "group1", "group2", ...) -cvm::atom_group::atom_group(std::string const &conf, - char const *key_in) +cvm::atom_group::atom_group() +{ + init(); +} + + +cvm::atom_group::atom_group(char const *key_in) { key = key_in; - cvm::log("Defining atom group \"" + key + "\".\n"); init(); - // real work is done by parse - parse(conf); - setup(); } @@ -90,12 +88,6 @@ cvm::atom_group::atom_group(std::vector const &atoms_in) } -cvm::atom_group::atom_group() -{ - init(); -} - - cvm::atom_group::~atom_group() { if (is_enabled(f_ag_scalable) && !b_dummy) { @@ -180,7 +172,7 @@ int cvm::atom_group::init() { if (!key.size()) key = "unnamed"; description = "atom group " + key; - // These will be overwritten by parse(), if initializing from a config string + // These may be overwritten by parse(), if a name is provided atoms.clear(); @@ -193,7 +185,6 @@ int cvm::atom_group::init() b_center = false; b_rotate = false; b_user_defined_fit = false; - b_fit_gradients = false; fitting_group = NULL; noforce = false; @@ -265,34 +256,10 @@ void cvm::atom_group::update_total_charge() } -int cvm::atom_group::parse(std::string const &conf) +int cvm::atom_group::parse(std::string const &group_conf) { - std::string group_conf; - - // TODO move this to the cvc class constructor/init - - // save_delimiters is set to false for this call, because "conf" is - // not the config string of this group, but of its parent object - // (which has already taken care of the delimiters) - save_delimiters = false; - key_lookup(conf, key.c_str(), group_conf, dummy_pos); - // restoring the normal value, because we do want keywords checked - // inside "group_conf" - save_delimiters = true; - - if (group_conf.size() == 0) { - cvm::error("Error: atom group \""+key+ - "\" is set, but has no definition.\n", - INPUT_ERROR); - return COLVARS_ERROR; - } - - cvm::increase_depth(); - cvm::log("Initializing atom group \""+key+"\".\n"); - description = "atom group " + key; - // whether or not to include messages in the log // colvarparse::Parse_Mode mode = parse_silent; // { @@ -304,10 +271,53 @@ int cvm::atom_group::parse(std::string const &conf) int parse_error = COLVARS_OK; + // Optional group name will let other groups reuse atom definition + if (get_keyval(group_conf, "name", name)) { + if ((cvm::atom_group_by_name(this->name) != NULL) && + (cvm::atom_group_by_name(this->name) != this)) { + cvm::error("Error: this atom group cannot have the same name, \""+this->name+ + "\", as another atom group.\n", + INPUT_ERROR); + return INPUT_ERROR; + } + cvm::main()->register_named_atom_group(this); + description = "atom group " + name; + } + + // We need to know about fitting to decide whether the group is scalable + // and we need to know about scalability before adding atoms + bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false); + bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false); + // is the user setting explicit options? + b_user_defined_fit = b_defined_center || b_defined_rotate; + + if (is_available(f_ag_scalable_com) && !b_rotate && !b_center) { + enable(f_ag_scalable_com); + enable(f_ag_scalable); + } + + { + std::string atoms_of = ""; + if (get_keyval(group_conf, "atomsOfGroup", atoms_of)) { + atom_group * ag = atom_group_by_name(atoms_of); + if (ag == NULL) { + cvm::error("Error: cannot find atom group with name " + atoms_of + ".\n"); + return COLVARS_ERROR; + } + parse_error |= add_atoms_of_group(ag); + } + } + +// if (get_keyval(group_conf, "copyOfGroup", source)) { +// // Goal: Initialize this as a full copy +// // for this we'll need an atom_group copy constructor +// return COLVARS_OK; +// } + { std::string numbers_conf = ""; size_t pos = 0; - while (key_lookup(group_conf, "atomNumbers", numbers_conf, pos)) { + while (key_lookup(group_conf, "atomNumbers", &numbers_conf, &pos)) { parse_error |= add_atom_numbers(numbers_conf); numbers_conf = ""; } @@ -325,7 +335,7 @@ int cvm::atom_group::parse(std::string const &conf) std::string range_conf = ""; size_t pos = 0; while (key_lookup(group_conf, "atomNumbersRange", - range_conf, pos)) { + &range_conf, &pos)) { parse_error |= add_atom_numbers_range(range_conf); range_conf = ""; } @@ -347,7 +357,7 @@ int cvm::atom_group::parse(std::string const &conf) size_t range_count = 0; psii = psf_segids.begin(); while (key_lookup(group_conf, "atomNameResidueRange", - range_conf, pos)) { + &range_conf, &pos)) { range_count++; if (psf_segids.size() && (range_count > psf_segids.size())) { cvm::error("Error: more instances of \"atomNameResidueRange\" than " @@ -415,14 +425,9 @@ int cvm::atom_group::parse(std::string const &conf) } } - // We need to know the fitting options to decide whether the group is scalable + // Now that atoms are defined we can parse the detailed fitting options parse_error |= parse_fitting_options(group_conf); - if (is_available(f_ag_scalable_com) && !b_rotate && !b_center) { - enable(f_ag_scalable_com); - enable(f_ag_scalable); - } - if (is_enabled(f_ag_scalable) && !b_dummy) { cvm::log("Enabling scalable calculation for group \""+this->key+"\".\n"); index = (cvm::proxy)->init_atom_group(atoms_ids); @@ -431,13 +436,6 @@ int cvm::atom_group::parse(std::string const &conf) bool b_print_atom_ids = false; get_keyval(group_conf, "printAtomIDs", b_print_atom_ids, false, colvarparse::parse_silent); - // TODO move this to colvarparse object - check_keywords(group_conf, key.c_str()); - if (cvm::get_error()) { - cvm::error("Error setting up atom group \""+key+"\"."); - return COLVARS_ERROR; - } - // Calculate all required properties (such as total mass) setup(); @@ -446,7 +444,7 @@ int cvm::atom_group::parse(std::string const &conf) cvm::log("Atom group \""+key+"\" defined, "+ cvm::to_str(atoms_ids.size())+" atoms initialized: total mass = "+ - cvm::to_str(total_mass)+", total charge = "+ + cvm::to_str(total_mass)+", total charge = "+ cvm::to_str(total_charge)+".\n"); if (b_print_atom_ids) { @@ -454,12 +452,41 @@ int cvm::atom_group::parse(std::string const &conf) cvm::log(print_atom_ids()); } - cvm::decrease_depth(); - return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } +int cvm::atom_group::add_atoms_of_group(atom_group const * ag) +{ + std::vector const &source_ids = ag->atoms_ids; + + if (source_ids.size()) { + atoms_ids.reserve(atoms_ids.size()+source_ids.size()); + + if (is_enabled(f_ag_scalable)) { + for (size_t i = 0; i < source_ids.size(); i++) { + add_atom_id(source_ids[i]); + } + } else { + atoms.reserve(atoms.size()+source_ids.size()); + for (size_t i = 0; i < source_ids.size(); i++) { + // We could use the atom copy constructor, but only if the source + // group is not scalable - whereas this works in both cases + // atom constructor expects 1-based atom number + add_atom(cvm::atom(source_ids[i] + 1)); + } + } + + if (cvm::get_error()) return COLVARS_ERROR; + } else { + cvm::error("Error: source atom group contains no atoms\".\n", INPUT_ERROR); + return COLVARS_ERROR; + } + + return COLVARS_OK; +} + + int cvm::atom_group::add_atom_numbers(std::string const &numbers_conf) { std::vector atom_indexes; @@ -629,13 +656,6 @@ std::string const cvm::atom_group::print_atom_ids() const int cvm::atom_group::parse_fitting_options(std::string const &group_conf) { - bool b_defined_center = get_keyval(group_conf, "centerReference", b_center, false); - bool b_defined_rotate = get_keyval(group_conf, "rotateReference", b_rotate, false); - // is the user setting explicit options? - b_user_defined_fit = b_defined_center || b_defined_rotate; - - get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true); - if (b_center || b_rotate) { if (b_dummy) @@ -643,27 +663,31 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf) "cannot be defined for a dummy atom.\n"); bool b_ref_pos_group = false; - if (key_lookup(group_conf, "refPositionsGroup")) { + std::string fitting_group_conf; + if (key_lookup(group_conf, "refPositionsGroup", &fitting_group_conf)) { b_ref_pos_group = true; cvm::log("Warning: keyword \"refPositionsGroup\" is deprecated: please use \"fittingGroup\" instead.\n"); } - if (b_ref_pos_group || key_lookup(group_conf, "fittingGroup")) { + if (b_ref_pos_group || key_lookup(group_conf, "fittingGroup", &fitting_group_conf)) { // instead of this group, define another group to compute the fit if (fitting_group) { cvm::error("Error: the atom group \""+ key+"\" has already a reference group " "for the rototranslational fit, which was communicated by the " "colvar component. You should not use fittingGroup " - "in this case.\n"); + "in this case.\n", INPUT_ERROR); + return INPUT_ERROR; } cvm::log("Within atom group \""+key+"\":\n"); - fitting_group = b_ref_pos_group ? - new atom_group(group_conf, "refPositionsGroup") : - new atom_group(group_conf, "fittingGroup"); - - // regardless of the configuration, fit gradients must be calculated by fittingGroup - fitting_group->b_fit_gradients = this->b_fit_gradients; + fitting_group = new atom_group("fittingGroup"); + if (fitting_group->parse(fitting_group_conf) == COLVARS_OK) { + fitting_group->check_keywords(fitting_group_conf, "fittingGroup"); + if (cvm::get_error()) { + cvm::error("Error setting up atom group \"fittingGroup\".", INPUT_ERROR); + return INPUT_ERROR; + } + } } atom_group *group_for_fit = fitting_group ? fitting_group : this; @@ -720,11 +744,6 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf) return COLVARS_ERROR; } - if (b_fit_gradients) { - group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0)); - rot.request_group1_gradients(group_for_fit->size()); - } - if (b_rotate && !noforce) { cvm::log("Warning: atom group \""+key+ "\" will be aligned to a fixed orientation given by the reference positions provided. " @@ -737,10 +756,37 @@ int cvm::atom_group::parse_fitting_options(std::string const &group_conf) } } + // Enable fit gradient calculation only if necessary, and not disabled by the user + // This must happen after fitting group is defined so that side-effects are performed + // properly (ie. allocating fitting group gradients) + { + bool b_fit_gradients; + get_keyval(group_conf, "enableFitGradients", b_fit_gradients, true); + + if (b_fit_gradients && (b_center || b_rotate)) { + enable(f_ag_fit_gradients); + } + } + return COLVARS_OK; } +void cvm::atom_group::do_feature_side_effects(int id) +{ + // If enabled features are changed upstream, the features below should be refreshed + switch (id) { + case f_ag_fit_gradients: + if (b_center || b_rotate) { + atom_group *group_for_fit = fitting_group ? fitting_group : this; + group_for_fit->fit_gradients.assign(group_for_fit->size(), cvm::atom_pos(0.0, 0.0, 0.0)); + rot.request_group1_gradients(group_for_fit->size()); + } + break; + } +} + + int cvm::atom_group::create_sorted_ids(void) { // Only do the work if the vector is not yet populated @@ -1000,12 +1046,12 @@ void cvm::atom_group::set_weighted_gradient(cvm::rvector const &grad) void cvm::atom_group::calc_fit_gradients() { - if (b_dummy) return; + if (b_dummy || ! is_enabled(f_ag_fit_gradients)) return; if (cvm::debug()) cvm::log("Calculating fit gradients.\n"); - atom_group *group_for_fit = fitting_group ? fitting_group : this; + cvm::atom_group *group_for_fit = fitting_group ? fitting_group : this; if (b_center) { // add the center of geometry contribution to the gradients @@ -1190,7 +1236,7 @@ void cvm::atom_group::apply_colvar_force(cvm::real const &force) } } - if ((b_center || b_rotate) && b_fit_gradients) { + if ((b_center || b_rotate) && is_enabled(f_ag_fit_gradients)) { atom_group *group_for_fit = fitting_group ? fitting_group : this; diff --git a/lib/colvars/colvaratoms.h b/lib/colvars/colvaratoms.h index 85f6212951..dba2890abc 100644 --- a/lib/colvars/colvaratoms.h +++ b/lib/colvars/colvaratoms.h @@ -150,12 +150,21 @@ class colvarmodule::atom_group { public: - /// \brief Initialize the group by looking up its configuration - /// string in conf and parsing it; this is actually done by parse(), - /// which is a member function so that a group can be initialized - /// also after construction - atom_group(std::string const &conf, - char const *key); + + /// \brief Default constructor + atom_group(); + + /// \brief Create a group object, assign a name to it + atom_group(char const *key); + + /// \brief Initialize the group after a (temporary) vector of atoms + atom_group(std::vector const &atoms_in); + + /// \brief Destructor + ~atom_group(); + + /// \brief Optional name to reuse properties of this in other groups + std::string name; /// \brief Keyword used to define the group // TODO Make this field part of the data structures that link a group to a CVC @@ -172,15 +181,13 @@ public: int parse(std::string const &conf); int add_atom_numbers(std::string const &numbers_conf); + int add_atoms_of_group(atom_group const * ag); int add_index_group(std::string const &index_group_name); int add_atom_numbers_range(std::string const &range_conf); int add_atom_name_residue_range(std::string const &psf_segid, std::string const &range_conf); int parse_fitting_options(std::string const &group_conf); - /// \brief Initialize the group after a (temporary) vector of atoms - atom_group(std::vector const &atoms_in); - /// \brief Add an atom object to this group int add_atom(cvm::atom const &a); @@ -203,12 +210,6 @@ public: return ag_features; } - /// \brief Default constructor - atom_group(); - - /// \brief Destructor - ~atom_group(); - protected: /// \brief Array of atom objects @@ -294,10 +295,6 @@ public: /// cvc's (eg rmsd, eigenvector) will not override the user's choice bool b_user_defined_fit; - /// \brief Whether or not the derivatives of the roto-translation - /// should be included when calculating the colvar's gradients (default: yes) - bool b_fit_gradients; - /// \brief use reference coordinates for b_center or b_rotate std::vector ref_pos; @@ -464,6 +461,10 @@ public: /// apply_colvar_force() once that is implemented for non-scalar values void apply_force(cvm::rvector const &force); + /// Implements possible actions to be carried out + /// when a given feature is enabled + /// This overloads the base function in colvardeps + void do_feature_side_effects(int id); }; diff --git a/lib/colvars/colvarbias.cpp b/lib/colvars/colvarbias.cpp index 3779c82aa3..e437466be9 100644 --- a/lib/colvars/colvarbias.cpp +++ b/lib/colvars/colvarbias.cpp @@ -23,9 +23,7 @@ colvarbias::colvarbias(char const *key) b_output_energy = false; reset(); state_file_step = 0; - - // Start in active state by default - enable(f_cvb_active); + description = "uninitialized " + cvm::to_str(key) + " bias"; } @@ -74,7 +72,6 @@ int colvarbias::init(std::string const &conf) cvm::error("Error: no collective variables specified.\n", INPUT_ERROR); return INPUT_ERROR; } - } else { cvm::log("Reinitializing bias \""+name+"\".\n"); } @@ -83,6 +80,16 @@ int colvarbias::init(std::string const &conf) get_keyval(conf, "outputEnergy", b_output_energy, b_output_energy); + get_keyval(conf, "timeStepFactor", time_step_factor, 1); + if (time_step_factor < 1) { + cvm::error("Error: timeStepFactor must be 1 or greater.\n"); + return COLVARS_ERROR; + } + + // Now that children are defined, we can solve dependencies + enable(f_cvb_active); + if (cvm::debug()) print_state(); + return COLVARS_OK; } @@ -110,6 +117,8 @@ colvarbias::~colvarbias() int colvarbias::clear() { + free_children_deps(); + // Remove references to this bias from colvars for (std::vector::iterator cvi = colvars.begin(); cvi != colvars.end(); @@ -200,7 +209,12 @@ void colvarbias::communicate_forces() cvm::log("Communicating a force to colvar \""+ variables(i)->name+"\".\n"); } - variables(i)->add_bias_force(colvar_forces[i]); + // Impulse-style multiple timestep + // Note that biases with different values of time_step_factor + // may send forces to the same colvar + // which is why rescaling has to happen now: the colvar is not + // aware of this bias' time_step_factor + variables(i)->add_bias_force(cvm::real(time_step_factor) * colvar_forces[i]); } } diff --git a/lib/colvars/colvarbias.h b/lib/colvars/colvarbias.h index 6d5776d3db..205e761cfc 100644 --- a/lib/colvars/colvarbias.h +++ b/lib/colvars/colvarbias.h @@ -56,7 +56,7 @@ public: /// \brief Compute the energy of the bias with alternative values of the /// collective variables (suitable for bias exchange) - virtual int calc_energy(std::vector const &values = + virtual int calc_energy(std::vector const &values = std::vector(0)) { cvm::error("Error: calc_energy() not implemented.\n", COLVARS_NOT_IMPLEMENTED); diff --git a/lib/colvars/colvarbias_abf.cpp b/lib/colvars/colvarbias_abf.cpp index d039004f09..a96fc21d64 100644 --- a/lib/colvars/colvarbias_abf.cpp +++ b/lib/colvars/colvarbias_abf.cpp @@ -71,10 +71,17 @@ int colvarbias_abf::init(std::string const &conf) // shared ABF get_keyval(conf, "shared", shared_on, false); if (shared_on) { - if (!cvm::replica_enabled() || cvm::replica_num() <= 1) + if (!cvm::replica_enabled() || cvm::replica_num() <= 1) { cvm::error("Error: shared ABF requires more than one replica."); - else - cvm::log("shared ABF will be applied among "+ cvm::to_str(cvm::replica_num()) + " replicas.\n"); + return COLVARS_ERROR; + } + cvm::log("shared ABF will be applied among "+ cvm::to_str(cvm::replica_num()) + " replicas.\n"); + if (cvm::proxy->smp_enabled() == COLVARS_OK) { + cvm::error("Error: shared ABF is currently not available with SMP parallelism; " + "please set \"SMP off\" at the top of the Colvars configuration file.\n", + COLVARS_NOT_IMPLEMENTED); + return COLVARS_NOT_IMPLEMENTED; + } // If shared_freq is not set, we default to output_freq get_keyval(conf, "sharedFreq", shared_freq, output_freq); @@ -84,11 +91,11 @@ int colvarbias_abf::init(std::string const &conf) if (colvars.size() == 0) { cvm::error("Error: no collective variables specified for the ABF bias.\n"); + return COLVARS_ERROR; } if (update_bias) { - // Request calculation of total force (which also checks for availability) - // TODO - change this to a dependency - needs ABF-specific features + // Request calculation of total force if(enable(f_cvb_get_total_force)) return cvm::get_error(); } @@ -108,6 +115,16 @@ int colvarbias_abf::init(std::string const &conf) if (colvars[i]->is_enabled(f_cv_extended_Lagrangian)) b_extended = true; + // Cannot mix and match coarse time steps with ABF because it gives + // wrong total force averages - total force needs to be averaged over + // every time step + if (colvars[i]->get_time_step_factor() != time_step_factor) { + cvm::error("Error: " + colvars[i]->description + " has a value of timeStepFactor (" + + cvm::to_str(colvars[i]->get_time_step_factor()) + ") different from that of " + + description + " (" + cvm::to_str(time_step_factor) + ").\n"); + return COLVARS_ERROR; + } + // Here we could check for orthogonality of the Cartesian coordinates // and make it just a warning if some parameter is set? } @@ -282,12 +299,12 @@ int colvarbias_abf::update() // Compute and apply the new bias, if applicable if (is_enabled(f_cvb_apply_force) && samples->index_ok(bin)) { - size_t count = samples->value(bin); - cvm::real fact = 1.0; + size_t count = samples->value(bin); + cvm::real fact = 1.0; // Factor that ensures smooth introduction of the force if ( count < full_samples ) { - fact = ( count < min_samples) ? 0.0 : + fact = (count < min_samples) ? 0.0 : (cvm::real(count - min_samples)) / (cvm::real(full_samples - min_samples)); } @@ -434,62 +451,57 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app std::string gradients_out_name = prefix + ".grad"; std::ios::openmode mode = (append ? std::ios::app : std::ios::out); - cvm::ofstream samples_os; - cvm::ofstream gradients_os; - - if (!append) cvm::backup_file(samples_out_name.c_str()); - samples_os.open(samples_out_name.c_str(), mode); - if (!samples_os.is_open()) { + std::ostream *samples_os = + cvm::proxy->output_stream(samples_out_name, mode); + if (!samples_os) { cvm::error("Error opening ABF samples file " + samples_out_name + " for writing"); } - samples->write_multicol(samples_os); - samples_os.close(); + samples->write_multicol(*samples_os); + cvm::proxy->close_output_stream(samples_out_name); - if (!append) cvm::backup_file(gradients_out_name.c_str()); - gradients_os.open(gradients_out_name.c_str(), mode); - if (!gradients_os.is_open()) { + std::ostream *gradients_os = + cvm::proxy->output_stream(gradients_out_name, mode); + if (!gradients_os) { cvm::error("Error opening ABF gradient file " + gradients_out_name + " for writing"); } - gradients->write_multicol(gradients_os); - gradients_os.close(); + gradients->write_multicol(*gradients_os); + cvm::proxy->close_output_stream(gradients_out_name); if (colvars.size() == 1) { - std::string pmf_out_name = prefix + ".pmf"; - if (!append) cvm::backup_file(pmf_out_name.c_str()); - cvm::ofstream pmf_os; // Do numerical integration and output a PMF - pmf_os.open(pmf_out_name.c_str(), mode); - if (!pmf_os.is_open()) cvm::error("Error opening pmf file " + pmf_out_name + " for writing"); - gradients->write_1D_integral(pmf_os); - pmf_os << std::endl; - pmf_os.close(); + std::string pmf_out_name = prefix + ".pmf"; + std::ostream *pmf_os = cvm::proxy->output_stream(pmf_out_name, mode); + if (!pmf_os) { + cvm::error("Error opening pmf file " + pmf_out_name + " for writing"); + } + gradients->write_1D_integral(*pmf_os); + *pmf_os << std::endl; + cvm::proxy->close_output_stream(pmf_out_name); } if (z_gradients) { // Write eABF-related quantities std::string z_samples_out_name = prefix + ".zcount"; - cvm::ofstream z_samples_os; - if (!append) cvm::backup_file(z_samples_out_name.c_str()); - z_samples_os.open(z_samples_out_name.c_str(), mode); - if (!z_samples_os.is_open()) { + std::ostream *z_samples_os = + cvm::proxy->output_stream(z_samples_out_name, mode); + if (!z_samples_os) { cvm::error("Error opening eABF z-histogram file " + z_samples_out_name + " for writing"); } - z_samples->write_multicol(z_samples_os); - z_samples_os.close(); + z_samples->write_multicol(*z_samples_os); + cvm::proxy->close_output_stream(z_samples_out_name); if (b_czar_window_file) { std::string z_gradients_out_name = prefix + ".zgrad"; - cvm::ofstream z_gradients_os; - if (!append) cvm::backup_file(z_gradients_out_name.c_str()); - z_gradients_os.open(z_gradients_out_name.c_str(), mode); - if (!z_gradients_os.is_open()) { + std::ostream *z_gradients_os = + cvm::proxy->output_stream(z_gradients_out_name, mode); + if (!z_gradients_os) { cvm::error("Error opening eABF z-gradient file " + z_gradients_out_name + " for writing"); } - z_gradients->write_multicol(z_gradients_os); - z_gradients_os.close(); + z_gradients->write_multicol(*z_gradients_os); + cvm::proxy->close_output_stream(z_gradients_out_name); } // Calculate CZAR estimator of gradients @@ -503,26 +515,24 @@ void colvarbias_abf::write_gradients_samples(const std::string &prefix, bool app } std::string czar_gradients_out_name = prefix + ".czar.grad"; - cvm::ofstream czar_gradients_os; - if (!append) cvm::backup_file(czar_gradients_out_name.c_str()); - czar_gradients_os.open(czar_gradients_out_name.c_str(), mode); - if (!czar_gradients_os.is_open()) { + std::ostream *czar_gradients_os = + cvm::proxy->output_stream(czar_gradients_out_name, mode); + if (!czar_gradients_os) { cvm::error("Error opening CZAR gradient file " + czar_gradients_out_name + " for writing"); } - czar_gradients->write_multicol(czar_gradients_os); - czar_gradients_os.close(); + czar_gradients->write_multicol(*czar_gradients_os); + cvm::proxy->close_output_stream(czar_gradients_out_name); if (colvars.size() == 1) { - std::string czar_pmf_out_name = prefix + ".czar.pmf"; - if (!append) cvm::backup_file(czar_pmf_out_name.c_str()); - cvm::ofstream czar_pmf_os; // Do numerical integration and output a PMF - czar_pmf_os.open(czar_pmf_out_name.c_str(), mode); - if (!czar_pmf_os.is_open()) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing"); - czar_gradients->write_1D_integral(czar_pmf_os); - czar_pmf_os << std::endl; - czar_pmf_os.close(); + std::string czar_pmf_out_name = prefix + ".czar.pmf"; + std::ostream *czar_pmf_os = + cvm::proxy->output_stream(czar_pmf_out_name, mode); + if (!czar_pmf_os) cvm::error("Error opening CZAR pmf file " + czar_pmf_out_name + " for writing"); + czar_gradients->write_1D_integral(*czar_pmf_os); + *czar_pmf_os << std::endl; + cvm::proxy->close_output_stream(czar_pmf_out_name); } } return; @@ -570,9 +580,13 @@ void colvarbias_abf::read_gradients_samples() is.clear(); is.open(gradients_in_name.c_str()); - if (!is.is_open()) cvm::error("Error opening ABF gradient file " + gradients_in_name + " for reading"); - gradients->read_multicol(is, true); - is.close(); + if (!is.is_open()) { + cvm::error("Error opening ABF gradient file " + + gradients_in_name + " for reading", INPUT_ERROR); + } else { + gradients->read_multicol(is, true); + is.close(); + } if (z_gradients) { // Read eABF z-averaged data for CZAR diff --git a/lib/colvars/colvarbias_alb.cpp b/lib/colvars/colvarbias_alb.cpp index d096ac3daf..124a15c5da 100644 --- a/lib/colvars/colvarbias_alb.cpp +++ b/lib/colvars/colvarbias_alb.cpp @@ -156,8 +156,8 @@ int colvarbias_alb::update() colvars[i], colvar_centers[i]); bias_energy += restraint_potential(restraint_convert_k(current_coupling[i], colvars[i]->width), - colvars[i], - colvar_centers[i]); + colvars[i], + colvar_centers[i]); if (!b_equilibration) { //Welford, West, and Hanso online variance method @@ -169,26 +169,26 @@ int colvarbias_alb::update() } else { //check if we've reached the setpoint if (coupling_rate[i] == 0 || pow(current_coupling[i] - set_coupling[i],2) < pow(coupling_rate[i],2)) { - finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points + finished_equil_flag &= 1; //we continue equilibrating as long as we haven't reached all the set points } else { - current_coupling[i] += coupling_rate[i]; - finished_equil_flag = 0; + current_coupling[i] += coupling_rate[i]; + finished_equil_flag = 0; } //update max_coupling_range if (!b_hard_coupling_range && fabs(current_coupling[i]) > max_coupling_range[i]) { - std::ostringstream logStream; - logStream << "Coupling constant for " - << colvars[i]->name - << " has exceeded coupling range of " - << max_coupling_range[i] - << ".\n"; + std::ostringstream logStream; + logStream << "Coupling constant for " + << colvars[i]->name + << " has exceeded coupling range of " + << max_coupling_range[i] + << ".\n"; - max_coupling_range[i] *= 1.25; - logStream << "Expanding coupling range to " << max_coupling_range[i] << ".\n"; - cvm::log(logStream.str()); + max_coupling_range[i] *= 1.25; + logStream << "Expanding coupling range to " << max_coupling_range[i] << ".\n"; + cvm::log(logStream.str()); } @@ -214,23 +214,23 @@ int colvarbias_alb::update() temp = 2. * (means[i] / (static_cast (colvar_centers[i])) - 1) * ssd[i] / (update_calls - 1); if (cvm::temperature() > 0) - step_size = temp / (cvm::temperature() * cvm::boltzmann()); + step_size = temp / (cvm::temperature() * cvm::boltzmann()); else - step_size = temp / cvm::boltzmann(); + step_size = temp / cvm::boltzmann(); means[i] = 0; ssd[i] = 0; //stochastic if we do that update or not if (colvars.size() == 1 || rand() < RAND_MAX / ((int) colvars.size())) { - coupling_accum[i] += step_size * step_size; - current_coupling[i] = set_coupling[i]; - set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size; - coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq; - //set to the minimum rate and then put the sign back on it - coupling_rate[i] = copysign(fmin(fabs(coupling_rate[i]), max_coupling_rate[i]), coupling_rate[i]); + coupling_accum[i] += step_size * step_size; + current_coupling[i] = set_coupling[i]; + set_coupling[i] += max_coupling_range[i] / sqrt(coupling_accum[i]) * step_size; + coupling_rate[i] = (set_coupling[i] - current_coupling[i]) / update_freq; + //set to the minimum rate and then put the sign back on it + coupling_rate[i] = copysign(fmin(fabs(coupling_rate[i]), max_coupling_rate[i]), coupling_rate[i]); } else { - coupling_rate[i] = 0; + coupling_rate[i] = 0; } } @@ -339,14 +339,14 @@ std::ostream & colvarbias_alb::write_traj_label(std::ostream &os) if (b_output_coupling) for (size_t i = 0; i < current_coupling.size(); i++) { os << " ForceConst_" << i - <name, cvm::cv_width - 4); + << cvm::wrap_string(colvars[i]->name, cvm::cv_width - 4); } if (b_output_centers) @@ -372,8 +372,8 @@ std::ostream & colvarbias_alb::write_traj(std::ostream &os) if (b_output_coupling) for (size_t i = 0; i < current_coupling.size(); i++) { os << " " - << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) - << current_coupling[i]; + << std::setprecision(cvm::en_prec) << std::setw(cvm::en_width) + << current_coupling[i]; } @@ -387,8 +387,8 @@ std::ostream & colvarbias_alb::write_traj(std::ostream &os) if (b_output_grad) for (size_t i = 0; i < means.size(); i++) { os << " " - << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) - << -2. * (means[i] / (static_cast (colvar_centers[i])) - 1) * ssd[i] / (fmax(update_calls,2) - 1); + << std::setprecision(cvm::cv_prec) << std::setw(cvm::cv_width) + << -2. * (means[i] / (static_cast (colvar_centers[i])) - 1) * ssd[i] / (fmax(update_calls,2) - 1); } diff --git a/lib/colvars/colvarbias_histogram.cpp b/lib/colvars/colvarbias_histogram.cpp index 502a7455b1..0722e6384d 100644 --- a/lib/colvars/colvarbias_histogram.cpp +++ b/lib/colvars/colvarbias_histogram.cpp @@ -86,8 +86,9 @@ int colvarbias_histogram::init(std::string const &conf) { std::string grid_conf; - if (key_lookup(conf, "histogramGrid", grid_conf)) { + if (key_lookup(conf, "histogramGrid", &grid_conf)) { grid->parse_params(grid_conf); + grid->check_keywords(grid_conf, "histogramGrid"); } } @@ -176,26 +177,27 @@ int colvarbias_histogram::write_output_files() if (out_name.size()) { cvm::log("Writing the histogram file \""+out_name+"\".\n"); cvm::backup_file(out_name.c_str()); - cvm::ofstream grid_os(out_name.c_str()); - if (!grid_os.is_open()) { - cvm::error("Error opening histogram file " + out_name + " for writing.\n", FILE_ERROR); + std::ostream *grid_os = cvm::proxy->output_stream(out_name); + if (!grid_os) { + return cvm::error("Error opening histogram file "+out_name+ + " for writing.\n", FILE_ERROR); } - // TODO add return code here - grid->write_multicol(grid_os); - grid_os.close(); + grid->write_multicol(*grid_os); + cvm::proxy->close_output_stream(out_name); } if (out_name_dx.size()) { cvm::log("Writing the histogram file \""+out_name_dx+"\".\n"); cvm::backup_file(out_name_dx.c_str()); - cvm::ofstream grid_os(out_name_dx.c_str()); - if (!grid_os.is_open()) { - cvm::error("Error opening histogram file " + out_name_dx + " for writing.\n", FILE_ERROR); + std::ostream *grid_os = cvm::proxy->output_stream(out_name_dx); + if (!grid_os) { + return cvm::error("Error opening histogram file "+out_name_dx+ + " for writing.\n", FILE_ERROR); } - // TODO add return code here - grid->write_opendx(grid_os); - grid_os.close(); + grid->write_opendx(*grid_os); + cvm::proxy->close_output_stream(out_name_dx); } + return COLVARS_OK; } diff --git a/lib/colvars/colvarbias_meta.cpp b/lib/colvars/colvarbias_meta.cpp index b0acfe974a..66806fc9fc 100644 --- a/lib/colvars/colvarbias_meta.cpp +++ b/lib/colvars/colvarbias_meta.cpp @@ -36,6 +36,8 @@ colvarbias_meta::colvarbias_meta(char const *key) : colvarbias(key) { new_hills_begin = hills.end(); + hills_traj_os = NULL; + replica_hills_os = NULL; } @@ -163,7 +165,6 @@ int colvarbias_meta::init(std::string const &conf) cvm::log("Done initializing the metadynamics bias \""+this->name+"\""+ ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+".\n"); - save_delimiters = false; return COLVARS_OK; } @@ -239,11 +240,15 @@ colvarbias_meta::~colvarbias_meta() hills_energy_gradients = NULL; } - if (replica_hills_os.is_open()) - replica_hills_os.close(); + if (replica_hills_os) { + cvm::proxy->close_output_stream(replica_hills_file); + replica_hills_os = NULL; + } - if (hills_traj_os.is_open()) - hills_traj_os.close(); + if (hills_traj_os) { + cvm::proxy->close_output_stream(hills_traj_file_name()); + hills_traj_os = NULL; + } if(target_dist) { delete target_dist; @@ -280,9 +285,9 @@ colvarbias_meta::create_hill(colvarbias_meta::hill const &h) } // output to trajectory (if specified) - if (hills_traj_os.is_open()) { - hills_traj_os << (hills.back()).output_traj(); - hills_traj_os.flush(); + if (hills_traj_os) { + *hills_traj_os << (hills.back()).output_traj(); + cvm::proxy->flush_output_stream(hills_traj_os); } has_data = true; @@ -312,12 +317,12 @@ colvarbias_meta::delete_hill(hill_iter &h) } } - if (hills_traj_os.is_open()) { + if (hills_traj_os) { // output to the trajectory - hills_traj_os << "# DELETED this hill: " - << (hills.back()).output_traj() - << "\n"; - hills_traj_os.flush(); + *hills_traj_os << "# DELETED this hill: " + << (hills.back()).output_traj() + << "\n"; + cvm::proxy->flush_output_stream(hills_traj_os); } return hills.erase(h); @@ -501,12 +506,12 @@ int colvarbias_meta::update_bias() case multiple_replicas: create_hill(hill(hill_weight*hills_scale, colvars, hill_width, replica_id)); - if (replica_hills_os.is_open()) { - replica_hills_os << hills.back(); + if (replica_hills_os) { + *replica_hills_os << hills.back(); } else { - cvm::fatal_error("Error: in metadynamics bias \""+this->name+"\""+ - ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ - " while writing hills for the other replicas.\n"); + return cvm::error("Error: in metadynamics bias \""+this->name+"\""+ + ((comm != single_replica) ? ", replica \""+replica_id+"\"" : "")+ + " while writing hills for the other replicas.\n", FILE_ERROR); } break; } @@ -904,8 +909,9 @@ int colvarbias_meta::replica_share() // reread the replicas registry update_replicas_registry(); // empty the output buffer - if (replica_hills_os.is_open()) - replica_hills_os.flush(); + if (replica_hills_os) { + cvm::proxy->flush_output_stream(replica_hills_os); + } read_replica_files(); } return COLVARS_OK; @@ -1421,7 +1427,7 @@ std::istream & colvarbias_meta::read_hill(std::istream &is) // it is safer to read colvarvalue objects one at a time; // TODO: change this it later std::string centers_input; - key_lookup(data, "centers", centers_input); + key_lookup(data, "centers", ¢ers_input); std::istringstream centers_is(centers_input); for (size_t i = 0; i < num_variables(); i++) { centers_is >> h_centers[i]; @@ -1521,13 +1527,11 @@ int colvarbias_meta::setup_output() // for the others to read // open the "hills" buffer file - if (!replica_hills_os.is_open()) { - cvm::backup_file(replica_hills_file.c_str()); - replica_hills_os.open(replica_hills_file.c_str()); - if (!replica_hills_os.is_open()) - cvm::error("Error: in opening file \""+ - replica_hills_file+"\" for writing.\n", FILE_ERROR); - replica_hills_os.setf(std::ios::scientific, std::ios::floatfield); + if (!replica_hills_os) { + cvm::proxy->backup_file(replica_hills_file); + replica_hills_os = cvm::proxy->output_stream(replica_hills_file); + if (!replica_hills_os) return cvm::get_error(); + replica_hills_os->setf(std::ios::scientific, std::ios::floatfield); } // write the state file (so that there is always one available) @@ -1539,46 +1543,52 @@ int colvarbias_meta::setup_output() // if we're running without grids, use a growing list of "hills" files // otherwise, just one state file and one "hills" file as buffer - std::ofstream list_os(replica_list_file.c_str(), - (use_grids ? std::ios::trunc : std::ios::app)); - if (! list_os.is_open()) - cvm::fatal_error("Error: in opening file \""+ - replica_list_file+"\" for writing.\n"); - list_os << "stateFile " << replica_state_file << "\n"; - list_os << "hillsFile " << replica_hills_file << "\n"; - list_os.close(); + std::ostream *list_os = + cvm::proxy->output_stream(replica_list_file, + (use_grids ? std::ios_base::trunc : + std::ios_base::app)); + if (!list_os) { + return cvm::get_error(); + } + *list_os << "stateFile " << replica_state_file << "\n"; + *list_os << "hillsFile " << replica_hills_file << "\n"; + cvm::proxy->close_output_stream(replica_list_file); - // finally, if add a new record for this replica to the registry + // finally, add a new record for this replica to the registry if (! registered_replica) { - std::ofstream reg_os(replicas_registry_file.c_str(), std::ios::app); - if (! reg_os.is_open()) - cvm::error("Error: in opening file \""+ - replicas_registry_file+"\" for writing.\n", FILE_ERROR); - reg_os << replica_id << " " << replica_list_file << "\n"; - reg_os.close(); + std::ostream *reg_os = + cvm::proxy->output_stream(replicas_registry_file, + std::ios::app); + if (!reg_os) { + return cvm::get_error(); + } + *reg_os << replica_id << " " << replica_list_file << "\n"; + cvm::proxy->close_output_stream(replicas_registry_file); } } if (b_hills_traj) { - std::string const traj_file_name(cvm::output_prefix()+ - ".colvars."+this->name+ - ( (comm != single_replica) ? - ("."+replica_id) : - ("") )+ - ".hills.traj"); - if (!hills_traj_os.is_open()) { - cvm::backup_file(traj_file_name.c_str()); - hills_traj_os.open(traj_file_name.c_str()); + if (!hills_traj_os) { + hills_traj_os = cvm::proxy->output_stream(hills_traj_file_name()); + if (!hills_traj_os) return cvm::get_error(); } - if (!hills_traj_os.is_open()) - cvm::error("Error: in opening hills output file \"" + - traj_file_name+"\".\n", FILE_ERROR); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); } +std::string const colvarbias_meta::hills_traj_file_name() const +{ + return std::string(cvm::output_prefix()+ + ".colvars."+this->name+ + ( (comm != single_replica) ? + ("."+replica_id) : + ("") )+ + ".hills.traj"); +} + + std::string const colvarbias_meta::get_state_params() const { std::ostringstream os; @@ -1671,12 +1681,13 @@ void colvarbias_meta::write_pmf() (dump_fes_save ? "."+cvm::to_str(cvm::step_absolute()) : "") + ".pmf"); - cvm::backup_file(fes_file_name.c_str()); - cvm::ofstream fes_os(fes_file_name.c_str()); - pmf->write_multicol(fes_os); - fes_os.close(); + cvm::proxy->backup_file(fes_file_name); + std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name); + pmf->write_multicol(*fes_os); + cvm::proxy->close_output_stream(fes_file_name); } } + if (comm != single_replica) { // output the combined PMF from all replicas pmf->reset(); @@ -1695,10 +1706,10 @@ void colvarbias_meta::write_pmf() (dump_fes_save ? "."+cvm::to_str(cvm::step_absolute()) : "") + ".pmf"); - cvm::backup_file(fes_file_name.c_str()); - cvm::ofstream fes_os(fes_file_name.c_str()); - pmf->write_multicol(fes_os); - fes_os.close(); + cvm::proxy->backup_file(fes_file_name); + std::ostream *fes_os = cvm::proxy->output_stream(fes_file_name); + pmf->write_multicol(*fes_os); + cvm::proxy->close_output_stream(fes_file_name); } delete pmf; @@ -1769,13 +1780,11 @@ int colvarbias_meta::write_replica_state_file() // rep_state_os.close(); // reopen the hills file - replica_hills_os.close(); - cvm::backup_file(replica_hills_file.c_str()); - replica_hills_os.open(replica_hills_file.c_str()); - if (!replica_hills_os.is_open()) - cvm::fatal_error("Error: in opening file \""+ - replica_hills_file+"\" for writing.\n"); - replica_hills_os.setf(std::ios::scientific, std::ios::floatfield); + cvm::proxy->close_output_stream(replica_hills_file); + cvm::proxy->backup_file(replica_hills_file); + replica_hills_os = cvm::proxy->output_stream(replica_hills_file); + if (!replica_hills_os) return cvm::get_error(); + replica_hills_os->setf(std::ios::scientific, std::ios::floatfield); return COLVARS_OK; } diff --git a/lib/colvars/colvarbias_meta.h b/lib/colvars/colvarbias_meta.h index 01921eaf64..249f7342bc 100644 --- a/lib/colvars/colvarbias_meta.h +++ b/lib/colvars/colvarbias_meta.h @@ -78,7 +78,10 @@ protected: /// Write the hill logfile bool b_hills_traj; /// Logfile of hill management (creation and deletion) - cvm::ofstream hills_traj_os; + std::ostream *hills_traj_os; + + /// Name of the hill logfile + std::string const hills_traj_file_name() const; /// \brief List of hills used on this bias (total); if a grid is /// employed, these don't need to be updated at every time step @@ -241,7 +244,7 @@ protected: std::string replica_hills_file; /// \brief Output stream corresponding to replica_hills_file - cvm::ofstream replica_hills_os; + std::ostream *replica_hills_os; /// Position within replica_hills_file (when reading it) int replica_hills_file_pos; diff --git a/lib/colvars/colvarbias_restraint.cpp b/lib/colvars/colvarbias_restraint.cpp index 159d9eae64..bb6d6164e5 100644 --- a/lib/colvars/colvarbias_restraint.cpp +++ b/lib/colvars/colvarbias_restraint.cpp @@ -853,6 +853,21 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf) get_keyval(conf, "upperWallConstant", upper_wall_k, (upper_wall_k > 0.0) ? upper_wall_k : force_k); + if (lower_wall_k * upper_wall_k > 0.0) { + for (size_t i = 0; i < num_variables(); i++) { + if (variables(i)->width != 1.0) + cvm::log("The lower and upper wall force constants for colvar \""+ + variables(i)->name+ + "\" will be rescaled to "+ + cvm::to_str(lower_wall_k / + (variables(i)->width * variables(i)->width))+ + " and "+ + cvm::to_str(upper_wall_k / + (variables(i)->width * variables(i)->width))+ + " according to the specified width.\n"); + } + } + enable(f_cvb_scalar_variables); size_t i; @@ -869,7 +884,7 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf) if (!get_keyval(conf, "lowerWalls", lower_walls, lower_walls) && b_null_lower_walls) { cvm::log("Lower walls were not provided.\n"); - lower_walls.resize(0); + lower_walls.clear(); } bool b_null_upper_walls = false; @@ -884,7 +899,7 @@ int colvarbias_restraint_harmonic_walls::init(std::string const &conf) if (!get_keyval(conf, "upperWalls", upper_walls, upper_walls) && b_null_upper_walls) { cvm::log("Upper walls were not provided.\n"); - upper_walls.resize(0); + upper_walls.clear(); } if ((lower_walls.size() == 0) && (upper_walls.size() == 0)) { @@ -954,7 +969,8 @@ void colvarbias_restraint_harmonic_walls::communicate_forces() cvm::log("Communicating a force to colvar \""+ variables(i)->name+"\".\n"); } - variables(i)->add_bias_force_actual_value(colvar_forces[i]); + // Impulse-style multiple timestep + variables(i)->add_bias_force_actual_value(cvm::real(time_step_factor) * colvar_forces[i]); } } @@ -1282,9 +1298,9 @@ int colvarbias_restraint_histogram::init(std::string const &conf) colvarbias_restraint_histogram::~colvarbias_restraint_histogram() { - p.resize(0); - ref_p.resize(0); - p_diff.resize(0); + p.clear(); + ref_p.clear(); + p_diff.clear(); } @@ -1382,23 +1398,23 @@ std::ostream & colvarbias_restraint_histogram::write_restart(std::ostream &os) { if (b_write_histogram) { std::string file_name(cvm::output_prefix()+"."+this->name+".hist.dat"); - std::ofstream os(file_name.c_str()); - os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width) - << " " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3) - << ")\n"; + std::ostream *os = cvm::proxy->output_stream(file_name); + *os << "# " << cvm::wrap_string(variables(0)->name, cvm::cv_width) + << " " << "p(" << cvm::wrap_string(variables(0)->name, cvm::cv_width-3) + << ")\n"; size_t igrid; for (igrid = 0; igrid < p.size(); igrid++) { cvm::real const x_grid = (lower_boundary + (igrid+1)*width); - os << " " - << std::setprecision(cvm::cv_prec) - << std::setw(cvm::cv_width) - << x_grid - << " " - << std::setprecision(cvm::cv_prec) - << std::setw(cvm::cv_width) - << p[igrid] << "\n"; + *os << " " + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) + << x_grid + << " " + << std::setprecision(cvm::cv_prec) + << std::setw(cvm::cv_width) + << p[igrid] << "\n"; } - os.close(); + cvm::proxy->close_output_stream(file_name); } return os; } diff --git a/lib/colvars/colvarcomp.cpp b/lib/colvars/colvarcomp.cpp index 786bc032d2..589de1d32a 100644 --- a/lib/colvars/colvarcomp.cpp +++ b/lib/colvars/colvarcomp.cpp @@ -51,6 +51,17 @@ colvar::cvc::cvc(std::string const &conf) get_keyval_feature((colvarparse *)this, conf, "debugGradients", f_cvc_debug_gradient, false, parse_silent); + { + bool b_no_PBC = false; + get_keyval(conf, "forceNoPBC", b_no_PBC, false); + if (b_no_PBC) { + disable(f_cvc_pbc_minimum_image); + } else { + enable(f_cvc_pbc_minimum_image); + } + // this does not use get_keyval_feature() only for backward compatibility + } + // Attempt scalable calculations when in parallel? (By default yes, if available) get_keyval(conf, "scalable", b_try_scalable, true); @@ -94,13 +105,15 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf, bool optional) { cvm::atom_group *group = NULL; + std::string group_conf; - if (key_lookup(conf, group_key)) { - group = new cvm::atom_group; - group->key = group_key; + if (key_lookup(conf, group_key, &group_conf)) { + group = new cvm::atom_group(group_key); if (b_try_scalable) { - if (is_available(f_cvc_scalable_com) && is_enabled(f_cvc_com_based)) { + if (is_available(f_cvc_scalable_com) + && is_enabled(f_cvc_com_based) + && !is_enabled(f_cvc_debug_gradient)) { enable(f_cvc_scalable_com); enable(f_cvc_scalable); // The CVC makes the feature available; @@ -111,44 +124,51 @@ cvm::atom_group *colvar::cvc::parse_group(std::string const &conf, // TODO check for other types of parallelism here } - if (group->parse(conf) == COLVARS_OK) { - atom_groups.push_back(group); - } else { - cvm::error("Error parsing definition for atom group \""+ - std::string(group_key)+"\".\n"); + if (group_conf.size() == 0) { + cvm::error("Error: atom group \""+group->key+ + "\" is set, but has no definition.\n", + INPUT_ERROR); + return group; } + + cvm::increase_depth(); + if (group->parse(group_conf) == COLVARS_OK) { + register_atom_group(group); + } + group->check_keywords(group_conf, group_key); + if (cvm::get_error()) { + cvm::error("Error parsing definition for atom group \""+ + std::string(group_key)+"\"\n.", INPUT_ERROR); + } + cvm::decrease_depth(); + } else { if (! optional) { cvm::error("Error: definition for atom group \""+ - std::string(group_key)+"\" not found.\n"); + std::string(group_key)+"\" not found.\n"); } } + return group; } int colvar::cvc::setup() { - size_t i; description = "cvc " + name; - - for (i = 0; i < atom_groups.size(); i++) { - add_child((colvardeps *) atom_groups[i]); - } - return COLVARS_OK; } colvar::cvc::~cvc() { + free_children_deps(); remove_all_children(); for (size_t i = 0; i < atom_groups.size(); i++) { if (atom_groups[i] != NULL) delete atom_groups[i]; } } - void colvar::cvc::read_data() { size_t ig; @@ -187,117 +207,129 @@ void colvar::cvc::calc_Jacobian_derivative() } -void colvar::cvc::debug_gradients(cvm::atom_group *group) +void colvar::cvc::calc_fit_gradients() { - // this function should work for any scalar variable: + for (size_t ig = 0; ig < atom_groups.size(); ig++) { + atom_groups[ig]->calc_fit_gradients(); + } +} + + +void colvar::cvc::debug_gradients() +{ + // this function should work for any scalar cvc: // the only difference will be the name of the atom group (here, "group") // NOTE: this assumes that groups for this cvc are non-overlapping, // since atom coordinates are modified only within the current group - if (group->b_dummy) return; + cvm::log("Debugging gradients for " + description); - cvm::rotation const rot_0 = group->rot; - cvm::rotation const rot_inv = group->rot.inverse(); + for (size_t ig = 0; ig < atom_groups.size(); ig++) { + cvm::atom_group *group = atom_groups[ig]; + if (group->b_dummy) continue; - cvm::real x_0 = x.real_value; - if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0]; + cvm::rotation const rot_0 = group->rot; + cvm::rotation const rot_inv = group->rot.inverse(); - // cvm::log("gradients = "+cvm::to_str (gradients)+"\n"); + cvm::real x_0 = x.real_value; + if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_0 = x[0]; - cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group; - cvm::atom_pos fit_gradient_sum, gradient_sum; + // cvm::log("gradients = "+cvm::to_str (gradients)+"\n"); - // print the values of the fit gradients - if (group->b_rotate || group->b_center) { - if (group->b_fit_gradients) { - size_t j; + cvm::atom_group *group_for_fit = group->fitting_group ? group->fitting_group : group; + cvm::atom_pos fit_gradient_sum, gradient_sum; - // fit_gradients are in the simulation frame: we should print them in the rotated frame - cvm::log("Fit gradients:\n"); - for (j = 0; j < group_for_fit->fit_gradients.size(); j++) { - cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) + - "[" + cvm::to_str(j) + "] = " + - (group->b_rotate ? - cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) : - cvm::to_str(group_for_fit->fit_gradients[j]))); + // print the values of the fit gradients + if (group->b_rotate || group->b_center) { + if (group->is_enabled(f_ag_fit_gradients)) { + size_t j; + + // fit_gradients are in the simulation frame: we should print them in the rotated frame + cvm::log("Fit gradients:\n"); + for (j = 0; j < group_for_fit->fit_gradients.size(); j++) { + cvm::log((group->fitting_group ? std::string("refPosGroup") : group->key) + + "[" + cvm::to_str(j) + "] = " + + (group->b_rotate ? + cvm::to_str(rot_0.rotate(group_for_fit->fit_gradients[j])) : + cvm::to_str(group_for_fit->fit_gradients[j]))); + } } } - } - // debug the gradients - for (size_t ia = 0; ia < group->size(); ia++) { + // debug the gradients + for (size_t ia = 0; ia < group->size(); ia++) { - // tests are best conducted in the unrotated (simulation) frame - cvm::rvector const atom_grad = (group->b_rotate ? - rot_inv.rotate((*group)[ia].grad) : - (*group)[ia].grad); - gradient_sum += atom_grad; - - for (size_t id = 0; id < 3; id++) { - // (re)read original positions - group->read_positions(); - // change one coordinate - (*group)[ia].pos[id] += cvm::debug_gradients_step_size; - group->calc_required_properties(); - calc_value(); - cvm::real x_1 = x.real_value; - if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0]; - cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n"); - cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0, - 21, 14)+"\n"); - cvm::real const dx_pred = (group->fit_gradients.size()) ? - (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) : - (cvm::debug_gradients_step_size * atom_grad[id]); - cvm::log("dx(interp) = "+cvm::to_str(dx_pred, - 21, 14)+"\n"); - cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+ - cvm::to_str(std::fabs(x_1 - x_0 - dx_pred) / - std::fabs(x_1 - x_0), 12, 5)+"\n"); - } - } - - if ((group->b_fit_gradients) && (group->fitting_group != NULL)) { - cvm::atom_group *ref_group = group->fitting_group; - group->read_positions(); - group->calc_required_properties(); - - for (size_t ia = 0; ia < ref_group->size(); ia++) { - - // fit gradients are in the unrotated (simulation) frame - cvm::rvector const atom_grad = ref_group->fit_gradients[ia]; - fit_gradient_sum += atom_grad; + // tests are best conducted in the unrotated (simulation) frame + cvm::rvector const atom_grad = (group->b_rotate ? + rot_inv.rotate((*group)[ia].grad) : + (*group)[ia].grad); + gradient_sum += atom_grad; for (size_t id = 0; id < 3; id++) { // (re)read original positions group->read_positions(); - ref_group->read_positions(); // change one coordinate - (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size; + (*group)[ia].pos[id] += cvm::debug_gradients_step_size; group->calc_required_properties(); calc_value(); - - cvm::real const x_1 = x.real_value; - cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n"); - cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0, - 21, 14)+"\n"); - - cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id]; - - cvm::log("dx(interp) = "+cvm::to_str (dx_pred, - 21, 14)+"\n"); - cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+ - cvm::to_str(std::fabs (x_1 - x_0 - dx_pred) / - std::fabs (x_1 - x_0), - 12, 5)+ - ".\n"); + cvm::real x_1 = x.real_value; + if ((x.type() == colvarvalue::type_vector) && (x.size() == 1)) x_1 = x[0]; + cvm::log("Atom "+cvm::to_str(ia)+", component "+cvm::to_str(id)+":\n"); + cvm::log("dx(actual) = "+cvm::to_str(x_1 - x_0, + 21, 14)+"\n"); + cvm::real const dx_pred = (group->fit_gradients.size()) ? + (cvm::debug_gradients_step_size * (atom_grad[id] + group->fit_gradients[ia][id])) : + (cvm::debug_gradients_step_size * atom_grad[id]); + cvm::log("dx(interp) = "+cvm::to_str(dx_pred, + 21, 14)+"\n"); + cvm::log("|dx(actual) - dx(interp)|/|dx(actual)| = "+ + cvm::to_str(std::fabs(x_1 - x_0 - dx_pred) / + std::fabs(x_1 - x_0), 12, 5)+"\n"); } } + + if ((group->is_enabled(f_ag_fit_gradients)) && (group->fitting_group != NULL)) { + cvm::atom_group *ref_group = group->fitting_group; + group->read_positions(); + group->calc_required_properties(); + + for (size_t ia = 0; ia < ref_group->size(); ia++) { + + // fit gradients are in the unrotated (simulation) frame + cvm::rvector const atom_grad = ref_group->fit_gradients[ia]; + fit_gradient_sum += atom_grad; + + for (size_t id = 0; id < 3; id++) { + // (re)read original positions + group->read_positions(); + ref_group->read_positions(); + // change one coordinate + (*ref_group)[ia].pos[id] += cvm::debug_gradients_step_size; + group->calc_required_properties(); + calc_value(); + + cvm::real const x_1 = x.real_value; + cvm::log("refPosGroup atom "+cvm::to_str(ia)+", component "+cvm::to_str (id)+":\n"); + cvm::log("dx(actual) = "+cvm::to_str (x_1 - x_0, + 21, 14)+"\n"); + + cvm::real const dx_pred = cvm::debug_gradients_step_size * atom_grad[id]; + + cvm::log("dx(interp) = "+cvm::to_str (dx_pred, + 21, 14)+"\n"); + cvm::log ("|dx(actual) - dx(interp)|/|dx(actual)| = "+ + cvm::to_str(std::fabs (x_1 - x_0 - dx_pred) / + std::fabs (x_1 - x_0), + 12, 5)+ + ".\n"); + } + } + } + + cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) + + " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) + + " Total " + cvm::to_str(gradient_sum + fit_gradient_sum)); } - - cvm::log("Gradient sum: " + cvm::to_str(gradient_sum) + - " Fit gradient sum: " + cvm::to_str(fit_gradient_sum) + - " Total " + cvm::to_str(gradient_sum + fit_gradient_sum)); - return; } diff --git a/lib/colvars/colvarcomp.h b/lib/colvars/colvarcomp.h index ec215cbad1..2c865a166b 100644 --- a/lib/colvars/colvarcomp.h +++ b/lib/colvars/colvarcomp.h @@ -146,8 +146,11 @@ public: /// order to apply forces virtual void calc_gradients() = 0; + /// \brief Calculate the atomic fit gradients + void calc_fit_gradients(); + /// \brief Calculate finite-difference gradients alongside the analytical ones, for each Cartesian component - virtual void debug_gradients(cvm::atom_group *group); + virtual void debug_gradients(); /// \brief Calculate the total force from the system using the /// inverse atomic gradients @@ -228,6 +231,12 @@ public: /// e.g. atomic gradients std::vector atom_groups; + /// \brief Store a pointer to new atom group, and list as child for dependencies + inline void register_atom_group(cvm::atom_group *ag) { + atom_groups.push_back(ag); + add_child((colvardeps *) ag); + } + /// \brief Whether or not this CVC will be computed in parallel whenever possible bool b_try_scalable; @@ -427,15 +436,77 @@ public: }; +/// \brief Colvar component: polar coordinate phi of a group +/// (colvarvalue::type_scalar type, range [-180:180]) +class colvar::polar_phi + : public colvar::cvc +{ +public: + polar_phi(std::string const &conf); + polar_phi(); + virtual ~polar_phi() {} +protected: + cvm::atom_group *atoms; + cvm::real r, theta, phi; +public: + virtual void calc_value(); + virtual void calc_gradients(); + virtual void apply_force(colvarvalue const &force); + /// Redefined to handle the 2*PI periodicity + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + /// Redefined to handle the 2*PI periodicity + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + /// Redefined to handle the 2*PI periodicity + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + /// Redefined to handle the 2*PI periodicity + virtual void wrap(colvarvalue &x) const; +}; + + +/// \brief Colvar component: polar coordinate theta of a group +/// (colvarvalue::type_scalar type, range [0:180]) +class colvar::polar_theta + : public colvar::cvc +{ +public: + polar_theta(std::string const &conf); + polar_theta(); + virtual ~polar_theta() {} +protected: + cvm::atom_group *atoms; + cvm::real r, theta, phi; +public: + virtual void calc_value(); + virtual void calc_gradients(); + virtual void apply_force(colvarvalue const &force); + /// Redefined to override the distance ones + virtual cvm::real dist2(colvarvalue const &x1, + colvarvalue const &x2) const; + /// Redefined to override the distance ones + virtual colvarvalue dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const; + /// Redefined to override the distance ones + virtual colvarvalue dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const; +}; /// \brief Colvar component: average distance between two groups of atoms, weighted as the sixth power, /// as in NMR refinements(colvarvalue::type_scalar type, range (0:*)) class colvar::distance_inv - : public colvar::distance + : public colvar::cvc { protected: + /// First atom group + cvm::atom_group *group1; + /// Second atom group + cvm::atom_group *group2; /// Components of the distance vector orthogonal to the axis int exponent; + /// Use absolute positions, ignoring PBCs when present + bool b_no_PBC; public: distance_inv(std::string const &conf); distance_inv(); diff --git a/lib/colvars/colvarcomp_angles.cpp b/lib/colvars/colvarcomp_angles.cpp index 0204f3b4b1..9f879a4c41 100644 --- a/lib/colvars/colvarcomp_angles.cpp +++ b/lib/colvars/colvarcomp_angles.cpp @@ -45,9 +45,9 @@ colvar::angle::angle(cvm::atom const &a1, group1 = new cvm::atom_group(std::vector(1, a1)); group2 = new cvm::atom_group(std::vector(1, a2)); group3 = new cvm::atom_group(std::vector(1, a3)); - atom_groups.push_back(group1); - atom_groups.push_back(group2); - atom_groups.push_back(group3); + register_atom_group(group1); + register_atom_group(group2); + register_atom_group(group3); x.type(colvarvalue::type_scalar); } @@ -66,12 +66,16 @@ void colvar::angle::calc_value() cvm::atom_pos const g2_pos = group2->center_of_mass(); cvm::atom_pos const g3_pos = group3->center_of_mass(); - r21 = cvm::position_distance(g2_pos, g1_pos); + r21 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g2_pos, g1_pos) : + g1_pos - g2_pos; r21l = r21.norm(); - r23 = cvm::position_distance(g2_pos, g3_pos); + r23 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g2_pos, g3_pos) : + g3_pos - g2_pos; r23l = r23.norm(); - cvm::real const cos_theta = (r21*r23)/(r21l*r23l); + cvm::real const cos_theta = (r21*r23)/(r21l*r23l); x.real_value = (180.0/PI) * std::acos(cos_theta); } @@ -166,9 +170,9 @@ colvar::dipole_angle::dipole_angle(cvm::atom const &a1, group1 = new cvm::atom_group(std::vector(1, a1)); group2 = new cvm::atom_group(std::vector(1, a2)); group3 = new cvm::atom_group(std::vector(1, a3)); - atom_groups.push_back(group1); - atom_groups.push_back(group2); - atom_groups.push_back(group3); + register_atom_group(group1); + register_atom_group(group2); + register_atom_group(group3); x.type(colvarvalue::type_scalar); } @@ -191,10 +195,12 @@ void colvar::dipole_angle::calc_value() r21 = group1->dipole(); r21l = r21.norm(); - r23 = cvm::position_distance(g2_pos, g3_pos); + r23 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g2_pos, g3_pos) : + g3_pos - g2_pos; r23l = r23.norm(); - cvm::real const cos_theta = (r21*r23)/(r21l*r23l); + cvm::real const cos_theta = (r21*r23)/(r21l*r23l); x.real_value = (180.0/PI) * std::acos(cos_theta); } @@ -293,10 +299,10 @@ colvar::dihedral::dihedral(cvm::atom const &a1, group2 = new cvm::atom_group(std::vector(1, a2)); group3 = new cvm::atom_group(std::vector(1, a3)); group4 = new cvm::atom_group(std::vector(1, a4)); - atom_groups.push_back(group1); - atom_groups.push_back(group2); - atom_groups.push_back(group3); - atom_groups.push_back(group4); + register_atom_group(group1); + register_atom_group(group2); + register_atom_group(group3); + register_atom_group(group4); x.type(colvarvalue::type_scalar); @@ -324,9 +330,15 @@ void colvar::dihedral::calc_value() cvm::atom_pos const g4_pos = group4->center_of_mass(); // Usual sign convention: r12 = r2 - r1 - r12 = cvm::position_distance(g1_pos, g2_pos); - r23 = cvm::position_distance(g2_pos, g3_pos); - r34 = cvm::position_distance(g3_pos, g4_pos); + r12 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g1_pos, g2_pos) : + g2_pos - g1_pos; + r23 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g2_pos, g3_pos) : + g3_pos - g2_pos; + r34 = is_enabled(f_cvc_pbc_minimum_image) ? + cvm::position_distance(g3_pos, g4_pos) : + g4_pos - g3_pos; cvm::rvector const n1 = cvm::rvector::outer(r12, r23); cvm::rvector const n2 = cvm::rvector::outer(r23, r34); @@ -365,10 +377,10 @@ void colvar::dihedral::calc_gradients() cvm::real const K = (1.0/sin_phi) * (180.0/PI); - f1 = K * cvm::rvector::outer(r23, dcosdA); - f3 = K * cvm::rvector::outer(dcosdB, r23); - f2 = K * (cvm::rvector::outer(dcosdA, r12) - + cvm::rvector::outer(r34, dcosdB)); + f1 = K * cvm::rvector::outer(r23, dcosdA); + f3 = K * cvm::rvector::outer(dcosdB, r23); + f2 = K * (cvm::rvector::outer(dcosdA, r12) + + cvm::rvector::outer(r34, dcosdB)); } else { rC = 1.0/rC; @@ -439,7 +451,7 @@ void colvar::dihedral::calc_force_invgrads() // Default case: use groups 1 and 4 group4->read_total_forces(); ft.real_value = PI/180.0 * 0.5 * (fact1 * (cross1 * group1->total_force()) - + fact4 * (cross4 * group4->total_force())); + + fact4 * (cross4 * group4->total_force())); } } @@ -510,3 +522,148 @@ void colvar::dihedral::wrap(colvarvalue &x) const return; } + + +colvar::polar_theta::polar_theta(std::string const &conf) + : cvc(conf) +{ + function_type = "polar_theta"; + enable(f_cvc_com_based); + + atoms = parse_group(conf, "atoms"); + init_total_force_params(conf); + x.type(colvarvalue::type_scalar); +} + + +colvar::polar_theta::polar_theta() +{ + function_type = "polar_theta"; + x.type(colvarvalue::type_scalar); +} + + +void colvar::polar_theta::calc_value() +{ + cvm::rvector pos = atoms->center_of_mass(); + r = atoms->center_of_mass().norm(); + // Internal values of theta and phi are radians + theta = (r > 0.) ? std::acos(pos.z / r) : 0.; + phi = std::atan2(pos.y, pos.x); + x.real_value = (180.0/PI) * theta; +} + + +void colvar::polar_theta::calc_gradients() +{ + if (r == 0.) + atoms->set_weighted_gradient(cvm::rvector(0., 0., 0.)); + else + atoms->set_weighted_gradient(cvm::rvector( + (180.0/PI) * std::cos(theta) * std::cos(phi) / r, + (180.0/PI) * std::cos(theta) * std::sin(phi) / r, + (180.0/PI) * -std::sin(theta) / r)); +} + + +void colvar::polar_theta::apply_force(colvarvalue const &force) +{ + if (!atoms->noforce) + atoms->apply_colvar_force(force.real_value); +} + + +simple_scalar_dist_functions(polar_theta) + + +colvar::polar_phi::polar_phi(std::string const &conf) + : cvc(conf) +{ + function_type = "polar_phi"; + period = 360.0; + enable(f_cvc_com_based); + + atoms = parse_group(conf, "atoms"); + init_total_force_params(conf); + x.type(colvarvalue::type_scalar); +} + + +colvar::polar_phi::polar_phi() +{ + function_type = "polar_phi"; + period = 360.0; + x.type(colvarvalue::type_scalar); +} + + +void colvar::polar_phi::calc_value() +{ + cvm::rvector pos = atoms->center_of_mass(); + r = atoms->center_of_mass().norm(); + // Internal values of theta and phi are radians + theta = (r > 0.) ? std::acos(pos.z / r) : 0.; + phi = std::atan2(pos.y, pos.x); + x.real_value = (180.0/PI) * phi; +} + + +void colvar::polar_phi::calc_gradients() +{ + atoms->set_weighted_gradient(cvm::rvector( + (180.0/PI) * -std::sin(phi) / (r*std::sin(theta)), + (180.0/PI) * std::cos(phi) / (r*std::sin(theta)), + 0.)); +} + + +void colvar::polar_phi::apply_force(colvarvalue const &force) +{ + if (!atoms->noforce) + atoms->apply_colvar_force(force.real_value); +} + + +// Same as dihedral, for polar_phi + +cvm::real colvar::polar_phi::dist2(colvarvalue const &x1, + colvarvalue const &x2) const +{ + cvm::real diff = x1.real_value - x2.real_value; + diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); + return diff * diff; +} + + +colvarvalue colvar::polar_phi::dist2_lgrad(colvarvalue const &x1, + colvarvalue const &x2) const +{ + cvm::real diff = x1.real_value - x2.real_value; + diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); + return 2.0 * diff; +} + + +colvarvalue colvar::polar_phi::dist2_rgrad(colvarvalue const &x1, + colvarvalue const &x2) const +{ + cvm::real diff = x1.real_value - x2.real_value; + diff = (diff < -180.0 ? diff + 360.0 : (diff > 180.0 ? diff - 360.0 : diff)); + return (-2.0) * diff; +} + + +void colvar::polar_phi::wrap(colvarvalue &x) const +{ + if ((x.real_value - wrap_center) >= 180.0) { + x.real_value -= 360.0; + return; + } + + if ((x.real_value - wrap_center) < -180.0) { + x.real_value += 360.0; + return; + } + + return; +} diff --git a/lib/colvars/colvarcomp_coordnums.cpp b/lib/colvars/colvarcomp_coordnums.cpp index 987a16a816..369d489e27 100644 --- a/lib/colvars/colvarcomp_coordnums.cpp +++ b/lib/colvars/colvarcomp_coordnums.cpp @@ -87,8 +87,10 @@ colvar::coordnum::coordnum(std::string const &conf) group1 = parse_group(conf, "group1"); group2 = parse_group(conf, "group2"); - if (group1->b_dummy) - cvm::fatal_error("Error: only group2 is allowed to be a dummy atom\n"); + if (group1->b_dummy) { + cvm::error("Error: only group2 is allowed to be a dummy atom\n"); + return; + } bool const b_isotropic = get_keyval(conf, "cutoff", r0, cvm::real(4.0 * cvm::unit_angstrom())); @@ -99,6 +101,7 @@ colvar::coordnum::coordnum(std::string const &conf) if (b_isotropic) { cvm::error("Error: cannot specify \"cutoff\" and \"cutoff3\" at the same time.\n", INPUT_ERROR); + return; } b_anisotropic = true; @@ -115,6 +118,10 @@ colvar::coordnum::coordnum(std::string const &conf) cvm::error("Error: odd exponents provided, can only use even ones.\n", INPUT_ERROR); } + if (!is_enabled(f_cvc_pbc_minimum_image)) { + cvm::log("Warning: only minimum-image distances are used by this variable.\n"); + } + get_keyval(conf, "group2CenterOnly", b_group2_center_only, group2->b_dummy); } @@ -228,12 +235,13 @@ colvar::h_bond::h_bond(std::string const &conf) get_keyval(conf, "donor", d_num, -1); if ( (a_num == -1) || (d_num == -1) ) { - cvm::fatal_error("Error: either acceptor or donor undefined.\n"); + cvm::error("Error: either acceptor or donor undefined.\n"); + return; } cvm::atom acceptor = cvm::atom(a_num); cvm::atom donor = cvm::atom(d_num); - atom_groups.push_back(new cvm::atom_group); + register_atom_group(new cvm::atom_group); atom_groups[0]->add_atom(acceptor); atom_groups[0]->add_atom(donor); @@ -242,7 +250,8 @@ colvar::h_bond::h_bond(std::string const &conf) get_keyval(conf, "expDenom", ed, 8); if ( (en%2) || (ed%2) ) { - cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); + cvm::error("Error: odd exponents provided, can only use even ones.\n"); + return; } if (cvm::debug()) @@ -258,7 +267,7 @@ colvar::h_bond::h_bond(cvm::atom const &acceptor, function_type = "h_bond"; x.type(colvarvalue::type_scalar); - atom_groups.push_back(new cvm::atom_group); + register_atom_group(new cvm::atom_group); atom_groups[0]->add_atom(acceptor); atom_groups[0]->add_atom(donor); } @@ -313,7 +322,12 @@ colvar::selfcoordnum::selfcoordnum(std::string const &conf) get_keyval(conf, "expDenom", ed, int(12)); if ( (en%2) || (ed%2) ) { - cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); + cvm::error("Error: odd exponents provided, can only use even ones.\n"); + return; + } + + if (!is_enabled(f_cvc_pbc_minimum_image)) { + cvm::log("Warning: only minimum-image distances are used by this variable.\n"); } } @@ -364,8 +378,10 @@ colvar::groupcoordnum::groupcoordnum(std::string const &conf) x.type(colvarvalue::type_scalar); // group1 and group2 are already initialized by distance() - if (group1->b_dummy || group2->b_dummy) - cvm::fatal_error("Error: neither group can be a dummy atom\n"); + if (group1->b_dummy || group2->b_dummy) { + cvm::error("Error: neither group can be a dummy atom\n"); + return; + } bool const b_scale = get_keyval(conf, "cutoff", r0, cvm::real(4.0 * cvm::unit_angstrom())); @@ -373,9 +389,11 @@ colvar::groupcoordnum::groupcoordnum(std::string const &conf) if (get_keyval(conf, "cutoff3", r0_vec, cvm::rvector(4.0, 4.0, 4.0), parse_silent)) { - if (b_scale) - cvm::fatal_error("Error: cannot specify \"scale\" and " + if (b_scale) { + cvm::error("Error: cannot specify \"scale\" and " "\"scale3\" at the same time.\n"); + return; + } b_anisotropic = true; // remove meaningless negative signs if (r0_vec.x < 0.0) r0_vec.x *= -1.0; @@ -387,7 +405,12 @@ colvar::groupcoordnum::groupcoordnum(std::string const &conf) get_keyval(conf, "expDenom", ed, int(12)); if ( (en%2) || (ed%2) ) { - cvm::fatal_error("Error: odd exponents provided, can only use even ones.\n"); + cvm::error("Error: odd exponents provided, can only use even ones.\n"); + return; + } + + if (!is_enabled(f_cvc_pbc_minimum_image)) { + cvm::log("Warning: only minimum-image distances are used by this variable.\n"); } } diff --git a/lib/colvars/colvarcomp_distances.cpp b/lib/colvars/colvarcomp_distances.cpp index f46270246f..18d154515a 100644 --- a/lib/colvars/colvarcomp_distances.cpp +++ b/lib/colvars/colvarcomp_distances.cpp @@ -28,10 +28,6 @@ colvar::distance::distance(std::string const &conf) group1 = parse_group(conf, "group1"); group2 = parse_group(conf, "group2"); - if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { - cvm::log("Computing distance using absolute positions (not minimal-image)"); - } - init_total_force_params(conf); x.type(colvarvalue::type_scalar); @@ -45,18 +41,17 @@ colvar::distance::distance() provide(f_cvc_inv_gradient); provide(f_cvc_Jacobian); enable(f_cvc_com_based); - b_no_PBC = false; x.type(colvarvalue::type_scalar); } void colvar::distance::calc_value() { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { dist_v = group2->center_of_mass() - group1->center_of_mass(); } else { dist_v = cvm::position_distance(group1->center_of_mass(), - group2->center_of_mass()); + group2->center_of_mass()); } x.real_value = dist_v.norm(); } @@ -107,6 +102,7 @@ colvar::distance_vec::distance_vec(std::string const &conf) { function_type = "distance_vec"; enable(f_cvc_com_based); + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_3vector); } @@ -116,17 +112,18 @@ colvar::distance_vec::distance_vec() { function_type = "distance_vec"; enable(f_cvc_com_based); + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_3vector); } void colvar::distance_vec::calc_value() { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { x.rvector_value = group2->center_of_mass() - group1->center_of_mass(); } else { x.rvector_value = cvm::position_distance(group1->center_of_mass(), - group2->center_of_mass()); + group2->center_of_mass()); } } @@ -214,10 +211,6 @@ colvar::distance_z::distance_z(std::string const &conf) fixed_axis = true; } - if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { - cvm::log("Computing distance using absolute positions (not minimal-image)"); - } - init_total_force_params(conf); } @@ -236,22 +229,24 @@ colvar::distance_z::distance_z() void colvar::distance_z::calc_value() { if (fixed_axis) { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { dist_v = main->center_of_mass() - ref1->center_of_mass(); } else { dist_v = cvm::position_distance(ref1->center_of_mass(), - main->center_of_mass()); + main->center_of_mass()); } } else { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { dist_v = main->center_of_mass() - (0.5 * (ref1->center_of_mass() + ref2->center_of_mass())); axis = ref2->center_of_mass() - ref1->center_of_mass(); } else { dist_v = cvm::position_distance(0.5 * (ref1->center_of_mass() + - ref2->center_of_mass()), main->center_of_mass()); - axis = cvm::position_distance(ref1->center_of_mass(), ref2->center_of_mass()); + ref2->center_of_mass()), + main->center_of_mass()); + axis = cvm::position_distance(ref1->center_of_mass(), + ref2->center_of_mass()); } axis_norm = axis.norm(); axis = axis.unit(); @@ -268,16 +263,20 @@ void colvar::distance_z::calc_gradients() if (fixed_axis) { ref1->set_weighted_gradient(-1.0 * axis); } else { - if (b_no_PBC) { - ref1->set_weighted_gradient( 1.0 / axis_norm * (main->center_of_mass() - ref2->center_of_mass() - + if (!is_enabled(f_cvc_pbc_minimum_image)) { + ref1->set_weighted_gradient( 1.0 / axis_norm * + (main->center_of_mass() - ref2->center_of_mass() - x.real_value * axis )); - ref2->set_weighted_gradient( 1.0 / axis_norm * (ref1->center_of_mass() - main->center_of_mass() + + ref2->set_weighted_gradient( 1.0 / axis_norm * + (ref1->center_of_mass() - main->center_of_mass() + x.real_value * axis )); } else { ref1->set_weighted_gradient( 1.0 / axis_norm * ( - cvm::position_distance(ref2->center_of_mass(), main->center_of_mass()) - x.real_value * axis )); + cvm::position_distance(ref2->center_of_mass(), + main->center_of_mass()) - x.real_value * axis )); ref2->set_weighted_gradient( 1.0 / axis_norm * ( - cvm::position_distance(main->center_of_mass(), ref1->center_of_mass()) + x.real_value * axis )); + cvm::position_distance(main->center_of_mass(), + ref1->center_of_mass()) + x.real_value * axis )); } } } @@ -390,17 +389,18 @@ colvar::distance_xy::distance_xy() void colvar::distance_xy::calc_value() { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { dist_v = main->center_of_mass() - ref1->center_of_mass(); } else { dist_v = cvm::position_distance(ref1->center_of_mass(), - main->center_of_mass()); + main->center_of_mass()); } if (!fixed_axis) { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { v12 = ref2->center_of_mass() - ref1->center_of_mass(); } else { - v12 = cvm::position_distance(ref1->center_of_mass(), ref2->center_of_mass()); + v12 = cvm::position_distance(ref1->center_of_mass(), + ref2->center_of_mass()); } axis_norm = v12.norm(); axis = v12.unit(); @@ -425,10 +425,11 @@ void colvar::distance_xy::calc_gradients() ref1->set_weighted_gradient(-1.0 * x_inv * dist_v_ortho); main->set_weighted_gradient( x_inv * dist_v_ortho); } else { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { v13 = main->center_of_mass() - ref1->center_of_mass(); } else { - v13 = cvm::position_distance(ref1->center_of_mass(), main->center_of_mass()); + v13 = cvm::position_distance(ref1->center_of_mass(), + main->center_of_mass()); } A = (dist_v * axis) / axis_norm; @@ -480,6 +481,7 @@ colvar::distance_dir::distance_dir(std::string const &conf) { function_type = "distance_dir"; enable(f_cvc_com_based); + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_unit3vector); } @@ -489,13 +491,14 @@ colvar::distance_dir::distance_dir() { function_type = "distance_dir"; enable(f_cvc_com_based); + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_unit3vector); } void colvar::distance_dir::calc_value() { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { dist_v = group2->center_of_mass() - group1->center_of_mass(); } else { dist_v = cvm::position_distance(group1->center_of_mass(), @@ -539,22 +542,26 @@ cvm::real colvar::distance_dir::dist2(colvarvalue const &x1, colvarvalue colvar::distance_dir::dist2_lgrad(colvarvalue const &x1, colvarvalue const &x2) const { - return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vector); + return colvarvalue((x1.rvector_value - x2.rvector_value), colvarvalue::type_unit3vectorderiv); } colvarvalue colvar::distance_dir::dist2_rgrad(colvarvalue const &x1, colvarvalue const &x2) const { - return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vector); + return colvarvalue((x2.rvector_value - x1.rvector_value), colvarvalue::type_unit3vectorderiv); } colvar::distance_inv::distance_inv(std::string const &conf) - : distance(conf) + : cvc(conf) { function_type = "distance_inv"; + + group1 = parse_group(conf, "group1"); + group2 = parse_group(conf, "group2"); + get_keyval(conf, "exponent", exponent, 6); if (exponent%2) { cvm::error("Error: odd exponent provided, can only use even ones.\n"); @@ -589,7 +596,7 @@ colvar::distance_inv::distance_inv() void colvar::distance_inv::calc_value() { x.real_value = 0.0; - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { for (cvm::atom_iter ai1 = group1->begin(); ai1 != group1->end(); ai1++) { for (cvm::atom_iter ai2 = group2->begin(); ai2 != group2->end(); ai2++) { cvm::rvector const dv = ai2->pos - ai1->pos; @@ -655,14 +662,11 @@ colvar::distance_pairs::distance_pairs(std::string const &conf) { function_type = "distance_pairs"; - if (get_keyval(conf, "forceNoPBC", b_no_PBC, false)) { - cvm::log("Computing distance using absolute positions (not minimal-image)"); - } - group1 = parse_group(conf, "group1"); group2 = parse_group(conf, "group2"); x.type(colvarvalue::type_vector); + enable(f_cvc_implicit_gradient); x.vector1d_value.resize(group1->size() * group2->size()); } @@ -670,6 +674,7 @@ colvar::distance_pairs::distance_pairs(std::string const &conf) colvar::distance_pairs::distance_pairs() { function_type = "distance_pairs"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_vector); } @@ -678,7 +683,7 @@ void colvar::distance_pairs::calc_value() { x.vector1d_value.resize(group1->size() * group2->size()); - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { size_t i1, i2; for (i1 = 0; i1 < group1->size(); i1++) { for (i2 = 0; i2 < group2->size(); i2++) { @@ -693,7 +698,8 @@ void colvar::distance_pairs::calc_value() size_t i1, i2; for (i1 = 0; i1 < group1->size(); i1++) { for (i2 = 0; i2 < group2->size(); i2++) { - cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, (*group2)[i2].pos); + cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, + (*group2)[i2].pos); cvm::real const d = dv.norm(); x.vector1d_value[i1*group2->size() + i2] = d; (*group1)[i1].grad = -1.0 * dv.unit(); @@ -712,7 +718,7 @@ void colvar::distance_pairs::calc_gradients() void colvar::distance_pairs::apply_force(colvarvalue const &force) { - if (b_no_PBC) { + if (!is_enabled(f_cvc_pbc_minimum_image)) { size_t i1, i2; for (i1 = 0; i1 < group1->size(); i1++) { for (i2 = 0; i2 < group2->size(); i2++) { @@ -725,7 +731,8 @@ void colvar::distance_pairs::apply_force(colvarvalue const &force) size_t i1, i2; for (i1 = 0; i1 < group1->size(); i1++) { for (i2 = 0; i2 < group2->size(); i2++) { - cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, (*group2)[i2].pos); + cvm::rvector const dv = cvm::position_distance((*group1)[i1].pos, + (*group2)[i2].pos); (*group1)[i1].apply_force(force[i1*group2->size() + i2] * (-1.0) * dv.unit()); (*group2)[i2].apply_force(force[i1*group2->size() + i2] * dv.unit()); } @@ -999,7 +1006,7 @@ colvar::rmsd::rmsd(std::string const &conf) cvm::log("This is a standard minimum RMSD, derivatives of the optimal rotation " "will not be computed as they cancel out in the gradients."); - atoms->b_fit_gradients = false; + atoms->disable(f_ag_fit_gradients); // request the calculation of the derivatives of the rotation defined by the atom group atoms->rot.request_group1_gradients(atoms->size()); @@ -1191,8 +1198,8 @@ colvar::eigenvector::eigenvector(std::string const &conf) atoms->b_rotate = true; atoms->ref_pos = ref_pos; atoms->center_ref_pos(); - atoms->b_fit_gradients = false; // cancel out if group is fitted on itself - // and cvc is translationally invariant + atoms->disable(f_ag_fit_gradients); // cancel out if group is fitted on itself + // and cvc is translationally invariant // request the calculation of the derivatives of the rotation defined by the atom group atoms->rot.request_group1_gradients(atoms->size()); @@ -1207,8 +1214,9 @@ colvar::eigenvector::eigenvector(std::string const &conf) if (b_inline) { cvm::log("Using vector components from input file.\n"); if (eigenvec.size() != atoms->size()) { - cvm::fatal_error("Error: vector components do not " + cvm::error("Error: vector components do not " "match the number of requested atoms->\n"); + return; } } @@ -1422,6 +1430,7 @@ colvar::cartesian::cartesian(std::string const &conf) } x.type(colvarvalue::type_vector); + enable(f_cvc_implicit_gradient); x.vector1d_value.resize(atoms->size() * axes.size()); } diff --git a/lib/colvars/colvarcomp_protein.cpp b/lib/colvars/colvarcomp_protein.cpp index 393c7dcf9a..b8fc96cfad 100644 --- a/lib/colvars/colvarcomp_protein.cpp +++ b/lib/colvars/colvarcomp_protein.cpp @@ -20,15 +20,6 @@ // alpha component ////////////////////////////////////////////////////////////////////// - // FIXME: this will not make collect_gradients work - // because gradients in individual atom groups - // are those of the sub-cvcs (angle, hb), not those - // of this cvc (alpha) - // This is true of all cvcs with sub-cvcs, and those - // that do not calculate explicit gradients - // SO: we need a flag giving the availability of - // atomic gradients - colvar::alpha_angles::alpha_angles(std::string const &conf) : cvc(conf) { @@ -36,6 +27,7 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) cvm::log("Initializing alpha_angles object.\n"); function_type = "alpha_angles"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_scalar); std::string segment_id; @@ -44,7 +36,7 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) std::vector residues; { std::string residues_conf = ""; - key_lookup(conf, "residueRange", residues_conf); + key_lookup(conf, "residueRange", &residues_conf); if (residues_conf.size()) { std::istringstream is(residues_conf); int initial, final; @@ -57,12 +49,14 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) } } } else { - cvm::fatal_error("Error: no residues defined in \"residueRange\".\n"); + cvm::error("Error: no residues defined in \"residueRange\".\n"); + return; } } if (residues.size() < 5) { - cvm::fatal_error("Error: not enough residues defined in \"residueRange\".\n"); + cvm::error("Error: not enough residues defined in \"residueRange\".\n"); + return; } std::string const &sid = segment_id; @@ -71,7 +65,8 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) get_keyval(conf, "hBondCoeff", hb_coeff, 0.5); if ( (hb_coeff < 0.0) || (hb_coeff > 1.0) ) { - cvm::fatal_error("Error: hBondCoeff must be defined between 0 and 1.\n"); + cvm::error("Error: hBondCoeff must be defined between 0 and 1.\n"); + return; } @@ -84,9 +79,9 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) theta.push_back(new colvar::angle(cvm::atom(r[i ], "CA", sid), cvm::atom(r[i+1], "CA", sid), cvm::atom(r[i+2], "CA", sid))); - atom_groups.push_back(theta.back()->atom_groups[0]); - atom_groups.push_back(theta.back()->atom_groups[1]); - atom_groups.push_back(theta.back()->atom_groups[2]); + register_atom_group(theta.back()->atom_groups[0]); + register_atom_group(theta.back()->atom_groups[1]); + register_atom_group(theta.back()->atom_groups[2]); } } else { @@ -106,7 +101,7 @@ colvar::alpha_angles::alpha_angles(std::string const &conf) hb.push_back(new colvar::h_bond(cvm::atom(r[i ], "O", sid), cvm::atom(r[i+4], "N", sid), r0, en, ed)); - atom_groups.push_back(hb.back()->atom_groups[0]); + register_atom_group(hb.back()->atom_groups[0]); } } else { @@ -123,6 +118,7 @@ colvar::alpha_angles::alpha_angles() : cvc() { function_type = "alpha_angles"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_scalar); } @@ -239,15 +235,6 @@ simple_scalar_dist_functions(alpha_angles) // dihedral principal component ////////////////////////////////////////////////////////////////////// - // FIXME: this will not make collect_gradients work - // because gradients in individual atom groups - // are those of the sub-cvcs (dihedral), not those - // of this cvc - // This is true of all cvcs with sub-cvcs, and those - // that do not calculate explicit gradients - // SO: we need a flag giving the availability of - // atomic gradients - colvar::dihedPC::dihedPC(std::string const &conf) : cvc(conf) { @@ -255,6 +242,7 @@ colvar::dihedPC::dihedPC(std::string const &conf) cvm::log("Initializing dihedral PC object.\n"); function_type = "dihedPC"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_scalar); std::string segment_id; @@ -263,7 +251,7 @@ colvar::dihedPC::dihedPC(std::string const &conf) std::vector residues; { std::string residues_conf = ""; - key_lookup(conf, "residueRange", residues_conf); + key_lookup(conf, "residueRange", &residues_conf); if (residues_conf.size()) { std::istringstream is(residues_conf); int initial, final; @@ -276,12 +264,14 @@ colvar::dihedPC::dihedPC(std::string const &conf) } } } else { - cvm::fatal_error("Error: no residues defined in \"residueRange\".\n"); + cvm::error("Error: no residues defined in \"residueRange\".\n"); + return; } } if (residues.size() < 2) { - cvm::fatal_error("Error: dihedralPC requires at least two residues.\n"); + cvm::error("Error: dihedralPC requires at least two residues.\n"); + return; } std::string const &sid = segment_id; @@ -291,13 +281,16 @@ colvar::dihedPC::dihedPC(std::string const &conf) int vecNumber; if (get_keyval(conf, "vectorFile", vecFileName, vecFileName)) { get_keyval(conf, "vectorNumber", vecNumber, 0); - if (vecNumber < 1) - cvm::fatal_error("A positive value of vectorNumber is required."); + if (vecNumber < 1) { + cvm::error("A positive value of vectorNumber is required."); + return; + } std::ifstream vecFile; vecFile.open(vecFileName.c_str()); - if (!vecFile.good()) - cvm::fatal_error("Error opening dihedral PCA vector file " + vecFileName + " for reading"); + if (!vecFile.good()) { + cvm::error("Error opening dihedral PCA vector file " + vecFileName + " for reading"); + } // TODO: adapt to different formats by setting this flag bool eigenvectors_as_columns = true; @@ -321,8 +314,9 @@ colvar::dihedPC::dihedPC(std::string const &conf) for (int i = 1; iatom_groups[0]); - atom_groups.push_back(theta.back()->atom_groups[1]); - atom_groups.push_back(theta.back()->atom_groups[2]); - atom_groups.push_back(theta.back()->atom_groups[3]); + register_atom_group(theta.back()->atom_groups[0]); + register_atom_group(theta.back()->atom_groups[1]); + register_atom_group(theta.back()->atom_groups[2]); + register_atom_group(theta.back()->atom_groups[3]); // Phi (next res) theta.push_back(new colvar::dihedral(cvm::atom(r[i ], "C", sid), cvm::atom(r[i+1], "N", sid), cvm::atom(r[i+1], "CA", sid), cvm::atom(r[i+1], "C", sid))); - atom_groups.push_back(theta.back()->atom_groups[0]); - atom_groups.push_back(theta.back()->atom_groups[1]); - atom_groups.push_back(theta.back()->atom_groups[2]); - atom_groups.push_back(theta.back()->atom_groups[3]); + register_atom_group(theta.back()->atom_groups[0]); + register_atom_group(theta.back()->atom_groups[1]); + register_atom_group(theta.back()->atom_groups[2]); + register_atom_group(theta.back()->atom_groups[3]); } if (cvm::debug()) @@ -377,6 +372,7 @@ colvar::dihedPC::dihedPC() : cvc() { function_type = "dihedPC"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_scalar); } diff --git a/lib/colvars/colvarcomp_rotations.cpp b/lib/colvars/colvarcomp_rotations.cpp index 936e770169..2650a9fe18 100644 --- a/lib/colvars/colvarcomp_rotations.cpp +++ b/lib/colvars/colvarcomp_rotations.cpp @@ -22,6 +22,7 @@ colvar::orientation::orientation(std::string const &conf) { function_type = "orientation"; atoms = parse_group(conf, "atoms"); + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_quaternion); ref_pos.reserve(atoms->size()); @@ -29,8 +30,9 @@ colvar::orientation::orientation(std::string const &conf) if (get_keyval(conf, "refPositions", ref_pos, ref_pos)) { cvm::log("Using reference positions from input file.\n"); if (ref_pos.size() != atoms->size()) { - cvm::fatal_error("Error: reference positions do not " + cvm::error("Error: reference positions do not " "match the number of requested atoms.\n"); + return; } } @@ -43,9 +45,11 @@ colvar::orientation::orientation(std::string const &conf) if (get_keyval(conf, "refPositionsCol", file_col, std::string(""))) { // use PDB flags if column is provided bool found = get_keyval(conf, "refPositionsColValue", file_col_value, 0.0); - if (found && file_col_value==0.0) - cvm::fatal_error("Error: refPositionsColValue, " + if (found && file_col_value==0.0) { + cvm::error("Error: refPositionsColValue, " "if provided, must be non-zero.\n"); + return; + } } else { // if not, use atom indices atoms->create_sorted_ids(); @@ -56,8 +60,9 @@ colvar::orientation::orientation(std::string const &conf) } if (!ref_pos.size()) { - cvm::fatal_error("Error: must define a set of " + cvm::error("Error: must define a set of " "reference coordinates.\n"); + return; } @@ -88,6 +93,7 @@ colvar::orientation::orientation() : cvc() { function_type = "orientation"; + enable(f_cvc_implicit_gradient); x.type(colvarvalue::type_quaternion); } diff --git a/lib/colvars/colvardeps.cpp b/lib/colvars/colvardeps.cpp index 8252f77e62..5402836f53 100644 --- a/lib/colvars/colvardeps.cpp +++ b/lib/colvars/colvardeps.cpp @@ -10,24 +10,77 @@ #include "colvardeps.h" +colvardeps::colvardeps() + : time_step_factor (1) {} colvardeps::~colvardeps() { size_t i; - // Do not delete features if it's static -// for (i=0; idescription); } } + + // Do not delete features if it's a static object + // may change in the future though +// for (i=0; irequires_children.size(); i++) { + int g = features()[fid]->requires_children[i]; + for (j=0; jfeatures()[g]->description); + children[j]->decr_ref_count(g); + } + } + } + } + cvm::decrease_depth(); +} + + +// re-enable children features (and increase ref count accordingly) +// So free_children_deps() can be called whenever an object becomes inactive +void colvardeps::restore_children_deps() { + size_t i,j,fid; + + cvm::increase_depth(); + for (fid = 0; fid < feature_states.size(); fid++) { + if (is_enabled(fid)) { + for (i=0; irequires_children.size(); i++) { + int g = features()[fid]->requires_children[i]; + for (j=0; jfeatures()[g]->description); + children[j]->enable(g, false, false); + } + } + } + } + cvm::decrease_depth(); } @@ -37,15 +90,10 @@ void colvardeps::provide(int feature_id, bool truefalse) { void colvardeps::set_enabled(int feature_id, bool truefalse) { -// if (!is_static(feature_id)) { -// cvm::error("Cannot set feature " + features()[feature_id]->description + " statically in " + description + ".\n"); -// return; -// } if (truefalse) { - // Resolve dependencies too enable(feature_id); } else { - feature_states[feature_id].enabled = false; + disable(feature_id); } } @@ -56,7 +104,7 @@ bool colvardeps::get_keyval_feature(colvarparse *cvp, colvarparse::Parse_Mode const parse_mode) { if (!is_user(feature_id)) { - cvm::error("Cannot set feature " + features()[feature_id]->description + " from user input in " + description + ".\n"); + cvm::error("Cannot set feature \"" + features()[feature_id]->description + "\" from user input in \"" + description + "\".\n"); return false; } bool value; @@ -83,21 +131,34 @@ int colvardeps::enable(int feature_id, if (cvm::debug()) { cvm::log("DEPS: " + description + - (dry_run ? " testing " : " requiring ") + + (dry_run ? " testing " : " enabling ") + "\"" + f->description +"\""); } if (fs->enabled) { - // Do not try to solve deps if already enabled + if (!(dry_run || toplevel)) { + // This is a dependency + // Prevent disabling this feature as long + // as requirement is enabled + fs->ref_count++; + if (cvm::debug()) + cvm::log("DEPS: bumping ref_count to " + cvm::to_str(fs->ref_count)); + } + // Do not try to further resolve deps return COLVARS_OK; } + std::string feature_type_descr = is_static(feature_id) ? "Static" : + (is_dynamic(feature_id) ? "Dynamic" : "User-controlled"); + if (!fs->available) { if (!dry_run) { if (toplevel) { - cvm::error("Error: Feature unavailable: \"" + f->description + "\" in " + description + "."); + cvm::error("Error: " + feature_type_descr + " feature unavailable: \"" + + f->description + "\" in " + description + "."); } else { - cvm::log("Feature unavailable: \"" + f->description + "\" in " + description); + cvm::log(feature_type_descr + " feature unavailable: \"" + + f->description + "\" in " + description + "."); } } return COLVARS_ERROR; @@ -105,21 +166,22 @@ int colvardeps::enable(int feature_id, if (!toplevel && !is_dynamic(feature_id)) { if (!dry_run) { - cvm::log("Non-dynamic feature : \"" + f->description - + "\" in " + description + " may not be enabled as a dependency.\n"); + cvm::log(feature_type_descr + " feature \"" + f->description + + "\" may not be enabled as a dependency in " + description + ".\n"); } return COLVARS_ERROR; } // 1) enforce exclusions + // reminder: exclusions must be mutual for this to work for (i=0; irequires_exclude.size(); i++) { feature *g = features()[f->requires_exclude[i]]; if (cvm::debug()) cvm::log(f->description + " requires exclude " + g->description); if (is_enabled(f->requires_exclude[i])) { if (!dry_run) { - cvm::log("Features \"" + f->description + "\" is incompatible with \"" - + g->description + "\" in " + description); + cvm::log("Feature \"" + f->description + "\" is incompatible with \"" + + g->description + "\" in " + description + "."); if (toplevel) { cvm::error("Error: Failed dependency in " + description + "."); } @@ -156,23 +218,27 @@ int colvardeps::enable(int feature_id, res = enable(g, true, false); // see if available if (res == COLVARS_OK) { ok = true; - if (!dry_run) enable(g, false, false); // Require again, for real + if (!dry_run) { + enable(g, false, false); // Require again, for real + fs->alternate_refs.push_back(g); // We remember we enabled this + // so we can free it if this feature gets disabled + } break; } } if (!ok) { if (!dry_run) { - cvm::log("No dependency satisfied among alternates:"); - cvm::log("-----------------------------------------"); + cvm::log("\"" + f->description + "\" in " + description + + " requires one of the following features, none of which can be enabled:\n"); + cvm::log("-----------------------------------------\n"); + cvm::increase_depth(); for (j=0; jrequires_alt[i].size(); j++) { int g = f->requires_alt[i][j]; cvm::log(cvm::to_str(j+1) + ". " + features()[g]->description); - cvm::increase_depth(); enable(g, false, false); // Just for printing error output - cvm::decrease_depth(); } + cvm::decrease_depth(); cvm::log("-----------------------------------------"); - cvm::log("for \"" + f->description + "\" in " + description); if (toplevel) { cvm::error("Error: Failed dependency in " + description + "."); } @@ -182,12 +248,13 @@ int colvardeps::enable(int feature_id, } // 4) solve deps in children + // if the object is inactive, we solve but do not enable: will be enabled + // when the object becomes active + cvm::increase_depth(); for (i=0; irequires_children.size(); i++) { int g = f->requires_children[i]; for (j=0; jenable(g, dry_run, false); - cvm::decrease_depth(); + res = children[j]->enable(g, dry_run || !is_enabled(), false); if (res != COLVARS_OK) { if (!dry_run) { cvm::log("...required by \"" + f->description + "\" in " + description); @@ -198,25 +265,114 @@ int colvardeps::enable(int feature_id, return res; } } - // If we've just touched the features of child objects, refresh them - if (!dry_run && f->requires_children.size() != 0) { - for (j=0; jrefresh_deps(); - } - } } + cvm::decrease_depth(); // Actually enable feature only once everything checks out - if (!dry_run) fs->enabled = true; + if (!dry_run) { + fs->enabled = true; + // This should be the only reference + if (!toplevel) fs->ref_count = 1; + if (feature_id == 0) { + // Waking up this object, enable all deps in children + restore_children_deps(); + } + do_feature_side_effects(feature_id); + if (cvm::debug()) + cvm::log("DEPS: feature \"" + f->description + "\" in " + + description + " enabled, ref_count = 1."); + } return COLVARS_OK; } -// disable() { -// -// // we need refs to parents to walk up the deps tree! -// // or refresh -// } +int colvardeps::disable(int feature_id) { + size_t i, j; + feature *f = features()[feature_id]; + feature_state *fs = &feature_states[feature_id]; + + if (cvm::debug()) cvm::log("DEPS: disabling feature \"" + + f->description + "\" in " + description); + + if (fs->enabled == false) { + return COLVARS_OK; + } + + if (fs->ref_count > 1) { + cvm::error("Error: cannot disable feature \"" + f->description + + "\" in " + description + " because of " + cvm::to_str(fs->ref_count-1) + + " remaining references.\n" ); + return COLVARS_ERROR; + } + + // internal deps (self) + for (i=0; irequires_self.size(); i++) { + if (cvm::debug()) cvm::log("DEPS: dereferencing self " + + features()[f->requires_self[i]]->description); + decr_ref_count(f->requires_self[i]); + } + + // alternates + for (i=0; ialternate_refs.size(); i++) { + if (cvm::debug()) cvm::log("DEPS: dereferencing alt " + + features()[fs->alternate_refs[i]]->description); + decr_ref_count(fs->alternate_refs[i]); + } + // Forget these, now that they are dereferenced + fs->alternate_refs.clear(); + + // deps in children + // except if the object is inactive, then children dependencies + // have already been dereferenced by this function + // (or never referenced if feature was enabled while the object + // was inactive) + if (is_enabled()) { + cvm::increase_depth(); + for (i=0; irequires_children.size(); i++) { + int g = f->requires_children[i]; + for (j=0; jfeatures()[g]->description); + children[j]->decr_ref_count(g); + } + } + cvm::decrease_depth(); + } + + fs->enabled = false; + fs->ref_count = 0; + if (feature_id == 0) { + // Putting this object to sleep + free_children_deps(); + } + return COLVARS_OK; +} + +int colvardeps::decr_ref_count(int feature_id) { + int &rc = feature_states[feature_id].ref_count; + feature *f = features()[feature_id]; + + if (cvm::debug()) + cvm::log("DEPS: decreasing reference count of \"" + f->description + + "\" in " + description + ".\n"); + + if (rc <= 0) { + cvm::error("Error: cannot decrease reference count of feature \"" + f->description + + "\" in " + description + ", which is " + cvm::to_str(rc) + ".\n"); + return COLVARS_ERROR; + } + + rc--; + if (rc == 0 && f->is_dynamic()) { + // we can auto-disable this feature + if (cvm::debug()) + cvm::log("DEPS will now auto-disable dynamic feature \"" + f->description + + "\" in " + description + ".\n"); + disable(feature_id); + } + return COLVARS_OK; +} + void colvardeps::init_feature(int feature_id, const char *description, feature_type type) { features()[feature_id]->description = description; features()[feature_id]->type = type; @@ -235,6 +391,11 @@ void colvardeps::init_feature(int feature_id, const char *description, feature_t features()[f]->requires_alt.back()[0] = g; \ features()[f]->requires_alt.back()[1] = h; \ features()[f]->requires_alt.back()[2] = i +#define f_req_alt4(f, g, h, i, j) features()[f]->requires_alt.push_back(std::vector(4));\ + features()[f]->requires_alt.back()[0] = g; \ + features()[f]->requires_alt.back()[1] = h; \ + features()[f]->requires_alt.back()[2] = i; \ + features()[f]->requires_alt.back()[3] = j void colvardeps::init_cvb_requires() { int i; @@ -246,6 +407,9 @@ void colvardeps::init_cvb_requires() { init_feature(f_cvb_active, "active", f_type_dynamic); f_req_children(f_cvb_active, f_cv_active); + init_feature(f_cvb_awake, "awake", f_type_static); + f_req_self(f_cvb_awake, f_cvb_active); + init_feature(f_cvb_apply_force, "apply force", f_type_user); f_req_children(f_cvb_apply_force, f_cv_gradient); @@ -278,9 +442,12 @@ void colvardeps::init_cv_requires() { } init_feature(f_cv_active, "active", f_type_dynamic); - f_req_children(f_cv_active, f_cvc_active); - // Colvars must be either a linear combination, or scalar (and polynomial) or scripted - f_req_alt3(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted); + // Do not require f_cvc_active in children, as some components may be disabled + // Colvars must be either a linear combination, or scalar (and polynomial) or scripted/custom + f_req_alt4(f_cv_active, f_cv_scalar, f_cv_linear, f_cv_scripted, f_cv_custom_function); + + init_feature(f_cv_awake, "awake", f_type_static); + f_req_self(f_cv_awake, f_cv_active); init_feature(f_cv_gradient, "gradient", f_type_dynamic); f_req_children(f_cv_gradient, f_cvc_gradient); @@ -288,8 +455,10 @@ void colvardeps::init_cv_requires() { init_feature(f_cv_collect_gradient, "collect gradient", f_type_dynamic); f_req_self(f_cv_collect_gradient, f_cv_gradient); f_req_self(f_cv_collect_gradient, f_cv_scalar); + // The following exlusion could be lifted by implementing the feature + f_req_exclude(f_cv_collect_gradient, f_cv_scripted); - init_feature(f_cv_fdiff_velocity, "fdiff_velocity", f_type_dynamic); + init_feature(f_cv_fdiff_velocity, "velocity from finite differences", f_type_dynamic); // System force: either trivial (spring force); through extended Lagrangian, or calculated explicitly init_feature(f_cv_total_force, "total force", f_type_dynamic); @@ -335,6 +504,9 @@ void colvardeps::init_cv_requires() { init_feature(f_cv_subtract_applied_force, "subtract applied force from total force", f_type_user); f_req_self(f_cv_subtract_applied_force, f_cv_total_force); + // There is no well-defined way to implement f_cv_subtract_applied_force + // in the case of extended-Lagrangian colvars + f_req_exclude(f_cv_subtract_applied_force, f_cv_extended_Lagrangian); init_feature(f_cv_lower_boundary, "lower boundary", f_type_user); f_req_self(f_cv_lower_boundary, f_cv_scalar); @@ -350,12 +522,21 @@ void colvardeps::init_cv_requires() { init_feature(f_cv_corrfunc, "correlation function", f_type_user); - init_feature(f_cv_scripted, "scripted", f_type_static); + init_feature(f_cv_scripted, "scripted", f_type_user); + + init_feature(f_cv_custom_function, "custom function", f_type_user); + f_req_exclude(f_cv_custom_function, f_cv_scripted); + init_feature(f_cv_periodic, "periodic", f_type_static); f_req_self(f_cv_periodic, f_cv_homogeneous); init_feature(f_cv_scalar, "scalar", f_type_static); init_feature(f_cv_linear, "linear", f_type_static); init_feature(f_cv_homogeneous, "homogeneous", f_type_static); + + // because total forces are obtained from the previous time step, + // we cannot (currently) have colvar values and total forces for the same timestep + init_feature(f_cv_multiple_ts, "multiple timestep colvar"); + f_req_exclude(f_cv_multiple_ts, f_cv_total_force_calc); } // Initialize feature_states for each instance @@ -365,23 +546,6 @@ void colvardeps::init_cv_requires() { // Most features are available, so we set them so // and list exceptions below } - -// // properties that may NOT be enabled as a dependency -// // This will be deprecated by feature types -// int unavailable_deps[] = { -// f_cv_lower_boundary, -// f_cv_upper_boundary, -// f_cv_extended_Lagrangian, -// f_cv_Langevin, -// f_cv_scripted, -// f_cv_periodic, -// f_cv_scalar, -// f_cv_linear, -// f_cv_homogeneous -// }; -// for (i = 0; i < sizeof(unavailable_deps) / sizeof(unavailable_deps[0]); i++) { -// feature_states[unavailable_deps[i]].available = false; -// } } @@ -401,20 +565,26 @@ void colvardeps::init_cvc_requires() { init_feature(f_cvc_gradient, "gradient", f_type_dynamic); + init_feature(f_cvc_implicit_gradient, "implicit gradient", f_type_static); + f_req_children(f_cvc_implicit_gradient, f_ag_implicit_gradient); + init_feature(f_cvc_inv_gradient, "inverse gradient", f_type_dynamic); f_req_self(f_cvc_inv_gradient, f_cvc_gradient); init_feature(f_cvc_debug_gradient, "debug gradient", f_type_user); f_req_self(f_cvc_debug_gradient, f_cvc_gradient); + f_req_exclude(f_cvc_debug_gradient, f_cvc_implicit_gradient); init_feature(f_cvc_Jacobian, "Jacobian derivative", f_type_dynamic); f_req_self(f_cvc_Jacobian, f_cvc_inv_gradient); init_feature(f_cvc_com_based, "depends on group centers of mass", f_type_static); + // init_feature(f_cvc_pbc_minimum_image, "use minimum-image distances with PBCs", f_type_user); + // Compute total force on first site only to avoid unwanted // coupling to other colvars (see e.g. Ciccotti et al., 2005) - init_feature(f_cvc_one_site_total_force, "compute total collective force only from one group center", f_type_user); + init_feature(f_cvc_one_site_total_force, "compute total force from one group", f_type_user); f_req_self(f_cvc_one_site_total_force, f_cvc_com_based); init_feature(f_cvc_scalable, "scalable calculation", f_type_static); @@ -438,11 +608,17 @@ void colvardeps::init_cvc_requires() { feature_states.push_back(feature_state(avail, false)); } + // CVCs are enabled from the start - get disabled based on flags + feature_states[f_cvc_active].enabled = true; + // Features that are implemented by all cvcs by default // Each cvc specifies what other features are available feature_states[f_cvc_active].available = true; feature_states[f_cvc_gradient].available = true; + // Use minimum-image distances by default + feature_states[f_cvc_pbc_minimum_image].enabled = true; + // Features that are implemented by default if their requirements are feature_states[f_cvc_one_site_total_force].available = true; @@ -464,8 +640,10 @@ void colvardeps::init_ag_requires() { init_feature(f_ag_center, "translational fit", f_type_static); init_feature(f_ag_rotate, "rotational fit", f_type_static); init_feature(f_ag_fitting_group, "reference positions group", f_type_static); - init_feature(f_ag_fit_gradient_group, "fit gradient for main group", f_type_static); - init_feature(f_ag_fit_gradient_ref, "fit gradient for reference group", f_type_static); + init_feature(f_ag_implicit_gradient, "implicit atom gradient", f_type_dynamic); + init_feature(f_ag_fit_gradients, "fit gradients", f_type_user); + f_req_exclude(f_ag_fit_gradients, f_ag_implicit_gradient); + init_feature(f_ag_atom_forces, "atomic forces", f_type_dynamic); // parallel calculation implies that we have at least a scalable center of mass, @@ -493,29 +671,50 @@ void colvardeps::init_ag_requires() { feature_states[f_ag_scalable_com].available = false; // TODO make f_ag_scalable depend on f_ag_scalable_com (or something else) feature_states[f_ag_scalable].available = true; + feature_states[f_ag_fit_gradients].available = true; + feature_states[f_ag_implicit_gradient].available = true; } void colvardeps::print_state() { size_t i; - cvm::log("Enabled features of " + description); + cvm::log("Enabled features of \"" + description + "\" (with reference count)"); for (i = 0; i < feature_states.size(); i++) { - if (feature_states[i].enabled) - cvm::log("- " + features()[i]->description); + if (is_enabled(i)) + cvm::log("- " + features()[i]->description + " (" + + cvm::to_str(feature_states[i].ref_count) + ")"); } + cvm::increase_depth(); for (i=0; iprint_state(); - cvm::decrease_depth(); } + cvm::decrease_depth(); } void colvardeps::add_child(colvardeps *child) { + children.push_back(child); child->parents.push_back((colvardeps *)this); + + // Solve dependencies of already enabled parent features + // in the new child + + size_t i, fid; + cvm::increase_depth(); + for (fid = 0; fid < feature_states.size(); fid++) { + if (is_enabled(fid)) { + for (i=0; irequires_children.size(); i++) { + int g = features()[fid]->requires_children[i]; + if (cvm::debug()) cvm::log("DEPS: re-enabling children's " + + child->features()[g]->description); + child->enable(g, false, false); + } + } + } + cvm::decrease_depth(); } diff --git a/lib/colvars/colvardeps.h b/lib/colvars/colvardeps.h index fd07cb6457..b810a5fca1 100644 --- a/lib/colvars/colvardeps.h +++ b/lib/colvars/colvardeps.h @@ -23,10 +23,14 @@ /// 3. Static features are static properties of the object, determined /// programatically at initialization time. /// +/// In all classes, feature 0 is active. When an object is inactivated +/// all its children dependencies are dereferenced (free_children_deps) +/// While the object is inactive, no dependency solving is done on children +/// it is done when the object is activated back (restore_children_deps) class colvardeps { public: - colvardeps() {} + colvardeps(); virtual ~colvardeps(); // Subclasses should initialize the following members: @@ -34,9 +38,10 @@ public: std::string description; // reference to object name (cv, cvc etc.) /// This contains the current state of each feature for each object + // since the feature class only contains static properties struct feature_state { feature_state(bool a, bool e) - : available(a), enabled(e) {} + : available(a), enabled(e), ref_count(0) {} /// Feature may be enabled, subject to possible dependencies bool available; @@ -44,9 +49,28 @@ public: /// TODO consider implications for dependency solving: anyone who disables /// it should trigger a refresh of parent objects bool enabled; // see if this should be private depending on implementation + // bool enabledOnce; // this should trigger an update when object is evaluated + + /// Number of features requiring this one as a dependency + /// When it falls to zero: + /// - a dynamic feature is disabled automatically + /// - other features may be disabled statically + int ref_count; + /// List of features that were enabled by this one + /// as part of an alternate requirement (for ref counting purposes) + /// This is necessary because we don't know which feature in the list + /// we enabled, otherwise + std::vector alternate_refs; }; +protected: + /// Time step multiplier (for coarse-timestep biases & colvars) + /// Biases and colvars will only be calculated at those times + /// (f_cvb_awake and f_cv_awake); a + /// Biases use this to apply "impulse" biasing forces at the outer timestep + /// Unused by lower-level objects (cvcs and atom groups) + int time_step_factor; private: /// List of the states of all features @@ -61,10 +85,13 @@ private: }; public: + /// \brief returns time_step_factor + inline int get_time_step_factor() const {return time_step_factor;} + /// Pair a numerical feature ID with a description and type void init_feature(int feature_id, const char *description, feature_type type = f_type_not_set); - /// Describes a feature and its dependecies + /// Describes a feature and its dependencies /// used in a static array within each subclass class feature { @@ -120,30 +147,16 @@ public: private: - // pointers to objects this object depends on - // list should be maintained by any code that modifies the object - // this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions + /// pointers to objects this object depends on + /// list should be maintained by any code that modifies the object + /// this could be secured by making lists of colvars / cvcs / atom groups private and modified through accessor functions std::vector children; - // pointers to objects that depend on this object - // the size of this array is in effect a reference counter + /// pointers to objects that depend on this object + /// the size of this array is in effect a reference counter std::vector parents; public: - // disabling a feature f: - // if parents depend on f, tell them to refresh / check that they are ok? - // if children provide features to satisfy f ONLY, disable that - - // When the state of this object has changed, recursively tell parents - // to enforce their dependencies -// void refresh_parents() { -// -// } - - // std::vector parents; // Needed to trigger a refresh if capabilities of this object change - - // End of members to be initialized by subclasses - // Checks whether given feature is enabled // Defaults to querying f_*_active inline bool is_enabled(int f = f_cv_active) const { @@ -161,9 +174,7 @@ public: /// dependencies will be checked by enable() void provide(int feature_id, bool truefalse = true); - /// Set the feature's enabled flag, without dependency check or resolution - /// To be used for static properties only - /// Checking for availability is up to the caller + /// Enable or disable, depending on flag value void set_enabled(int feature_id, bool truefalse = true); protected: @@ -178,31 +189,57 @@ protected: public: - int enable(int f, bool dry_run = false, bool toplevel = true); // enable a feature and recursively solve its dependencies - // dry_run is set to true to recursively test if a feature is available, without enabling it -// int disable(int f); + /// enable a feature and recursively solve its dependencies + /// for proper reference counting, one should not add + /// spurious calls to enable() + /// dry_run is set to true to recursively test if a feature is available, without enabling it + int enable(int f, bool dry_run = false, bool toplevel = true); + /// Disable a feature, decrease the reference count of its dependencies + /// and recursively disable them as applicable + int disable(int f); - /// This function is called whenever feature states are changed outside - /// of the object's control, that is, by parents - /// Eventually it may also be used when properties of children change - virtual int refresh_deps() { return COLVARS_OK; } + /// disable all enabled features to free their dependencies + /// to be done when deleting the object + /// Cannot be in the base class destructor because it needs the derived class features() + void free_children_deps(); + + /// re-enable children features (to be used when object becomes active) + void restore_children_deps(); + + /// Decrement the reference count of a feature + /// disabling it if it's dynamic and count reaches zero + int decr_ref_count(int f); + + /// Implements possible actions to be carried out + /// when a given feature is enabled + /// Base function does nothing, can be overloaded + virtual void do_feature_side_effects(int id) {} // NOTE that all feature enums should start with f_*_active enum features_biases { /// \brief Bias is active f_cvb_active, - f_cvb_apply_force, // will apply forces - f_cvb_get_total_force, // requires total forces - f_cvb_history_dependent, // depends on simulation history - f_cvb_scalar_variables, // requires scalar colvars - f_cvb_calc_pmf, // whether this bias will compute a PMF + /// \brief Bias is awake (active on its own accord) this timestep + f_cvb_awake, + /// \brief will apply forces + f_cvb_apply_force, + /// \brief requires total forces + f_cvb_get_total_force, + /// \brief depends on simulation history + f_cvb_history_dependent, + /// \brief requires scalar colvars + f_cvb_scalar_variables, + /// \brief whether this bias will compute a PMF + f_cvb_calc_pmf, f_cvb_ntot }; enum features_colvar { /// \brief Calculate colvar f_cv_active, + /// \brief Colvar is awake (active on its own accord) this timestep + f_cv_awake, /// \brief Gradients are calculated and temporarily stored, so /// that external forces can be applied f_cv_gradient, @@ -254,12 +291,16 @@ public: f_cv_corrfunc, /// \brief Value and gradient computed by user script f_cv_scripted, + /// \brief Value and gradient computed by user function through Lepton + f_cv_custom_function, /// \brief Colvar is periodic f_cv_periodic, /// \brief is scalar f_cv_scalar, f_cv_linear, f_cv_homogeneous, + /// \brief multiple timestep through time_step_factor + f_cv_multiple_ts, /// \brief Number of colvar features f_cv_ntot }; @@ -268,10 +309,13 @@ public: f_cvc_active, f_cvc_scalar, f_cvc_gradient, + /// \brief CVC doesn't calculate and store explicit atom gradients + f_cvc_implicit_gradient, f_cvc_inv_gradient, /// \brief If enabled, calc_gradients() will call debug_gradients() for every group needed f_cvc_debug_gradient, f_cvc_Jacobian, + f_cvc_pbc_minimum_image, f_cvc_one_site_total_force, f_cvc_com_based, f_cvc_scalable, @@ -287,9 +331,9 @@ public: /// Perform a standard minimum msd fit for given atoms /// ie. not using refpositionsgroup // f_ag_min_msd_fit, - f_ag_fit_gradient_group,// TODO check that these are sometimes needed separately - // maybe for minimum RMSD? - f_ag_fit_gradient_ref, + /// \brief Does not have explicit atom gradients from parent CVC + f_ag_implicit_gradient, + f_ag_fit_gradients, f_ag_atom_forces, f_ag_scalable, f_ag_scalable_com, diff --git a/lib/colvars/colvargrid.cpp b/lib/colvars/colvargrid.cpp index 3b25acd2ef..9016e2c23a 100644 --- a/lib/colvars/colvargrid.cpp +++ b/lib/colvars/colvargrid.cpp @@ -144,7 +144,8 @@ void colvar_grid_gradient::write_1D_integral(std::ostream &os) os << "# xi A(xi)\n"; if ( cv.size() != 1 ) { - cvm::fatal_error("Cannot write integral for multi-dimensional gradient grids."); + cvm::error("Cannot write integral for multi-dimensional gradient grids."); + return; } integral = 0.0; diff --git a/lib/colvars/colvargrid.h b/lib/colvars/colvargrid.h index d4b9295c6e..6f06cb1066 100644 --- a/lib/colvars/colvargrid.h +++ b/lib/colvars/colvargrid.h @@ -198,7 +198,6 @@ public: /// Default constructor colvar_grid() : has_data(false) { - save_delimiters = false; nd = nt = 0; mult = 1; this->setup(); @@ -225,7 +224,6 @@ public: widths(g.widths), has_data(false) { - save_delimiters = false; } /// \brief Constructor from explicit grid sizes \param nx_i Number @@ -237,7 +235,6 @@ public: size_t mult_i = 1) : has_data(false) { - save_delimiters = false; this->setup(nx_i, t, mult_i); } @@ -248,7 +245,6 @@ public: bool margin = false) : has_data(false) { - save_delimiters = false; this->init_from_colvars(colvars, t, mult_i, margin); } @@ -840,7 +836,7 @@ public: // reallocate the array in case the grid params have just changed if (new_params) { init_from_boundaries(); - // data.resize(0); // no longer needed: setup calls clear() + // data.clear(); // no longer needed: setup calls clear() return this->setup(nx, T(), mult); } diff --git a/lib/colvars/colvarmodule.cpp b/lib/colvars/colvarmodule.cpp index 10cd3c0e47..780dc28afa 100644 --- a/lib/colvars/colvarmodule.cpp +++ b/lib/colvars/colvarmodule.cpp @@ -21,10 +21,14 @@ #include "colvarbias_meta.h" #include "colvarbias_restraint.h" #include "colvarscript.h" +#include "colvaratoms.h" colvarmodule::colvarmodule(colvarproxy *proxy_in) { + depth_s = 0; + cv_traj_os = NULL; + // pointer to the proxy object if (proxy == NULL) { proxy = proxy_in; @@ -33,12 +37,10 @@ colvarmodule::colvarmodule(colvarproxy *proxy_in) // TODO relax this error to handle multiple molecules in VMD // once the module is not static anymore cvm::error("Error: trying to allocate the collective " - "variable module twice.\n"); + "variable module twice.\n", BUG_ERROR); return; } - depth_s = 0; - cvm::log(cvm::line_marker); cvm::log("Initializing the collective variables module, version "+ cvm::to_str(COLVARS_VERSION)+".\n"); @@ -222,9 +224,9 @@ int colvarmodule::parse_config(std::string &conf) // update any necessary proxy data proxy->setup(); - if (cv_traj_os.is_open()) { + if (cv_traj_os != NULL) { // configuration might have changed, better redo the labels - write_traj_label(cv_traj_os); + write_traj_label(*cv_traj_os); } return get_error(); @@ -295,7 +297,7 @@ int colvarmodule::parse_colvars(std::string const &conf) std::string colvar_conf = ""; size_t pos = 0; - while (parse->key_lookup(conf, "colvar", colvar_conf, pos)) { + while (parse->key_lookup(conf, "colvar", &colvar_conf, &pos)) { if (colvar_conf.size()) { cvm::log(cvm::line_marker); @@ -350,7 +352,7 @@ int colvarmodule::parse_biases_type(std::string const &conf, { std::string bias_conf = ""; size_t conf_saved_pos = 0; - while (parse->key_lookup(conf, keyword, bias_conf, conf_saved_pos)) { + while (parse->key_lookup(conf, keyword, &bias_conf, &conf_saved_pos)) { if (bias_conf.size()) { cvm::log(cvm::line_marker); cvm::increase_depth(); @@ -409,12 +411,6 @@ int colvarmodule::parse_biases(std::string const &conf) size_t i; - for (i = 0; i < biases.size(); i++) { - biases[i]->enable(colvardeps::f_cvb_active); - if (cvm::debug()) - biases[i]->print_state(); - } - size_t n_hist_dep_biases = 0; std::vector hist_dep_biases_names; for (i = 0; i < biases.size(); i++) { @@ -487,7 +483,8 @@ int colvarmodule::catch_input_errors(int result) } -colvarbias * colvarmodule::bias_by_name(std::string const &name) { +colvarbias * colvarmodule::bias_by_name(std::string const &name) +{ colvarmodule *cv = cvm::main(); for (std::vector::iterator bi = cv->biases.begin(); bi != cv->biases.end(); @@ -500,7 +497,8 @@ colvarbias * colvarmodule::bias_by_name(std::string const &name) { } -colvar *colvarmodule::colvar_by_name(std::string const &name) { +colvar *colvarmodule::colvar_by_name(std::string const &name) +{ colvarmodule *cv = cvm::main(); for (std::vector::iterator cvi = cv->colvars.begin(); cvi != cv->colvars.end(); @@ -513,6 +511,20 @@ colvar *colvarmodule::colvar_by_name(std::string const &name) { } +cvm::atom_group *colvarmodule::atom_group_by_name(std::string const &name) +{ + colvarmodule *cv = cvm::main(); + for (std::vector::iterator agi = cv->named_atom_groups.begin(); + agi != cv->named_atom_groups.end(); + agi++) { + if ((*agi)->name == name) { + return (*agi); + } + } + return NULL; +} + + int colvarmodule::change_configuration(std::string const &bias_name, std::string const &conf) { @@ -521,7 +533,10 @@ int colvarmodule::change_configuration(std::string const &bias_name, cvm::increase_depth(); colvarbias *b; b = bias_by_name(bias_name); - if (b == NULL) { cvm::error("Error: bias not found: " + bias_name); } + if (b == NULL) { + cvm::error("Error: bias not found: " + bias_name); + return COLVARS_ERROR; + } b->change_configuration(conf); cvm::decrease_depth(); return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -534,7 +549,10 @@ std::string colvarmodule::read_colvar(std::string const &name) colvar *c; std::stringstream ss; c = colvar_by_name(name); - if (c == NULL) { cvm::fatal_error("Error: colvar not found: " + name); } + if (c == NULL) { + cvm::error("Error: colvar not found: " + name); + return std::string(); + } ss << c->value(); cvm::decrease_depth(); return ss.str(); @@ -547,7 +565,10 @@ cvm::real colvarmodule::energy_difference(std::string const &bias_name, colvarbias *b; cvm::real energy_diff = 0.; b = bias_by_name(bias_name); - if (b == NULL) { cvm::fatal_error("Error: bias not found: " + bias_name); } + if (b == NULL) { + cvm::error("Error: bias not found: " + bias_name); + return 0.; + } energy_diff = b->energy_difference(conf); cvm::decrease_depth(); return energy_diff; @@ -666,18 +687,36 @@ int colvarmodule::calc_colvars() cvm::log("Calculating collective variables.\n"); // calculate collective variables and their gradients + // First, we need to decide which biases are awake + // so they can activate colvars as needed + std::vector::iterator bi; + for (bi = biases.begin(); bi != biases.end(); bi++) { + int tsf = (*bi)->get_time_step_factor(); + if (tsf > 0 && (step_absolute() % tsf == 0)) { + (*bi)->enable(colvardeps::f_cvb_awake); + } else { + (*bi)->disable(colvardeps::f_cvb_awake); + } + } + int error_code = COLVARS_OK; std::vector::iterator cvi; // Determine which colvars are active at this iteration - variables_active()->resize(0); + variables_active()->clear(); variables_active()->reserve(variables()->size()); for (cvi = variables()->begin(); cvi != variables()->end(); cvi++) { - // This is a dynamic feature - the next call should be to enable() - // or disable() when dynamic dependency resolution is fully implemented - (*cvi)->set_enabled(colvardeps::f_cv_active, - step_absolute() % (*cvi)->get_time_step_factor() == 0); - variables_active()->push_back(*cvi); + // Wake up or put to sleep variables + int tsf = (*cvi)->get_time_step_factor(); + if (tsf > 0 && (step_absolute() % tsf == 0)) { + (*cvi)->enable(colvardeps::f_cv_awake); + } else { + (*cvi)->disable(colvardeps::f_cv_awake); + } + + if ((*cvi)->is_enabled()) { + variables_active()->push_back(*cvi); + } } // if SMP support is available, split up the work @@ -685,8 +724,8 @@ int colvarmodule::calc_colvars() // first, calculate how much work (currently, how many active CVCs) each colvar has - variables_active_smp()->resize(0); - variables_active_smp_items()->resize(0); + variables_active_smp()->clear(); + variables_active_smp_items()->clear(); variables_active_smp()->reserve(variables_active()->size()); variables_active_smp_items()->reserve(variables_active()->size()); @@ -748,7 +787,8 @@ int colvarmodule::calc_biases() total_bias_energy = 0.0; // update the list of active biases - biases_active()->resize(0); + // which may have changed based on f_cvb_awake in calc_colvars() + biases_active()->clear(); biases_active()->reserve(biases.size()); for (bi = biases.begin(); bi != biases.end(); bi++) { if ((*bi)->is_enabled()) { @@ -828,8 +868,7 @@ int colvarmodule::update_colvar_forces() "of colvars (if they have any).\n"); cvm::increase_depth(); for (cvi = variables()->begin(); cvi != variables()->end(); cvi++) { - // Here we call even inactive colvars, so they accumulate biasing forces - // as well as update their extended-system dynamics + // Inactive colvars will only reset their forces and return 0 energy total_colvar_energy += (*cvi)->update_forces_energy(); if (cvm::get_error()) { return COLVARS_ERROR; @@ -883,11 +922,13 @@ int colvarmodule::write_restart_files() ((cvm::step_absolute() % restart_out_freq) == 0) ) { cvm::log("Writing the state file \""+ restart_out_name+"\".\n"); - proxy->backup_file(restart_out_name.c_str()); - restart_out_os.open(restart_out_name.c_str()); - if (!restart_out_os.is_open() || !write_restart(restart_out_os)) - cvm::error("Error: in writing restart file.\n"); - restart_out_os.close(); + proxy->backup_file(restart_out_name); + std::ostream *restart_out_os = proxy->output_stream(restart_out_name); + if (!restart_out_os) return cvm::get_error(); + if (!write_restart(*restart_out_os)) { + return cvm::error("Error: in writing restart file.\n", FILE_ERROR); + } + proxy->close_output_stream(restart_out_name); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -896,26 +937,26 @@ int colvarmodule::write_restart_files() int colvarmodule::write_traj_files() { - if (!cv_traj_os.is_open()) { + if (cv_traj_os == NULL) { open_traj_file(cv_traj_name); } // write labels in the traj file every 1000 lines and at first timestep if ((cvm::step_absolute() % (cv_traj_freq * 1000)) == 0 || cvm::step_relative() == 0) { - write_traj_label(cv_traj_os); + write_traj_label(*cv_traj_os); } if ((cvm::step_absolute() % cv_traj_freq) == 0) { - write_traj(cv_traj_os); + write_traj(*cv_traj_os); } - if (restart_out_freq && cv_traj_os.is_open()) { + if (restart_out_freq && (cv_traj_os != NULL)) { // flush the trajectory file if we are at the restart frequency if ( (cvm::step_relative() > 0) && ((cvm::step_absolute() % restart_out_freq) == 0) ) { cvm::log("Synchronizing (emptying the buffer of) trajectory file \""+ cv_traj_name+"\".\n"); - cv_traj_os.flush(); + proxy->flush_output_stream(cv_traj_os); } } @@ -1003,9 +1044,11 @@ int colvarmodule::reset() index_groups.clear(); index_group_names.clear(); - if (cv_traj_os.is_open()) { + proxy->reset(); + + if (cv_traj_os != NULL) { // Do not close file here, as we might not be done with it yet. - cv_traj_os.flush(); + proxy->flush_output_stream(cv_traj_os); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -1264,9 +1307,9 @@ int colvarmodule::write_output_files() } cvm::decrease_depth(); - if (cv_traj_os.is_open()) { - // do not close to avoid problems with multiple NAMD runs - cv_traj_os.flush(); + if (cv_traj_os != NULL) { + // do not close, there may be another run command + proxy->flush_output_stream(cv_traj_os); } return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); @@ -1380,9 +1423,10 @@ std::ostream & colvarmodule::write_restart(std::ostream &os) return os; } + int colvarmodule::open_traj_file(std::string const &file_name) { - if (cv_traj_os.is_open()) { + if (cv_traj_os != NULL) { return COLVARS_OK; } @@ -1390,36 +1434,35 @@ int colvarmodule::open_traj_file(std::string const &file_name) if (cv_traj_append) { cvm::log("Appending to colvar trajectory file \""+file_name+ "\".\n"); - cv_traj_os.open(file_name.c_str(), std::ios::app); + cv_traj_os = (cvm::proxy)->output_stream(file_name, std::ios::app); } else { cvm::log("Writing to colvar trajectory file \""+file_name+ "\".\n"); proxy->backup_file(file_name.c_str()); - cv_traj_os.open(file_name.c_str()); + cv_traj_os = (cvm::proxy)->output_stream(file_name); } - if (!cv_traj_os.is_open()) { + if (cv_traj_os == NULL) { cvm::error("Error: cannot write to file \""+file_name+"\".\n", FILE_ERROR); } - return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); + return cvm::get_error(); } + int colvarmodule::close_traj_file() { - if (cv_traj_os.is_open()) { - cv_traj_os.close(); + if (cv_traj_os != NULL) { + proxy->close_output_stream(cv_traj_name); + cv_traj_os = NULL; } - return (cvm::get_error() ? COLVARS_ERROR : COLVARS_OK); + return cvm::get_error(); } + std::ostream & colvarmodule::write_traj_label(std::ostream &os) { - if (!os.good()) { - cvm::error("Cannot write to trajectory file."); - return os; - } os.setf(std::ios::scientific, std::ios::floatfield); os << "# " << cvm::wrap_string("step", cvm::it_width-2) @@ -1437,13 +1480,16 @@ std::ostream & colvarmodule::write_traj_label(std::ostream &os) (*bi)->write_traj_label(os); } os << "\n"; + if (cvm::debug()) { - os.flush(); + proxy->flush_output_stream(&os); } + cvm::decrease_depth(); return os; } + std::ostream & colvarmodule::write_traj(std::ostream &os) { os.setf(std::ios::scientific, std::ios::floatfield); @@ -1463,9 +1509,11 @@ std::ostream & colvarmodule::write_traj(std::ostream &os) (*bi)->write_traj(os); } os << "\n"; + if (cvm::debug()) { - os.flush(); + proxy->flush_output_stream(&os); } + cvm::decrease_depth(); return os; } @@ -1540,25 +1588,19 @@ void colvarmodule::clear_error() } -void cvm::error(std::string const &message, int code) +int colvarmodule::error(std::string const &message, int code) { set_error_bits(code); proxy->error(message); + return get_error(); } -void cvm::fatal_error(std::string const &message) +int colvarmodule::fatal_error(std::string const &message) { - // TODO once all non-fatal errors have been set to be handled by error(), - // set DELETE_COLVARS here for VMD to handle it set_error_bits(FATAL_ERROR); proxy->fatal_error(message); -} - - -void cvm::exit(std::string const &message) -{ - proxy->exit(message); + return get_error(); } diff --git a/lib/colvars/colvarmodule.h b/lib/colvars/colvarmodule.h index b4f80e0b5e..0f6efd14c4 100644 --- a/lib/colvars/colvarmodule.h +++ b/lib/colvars/colvarmodule.h @@ -10,9 +10,7 @@ #ifndef COLVARMODULE_H #define COLVARMODULE_H -#ifndef COLVARS_VERSION -#define COLVARS_VERSION "2017-03-09" -#endif +#include "colvars_version.h" #ifndef COLVARS_DEBUG #define COLVARS_DEBUG false @@ -54,11 +52,6 @@ You can browse the class hierarchy or the list of source files. #include #include -#ifdef NAMD_VERSION -// use Lustre-friendly wrapper to POSIX write() -#include "fstream_namd.h" -#endif - class colvarparse; class colvar; class colvarbias; @@ -188,7 +181,13 @@ private: /// Indexes of the items to calculate for each colvar std::vector colvars_smp_items; + /// Array of named atom groups + std::vector named_atom_groups; public: + /// Register a named atom group into named_atom_groups + inline void register_named_atom_group(atom_group * ag) { + named_atom_groups.push_back(ag); + } /// Array of collective variables std::vector *variables(); @@ -319,12 +318,6 @@ public: /// (Re)initialize the output trajectory and state file (does not write it yet) int setup_output(); -#ifdef NAMD_VERSION - typedef ofstream_namd ofstream; -#else - typedef std::ofstream ofstream; -#endif - /// Read the input restart file std::istream & read_restart(std::istream &is); /// Write the output restart file @@ -332,7 +325,7 @@ public: /// Open a trajectory file if requested (and leave it open) int open_traj_file(std::string const &file_name); - /// Close it + /// Close it (note: currently unused) int close_traj_file(); /// Write in the trajectory file std::ostream & write_traj(std::ostream &os); @@ -354,6 +347,9 @@ public: /// Look up a colvar by name; returns NULL if not found static colvar * colvar_by_name(std::string const &name); + /// Look up a named atom group by name; returns NULL if not found + static atom_group * atom_group_by_name(std::string const &name); + /// Load new configuration for the given bias - /// currently works for harmonic (force constant and/or centers) int change_configuration(std::string const &bias_name, std::string const &conf); @@ -452,10 +448,10 @@ public: static void log(std::string const &message); /// Print a message to the main log and exit with error code - static void fatal_error(std::string const &message); + static int fatal_error(std::string const &message); /// Print a message to the main log and set global error code - static void error(std::string const &message, int code = COLVARS_ERROR); + static int error(std::string const &message, int code = COLVARS_ERROR); /// Print a message to the main log and exit normally static void exit(std::string const &message); @@ -471,8 +467,7 @@ public: /// \brief Get the distance between two atomic positions with pbcs handled /// correctly static rvector position_distance(atom_pos const &pos1, - atom_pos const &pos2); - + atom_pos const &pos2); /// \brief Get the square distance between two positions (with /// periodic boundary conditions handled transparently) @@ -481,21 +476,7 @@ public: /// an analytical square distance (while taking the square of /// position_distance() would produce leads to a cusp) static real position_dist2(atom_pos const &pos1, - atom_pos const &pos2); - - /// \brief Get the closest periodic image to a reference position - /// \param pos The position to look for the closest periodic image - /// \param ref_pos (optional) The reference position - static void select_closest_image(atom_pos &pos, - atom_pos const &ref_pos); - - /// \brief Perform select_closest_image() on a set of atomic positions - /// - /// After that, distance vectors can then be calculated directly, - /// without using position_distance() - static void select_closest_images(std::vector &pos, - atom_pos const &ref_pos); - + atom_pos const &pos2); /// \brief Names of groups from a Gromacs .ndx file to be read at startup std::list index_group_names; @@ -556,14 +537,11 @@ protected: std::string cv_traj_name; /// Collective variables output trajectory file - colvarmodule::ofstream cv_traj_os; + std::ostream *cv_traj_os; /// Appending to the existing trajectory file? bool cv_traj_append; - /// Output restart file - colvarmodule::ofstream restart_out_os; - private: /// Counter for the current depth in the object hierarchy (useg e.g. in output) @@ -704,18 +682,6 @@ inline void cvm::request_total_force() proxy->request_total_force(true); } -inline void cvm::select_closest_image(atom_pos &pos, - atom_pos const &ref_pos) -{ - proxy->select_closest_image(pos, ref_pos); -} - -inline void cvm::select_closest_images(std::vector &pos, - atom_pos const &ref_pos) -{ - proxy->select_closest_images(pos, ref_pos); -} - inline cvm::rvector cvm::position_distance(atom_pos const &pos1, atom_pos const &pos2) { diff --git a/lib/colvars/colvarparse.cpp b/lib/colvars/colvarparse.cpp index 8055d925db..9f333b7b76 100644 --- a/lib/colvars/colvarparse.cpp +++ b/lib/colvars/colvarparse.cpp @@ -17,10 +17,7 @@ // space & tab -std::string const colvarparse::white_space = " \t"; - -std::string colvarparse::dummy_string = ""; -size_t colvarparse::dummy_pos = 0; +char const * const colvarparse::white_space = " \t"; // definition of single-value keyword parsers @@ -37,7 +34,7 @@ template bool colvarparse::_get_keyval_scalar_(std::string const do { std::string data_this = ""; - b_found = key_lookup(conf, key, data_this, save_pos); + b_found = key_lookup(conf, key, &data_this, &save_pos); if (b_found) { if (!b_found_any) b_found_any = true; @@ -92,7 +89,7 @@ bool colvarparse::_get_keyval_scalar_string_(std::string const &conf, do { std::string data_this = ""; - b_found = key_lookup(conf, key, data_this, save_pos); + b_found = key_lookup(conf, key, &data_this, &save_pos); if (b_found) { if (!b_found_any) b_found_any = true; @@ -156,7 +153,7 @@ template bool colvarparse::_get_keyval_vector_(std::string const do { std::string data_this = ""; - b_found = key_lookup(conf, key, data_this, save_pos); + b_found = key_lookup(conf, key, &data_this, &save_pos); if (b_found) { if (!b_found_any) b_found_any = true; @@ -313,7 +310,7 @@ bool colvarparse::get_keyval(std::string const &conf, do { std::string data_this = ""; - b_found = key_lookup(conf, key, data_this, save_pos); + b_found = key_lookup(conf, key, &data_this, &save_pos); if (b_found) { if (!b_found_any) b_found_any = true; @@ -552,8 +549,8 @@ std::istream & colvarparse::getline_nocomments(std::istream &is, bool colvarparse::key_lookup(std::string const &conf, char const *key_in, - std::string &data, - size_t &save_pos) + std::string *data, + size_t *save_pos) { if (cvm::debug()) { cvm::log("Looking for the keyword \""+std::string(key_in)+"\" and its value.\n"); @@ -570,14 +567,12 @@ bool colvarparse::key_lookup(std::string const &conf, std::string const conf_lower(to_lower_cppstr(conf)); // by default, there is no value, unless we found one - data = ""; - - // when the function is invoked without save_pos, ensure that we - // start from zero - colvarparse::dummy_pos = 0; + if (data != NULL) { + data->clear(); + } // start from the first occurrence of key - size_t pos = conf_lower.find(key, save_pos); + size_t pos = conf_lower.find(key, (save_pos != NULL) ? *save_pos : 0); // iterate over all instances of the substring until it finds it as isolated keyword while (true) { @@ -593,7 +588,7 @@ bool colvarparse::key_lookup(std::string const &conf, bool b_isolated_left = true, b_isolated_right = true; if (pos > 0) { - if ( std::string("\n"+white_space+ + if ( std::string("\n"+std::string(white_space)+ "}").find(conf[pos-1]) == std::string::npos ) { // none of the valid delimiting characters is on the left of key @@ -602,7 +597,7 @@ bool colvarparse::key_lookup(std::string const &conf, } if (pos < conf.size()-key.size()-1) { - if ( std::string("\n"+white_space+ + if ( std::string("\n"+std::string(white_space)+ "{").find(conf[pos+key.size()]) == std::string::npos ) { // none of the valid delimiting characters is on the right of key @@ -625,9 +620,11 @@ bool colvarparse::key_lookup(std::string const &conf, } } + if (save_pos != NULL) { // save the pointer for a future call (when iterating over multiple // valid instances of the same keyword) - save_pos = pos + key.size(); + *save_pos = pos + key.size(); + } // get the remainder of the line size_t pl = conf.rfind("\n", pos); @@ -716,19 +713,21 @@ bool colvarparse::key_lookup(std::string const &conf, data_end) + 1; } - data.append(line, data_begin, (data_end-data_begin)); + if (data != NULL) { + data->append(line, data_begin, (data_end-data_begin)); - if (cvm::debug()) { - cvm::log("Keyword value = \""+data+"\".\n"); - } + if (cvm::debug()) { + cvm::log("Keyword value = \""+*data+"\".\n"); + } - if (data.size() && save_delimiters) { - data_begin_pos.push_back(conf.find(data, pos+key.size())); - data_end_pos.push_back(data_begin_pos.back()+data.size()); + if (data->size()) { + data_begin_pos.push_back(conf.find(*data, pos+key.size())); + data_end_pos.push_back(data_begin_pos.back()+data->size()); + } } } - save_pos = line_end; + if (save_pos != NULL) *save_pos = line_end; return true; } diff --git a/lib/colvars/colvarparse.h b/lib/colvars/colvarparse.h index 9f116caafd..9389bc49da 100644 --- a/lib/colvars/colvarparse.h +++ b/lib/colvars/colvarparse.h @@ -24,7 +24,7 @@ /// need to parse input inherit from this class colvarparse { -protected: +private: /// \brief List of legal keywords for this object: this is updated /// by each call to colvarparse::get_keyval() or @@ -41,14 +41,6 @@ protected: /// values before the keyword check is performed std::list data_end_pos; - /// \brief Whether or not to accumulate data_begin_pos and - /// data_end_pos in key_lookup(); it may be useful to disable - /// this after the constructor is called, because other files may be - /// read (e.g. restart) that would mess up the registry; in any - /// case, nothing serious happens until check_keywords() is invoked - /// (which should happen only right after construction) - bool save_delimiters; - /// \brief Add a new valid keyword to the list void add_keyword(char const *key); @@ -62,14 +54,12 @@ public: inline colvarparse() - : save_delimiters(true) { init(); } /// Constructor that stores the object's config string inline colvarparse(const std::string& conf) - : save_delimiters(true) { init(conf); } @@ -115,8 +105,6 @@ public: /// \brief Use this after parsing a config string (note that check_keywords() calls it already) void clear_keyword_registry(); -public: - /// \fn get_keyval bool const get_keyval (std::string const &conf, /// char const *key, _type_ &value, _type_ const &def_value, /// Parse_Mode const parse_mode) \brief Helper function to parse @@ -282,7 +270,7 @@ public: /// Accepted white space delimiters, used in key_lookup() - static std::string const white_space; + static const char * const white_space; /// \brief Low-level function for parsing configuration strings; /// automatically adds the requested keyword to the list of valid @@ -293,13 +281,8 @@ public: /// within "conf", useful when doing multiple calls bool key_lookup(std::string const &conf, char const *key, - std::string &data = dummy_string, - size_t &save_pos = dummy_pos); - - /// Used as a default argument by key_lookup - static std::string dummy_string; - /// Used as a default argument by key_lookup - static size_t dummy_pos; + std::string *data = NULL, + size_t *save_pos = NULL); /// \brief Works as std::getline() but also removes everything /// between a comment character and the following newline diff --git a/lib/colvars/colvarproxy.cpp b/lib/colvars/colvarproxy.cpp new file mode 100644 index 0000000000..fa24091d52 --- /dev/null +++ b/lib/colvars/colvarproxy.cpp @@ -0,0 +1,492 @@ +// -*- c++ -*- + +// This file is part of the Collective Variables module (Colvars). +// The original version of Colvars and its updates are located at: +// https://github.com/colvars/colvars +// Please update all Colvars source files before making any changes. +// If you wish to distribute your changes, please submit them to the +// Colvars repository at GitHub. + +#include +#include + +#include "colvarmodule.h" +#include "colvarproxy.h" +#include "colvarscript.h" +#include "colvaratoms.h" + + + +colvarproxy_system::colvarproxy_system() {} + + +colvarproxy_system::~colvarproxy_system() {} + + +void colvarproxy_system::add_energy(cvm::real energy) {} + + +void colvarproxy_system::request_total_force(bool yesno) +{ + if (yesno == true) + cvm::error("Error: total forces are currently not implemented.\n", + COLVARS_NOT_IMPLEMENTED); +} + + +bool colvarproxy_system::total_forces_enabled() const +{ + return false; +} + + +cvm::real colvarproxy_system::position_dist2(cvm::atom_pos const &pos1, + cvm::atom_pos const &pos2) +{ + return (position_distance(pos1, pos2)).norm2(); +} + + + +colvarproxy_atoms::colvarproxy_atoms() {} + + +colvarproxy_atoms::~colvarproxy_atoms() +{ + reset(); +} + + +int colvarproxy_atoms::reset() +{ + atoms_ids.clear(); + atoms_ncopies.clear(); + atoms_masses.clear(); + atoms_charges.clear(); + atoms_positions.clear(); + atoms_total_forces.clear(); + atoms_new_colvar_forces.clear(); + return COLVARS_OK; +} + + +int colvarproxy_atoms::add_atom_slot(int atom_id) +{ + atoms_ids.push_back(atom_id); + atoms_ncopies.push_back(1); + atoms_masses.push_back(1.0); + atoms_charges.push_back(0.0); + atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0)); + atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); + atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); + return (atoms_ids.size() - 1); +} + + +int colvarproxy_atoms::init_atom(cvm::residue_id const &residue, + std::string const &atom_name, + std::string const &segment_id) +{ + cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n", + COLVARS_NOT_IMPLEMENTED); + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_atoms::check_atom_id(cvm::residue_id const &residue, + std::string const &atom_name, + std::string const &segment_id) +{ + colvarproxy_atoms::init_atom(residue, atom_name, segment_id); + return COLVARS_NOT_IMPLEMENTED; +} + + +void colvarproxy_atoms::clear_atom(int index) +{ + if (((size_t) index) >= atoms_ids.size()) { + cvm::error("Error: trying to disable an atom that was not previously requested.\n", + INPUT_ERROR); + } + if (atoms_ncopies[index] > 0) { + atoms_ncopies[index] -= 1; + } +} + + +int colvarproxy_atoms::load_atoms(char const *filename, + cvm::atom_group &atoms, + std::string const &pdb_field, + double const) +{ + return cvm::error("Error: loading atom identifiers from a file " + "is currently not implemented.\n", + COLVARS_NOT_IMPLEMENTED); +} + + +int colvarproxy_atoms::load_coords(char const *filename, + std::vector &pos, + const std::vector &indices, + std::string const &pdb_field, + double const) +{ + return cvm::error("Error: loading atomic coordinates from a file " + "is currently not implemented.\n", + COLVARS_NOT_IMPLEMENTED); +} + + + +colvarproxy_atom_groups::colvarproxy_atom_groups() {} + + +colvarproxy_atom_groups::~colvarproxy_atom_groups() +{ + reset(); +} + + +int colvarproxy_atom_groups::reset() +{ + atom_groups_ids.clear(); + atom_groups_ncopies.clear(); + atom_groups_masses.clear(); + atom_groups_charges.clear(); + atom_groups_coms.clear(); + atom_groups_total_forces.clear(); + atom_groups_new_colvar_forces.clear(); + return COLVARS_OK; +} + + +int colvarproxy_atom_groups::add_atom_group_slot(int atom_group_id) +{ + atom_groups_ids.push_back(atom_group_id); + atom_groups_ncopies.push_back(1); + atom_groups_masses.push_back(1.0); + atom_groups_charges.push_back(0.0); + atom_groups_coms.push_back(cvm::rvector(0.0, 0.0, 0.0)); + atom_groups_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); + atom_groups_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); + return (atom_groups_ids.size() - 1); +} + + +int colvarproxy_atom_groups::scalable_group_coms() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_atom_groups::init_atom_group(std::vector const &atoms_ids) +{ + cvm::error("Error: initializing a group outside of the Colvars module " + "is currently not supported.\n", + COLVARS_NOT_IMPLEMENTED); + return COLVARS_NOT_IMPLEMENTED; +} + + +void colvarproxy_atom_groups::clear_atom_group(int index) +{ + if (((size_t) index) >= atom_groups_ids.size()) { + cvm::error("Error: trying to disable an atom group " + "that was not previously requested.\n", + INPUT_ERROR); + } + if (atom_groups_ncopies[index] > 0) { + atom_groups_ncopies[index] -= 1; + } +} + + + +colvarproxy_smp::colvarproxy_smp() +{ + b_smp_active = true; +} + + +colvarproxy_smp::~colvarproxy_smp() {} + + +int colvarproxy_smp::smp_enabled() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_colvars_loop() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_biases_loop() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_biases_script_loop() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_thread_id() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_num_threads() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_smp::smp_lock() +{ + return COLVARS_OK; +} + + +int colvarproxy_smp::smp_trylock() +{ + return COLVARS_OK; +} + + +int colvarproxy_smp::smp_unlock() +{ + return COLVARS_OK; +} + + + + +colvarproxy_replicas::colvarproxy_replicas() {} + + +colvarproxy_replicas::~colvarproxy_replicas() {} + + +bool colvarproxy_replicas::replica_enabled() +{ + return false; +} + + +int colvarproxy_replicas::replica_index() +{ + return 0; +} + + +int colvarproxy_replicas::replica_num() +{ + return 1; +} + + +void colvarproxy_replicas::replica_comm_barrier() {} + + +int colvarproxy_replicas::replica_comm_recv(char* msg_data, + int buf_len, + int src_rep) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_replicas::replica_comm_send(char* msg_data, + int msg_len, + int dest_rep) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + + + +colvarproxy_script::colvarproxy_script() +{ + script = NULL; +} + + +colvarproxy_script::~colvarproxy_script() {} + + +char *colvarproxy_script::script_obj_to_str(unsigned char *obj) +{ + return reinterpret_cast(obj); +} + + +int colvarproxy_script::run_force_callback() +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_script::run_colvar_callback( + std::string const &name, + std::vector const &cvcs, + colvarvalue &value) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_script::run_colvar_gradient_callback( + std::string const &name, + std::vector const &cvcs, + std::vector > &gradient) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + + + +colvarproxy_io::colvarproxy_io() {} + + +colvarproxy_io::~colvarproxy_io() {} + + +int colvarproxy_io::get_frame(long int&) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +int colvarproxy_io::set_frame(long int) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + +std::ostream * colvarproxy_io::output_stream(std::string const &output_name, + std::ios_base::openmode mode) +{ + if (cvm::debug()) { + cvm::log("Using colvarproxy::output_stream()\n"); + } + std::list::iterator osi = output_files.begin(); + std::list::iterator osni = output_stream_names.begin(); + for ( ; osi != output_files.end(); osi++, osni++) { + if (*osni == output_name) { + return *osi; + } + } + if (!(mode & (std::ios_base::app | std::ios_base::ate))) { + backup_file(output_name); + } + std::ofstream *os = new std::ofstream(output_name.c_str(), mode); + if (!os->is_open()) { + cvm::error("Error: cannot write to file/channel \""+output_name+"\".\n", + FILE_ERROR); + return NULL; + } + output_stream_names.push_back(output_name); + output_files.push_back(os); + return os; +} + + +int colvarproxy_io::flush_output_stream(std::ostream *os) +{ + std::list::iterator osi = output_files.begin(); + std::list::iterator osni = output_stream_names.begin(); + for ( ; osi != output_files.end(); osi++, osni++) { + if (*osi == os) { + ((std::ofstream *) (*osi))->flush(); + return COLVARS_OK; + } + } + return cvm::error("Error: trying to flush an output file/channel " + "that wasn't open.\n", BUG_ERROR); +} + + +int colvarproxy_io::close_output_stream(std::string const &output_name) +{ + std::list::iterator osi = output_files.begin(); + std::list::iterator osni = output_stream_names.begin(); + for ( ; osi != output_files.end(); osi++, osni++) { + if (*osni == output_name) { + ((std::ofstream *) (*osi))->close(); + output_files.erase(osi); + output_stream_names.erase(osni); + return COLVARS_OK; + } + } + return cvm::error("Error: trying to close an output file/channel " + "that wasn't open.\n", BUG_ERROR); +} + + +int colvarproxy_io::backup_file(char const *filename) +{ + return COLVARS_NOT_IMPLEMENTED; +} + + + +colvarproxy::colvarproxy() +{ + colvars = NULL; + b_simulation_running = true; +} + + +colvarproxy::~colvarproxy() {} + + +int colvarproxy::reset() +{ + int error_code = COLVARS_OK; + error_code |= colvarproxy_atoms::reset(); + error_code |= colvarproxy_atom_groups::reset(); + return error_code; +} + + +int colvarproxy::setup() +{ + return COLVARS_OK; +} + + +int colvarproxy::update_input() +{ + return COLVARS_OK; +} + + +int colvarproxy::update_output() +{ + return COLVARS_OK; +} + + +size_t colvarproxy::restart_frequency() +{ + return 0; +} + + + + + + + + + + + diff --git a/lib/colvars/colvarproxy.h b/lib/colvars/colvarproxy.h index 5b216c9d41..95d13cd7e0 100644 --- a/lib/colvars/colvarproxy.h +++ b/lib/colvars/colvarproxy.h @@ -16,55 +16,36 @@ #include "colvarmodule.h" #include "colvarvalue.h" + +/// \file colvarproxy.h +/// \brief Colvars proxy classes +/// +/// This file declares the class for the object responsible for interfacing +/// Colvars with other codes (MD engines, VMD, Python). The \link colvarproxy +/// \endlink class is a derivative of multiple classes, each devoted to a +/// specific task (e.g. \link colvarproxy_atoms \endlink to access data for +/// individual atoms). +/// +/// To interface to a new MD engine, the simplest solution is to derive a new +/// class from \link colvarproxy \endlink. Currently implemented are: \link +/// colvarproxy_lammps, \endlink, \link colvarproxy_namd, \endlink, \link +/// colvarproxy_vmd, \endlink. + + // forward declarations class colvarscript; -/// \brief Interface between the collective variables module and -/// the simulation or analysis program (NAMD, VMD, LAMMPS...). -/// This is the base class: each interfaced program is supported by a derived class. -/// Only pure virtual functions ("= 0") must be reimplemented to ensure baseline functionality. -class colvarproxy { +/// Methods for accessing the simulation system (PBCs, integrator, etc) +class colvarproxy_system { public: - /// Pointer to the main object - colvarmodule *colvars; - /// Constructor - colvarproxy() - { - colvars = NULL; - b_simulation_running = true; - b_smp_active = true; - script = NULL; - } + colvarproxy_system(); /// Destructor - virtual ~colvarproxy() - {} - - /// (Re)initialize required member data after construction - virtual int setup() - { - return COLVARS_OK; - } - - /// \brief Update data required by the colvars module (e.g. cache atom positions) - /// - /// TODO Break up colvarproxy_namd and colvarproxy_lammps function into these - virtual int update_input() - { - return COLVARS_OK; - } - - /// \brief Update data based from the results of a module update (e.g. send forces) - virtual int update_output() - { - return COLVARS_OK; - } - - // **************** SIMULATION PARAMETERS **************** + virtual ~colvarproxy_system(); /// \brief Value of the unit for atomic coordinates with respect to /// angstroms (used by some variables for hard-coded default values) @@ -73,7 +54,7 @@ public: /// \brief Boltzmann constant virtual cvm::real boltzmann() = 0; - /// \brief Temperature of the simulation (K) + /// \brief Target temperature of the simulation (K units) virtual cvm::real temperature() = 0; /// \brief Time step of the simulation (fs) @@ -82,263 +63,9 @@ public: /// \brief Pseudo-random number with Gaussian distribution virtual cvm::real rand_gaussian(void) = 0; - /// \brief Get the current frame number - // Returns error code - virtual int get_frame(long int&) { return COLVARS_NOT_IMPLEMENTED; } - - /// \brief Set the current frame number (as well as colvarmodule::it) - // Returns error code - virtual int set_frame(long int) { return COLVARS_NOT_IMPLEMENTED; } - - /// \brief Prefix to be used for input files (restarts, not - /// configuration) - std::string input_prefix_str, output_prefix_str, restart_output_prefix_str; - - inline std::string & input_prefix() - { - return input_prefix_str; - } - - /// \brief Prefix to be used for output restart files - inline std::string restart_output_prefix() - { - return restart_output_prefix_str; - } - - /// \brief Prefix to be used for output files (final system - /// configuration) - inline std::string output_prefix() - { - return output_prefix_str; - } - - /// \brief Restarts will be written each time this number of steps has passed - virtual size_t restart_frequency() - { - return 0; - } - -protected: - - /// Whether a simulation is running (and try to prevent irrecovarable errors) - bool b_simulation_running; - -public: - - /// Whether a simulation is running (and try to prevent irrecovarable errors) - virtual bool simulation_running() const - { - return b_simulation_running; - } - -protected: - - /// \brief Currently opened output files: by default, these are ofstream objects. - /// Allows redefinition to implement different output mechanisms - std::list output_files; - /// \brief Identifiers for output_stream objects: by default, these are the names of the files - std::list output_stream_names; - -public: - - // ***************** SHARED-MEMORY PARALLELIZATION ***************** - - /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature) - virtual int smp_enabled() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Whether threaded parallelization should be used (TODO: make this a cvm::deps feature) - bool b_smp_active; - - /// Distribute calculation of colvars (and their components) across threads - virtual int smp_colvars_loop() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Distribute calculation of biases across threads - virtual int smp_biases_loop() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Distribute calculation of biases across threads 2nd through last, with all scripted biased on 1st thread - virtual int smp_biases_script_loop() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Index of this thread - virtual int smp_thread_id() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Number of threads sharing this address space - virtual int smp_num_threads() - { - return COLVARS_NOT_IMPLEMENTED; - } - - /// Lock the proxy's shared data for access by a thread, if threads are implemented; if not implemented, does nothing - virtual int smp_lock() - { - return COLVARS_OK; - } - - /// Attempt to lock the proxy's shared data - virtual int smp_trylock() - { - return COLVARS_OK; - } - - /// Release the lock - virtual int smp_unlock() - { - return COLVARS_OK; - } - - // **************** MULTIPLE REPLICAS COMMUNICATION **************** - - // Replica exchange commands: - - /// \brief Indicate if multi-replica support is available and active - virtual bool replica_enabled() { return false; } - - /// \brief Index of this replica - virtual int replica_index() { return 0; } - - /// \brief Total number of replica - virtual int replica_num() { return 1; } - - /// \brief Synchronize replica - virtual void replica_comm_barrier() {} - - /// \brief Receive data from other replica - virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep) { - return COLVARS_NOT_IMPLEMENTED; - } - - /// \brief Send data to other replica - virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep) { - return COLVARS_NOT_IMPLEMENTED; - } - - - // **************** SCRIPTING INTERFACE **************** - - /// Pointer to the scripting interface object - /// (does not need to be allocated in a new interface) - colvarscript *script; - - /// is a user force script defined? - bool force_script_defined; - - /// Do we have a scripting interface? - bool have_scripts; - - /// Run a user-defined colvar forces script - virtual int run_force_callback() { return COLVARS_NOT_IMPLEMENTED; } - - virtual int run_colvar_callback(std::string const &name, - std::vector const &cvcs, - colvarvalue &value) - { return COLVARS_NOT_IMPLEMENTED; } - - virtual int run_colvar_gradient_callback(std::string const &name, - std::vector const &cvcs, - std::vector > &gradient) - { return COLVARS_NOT_IMPLEMENTED; } - - - // **************** INPUT/OUTPUT **************** - - /// Print a message to the main log - virtual void log(std::string const &message) = 0; - - /// Print a message to the main log and let the rest of the program handle the error - virtual void error(std::string const &message) = 0; - - /// Print a message to the main log and exit with error code - virtual void fatal_error(std::string const &message) = 0; - - /// Print a message to the main log and exit normally - virtual void exit(std::string const &message) - { - cvm::error("Error: exiting without error is not implemented, returning error code.\n", - COLVARS_NOT_IMPLEMENTED); - } - - // TODO the following definitions may be moved to a .cpp file - - /// \brief Returns a reference to the given output channel; - /// if this is not open already, then open it - virtual std::ostream * output_stream(std::string const &output_name) - { - std::list::iterator osi = output_files.begin(); - std::list::iterator osni = output_stream_names.begin(); - for ( ; osi != output_files.end(); osi++, osni++) { - if (*osni == output_name) { - return *osi; - } - } - output_stream_names.push_back(output_name); - std::ofstream * os = new std::ofstream(output_name.c_str()); - if (!os->is_open()) { - cvm::error("Error: cannot write to file \""+output_name+"\".\n", - FILE_ERROR); - } - output_files.push_back(os); - return os; - } - - /// \brief Closes the given output channel - virtual int close_output_stream(std::string const &output_name) - { - std::list::iterator osi = output_files.begin(); - std::list::iterator osni = output_stream_names.begin(); - for ( ; osi != output_files.end(); osi++, osni++) { - if (*osni == output_name) { - ((std::ofstream *) (*osi))->close(); - output_files.erase(osi); - output_stream_names.erase(osni); - return COLVARS_OK; - } - } - cvm::error("Error: trying to close an output file or stream that wasn't open.\n", - BUG_ERROR); - return COLVARS_ERROR; - } - - /// \brief Rename the given file, before overwriting it - virtual int backup_file(char const *filename) - { - return COLVARS_NOT_IMPLEMENTED; - } - - - - // **************** ACCESS SYSTEM DATA **************** - /// Pass restraint energy value for current timestep to MD engine virtual void add_energy(cvm::real energy) = 0; - /// Tell the proxy whether total forces are needed (may not always be available) - virtual void request_total_force(bool yesno) - { - if (yesno == true) - cvm::error("Error: total forces are currently not implemented.\n", - COLVARS_NOT_IMPLEMENTED); - } - - /// Are total forces being used? - virtual bool total_forces_enabled() const - { - return false; - } - /// \brief Get the PBC-aware distance vector between two positions virtual cvm::rvector position_distance(cvm::atom_pos const &pos1, cvm::atom_pos const &pos2) = 0; @@ -346,107 +73,72 @@ public: /// \brief Get the PBC-aware square distance between two positions; /// may need to be reimplemented independently from position_distance() for optimization purposes virtual cvm::real position_dist2(cvm::atom_pos const &pos1, - cvm::atom_pos const &pos2) - { - return (position_distance(pos1, pos2)).norm2(); - } + cvm::atom_pos const &pos2); - /// \brief Get the closest periodic image to a reference position - /// \param pos The position to look for the closest periodic image - /// \param ref_pos The reference position - virtual void select_closest_image(cvm::atom_pos &pos, - cvm::atom_pos const &ref_pos) - { - pos = position_distance(ref_pos, pos) + ref_pos; - } + /// Tell the proxy whether total forces are needed (may not always be available) + virtual void request_total_force(bool yesno); - /// \brief Perform select_closest_image() on a set of atomic positions - /// - /// After that, distance vectors can then be calculated directly, - /// without using position_distance() - void select_closest_images(std::vector &pos, - cvm::atom_pos const &ref_pos) - { - for (std::vector::iterator pi = pos.begin(); - pi != pos.end(); ++pi) { - select_closest_image(*pi, ref_pos); - } - } + /// Are total forces being used? + virtual bool total_forces_enabled() const; +}; - // **************** ACCESS ATOMIC DATA **************** -protected: - - /// \brief Array of 0-based integers used to uniquely associate atoms - /// within the host program - std::vector atoms_ids; - /// \brief Keep track of how many times each atom is used by a separate colvar object - std::vector atoms_ncopies; - /// \brief Masses of the atoms (allow redefinition during a run, as done e.g. in LAMMPS) - std::vector atoms_masses; - /// \brief Charges of the atoms (allow redefinition during a run, as done e.g. in LAMMPS) - std::vector atoms_charges; - /// \brief Current three-dimensional positions of the atoms - std::vector atoms_positions; - /// \brief Most recent total forces on each atom - std::vector atoms_total_forces; - /// \brief Forces applied from colvars, to be communicated to the MD integrator - std::vector atoms_new_colvar_forces; - - /// Used by all init_atom() functions: create a slot for an atom not requested yet - inline int add_atom_slot(int atom_id) - { - atoms_ids.push_back(atom_id); - atoms_ncopies.push_back(1); - atoms_masses.push_back(1.0); - atoms_charges.push_back(0.0); - atoms_positions.push_back(cvm::rvector(0.0, 0.0, 0.0)); - atoms_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); - atoms_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); - return (atoms_ids.size() - 1); - } +/// \brief Container of atomic data for processing by Colvars +class colvarproxy_atoms { public: - /// Prepare this atom for collective variables calculation, selecting it by numeric index (1-based) + /// Constructor + colvarproxy_atoms(); + + /// Destructor + virtual ~colvarproxy_atoms(); + + /// Prepare this atom for collective variables calculation, selecting it by + /// numeric index (1-based) virtual int init_atom(int atom_number) = 0; - /// Check that this atom number is valid, but do not initialize the corresponding atom yet + /// Check that this atom number is valid, but do not initialize the + /// corresponding atom yet virtual int check_atom_id(int atom_number) = 0; - /// Select this atom for collective variables calculation, using name and residue number. - /// Not all programs support this: leave this function as is in those cases. + /// Select this atom for collective variables calculation, using name and + /// residue number. Not all programs support this: leave this function as + /// is in those cases. virtual int init_atom(cvm::residue_id const &residue, std::string const &atom_name, - std::string const &segment_id) - { - cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n", - COLVARS_NOT_IMPLEMENTED); - return COLVARS_NOT_IMPLEMENTED; - } + std::string const &segment_id); /// Check that this atom is valid, but do not initialize it yet virtual int check_atom_id(cvm::residue_id const &residue, std::string const &atom_name, - std::string const &segment_id) - { - cvm::error("Error: initializing an atom by name and residue number is currently not supported.\n", - COLVARS_NOT_IMPLEMENTED); - return COLVARS_NOT_IMPLEMENTED; - } + std::string const &segment_id); /// \brief Used by the atom class destructor: rather than deleting the array slot /// (costly) set the corresponding atoms_ncopies to zero - virtual void clear_atom(int index) - { - if (((size_t) index) >= atoms_ids.size()) { - cvm::error("Error: trying to disable an atom that was not previously requested.\n", - INPUT_ERROR); - } - if (atoms_ncopies[index] > 0) { - atoms_ncopies[index] -= 1; - } - } + virtual void clear_atom(int index); + + /// \brief Read atom identifiers from a file \param filename name of + /// the file (usually a PDB) \param atoms array to which atoms read + /// from "filename" will be appended \param pdb_field (optiona) if + /// "filename" is a PDB file, use this field to determine which are + /// the atoms to be set + virtual int load_atoms(char const *filename, + cvm::atom_group &atoms, + std::string const &pdb_field, + double const pdb_field_value = 0.0); + + /// \brief Load the coordinates for a group of atoms from a file + /// (usually a PDB); if "pos" is already allocated, the number of its + /// elements must match the number of atoms in "filename" + virtual int load_coords(char const *filename, + std::vector &pos, + const std::vector &indices, + std::string const &pdb_field, + double const pdb_field_value = 0.0); + + /// Clear atomic data + int reset(); /// Get the numeric ID of the given atom (for the program) inline int get_atom_id(int index) const @@ -485,120 +177,95 @@ public: } /// Read the current velocity of the given atom - virtual cvm::rvector get_atom_velocity(int index) + inline cvm::rvector get_atom_velocity(int index) { - cvm::error("Error: reading the current velocity of an atom is not yet implemented.\n", + cvm::error("Error: reading the current velocity of an atom " + "is not yet implemented.\n", COLVARS_NOT_IMPLEMENTED); return cvm::rvector(0.0); } - // useful functions for data management outside this class - inline std::vector *modify_atom_ids() { return &atoms_ids; } - inline std::vector *modify_atom_masses() { return &atoms_masses; } - inline std::vector *modify_atom_charges() { return &atoms_charges; } - inline std::vector *modify_atom_positions() { return &atoms_positions; } - inline std::vector *modify_atom_total_forces() { return &atoms_total_forces; } - inline std::vector *modify_atom_new_colvar_forces() { return &atoms_new_colvar_forces; } - - /// \brief Read atom identifiers from a file \param filename name of - /// the file (usually a PDB) \param atoms array to which atoms read - /// from "filename" will be appended \param pdb_field (optiona) if - /// "filename" is a PDB file, use this field to determine which are - /// the atoms to be set - virtual int load_atoms(char const *filename, - cvm::atom_group &atoms, - std::string const &pdb_field, - double const pdb_field_value = 0.0) + inline std::vector *modify_atom_ids() { - cvm::error("Error: loading atom identifiers from a file is currently not implemented.\n", - COLVARS_NOT_IMPLEMENTED); - return COLVARS_NOT_IMPLEMENTED; + return &atoms_ids; } - /// \brief Load the coordinates for a group of atoms from a file - /// (usually a PDB); if "pos" is already allocated, the number of its - /// elements must match the number of atoms in "filename" - virtual int load_coords(char const *filename, - std::vector &pos, - const std::vector &indices, - std::string const &pdb_field, - double const pdb_field_value = 0.0) + inline std::vector *modify_atom_masses() { - cvm::error("Error: loading atomic coordinates from a file is currently not implemented.\n"); - return COLVARS_NOT_IMPLEMENTED; + return &atoms_masses; } - // **************** ACCESS GROUP DATA **************** + inline std::vector *modify_atom_charges() + { + return &atoms_charges; + } + + inline std::vector *modify_atom_positions() + { + return &atoms_positions; + } + + inline std::vector *modify_atom_total_forces() + { + return &atoms_total_forces; + } + + inline std::vector *modify_atom_new_colvar_forces() + { + return &atoms_new_colvar_forces; + } protected: - /// \brief Array of 0-based integers used to uniquely associate atom groups + /// \brief Array of 0-based integers used to uniquely associate atoms /// within the host program - std::vector atom_groups_ids; - /// \brief Keep track of how many times each group is used by a separate cvc - std::vector atom_groups_ncopies; - /// \brief Total masses of the atom groups - std::vector atom_groups_masses; - /// \brief Total charges of the atom groups (allow redefinition during a run, as done e.g. in LAMMPS) - std::vector atom_groups_charges; - /// \brief Current centers of mass of the atom groups - std::vector atom_groups_coms; - /// \brief Most recently updated total forces on the com of each group - std::vector atom_groups_total_forces; + std::vector atoms_ids; + /// \brief Keep track of how many times each atom is used by a separate colvar object + std::vector atoms_ncopies; + /// \brief Masses of the atoms (allow redefinition during a run, as done e.g. in LAMMPS) + std::vector atoms_masses; + /// \brief Charges of the atoms (allow redefinition during a run, as done e.g. in LAMMPS) + std::vector atoms_charges; + /// \brief Current three-dimensional positions of the atoms + std::vector atoms_positions; + /// \brief Most recent total forces on each atom + std::vector atoms_total_forces; /// \brief Forces applied from colvars, to be communicated to the MD integrator - std::vector atom_groups_new_colvar_forces; + std::vector atoms_new_colvar_forces; - /// TODO Add here containers of handles to cvc objects that are computed in parallel + /// Used by all init_atom() functions: create a slot for an atom not + /// requested yet; returns the index in the arrays + int add_atom_slot(int atom_id); + +}; + + +/// \brief Container of atom group data (allow collection of aggregated atomic +/// data) +class colvarproxy_atom_groups { public: - /// \brief Whether this proxy implementation has capability for scalable groups - virtual int scalable_group_coms() - { - return COLVARS_NOT_IMPLEMENTED; - } + /// Contructor + colvarproxy_atom_groups(); - /// Used by all init_atom_group() functions: create a slot for an atom group not requested yet - // TODO Add a handle to cvc objects - inline int add_atom_group_slot(int atom_group_id) - { - atom_groups_ids.push_back(atom_group_id); - atom_groups_ncopies.push_back(1); - atom_groups_masses.push_back(1.0); - atom_groups_charges.push_back(0.0); - atom_groups_coms.push_back(cvm::rvector(0.0, 0.0, 0.0)); - atom_groups_total_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); - atom_groups_new_colvar_forces.push_back(cvm::rvector(0.0, 0.0, 0.0)); - return (atom_groups_ids.size() - 1); - } + /// Destructor + virtual ~colvarproxy_atom_groups(); + + /// Clear atom group data + int reset(); + + /// \brief Whether this proxy implementation has capability for scalable groups + virtual int scalable_group_coms(); /// Prepare this group for collective variables calculation, selecting atoms by internal ids (0-based) - virtual int init_atom_group(std::vector const &atoms_ids) // TODO Add a handle to cvc objects - { - cvm::error("Error: initializing a group outside of the colvars module is currently not supported.\n", - COLVARS_NOT_IMPLEMENTED); - return COLVARS_NOT_IMPLEMENTED; - } + virtual int init_atom_group(std::vector const &atoms_ids); /// \brief Used by the atom_group class destructor - virtual void clear_atom_group(int index) - { - if (cvm::debug()) { - log("Trying to remove/disable atom group number "+cvm::to_str(index)+"\n"); - } - - if (((size_t) index) >= atom_groups_ids.size()) { - cvm::error("Error: trying to disable an atom group that was not previously requested.\n", - INPUT_ERROR); - } - - if (atom_groups_ncopies[index] > 0) { - atom_groups_ncopies[index] -= 1; - } - } + virtual void clear_atom_group(int index); /// Get the numeric ID of the given atom group (for the MD program) - inline cvm::real get_atom_group_id(int index) const + inline int get_atom_group_id(int index) const { return atom_groups_ids[index]; } @@ -634,13 +301,288 @@ public: } /// Read the current velocity of the given atom group - virtual cvm::rvector get_atom_group_velocity(int index) + inline cvm::rvector get_atom_group_velocity(int index) { cvm::error("Error: reading the current velocity of an atom group is not yet implemented.\n", COLVARS_NOT_IMPLEMENTED); return cvm::rvector(0.0); } +protected: + + /// \brief Array of 0-based integers used to uniquely associate atom groups + /// within the host program + std::vector atom_groups_ids; + /// \brief Keep track of how many times each group is used by a separate cvc + std::vector atom_groups_ncopies; + /// \brief Total masses of the atom groups + std::vector atom_groups_masses; + /// \brief Total charges of the atom groups (allow redefinition during a run, as done e.g. in LAMMPS) + std::vector atom_groups_charges; + /// \brief Current centers of mass of the atom groups + std::vector atom_groups_coms; + /// \brief Most recently updated total forces on the com of each group + std::vector atom_groups_total_forces; + /// \brief Forces applied from colvars, to be communicated to the MD integrator + std::vector atom_groups_new_colvar_forces; + + /// Used by all init_atom_group() functions: create a slot for an atom group not requested yet + int add_atom_group_slot(int atom_group_id); +}; + + +/// \brief Methods for SMP parallelization +class colvarproxy_smp { + +public: + + /// Constructor + colvarproxy_smp(); + + /// Destructor + virtual ~colvarproxy_smp(); + + /// Whether threaded parallelization should be used (TODO: make this a + /// cvm::deps feature) + bool b_smp_active; + + /// Whether threaded parallelization is available (TODO: make this a cvm::deps feature) + virtual int smp_enabled(); + + /// Distribute calculation of colvars (and their components) across threads + virtual int smp_colvars_loop(); + + /// Distribute calculation of biases across threads + virtual int smp_biases_loop(); + + /// Distribute calculation of biases across threads 2nd through last, with all scripted biased on 1st thread + virtual int smp_biases_script_loop(); + + /// Index of this thread + virtual int smp_thread_id(); + + /// Number of threads sharing this address space + virtual int smp_num_threads(); + + /// Lock the proxy's shared data for access by a thread, if threads are implemented; if not implemented, does nothing + virtual int smp_lock(); + + /// Attempt to lock the proxy's shared data + virtual int smp_trylock(); + + /// Release the lock + virtual int smp_unlock(); +}; + + +/// \brief Methods for multiple-replica communication +class colvarproxy_replicas { + +public: + + /// Constructor + colvarproxy_replicas(); + + /// Destructor + virtual ~colvarproxy_replicas(); + + /// \brief Indicate if multi-replica support is available and active + virtual bool replica_enabled(); + + /// \brief Index of this replica + virtual int replica_index(); + + /// \brief Total number of replica + virtual int replica_num(); + + /// \brief Synchronize replica + virtual void replica_comm_barrier(); + + /// \brief Receive data from other replica + virtual int replica_comm_recv(char* msg_data, int buf_len, int src_rep); + + /// \brief Send data to other replica + virtual int replica_comm_send(char* msg_data, int msg_len, int dest_rep); + +}; + + +/// Method for scripting language interface (Tcl or Python) +class colvarproxy_script { + +public: + + /// Constructor + colvarproxy_script(); + + /// Destructor + virtual ~colvarproxy_script(); + + /// Convert a script object (Tcl or Python call argument) to a C string + virtual char *script_obj_to_str(unsigned char *obj); + + /// Pointer to the scripting interface object + /// (does not need to be allocated in a new interface) + colvarscript *script; + + /// is a user force script defined? + bool force_script_defined; + + /// Do we have a scripting interface? + bool have_scripts; + + /// Run a user-defined colvar forces script + virtual int run_force_callback(); + + virtual int run_colvar_callback( + std::string const &name, + std::vector const &cvcs, + colvarvalue &value); + + virtual int run_colvar_gradient_callback( + std::string const &name, + std::vector const &cvcs, + std::vector > &gradient); +}; + + +/// Methods for data input/output +class colvarproxy_io { + +public: + + /// Constructor + colvarproxy_io(); + + /// Destructor + virtual ~colvarproxy_io(); + + /// \brief Save the current frame number in the argument given + // Returns error code + virtual int get_frame(long int &); + + /// \brief Set the current frame number (as well as colvarmodule::it) + // Returns error code + virtual int set_frame(long int); + + /// \brief Returns a reference to the given output channel; + /// if this is not open already, then open it + virtual std::ostream *output_stream(std::string const &output_name, + std::ios_base::openmode mode = + std::ios_base::out); + + /// \brief Flushes the given output channel + virtual int flush_output_stream(std::ostream *os); + + /// \brief Closes the given output channel + virtual int close_output_stream(std::string const &output_name); + + /// \brief Rename the given file, before overwriting it + virtual int backup_file(char const *filename); + + /// \brief Rename the given file, before overwriting it + inline int backup_file(std::string const &filename) + { + return backup_file(filename.c_str()); + } + + /// \brief Prefix of the input state file + inline std::string & input_prefix() + { + return input_prefix_str; + } + + /// \brief Prefix to be used for output restart files + inline std::string & restart_output_prefix() + { + return restart_output_prefix_str; + } + + /// \brief Prefix to be used for output files (final system + /// configuration) + inline std::string & output_prefix() + { + return output_prefix_str; + } + +protected: + + /// \brief Prefix to be used for input files (restarts, not + /// configuration) + std::string input_prefix_str, output_prefix_str, restart_output_prefix_str; + + /// \brief Currently opened output files: by default, these are ofstream objects. + /// Allows redefinition to implement different output mechanisms + std::list output_files; + /// \brief Identifiers for output_stream objects: by default, these are the names of the files + std::list output_stream_names; + +}; + + + +/// \brief Interface between the collective variables module and +/// the simulation or analysis program (NAMD, VMD, LAMMPS...). +/// This is the base class: each interfaced program is supported by a derived class. +/// Only pure virtual functions ("= 0") must be reimplemented to ensure baseline functionality. +class colvarproxy + : public colvarproxy_system, + public colvarproxy_atoms, + public colvarproxy_atom_groups, + public colvarproxy_smp, + public colvarproxy_replicas, + public colvarproxy_script, + public colvarproxy_io +{ + +public: + + /// Pointer to the main object + colvarmodule *colvars; + + /// Constructor + colvarproxy(); + + /// Destructor + virtual ~colvarproxy(); + + /// \brief Reset proxy state, e.g. requested atoms + virtual int reset(); + + /// (Re)initialize required member data after construction + virtual int setup(); + + /// \brief Update data required by the colvars module (e.g. cache atom positions) + /// + /// TODO Break up colvarproxy_namd and colvarproxy_lammps function into these + virtual int update_input(); + + /// \brief Update data based from the results of a module update (e.g. send forces) + virtual int update_output(); + + /// Print a message to the main log + virtual void log(std::string const &message) = 0; + + /// Print a message to the main log and let the rest of the program handle the error + virtual void error(std::string const &message) = 0; + + /// Print a message to the main log and exit with error code + virtual void fatal_error(std::string const &message) = 0; + + /// \brief Restarts will be written each time this number of steps has passed + virtual size_t restart_frequency(); + + /// Whether a simulation is running (warn against irrecovarable errors) + inline bool simulation_running() const + { + return b_simulation_running; + } + +protected: + + /// Whether a simulation is running (warn against irrecovarable errors) + bool b_simulation_running; + }; diff --git a/lib/colvars/colvars_version.h b/lib/colvars/colvars_version.h new file mode 100644 index 0000000000..e544756428 --- /dev/null +++ b/lib/colvars/colvars_version.h @@ -0,0 +1,8 @@ +#define COLVARS_VERSION "2017-07-15" +// This file is part of the Collective Variables module (Colvars). +// The original version of Colvars and its updates are located at: +// https://github.com/colvars/colvars +// Please update all Colvars source files before making any changes. +// If you wish to distribute your changes, please submit them to the +// Colvars repository at GitHub. + diff --git a/lib/colvars/colvarscript.cpp b/lib/colvars/colvarscript.cpp index f192dcb7c0..5bb2faae24 100644 --- a/lib/colvars/colvarscript.cpp +++ b/lib/colvars/colvarscript.cpp @@ -12,6 +12,7 @@ #include #include "colvarscript.h" +#include "colvarproxy.h" #include "colvardeps.h" @@ -27,7 +28,7 @@ extern "C" { // Generic hooks; NAMD and VMD have Tcl-specific versions in the respective proxies - int run_colvarscript_command(int argc, const char **argv) + int run_colvarscript_command(int objc, unsigned char *const objv[]) { colvarproxy *cvp = cvm::proxy; if (!cvp) { @@ -37,7 +38,7 @@ extern "C" { cvm::error("Called run_colvarscript_command without a script object initialized.\n"); return -1; } - return cvp->script->run(argc, argv); + return cvp->script->run(objc, objv); } const char * get_colvarscript_result() @@ -53,30 +54,52 @@ extern "C" { /// Run method based on given arguments -int colvarscript::run(int argc, char const *argv[]) { - - result = ""; +int colvarscript::run(int objc, unsigned char *const objv[]) +{ + result.clear(); if (cvm::debug()) { - cvm::log("Called script run with " + cvm::to_str(argc) + " args"); - for (int i = 0; i < argc; i++) { cvm::log(argv[i]); } + cvm::log("Called script run with " + cvm::to_str(objc) + " args:"); + for (int i = 0; i < objc; i++) { + cvm::log(obj_to_str(objv[i])); + } } - if (argc < 2) { + if (objc < 2) { result = help_string(); return COLVARS_OK; } - std::string cmd = argv[1]; + std::string const cmd(obj_to_str(objv[1])); int error_code = COLVARS_OK; if (cmd == "colvar") { - return proc_colvar(argc-1, &(argv[1])); + if (objc < 3) { + result = "Missing parameters\n" + help_string(); + return COLVARSCRIPT_ERROR; + } + std::string const name(obj_to_str(objv[2])); + colvar *cv = cvm::colvar_by_name(name); + if (cv == NULL) { + result = "Colvar not found: " + name; + return COLVARSCRIPT_ERROR; + } + return proc_colvar(cv, objc-1, &(objv[1])); } if (cmd == "bias") { - return proc_bias(argc-1, &(argv[1])); + if (objc < 3) { + result = "Missing parameters\n" + help_string(); + return COLVARSCRIPT_ERROR; + } + std::string const name(obj_to_str(objv[2])); + colvarbias *b = cvm::bias_by_name(name); + if (b == NULL) { + result = "Bias not found: " + name; + return COLVARSCRIPT_ERROR; + } + return proc_bias(b, objc-1, &(objv[1])); } if (cmd == "version") { @@ -102,20 +125,20 @@ int colvarscript::run(int argc, char const *argv[]) { error_code |= colvars->calc(); error_code |= proxy->update_output(); if (error_code) { - result += "Error updating the colvars module.\n"; + result += "Error updating the Colvars module.\n"; } return error_code; } if (cmd == "list") { - if (argc == 2) { + if (objc == 2) { for (std::vector::iterator cvi = colvars->colvars.begin(); cvi != colvars->colvars.end(); ++cvi) { result += (cvi == colvars->colvars.begin() ? "" : " ") + (*cvi)->name; } return COLVARS_OK; - } else if (argc == 3 && !strcmp(argv[2], "biases")) { + } else if (objc == 3 && !strcmp(obj_to_str(objv[2]), "biases")) { for (std::vector::iterator bi = colvars->biases.begin(); bi != colvars->biases.end(); ++bi) { @@ -130,11 +153,11 @@ int colvarscript::run(int argc, char const *argv[]) { /// Parse config from file if (cmd == "configfile") { - if (argc < 3) { + if (objc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } - if (colvars->read_config_file(argv[2]) == COLVARS_OK) { + if (colvars->read_config_file(obj_to_str(objv[2])) == COLVARS_OK) { return COLVARS_OK; } else { result = "Error parsing configuration file"; @@ -144,11 +167,11 @@ int colvarscript::run(int argc, char const *argv[]) { /// Parse config from string if (cmd == "config") { - if (argc < 3) { + if (objc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } - std::string conf = argv[2]; + std::string const conf(obj_to_str(objv[2])); if (colvars->read_config_string(conf) == COLVARS_OK) { return COLVARS_OK; } else { @@ -159,11 +182,11 @@ int colvarscript::run(int argc, char const *argv[]) { /// Load an input state file if (cmd == "load") { - if (argc < 3) { + if (objc < 3) { result = "Missing arguments\n" + help_string(); return COLVARSCRIPT_ERROR; } - proxy->input_prefix() = argv[2]; + proxy->input_prefix() = obj_to_str(objv[2]); if (colvars->setup_input() == COLVARS_OK) { return COLVARS_OK; } else { @@ -174,11 +197,11 @@ int colvarscript::run(int argc, char const *argv[]) { /// Save to an output state file if (cmd == "save") { - if (argc < 3) { + if (objc < 3) { result = "Missing arguments"; return COLVARSCRIPT_ERROR; } - proxy->output_prefix_str = argv[2]; + proxy->output_prefix() = obj_to_str(objv[2]); int error = 0; error |= colvars->setup_output(); error |= colvars->write_output_files(); @@ -200,7 +223,7 @@ int colvarscript::run(int argc, char const *argv[]) { } if (cmd == "frame") { - if (argc == 2) { + if (objc == 2) { long int f; int error = proxy->get_frame(f); if (error == COLVARS_OK) { @@ -210,10 +233,10 @@ int colvarscript::run(int argc, char const *argv[]) { result = "Frame number is not available"; return COLVARSCRIPT_ERROR; } - } else if (argc == 3) { + } else if (objc == 3) { // Failure of this function does not trigger an error, but // returns nonzero, to let scripts detect available frames - int error = proxy->set_frame(strtol(argv[2], NULL, 10)); + int error = proxy->set_frame(strtol(obj_to_str(objv[2]), NULL, 10)); result = cvm::to_str(error == COLVARS_OK ? 0 : -1); return COLVARS_OK; } else { @@ -223,8 +246,8 @@ int colvarscript::run(int argc, char const *argv[]) { } if (cmd == "addenergy") { - if (argc == 3) { - colvars->total_bias_energy += strtod(argv[2], NULL); + if (objc == 3) { + colvars->total_bias_energy += strtod(obj_to_str(objv[2]), NULL); return COLVARS_OK; } else { result = "Wrong arguments to command \"addenergy\"\n" + help_string(); @@ -237,19 +260,9 @@ int colvarscript::run(int argc, char const *argv[]) { } -int colvarscript::proc_colvar(int argc, char const *argv[]) { - if (argc < 3) { - result = "Missing parameters\n" + help_string(); - return COLVARSCRIPT_ERROR; - } +int colvarscript::proc_colvar(colvar *cv, int objc, unsigned char *const objv[]) { - std::string name = argv[1]; - colvar *cv = cvm::colvar_by_name(name); - if (cv == NULL) { - result = "Colvar not found: " + name; - return COLVARSCRIPT_ERROR; - } - std::string subcmd = argv[2]; + std::string const subcmd(obj_to_str(objv[2])); if (subcmd == "value") { result = (cv->value()).to_simple_string(); @@ -278,11 +291,11 @@ int colvarscript::proc_colvar(int argc, char const *argv[]) { for (i = 0; i < cv->biases.size(); i++) { delete cv->biases[i]; } - cv->biases.resize(0); + cv->biases.clear(); // colvar destructor is tasked with the cleanup delete cv; // TODO this could be done by the destructors - colvars->write_traj_label(colvars->cv_traj_os); + colvars->write_traj_label(*(colvars->cv_traj_os)); return COLVARS_OK; } @@ -308,11 +321,11 @@ int colvarscript::proc_colvar(int argc, char const *argv[]) { } if (subcmd == "addforce") { - if (argc < 4) { + if (objc < 4) { result = "addforce: missing parameter: force value\n" + help_string(); return COLVARSCRIPT_ERROR; } - std::string f_str = argv[3]; + std::string const f_str(obj_to_str(objv[3])); std::istringstream is(f_str); is.width(cvm::cv_width); is.precision(cvm::cv_prec); @@ -328,11 +341,11 @@ int colvarscript::proc_colvar(int argc, char const *argv[]) { } if (subcmd == "cvcflags") { - if (argc < 4) { + if (objc < 4) { result = "cvcflags: missing parameter: vector of flags"; return COLVARSCRIPT_ERROR; } - std::string flags_str = argv[3]; + std::string const flags_str(obj_to_str(objv[3])); std::istringstream is(flags_str); std::vector flags; @@ -351,7 +364,7 @@ int colvarscript::proc_colvar(int argc, char const *argv[]) { } if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) { - return proc_features(cv, argc, argv); + return proc_features(cv, objc, objv); } result = "Syntax error\n" + help_string(); @@ -359,20 +372,10 @@ int colvarscript::proc_colvar(int argc, char const *argv[]) { } -int colvarscript::proc_bias(int argc, char const *argv[]) { - if (argc < 3) { - result = "Missing parameters\n" + help_string(); - return COLVARSCRIPT_ERROR; - } +int colvarscript::proc_bias(colvarbias *b, int objc, unsigned char *const objv[]) { - std::string name = argv[1]; - colvarbias *b = cvm::bias_by_name(name); - if (b == NULL) { - result = "Bias not found: " + name; - return COLVARSCRIPT_ERROR; - } - - std::string subcmd = argv[2]; + std::string const key(obj_to_str(objv[0])); + std::string const subcmd(obj_to_str(objv[2])); if (subcmd == "energy") { result = cvm::to_str(b->get_energy()); @@ -422,16 +425,16 @@ int colvarscript::proc_bias(int argc, char const *argv[]) { // the bias destructor takes care of the cleanup at cvm level delete b; // TODO this could be done by the destructors - colvars->write_traj_label(colvars->cv_traj_os); + colvars->write_traj_label(*(colvars->cv_traj_os)); return COLVARS_OK; } if ((subcmd == "get") || (subcmd == "set") || (subcmd == "state")) { - return proc_features(b, argc, argv); + return proc_features(b, objc, objv); } - if (argc >= 4) { - std::string param = argv[3]; + if (objc >= 4) { + std::string const param(obj_to_str(objv[3])); if (subcmd == "count") { int index; if (!(std::istringstream(param) >> index)) { @@ -452,11 +455,11 @@ int colvarscript::proc_bias(int argc, char const *argv[]) { int colvarscript::proc_features(colvardeps *obj, - int argc, char const *argv[]) { + int objc, unsigned char *const objv[]) { // size was already checked before calling - std::string subcmd = argv[2]; + std::string const subcmd(obj_to_str(objv[2])); - if (argc == 3) { + if (objc == 3) { if (subcmd == "state") { // TODO make this returned as result? obj->print_state(); @@ -470,7 +473,7 @@ int colvarscript::proc_features(colvardeps *obj, if ((subcmd == "get") || (subcmd == "set")) { std::vector &features = obj->features(); - std::string const req_feature(argv[3]); + std::string const req_feature(obj_to_str(objv[3])); colvardeps::feature *f = NULL; int fid = 0; for (fid = 0; fid < int(features.size()); fid++) { @@ -499,9 +502,9 @@ int colvarscript::proc_features(colvardeps *obj, } if (subcmd == "set") { - if (argc == 5) { + if (objc == 5) { std::string const yesno = - colvarparse::to_lower_cppstr(std::string(argv[4])); + colvarparse::to_lower_cppstr(std::string(obj_to_str(objv[4]))); if ((yesno == std::string("yes")) || (yesno == std::string("on")) || (yesno == std::string("1"))) { @@ -510,10 +513,7 @@ int colvarscript::proc_features(colvardeps *obj, } else if ((yesno == std::string("no")) || (yesno == std::string("off")) || (yesno == std::string("0"))) { - // TODO disable() function does not exist yet, - // dependencies will not be resolved - // obj->disable(fid); - obj->set_enabled(fid, false); + obj->disable(fid); return COLVARS_OK; } } @@ -533,11 +533,11 @@ std::string colvarscript::help_string() std::string buf; buf = "Usage: cv [args...]\n\ \n\ -Managing the colvars module:\n\ +Managing the Colvars module:\n\ configfile -- read configuration from a file\n\ config -- read configuration from the given string\n\ reset -- delete all internal configuration\n\ - delete -- delete this colvars module instance\n\ + delete -- delete this Colvars module instance\n\ version -- return version of colvars code\n\ \n\ Input and output:\n\ diff --git a/lib/colvars/colvarscript.h b/lib/colvars/colvarscript.h index 46b1ddd203..94d451809c 100644 --- a/lib/colvars/colvarscript.h +++ b/lib/colvars/colvarscript.h @@ -41,22 +41,30 @@ public: /// If an error is returned by one of the methods, it should set this to the error message std::string result; - /// Run script command with given positional arguments - int run(int argc, char const *argv[]); + /// Run script command with given positional arguments (objects) + int run(int objc, unsigned char *const objv[]); private: /// Run subcommands on colvar - int proc_colvar(int argc, char const *argv[]); + int proc_colvar(colvar *cv, int argc, unsigned char *const argv[]); /// Run subcommands on bias - int proc_bias(int argc, char const *argv[]); + int proc_bias(colvarbias *b, int argc, unsigned char *const argv[]); /// Run subcommands on base colvardeps object (colvar, bias, ...) int proc_features(colvardeps *obj, - int argc, char const *argv[]); + int argc, unsigned char *const argv[]); - /// Builds and return a short help + /// Build and return a short help std::string help_string(void); + +public: + + inline char const *obj_to_str(unsigned char *const obj) + { + return cvm::proxy->script_obj_to_str(obj); + } + }; diff --git a/lib/colvars/colvartypes.h b/lib/colvars/colvartypes.h index e0cebb83bc..17c09a5095 100644 --- a/lib/colvars/colvartypes.h +++ b/lib/colvars/colvartypes.h @@ -91,6 +91,11 @@ public: data.resize(n); } + inline void clear() + { + data.clear(); + } + inline T & operator [] (size_t const i) { return data[i]; } diff --git a/lib/colvars/colvarvalue.cpp b/lib/colvars/colvarvalue.cpp index deccc6b7e0..7b498be6d6 100644 --- a/lib/colvars/colvarvalue.cpp +++ b/lib/colvars/colvarvalue.cpp @@ -16,6 +16,274 @@ +std::string const colvarvalue::type_desc(Type t) +{ + switch (t) { + case colvarvalue::type_scalar: + return "scalar number"; break; + case colvarvalue::type_3vector: + return "3-dimensional vector"; break; + case colvarvalue::type_unit3vector: + return "3-dimensional unit vector"; break; + case colvarvalue::type_unit3vectorderiv: + return "derivative of a 3-dimensional unit vector"; break; + case colvarvalue::type_quaternion: + return "4-dimensional unit quaternion"; break; + case colvarvalue::type_quaternionderiv: + return "4-dimensional tangent vector"; break; + case colvarvalue::type_vector: + return "n-dimensional vector"; break; + case colvarvalue::type_notset: + // fallthrough + default: + return "not set"; break; + } +} + + +std::string const colvarvalue::type_keyword(Type t) +{ + switch (t) { + case colvarvalue::type_notset: + default: + return "not_set"; break; + case colvarvalue::type_scalar: + return "scalar"; break; + case colvarvalue::type_3vector: + return "vector3"; break; + case colvarvalue::type_unit3vector: + return "unit_vector3"; break; + case colvarvalue::type_unit3vectorderiv: + return ""; break; + case colvarvalue::type_quaternion: + return "unit_quaternion"; break; + case colvarvalue::type_quaternionderiv: + return ""; break; + case colvarvalue::type_vector: + return "vector"; break; + } +} + + +size_t colvarvalue::num_df(Type t) +{ + switch (t) { + case colvarvalue::type_notset: + default: + return 0; break; + case colvarvalue::type_scalar: + return 1; break; + case colvarvalue::type_3vector: + return 3; break; + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return 2; break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return 3; break; + case colvarvalue::type_vector: + // the size of a vector is unknown without its object + return 0; break; + } +} + + +size_t colvarvalue::num_dimensions(Type t) +{ + switch (t) { + case colvarvalue::type_notset: + default: + return 0; break; + case colvarvalue::type_scalar: + return 1; break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return 3; break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return 4; break; + case colvarvalue::type_vector: + // the size of a vector is unknown without its object + return 0; break; + } +} + + +void colvarvalue::reset() +{ + switch (value_type) { + case colvarvalue::type_scalar: + real_value = 0.0; + break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + rvector_value.reset(); + break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + quaternion_value.reset(); + break; + case colvarvalue::type_vector: + vector1d_value.reset(); + break; + case colvarvalue::type_notset: + default: + break; + } +} + + +void colvarvalue::apply_constraints() +{ + switch (value_type) { + case colvarvalue::type_scalar: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: + case colvarvalue::type_quaternionderiv: + break; + case colvarvalue::type_unit3vector: + rvector_value /= std::sqrt(rvector_value.norm2()); + break; + case colvarvalue::type_quaternion: + quaternion_value /= std::sqrt(quaternion_value.norm2()); + break; + case colvarvalue::type_vector: + if (elem_types.size() > 0) { + // if we have information about non-scalar types, use it + size_t i; + for (i = 0; i < elem_types.size(); i++) { + if (elem_sizes[i] == 1) continue; // TODO this can be optimized further + colvarvalue cvtmp(vector1d_value.slice(elem_indices[i], + elem_indices[i] + elem_sizes[i]), elem_types[i]); + cvtmp.apply_constraints(); + set_elem(i, cvtmp); + } + } + break; + case colvarvalue::type_notset: + default: + break; + } +} + + +void colvarvalue::type(Type const &vti) +{ + if (vti != value_type) { + // reset the value based on the previous type + reset(); + if ((value_type == type_vector) && (vti != type_vector)) { + vector1d_value.clear(); + } + value_type = vti; + } +} + + +void colvarvalue::type(colvarvalue const &x) +{ + if (x.type() != value_type) { + // reset the value based on the previous type + reset(); + if (value_type == type_vector) { + vector1d_value.clear(); + } + value_type = x.type(); + } + + if (x.type() == type_vector) { + vector1d_value.resize(x.vector1d_value.size()); + } +} + + +void colvarvalue::is_derivative() +{ + switch (value_type) { + case colvarvalue::type_scalar: + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vectorderiv: + case colvarvalue::type_quaternionderiv: + break; + case colvarvalue::type_unit3vector: + type(colvarvalue::type_unit3vectorderiv); + break; + case colvarvalue::type_quaternion: + type(colvarvalue::type_quaternionderiv); + break; + case colvarvalue::type_vector: + // TODO + break; + case colvarvalue::type_notset: + default: + break; + } +} + + +colvarvalue::colvarvalue(colvarvalue const &x) + : value_type(x.type()) +{ + switch (x.type()) { + case type_scalar: + real_value = x.real_value; + break; + case type_3vector: + case type_unit3vector: + case type_unit3vectorderiv: + rvector_value = x.rvector_value; + break; + case type_quaternion: + case type_quaternionderiv: + quaternion_value = x.quaternion_value; + break; + case type_vector: + vector1d_value = x.vector1d_value; + elem_types = x.elem_types; + elem_indices = x.elem_indices; + elem_sizes = x.elem_sizes; + case type_notset: + default: + break; + } +} + + +colvarvalue::colvarvalue(cvm::vector1d const &v, Type vti) +{ + if ((vti != type_vector) && (v.size() != num_dimensions(vti))) { + cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+ + "\" using a vector of size "+cvm::to_str(v.size())+ + ".\n"); + value_type = type_notset; + } else { + value_type = vti; + switch (vti) { + case type_scalar: + real_value = v[0]; + break; + case type_3vector: + case type_unit3vector: + case type_unit3vectorderiv: + rvector_value = cvm::rvector(v); + break; + case type_quaternion: + case type_quaternionderiv: + quaternion_value = cvm::quaternion(v); + break; + case type_vector: + vector1d_value = v; + break; + case type_notset: + default: + break; + } + } +} + + void colvarvalue::add_elem(colvarvalue const &x) { if (this->value_type != type_vector) { @@ -111,6 +379,13 @@ void colvarvalue::set_random() } +void colvarvalue::undef_op() const +{ + cvm::error("Error: Undefined operation on a colvar of type \""+ + type_desc(this->type())+"\".\n"); +} + + // binary operations between two colvarvalues colvarvalue operator + (colvarvalue const &x1, diff --git a/lib/colvars/colvarvalue.h b/lib/colvars/colvarvalue.h index e369feefcd..fce0e1a970 100644 --- a/lib/colvars/colvarvalue.h +++ b/lib/colvars/colvarvalue.h @@ -169,38 +169,14 @@ public: } /// Set the type explicitly - inline void type(Type const &vti) - { - if (vti != value_type) { - // reset the value based on the previous type - reset(); - if ((value_type == type_vector) && (vti != type_vector)) { - vector1d_value.resize(0); - } - value_type = vti; - } - } + void type(Type const &vti); /// Set the type after another \link colvarvalue \endlink - inline void type(colvarvalue const &x) - { - if (x.type() != value_type) { - // reset the value based on the previous type - reset(); - if (value_type == type_vector) { - vector1d_value.resize(0); - } - value_type = x.type(); - } - - if (x.type() == type_vector) { - vector1d_value.resize(x.vector1d_value.size()); - } - } + void type(colvarvalue const &x); /// Make the type a derivative of the original type /// (so that its constraints do not apply) - inline void is_derivative(); + void is_derivative(); /// Square norm of this colvarvalue cvm::real norm2() const; @@ -303,28 +279,10 @@ public: void set_elem(int const icv, colvarvalue const &x); /// Get a scalar number out of an element of the vector - inline cvm::real operator [] (int const i) const - { - if (vector1d_value.size() > 0) { - return vector1d_value[i]; - } else { - cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n"); - return 0.0; - } - } + cvm::real operator [] (int const i) const; /// Use an element of the vector as a scalar number - inline cvm::real & operator [] (int const i) - { - if (vector1d_value.size() > 0) { - return vector1d_value[i]; - } else { - cvm::error("Error: trying to use as a vector a variable that is not initialized as such.\n"); - real_value = 0.0; - return real_value; - } - } - + cvm::real & operator [] (int const i); /// Ensure that the two types are the same within a binary operator int static check_types(colvarvalue const &x1, colvarvalue const &x2); @@ -389,101 +347,6 @@ public: }; - -inline std::string const colvarvalue::type_desc(Type t) -{ - switch (t) { - case colvarvalue::type_scalar: - return "scalar number"; break; - case colvarvalue::type_3vector: - return "3-dimensional vector"; break; - case colvarvalue::type_unit3vector: - return "3-dimensional unit vector"; break; - case colvarvalue::type_unit3vectorderiv: - return "derivative of a 3-dimensional unit vector"; break; - case colvarvalue::type_quaternion: - return "4-dimensional unit quaternion"; break; - case colvarvalue::type_quaternionderiv: - return "4-dimensional tangent vector"; break; - case colvarvalue::type_vector: - return "n-dimensional vector"; break; - case colvarvalue::type_notset: - // fallthrough - default: - return "not set"; break; - } -} - - -inline std::string const colvarvalue::type_keyword(Type t) -{ - switch (t) { - case colvarvalue::type_notset: - default: - return "not_set"; break; - case colvarvalue::type_scalar: - return "scalar"; break; - case colvarvalue::type_3vector: - return "vector3"; break; - case colvarvalue::type_unit3vector: - return "unit_vector3"; break; - case colvarvalue::type_unit3vectorderiv: - return ""; break; - case colvarvalue::type_quaternion: - return "unit_quaternion"; break; - case colvarvalue::type_quaternionderiv: - return ""; break; - case colvarvalue::type_vector: - return "vector"; break; - } -} - - -inline size_t colvarvalue::num_df(Type t) -{ - switch (t) { - case colvarvalue::type_notset: - default: - return 0; break; - case colvarvalue::type_scalar: - return 1; break; - case colvarvalue::type_3vector: - return 3; break; - case colvarvalue::type_unit3vector: - case colvarvalue::type_unit3vectorderiv: - return 2; break; - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return 3; break; - case colvarvalue::type_vector: - // the size of a vector is unknown without its object - return 0; break; - } -} - - -inline size_t colvarvalue::num_dimensions(Type t) -{ - switch (t) { - case colvarvalue::type_notset: - default: - return 0; break; - case colvarvalue::type_scalar: - return 1; break; - case colvarvalue::type_3vector: - case colvarvalue::type_unit3vector: - case colvarvalue::type_unit3vectorderiv: - return 3; break; - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - return 4; break; - case colvarvalue::type_vector: - // the size of a vector is unknown without its object - return 0; break; - } -} - - inline size_t colvarvalue::size() const { switch (value_type) { @@ -505,62 +368,48 @@ inline size_t colvarvalue::size() const } -inline colvarvalue::colvarvalue(colvarvalue const &x) - : value_type(x.type()) +inline cvm::real colvarvalue::operator [] (int const i) const { - switch (x.type()) { - case type_scalar: - real_value = x.real_value; - break; - case type_3vector: - case type_unit3vector: - case type_unit3vectorderiv: - rvector_value = x.rvector_value; - break; - case type_quaternion: - case type_quaternionderiv: - quaternion_value = x.quaternion_value; - break; - case type_vector: - vector1d_value = x.vector1d_value; - elem_types = x.elem_types; - elem_indices = x.elem_indices; - elem_sizes = x.elem_sizes; - case type_notset: + switch (value_type) { + case colvarvalue::type_notset: default: - break; + cvm::error("Error: trying to access a colvar value " + "that is not initialized.\n", BUG_ERROR); + return 0.0; break; + case colvarvalue::type_scalar: + return real_value; break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return rvector_value[i]; break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return quaternion_value[i]; break; + case colvarvalue::type_vector: + return vector1d_value[i]; break; } } -inline colvarvalue::colvarvalue(cvm::vector1d const &v, Type vti) + +inline cvm::real & colvarvalue::operator [] (int const i) { - if ((vti != type_vector) && (v.size() != num_dimensions(vti))) { - cvm::error("Error: trying to initialize a variable of type \""+type_desc(vti)+ - "\" using a vector of size "+cvm::to_str(v.size())+ - ".\n"); - value_type = type_notset; - } else { - value_type = vti; - switch (vti) { - case type_scalar: - real_value = v[0]; - break; - case type_3vector: - case type_unit3vector: - case type_unit3vectorderiv: - rvector_value = cvm::rvector(v); - break; - case type_quaternion: - case type_quaternionderiv: - quaternion_value = cvm::quaternion(v); - break; - case type_vector: - vector1d_value = v; - break; - case type_notset: - default: - break; - } + switch (value_type) { + case colvarvalue::type_notset: + default: + cvm::error("Error: trying to access a colvar value " + "that is not initialized.\n", BUG_ERROR); + return real_value; break; + case colvarvalue::type_scalar: + return real_value; break; + case colvarvalue::type_3vector: + case colvarvalue::type_unit3vector: + case colvarvalue::type_unit3vectorderiv: + return rvector_value[i]; break; + case colvarvalue::type_quaternion: + case colvarvalue::type_quaternionderiv: + return quaternion_value[i]; break; + case colvarvalue::type_vector: + return vector1d_value[i]; break; } } @@ -638,13 +487,6 @@ inline int colvarvalue::check_types_assign(colvarvalue::Type const &vt1, } -inline void colvarvalue::undef_op() const -{ - cvm::error("Error: Undefined operation on a colvar of type \""+ - type_desc(this->type())+"\".\n"); -} - - inline colvarvalue & colvarvalue::operator = (colvarvalue const &x) { check_types_assign(this->type(), x.type()); @@ -704,6 +546,7 @@ inline void colvarvalue::operator += (colvarvalue const &x) } } + inline void colvarvalue::operator -= (colvarvalue const &x) { colvarvalue::check_types(*this, x); @@ -802,89 +645,6 @@ inline cvm::vector1d const colvarvalue::as_vector() const } -inline void colvarvalue::reset() -{ - switch (value_type) { - case colvarvalue::type_scalar: - real_value = 0.0; - break; - case colvarvalue::type_3vector: - case colvarvalue::type_unit3vector: - case colvarvalue::type_unit3vectorderiv: - rvector_value.reset(); - break; - case colvarvalue::type_quaternion: - case colvarvalue::type_quaternionderiv: - quaternion_value.reset(); - break; - case colvarvalue::type_vector: - vector1d_value.reset(); - break; - case colvarvalue::type_notset: - default: - break; - } -} - - -inline void colvarvalue::apply_constraints() -{ - switch (value_type) { - case colvarvalue::type_scalar: - case colvarvalue::type_3vector: - case colvarvalue::type_unit3vectorderiv: - case colvarvalue::type_quaternionderiv: - break; - case colvarvalue::type_unit3vector: - rvector_value /= std::sqrt(rvector_value.norm2()); - break; - case colvarvalue::type_quaternion: - quaternion_value /= std::sqrt(quaternion_value.norm2()); - break; - case colvarvalue::type_vector: - if (elem_types.size() > 0) { - // if we have information about non-scalar types, use it - size_t i; - for (i = 0; i < elem_types.size(); i++) { - if (elem_sizes[i] == 1) continue; // TODO this can be optimized further - colvarvalue cvtmp(vector1d_value.slice(elem_indices[i], - elem_indices[i] + elem_sizes[i]), elem_types[i]); - cvtmp.apply_constraints(); - set_elem(i, cvtmp); - } - } - break; - case colvarvalue::type_notset: - default: - break; - } -} - - -inline void colvarvalue::is_derivative() -{ - switch (value_type) { - case colvarvalue::type_scalar: - case colvarvalue::type_3vector: - case colvarvalue::type_unit3vectorderiv: - case colvarvalue::type_quaternionderiv: - break; - case colvarvalue::type_unit3vector: - type(colvarvalue::type_unit3vectorderiv); - break; - case colvarvalue::type_quaternion: - type(colvarvalue::type_quaternionderiv); - break; - case colvarvalue::type_vector: - // TODO - break; - case colvarvalue::type_notset: - default: - break; - } -} - - inline cvm::real colvarvalue::norm2() const { switch (value_type) { diff --git a/src/USER-COLVARS/colvarproxy_lammps.cpp b/src/USER-COLVARS/colvarproxy_lammps.cpp index 89453ded9b..17dff30567 100644 --- a/src/USER-COLVARS/colvarproxy_lammps.cpp +++ b/src/USER-COLVARS/colvarproxy_lammps.cpp @@ -308,10 +308,6 @@ void colvarproxy_lammps::error(std::string const &message) void colvarproxy_lammps::fatal_error(std::string const &message) { log(message); - // if (!cvm::debug()) - // log("If this error message is unclear, try recompiling the " - // "colvars library and LAMMPS with -DCOLVARS_DEBUG.\n"); - _lmp->error->one(FLERR, "Fatal error in the collective variables module.\n"); } diff --git a/src/USER-COLVARS/colvarproxy_lammps.h b/src/USER-COLVARS/colvarproxy_lammps.h index ad63eb2f9e..6cdf0edfe8 100644 --- a/src/USER-COLVARS/colvarproxy_lammps.h +++ b/src/USER-COLVARS/colvarproxy_lammps.h @@ -7,10 +7,11 @@ // If you wish to distribute your changes, please submit them to the // Colvars repository at GitHub. - #ifndef COLVARPROXY_LAMMPS_H #define COLVARPROXY_LAMMPS_H +#include "colvarproxy_lammps_version.h" + #include "colvarmodule.h" #include "colvarproxy.h" #include "colvarvalue.h" @@ -28,10 +29,6 @@ #include #endif -#ifndef COLVARPROXY_VERSION -#define COLVARPROXY_VERSION "2017-01-09" -#endif - /* struct for packed data communication of coordinates and forces. */ struct commdata { int tag,type; diff --git a/src/USER-COLVARS/colvarproxy_lammps_version.h b/src/USER-COLVARS/colvarproxy_lammps_version.h new file mode 100644 index 0000000000..834bd1748a --- /dev/null +++ b/src/USER-COLVARS/colvarproxy_lammps_version.h @@ -0,0 +1,10 @@ +#ifndef COLVARPROXY_VERSION +#define COLVARPROXY_VERSION "2017-07-15" +// This file is part of the Collective Variables module (Colvars). +// The original version of Colvars and its updates are located at: +// https://github.com/colvars/colvars +// Please update all Colvars source files before making any changes. +// If you wish to distribute your changes, please submit them to the +// Colvars repository at GitHub. + +#endif From c95db97b83c3e7d6aa72ef2298d901903b3ce562 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 15:15:24 -0600 Subject: [PATCH 170/293] fix PYTHON install --- cmake/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9d8b93e12d..7b9d9f14f9 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -168,10 +168,18 @@ if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD OR ENABLE_USER-QUIP) endif() if(ENABLE_PYTHON) + find_package(PythonInterp REQUIRED) find_package(PythonLibs REQUIRED) add_definitions(-DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) + execute_process(COMMAND ${PYTHON_EXECUTABLE} + -c "import distutils.sysconfig as cg; print(cg.get_python_lib(1,0,prefix='${CMAKE_INSTALL_PREFIX}'))" + OUTPUT_VARIABLE PYTHON_INSTDIR OUTPUT_STRIP_TRAILING_WHITESPACE) + install(FILES ${CMAKE_SOURCE_DIR}/../python/lammps.py DESTINATION ${PYTHON_INSTDIR}) + if(NOT BUILD_SHARED_LIBS) + message(FATAL_ERROR "Python package need lammps to be build shared, -DBUILD_SHARED_LIBS=ON") + endif() endif() find_package(JPEG) From a99e3ef4f0e839cd7b6f21f5d1df6b55344e5849 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 15:15:49 -0600 Subject: [PATCH 171/293] cmake: fix typo and pkg info --- cmake/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7b9d9f14f9..af2740eba1 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -497,8 +497,8 @@ set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) if(INSTALL_LIB) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) -elseif(NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "Shared library has to install, use -DBUILD_SHARED_LIBS=OFF to install lammps with a a library") +elseif(BUILD_SHARED_LIBS) + message(FATAL_ERROR "Shared library has to be installed, use -DBUILD_SHARED_LIBS=ON to install lammps with a library") endif() add_executable(lmp ${LMP_SOURCES}) @@ -506,7 +506,7 @@ target_link_libraries(lmp lammps) install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) -foreach(PKG ${PACKAGES} ${ACCEL_PACKAGES}) +foreach(PKG ${PACKAGES} ${USER-PACKAGES} ${ACCEL_PACKAGES}) if(ENABLE_${PKG}) message(STATUS "Building package: ${PKG}") endif() From 355aad96916697277b1b4adbfc293d6093021b0b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 19 Jul 2017 17:19:44 -0400 Subject: [PATCH 172/293] restore python3 support. this now can run with python 2.7.13 and 3.5.3. --- lib/kim/Install.py | 45 +++++++++++++-------------------------------- 1 file changed, 13 insertions(+), 32 deletions(-) diff --git a/lib/kim/Install.py b/lib/kim/Install.py index cb089e41e2..1405cc5fad 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -87,14 +87,15 @@ url = "https://s3.openkim.org/kim-api/%s.tgz" % version if buildflag: # set install directory + dir = os.path.join(os.path.abspath(dir), "installed-" + version) - # check to see if an installed kim-api already exists + # check to see if an installed kim-api already exists and wipe it out. if os.path.isdir(dir): - print("kim-api is already installed at %s" % dir) - print("Must remove this directory in order to resintall at this location") - sys.exit() + print("kim-api is already installed at %s.\nRemoving it for re-install" % dir) + cmd = "rm -rf %s" % dir + subprocess.check_output(cmd,shell=True) # configure LAMMPS to use kim-api to be installed @@ -110,19 +111,9 @@ if buildflag: print("Created %s/Makefile.KIM_DIR : using %s" % (thisdir,dir)) # download entire kim-api tarball - # try first via urllib - # if fails (probably due to no SSL support), use wget print("Downloading kim-api tarball ...") - - try: geturl(url,"%s/%s.tgz" % (thisdir,version)) - except: - cmd = "wget %s %s/%s.tgz" % (url,thisdir,version) - subprocess.check_output(cmd,shell=True) - if not os.path.isfile("%s/%s.tgz" % (thisdir,version)): - print("Both urllib and wget command failed to download") - sys.exit() - + geturl(url,"%s/%s.tgz" % (thisdir,version)) print("Unpacking kim-api tarball ...") cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) subprocess.check_output(cmd,shell=True) @@ -182,17 +173,8 @@ if addflag: # if fails (probably due to no SSL support), use wget print("Downloading item tarball ...") - url = "https://openkim.org/download/%s.tgz" % addmodelname - - try: geturl(url,"%s/%s.tgz" % (thisdir,addmodelname)) - except: - cmd = "wget %s %s/%s.tgz" % (url,thisdir,addmodelname) - txt = subprocess.check_output(cmd,shell=True) - print(txt[1]) - if not os.path.isfile("%s/%s.tgz" % (thisdir,addmodelname)): - print("Both urllib.urlretrieve() and wget command failed to download") - sys.exit() + geturl(url,"%s/%s.tgz" % (thisdir,addmodelname)) print("Unpacking item tarball ...") cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) @@ -205,19 +187,19 @@ if addflag: except subprocess.CalledProcessError as e: # Error: but first, check to see if it needs a driver - - firstRunOutput = e.output + firstRunOutput = e.output.decode() cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + txt = txt.decode().strip() if txt == "ParameterizedModel": # Get and install driver cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) - adddrivername = txt - print("First Installing model driver: %s" % adddrivername) + adddrivername = txt.decode().strip() + print("First installing model driver: %s" % adddrivername) cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) try: txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) @@ -225,17 +207,16 @@ if addflag: print(e.output) sys.exit() - print(txt) - # now install the model that needed the driver + print("Now installing model : %s" % addmodelname) cmd = "cd %s; python Install.py -a %s" % (thisdir,addmodelname) try: txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) except subprocess.CalledProcessError as e: print(e.output) sys.exit() - print(txt) + print(txt.decode()) sys.exit() else: print(firstRunOutput) From babba1870efe58f9dbdf3118d44fc51557669965 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 15:33:02 -0600 Subject: [PATCH 173/293] added FFTW2 support --- cmake/CMakeLists.txt | 20 +++++++++----------- cmake/Modules/FindFFTW2.cmake | 22 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 11 deletions(-) create mode 100644 cmake/Modules/FindFFTW2.cmake diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index af2740eba1..7b6b2112da 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -116,17 +116,15 @@ if(ENABLE_USER-OMP OR ENABLE_KOKKOS OR ENABLE_USER-INTEL) endif() if(ENABLE_KSPACE) - find_package(FFTW3) - find_package(MKL) - if(FFTW3_FOUND) - add_definitions(-DFFT_FFTW3) - include_directories(${FFTW3_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${FFTW3_LIBRARIES}) - elseif(MKL_FOUND) - add_definitions(-DFFT_MKL) - include_directories(${MKL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) - endif() + foreach(FFT FFTW3 MKL FFTW2) + find_package(${FFT}) + if(${FFT}_FOUND) + add_definitions(-DFFT_${FFT}) + include_directories(${${FFT}_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${${FFT}_LIBRARIES}) + break() + endif() + endforeach() set(PACK_OPTIMIZATION "PACK_ARRAY" CACHE STRING "Optimization for FFT") set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) if(NOT PACK_OPTIMIZATION STREQUAL "PACK_ARRAY") diff --git a/cmake/Modules/FindFFTW2.cmake b/cmake/Modules/FindFFTW2.cmake new file mode 100644 index 0000000000..c77e6cf8e9 --- /dev/null +++ b/cmake/Modules/FindFFTW2.cmake @@ -0,0 +1,22 @@ +# - Find fftw2 +# Find the native FFTW2 headers and libraries. +# +# FFTW2_INCLUDE_DIRS - where to find fftw2.h, etc. +# FFTW2_LIBRARIES - List of libraries when using fftw2. +# FFTW2_FOUND - True if fftw2 found. +# + +find_path(FFTW2_INCLUDE_DIR fftw.h) + +find_library(FFTW2_LIBRARY NAMES fftw) + +set(FFTW2_LIBRARIES ${FFTW2_LIBRARY}) +set(FFTW2_INCLUDE_DIRS ${FFTW2_INCLUDE_DIR}) + +include(FindPackageHandleStandardArgs) +# handle the QUIETLY and REQUIRED arguments and set FFTW2_FOUND to TRUE +# if all listed variables are TRUE + +find_package_handle_standard_args(FFTW2 DEFAULT_MSG FFTW2_LIBRARY FFTW2_INCLUDE_DIR) + +mark_as_advanced(FFTW2_INCLUDE_DIR FFTW2_LIBRARY ) From 01bcb79bdc0c6043fc1c4f537884e5c8f5913463 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 18:34:07 -0600 Subject: [PATCH 174/293] cmake: clean up and updated comments --- cmake/CMakeLists.txt | 201 ++++++++++++++++++++++--------------------- 1 file changed, 103 insertions(+), 98 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 7b6b2112da..262857de16 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,3 +1,7 @@ +######################################## +# CMake build system +# This file is part of LAMMPS +# Created by Christoph Junghans and Richard Berger cmake_minimum_required(VERSION 3.1) project(lammps) @@ -6,6 +10,7 @@ set(LAMMPS_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../src) set(LAMMPS_LIB_SOURCE_DIR ${CMAKE_SOURCE_DIR}/../lib) set(LAMMPS_LIB_BINARY_DIR ${CMAKE_BINARY_DIR}/lib) +#To not conflict with old 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}) @@ -32,7 +37,6 @@ enable_language(CXX) # compiler tests # these need ot be done early (before further tests). ##################################################################### - include(CheckCCompilerFlag) ######################################################################## @@ -98,6 +102,9 @@ pkg_depends(USER-LB MPI) pkg_depends(USER-MISC MANYBODY) pkg_depends(USER-PHONON KSPACE) +###################################################### +# packages with special compiler needs or external libs +###################################################### if(ENABLE_REAX OR ENABLE_MEAM OR ENABLE_USER-QUIP OR ENABLE_USER-QMMM) enable_language(Fortran) endif() @@ -139,21 +146,6 @@ if(ENABLE_MISC) endif() endif() -if(ENABLE_KOKKOS) - set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) - set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) - add_definitions(-DLMP_KOKKOS) - add_subdirectory(${LAMMPS_LIB_KOKKOS_SRC_DIR} ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - - # TODO there probably is a better way - set(Kokkos_INCLUDE_DIRS ${LAMMPS_LIB_KOKKOS_SRC_DIR}/core/src - ${LAMMPS_LIB_KOKKOS_SRC_DIR}/containers/src - ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src - ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - include_directories(${Kokkos_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS kokkos) -endif() - if(ENABLE_MSCG OR ENABLE_USER-ATC OR ENABLE_USER-AWPMD OR ENABLE_USER-QUIP) find_package(LAPACK) if(LAPACK_FOUND) @@ -209,7 +201,6 @@ if(ENABLE_VORONOI) find_package(VORO REQUIRED) #some distros include_directories(${VORO_INCLUDE_DIRS}) list(APPEND LAMMPS_LINK_LIBS ${VORO_LIBRARIES}) - #TODO download and build voro++ endif() if(ENABLE_USER-MOLFILE) @@ -239,65 +230,6 @@ if(ENABLE_USER-QMMM) list(APPEND LAMMPS_LINK_LIBS ${QE_LIBRARIES} ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() -######################################################################## -# Basic system tests (standard libraries, headers, functions, types) # -######################################################################## -include(CheckIncludeFile) -foreach(HEADER math.h) - check_include_file(${HEADER} FOUND_${HEADER}) - if(NOT FOUND_${HEADER}) - message(FATAL_ERROR "Could not find needed header - ${HEADER}") - endif(NOT FOUND_${HEADER}) -endforeach(HEADER) - -set(MATH_LIBRARIES "m" CACHE STRING "math library") -mark_as_advanced( MATH_LIBRARIES ) -include(CheckLibraryExists) -foreach(FUNC sin cos) - check_library_exists(${MATH_LIBRARIES} ${FUNC} "" FOUND_${FUNC}_${MATH_LIBRARIES}) - if(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) - 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}) - -###################################### -# Include the following subdirectory # -###################################### - -#Do NOT go into src to not conflict with old Makefile build system -#add_subdirectory(src) - -include(StyleHeaderUtils) -RegisterStyles(${LAMMPS_SOURCE_DIR}) - -# packages which include entire content when enabled - -foreach(PKG ${PACKAGES} ${USER-PACKAGES}) - if(ENABLE_${PKG}) - set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) - - # detects styles in package and adds them to global list - RegisterStyles(${${PKG}_SOURCES_DIR}) - - file(GLOB ${PKG}_SOURCES ${${PKG}_SOURCES_DIR}/*.cpp) - list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) - include_directories(${${PKG}_SOURCES_DIR}) - endif() -endforeach() - -foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD - USER-MOLFILE USER-QMMM) - if(ENABLE_${SIMPLE_LIB}) - string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") - string(TOLOWER "${SIMPLE_LIB}" INC_DIR) - file(GLOB_RECURSE ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F - ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.c ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.cpp) - list(APPEND LIB_SOURCES ${${SIMPLE_LIB}_SOURCES}) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}) - endif() -endforeach() - if(ENABLE_USER-AWPMD) include_directories(${LAMMPS_LIB_SOURCE_DIR}/awpmd/systems/interact ${LAMMPS_LIB_SOURCE_DIR}/awpmd/ivutils/include) @@ -348,11 +280,69 @@ if(ENABLE_MSCG) list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES}) endif() +######################################################################## +# Basic system tests (standard libraries, headers, functions, types) # +######################################################################## +include(CheckIncludeFile) +foreach(HEADER math.h) + check_include_file(${HEADER} FOUND_${HEADER}) + if(NOT FOUND_${HEADER}) + message(FATAL_ERROR "Could not find needed header - ${HEADER}") + endif(NOT FOUND_${HEADER}) +endforeach(HEADER) + +set(MATH_LIBRARIES "m" CACHE STRING "math library") +mark_as_advanced( MATH_LIBRARIES ) +include(CheckLibraryExists) +foreach(FUNC sin cos) + check_library_exists(${MATH_LIBRARIES} ${FUNC} "" FOUND_${FUNC}_${MATH_LIBRARIES}) + if(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) + 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}) + +###################################### +# Generate Basic Style files +###################################### +include(StyleHeaderUtils) +RegisterStyles(${LAMMPS_SOURCE_DIR}) + +############################################## +# add sources of enabled packages +############################################ +foreach(PKG ${PACKAGES} ${USER-PACKAGES}) + if(ENABLE_${PKG}) + set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) + + # detects styles in package and adds them to global list + RegisterStyles(${${PKG}_SOURCES_DIR}) + + file(GLOB ${PKG}_SOURCES ${${PKG}_SOURCES_DIR}/*.cpp) + list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) + include_directories(${${PKG}_SOURCES_DIR}) + endif() +endforeach() + +############################################## +# add lib sources of (simple) enabled packages +############################################ +foreach(SIMPLE_LIB REAX MEAM POEMS USER-ATC USER-AWPMD USER-COLVARS USER-H5MD + USER-MOLFILE USER-QMMM) + if(ENABLE_${SIMPLE_LIB}) + string(REGEX REPLACE "^USER-" "" SIMPLE_LIB "${SIMPLE_LIB}") + string(TOLOWER "${SIMPLE_LIB}" INC_DIR) + file(GLOB_RECURSE ${SIMPLE_LIB}_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.F + ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.c ${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}/*.cpp) + list(APPEND LIB_SOURCES ${${SIMPLE_LIB}_SOURCES}) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/${INC_DIR}) + endif() +endforeach() + ###################################################################### # packages which selectively include variants based on enabled styles # e.g. accelerator packages ###################################################################### - if(ENABLE_USER-OMP) set(USER-OMP_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/USER-OMP) set(USER-OMP_SOURCES ${USER-OMP_SOURCES_DIR}/thr_data.cpp @@ -371,27 +361,39 @@ if(ENABLE_USER-OMP) endif() if(ENABLE_KOKKOS) - set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) - set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/atom_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/atom_vec_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/comm_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/comm_tiled_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/neighbor_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/neigh_list_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/neigh_bond_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/fix_nh_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/domain_kokkos.cpp - ${KOKKOS_PKG_SOURCES_DIR}/modify_kokkos.cpp) - set_property(GLOBAL PROPERTY "KOKKOS_PKG_SOURCES" "${KOKKOS_PKG_SOURCES}") + set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) + set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) + add_definitions(-DLMP_KOKKOS) + add_subdirectory(${LAMMPS_LIB_KOKKOS_SRC_DIR} ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - # detects styles which have KOKKOS version - RegisterStylesExt(${KOKKOS_PKG_SOURCES_DIR} kokkos KOKKOS_PKG_SOURCES) + set(Kokkos_INCLUDE_DIRS ${LAMMPS_LIB_KOKKOS_SRC_DIR}/core/src + ${LAMMPS_LIB_KOKKOS_SRC_DIR}/containers/src + ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src + ${LAMMPS_LIB_KOKKOS_BIN_DIR}) + include_directories(${Kokkos_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS kokkos) - get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) + set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) + set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/atom_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/atom_vec_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/comm_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/comm_tiled_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neighbor_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neigh_list_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/neigh_bond_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/fix_nh_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/domain_kokkos.cpp + ${KOKKOS_PKG_SOURCES_DIR}/modify_kokkos.cpp) + set_property(GLOBAL PROPERTY "KOKKOS_PKG_SOURCES" "${KOKKOS_PKG_SOURCES}") - list(APPEND LIB_SOURCES ${KOKKOS_PKG_SOURCES}) - include_directories(${KOKKOS_PKG_SOURCES_DIR}) + # detects styles which have KOKKOS version + RegisterStylesExt(${KOKKOS_PKG_SOURCES_DIR} kokkos KOKKOS_PKG_SOURCES) + + get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) + + list(APPEND LIB_SOURCES ${KOKKOS_PKG_SOURCES}) + include_directories(${KOKKOS_PKG_SOURCES_DIR}) endif() if(ENABLE_OPT) @@ -487,11 +489,12 @@ GenerateStyleHeaders(${LAMMPS_STYLE_HEADERS_DIR}) include_directories(${LAMMPS_SOURCE_DIR}) include_directories(${LAMMPS_STYLE_HEADERS_DIR}) - +########################################### +# Actually add executable and lib to build +############################################ add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) - if(INSTALL_LIB) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) @@ -501,9 +504,11 @@ endif() add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) - install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) +################################## +# Print package summary +################################## foreach(PKG ${PACKAGES} ${USER-PACKAGES} ${ACCEL_PACKAGES}) if(ENABLE_${PKG}) message(STATUS "Building package: ${PKG}") From 488609a5fdfabbf97e206277b81aa15660671f0b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 19 Jul 2017 18:54:15 -0600 Subject: [PATCH 175/293] make FFT a selective option --- cmake/CMakeLists.txt | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 262857de16..e8afb6fb56 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -123,15 +123,14 @@ if(ENABLE_USER-OMP OR ENABLE_KOKKOS OR ENABLE_USER-INTEL) endif() if(ENABLE_KSPACE) - foreach(FFT FFTW3 MKL FFTW2) - find_package(${FFT}) - if(${FFT}_FOUND) - add_definitions(-DFFT_${FFT}) - include_directories(${${FFT}_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${${FFT}_LIBRARIES}) - break() - endif() - endforeach() + set(FFT "KISSFFT" CACHE STRING "FFT library for KSPACE package") + set_property(CACHE FFT PROPERTY STRINGS KISSFFT FFTW3 MKL FFTW2) + if(NOT FFT STREQUAL "KISSFFT") + find_package(${FFT} REQUIRED) + add_definitions(-DFFT_${FFT}) + include_directories(${${FFT}_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${${FFT}_LIBRARIES}) + endif() set(PACK_OPTIMIZATION "PACK_ARRAY" CACHE STRING "Optimization for FFT") set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) if(NOT PACK_OPTIMIZATION STREQUAL "PACK_ARRAY") From 187a80be7738b37c3c398d9274a23ade00cf9661 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Wed, 19 Jul 2017 22:21:49 -0400 Subject: [PATCH 176/293] Add forgotten decode() in Install.py --- lib/colvars/Install.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index a367b8eeed..5b6b15dc3b 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -126,9 +126,9 @@ fp.close() print("Building lib%s.a ..." % lib) cmd = ["make -f Makefile.auto clean"] -print(subprocess.check_output(cmd, shell=True)) +print(subprocess.check_output(cmd, shell=True).decode()) cmd = ["make -f Makefile.auto -j12"] -print(subprocess.check_output(cmd, shell=True)) +print(subprocess.check_output(cmd, shell=True).decode()) if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) From ef9fb944c7272915b82832f4ac60749e5e0d96a6 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 20 Jul 2017 10:52:24 -0400 Subject: [PATCH 177/293] Detect number of processors for make --- lib/colvars/Install.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index 5b6b15dc3b..af658fa26c 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -124,10 +124,16 @@ fp.close() # make the library via Makefile.auto +try: + import multiprocessing + n_cpus = multiprocessing.cpu_count() +except: + n_cpus = 1 + print("Building lib%s.a ..." % lib) cmd = ["make -f Makefile.auto clean"] print(subprocess.check_output(cmd, shell=True).decode()) -cmd = ["make -f Makefile.auto -j12"] +cmd = ["make -f Makefile.auto -j%d" % n_cpus] print(subprocess.check_output(cmd, shell=True).decode()) if os.path.exists("lib%s.a" % lib): print("Build was successful") From 8499e72cdc91684549d77f4e154103a2df33af61 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 12:11:46 -0400 Subject: [PATCH 178/293] updates to USER-REAXC code in USER-OMP from Chris Knight. addresses issues with multiple threads in use --- src/USER-OMP/reaxc_bonds_omp.cpp | 2 +- src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp | 8 -------- src/USER-OMP/reaxc_multi_body_omp.cpp | 9 --------- src/USER-OMP/reaxc_nonbonded_omp.cpp | 9 --------- src/USER-OMP/reaxc_torsion_angles_omp.cpp | 5 ----- src/USER-OMP/reaxc_valence_angles_omp.cpp | 9 --------- 6 files changed, 1 insertion(+), 41 deletions(-) diff --git a/src/USER-OMP/reaxc_bonds_omp.cpp b/src/USER-OMP/reaxc_bonds_omp.cpp index d079db6674..2b7ab7e5e8 100644 --- a/src/USER-OMP/reaxc_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_bonds_omp.cpp @@ -86,7 +86,7 @@ void BondsOMP( reax_system *system, control_params *control, class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, natoms, + system->pair_ptr->vflag_either, system->N, system->pair_ptr->eatom, system->pair_ptr->vatom, thr); #if defined(_OPENMP) diff --git a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp index be1444824b..c6486ae8e6 100644 --- a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp @@ -102,11 +102,6 @@ void Hydrogen_BondsOMP( reax_system *system, control_params *control, class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, - natoms, system->pair_ptr->eatom, - system->pair_ptr->vatom, thr); - /* loops below discover the Hydrogen bonds between i-j-k triplets. here j is H atom and there has to be some bond between i and j. Hydrogen bond is between j and k. @@ -242,9 +237,6 @@ void Hydrogen_BondsOMP( reax_system *system, control_params *control, { data->my_en.e_hb += e_hb_thr; } - - pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, thr); } #ifdef OMP_TIMING diff --git a/src/USER-OMP/reaxc_multi_body_omp.cpp b/src/USER-OMP/reaxc_multi_body_omp.cpp index 13d250750b..27779f8e85 100644 --- a/src/USER-OMP/reaxc_multi_body_omp.cpp +++ b/src/USER-OMP/reaxc_multi_body_omp.cpp @@ -59,7 +59,6 @@ void Atom_EnergyOMP( reax_system *system, control_params *control, const double p_ovun7 = system->reax_param.gp.l[8]; const double p_ovun8 = system->reax_param.gp.l[9]; - const int natoms = system->n; reax_list *bonds = (*lists) + BONDS; double total_Elp = 0.0; @@ -99,10 +98,6 @@ void Atom_EnergyOMP( reax_system *system, control_params *control, pair_reax_ptr = static_cast(system->pair_ptr); class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, natoms, - system->pair_ptr->eatom, system->pair_ptr->vatom, thr); - #if defined(_OPENMP) #pragma omp for schedule(guided) #endif @@ -280,10 +275,6 @@ void Atom_EnergyOMP( reax_system *system, control_params *control, (workspace->Delta[j] - dfvl*workspace->Delta_lp_temp[j]); // UnCoor-2b } } - - pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, thr); - } data->my_en.e_lp += total_Elp; diff --git a/src/USER-OMP/reaxc_nonbonded_omp.cpp b/src/USER-OMP/reaxc_nonbonded_omp.cpp index 0c595e07df..d131195ca0 100644 --- a/src/USER-OMP/reaxc_nonbonded_omp.cpp +++ b/src/USER-OMP/reaxc_nonbonded_omp.cpp @@ -87,10 +87,6 @@ void vdW_Coulomb_Energy_OMP( reax_system *system, control_params *control, pair_reax_ptr = static_cast(system->pair_ptr); class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, - natoms, system->pair_ptr->eatom, - system->pair_ptr->vatom, thr); e_core = 0; e_vdW = 0; e_lg = 0; @@ -291,11 +287,6 @@ void Tabulated_vdW_Coulomb_Energy_OMP(reax_system *system,control_params *contro pair_reax_ptr = static_cast(system->pair_ptr); class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, - natoms, system->pair_ptr->eatom, - system->pair_ptr->vatom, thr); - #if defined(_OPENMP) #pragma omp for schedule(guided) #endif diff --git a/src/USER-OMP/reaxc_torsion_angles_omp.cpp b/src/USER-OMP/reaxc_torsion_angles_omp.cpp index b6920c6709..4227f62763 100644 --- a/src/USER-OMP/reaxc_torsion_angles_omp.cpp +++ b/src/USER-OMP/reaxc_torsion_angles_omp.cpp @@ -124,11 +124,6 @@ void Torsion_AnglesOMP( reax_system *system, control_params *control, pair_reax_ptr = static_cast(system->pair_ptr); class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, - system->N, system->pair_ptr->eatom, - system->pair_ptr->vatom, thr); - #if defined(_OPENMP) #pragma omp for schedule(static) #endif diff --git a/src/USER-OMP/reaxc_valence_angles_omp.cpp b/src/USER-OMP/reaxc_valence_angles_omp.cpp index 888eeab4a1..6c15a529d3 100644 --- a/src/USER-OMP/reaxc_valence_angles_omp.cpp +++ b/src/USER-OMP/reaxc_valence_angles_omp.cpp @@ -173,12 +173,6 @@ void Valence_AnglesOMP( reax_system *system, control_params *control, pair_reax_ptr = static_cast(system->pair_ptr); class ThrData *thr = pair_reax_ptr->getFixOMP()->get_thr(tid); - pair_reax_ptr->ev_setup_thr_proxy(system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, - system->N, system->pair_ptr->eatom, - system->pair_ptr->vatom, thr); - - // Run through a minimal for(jnum_intrs / nthreads; @@ -600,9 +594,6 @@ void Valence_AnglesOMP( reax_system *system, control_params *control, Set_End_Index(pi, my_offset, thb_intrs ); } // for(pi) } // for(j) - - pair_reax_ptr->reduce_thr_proxy(system->pair_ptr, system->pair_ptr->eflag_either, - system->pair_ptr->vflag_either, thr); } // end omp parallel data->my_en.e_ang = total_Eang; From a351977c59040745d5fcd1658441a1316ad37c8e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 12:55:55 -0400 Subject: [PATCH 179/293] update manual links that got broken when removing and renumbering a section --- doc/src/Manual.txt | 1 - doc/src/Section_accelerate.txt | 10 +- doc/src/Section_errors.txt | 2 +- doc/src/Section_howto.txt | 10 +- doc/src/Section_packages.txt | 30 +- doc/src/Section_python.txt | 6 +- doc/src/Section_start.txt | 12 +- doc/src/accelerate_gpu.txt | 10 +- doc/src/accelerate_intel.txt | 10 +- doc/src/accelerate_kokkos.txt | 24 +- doc/src/accelerate_omp.txt | 6 +- doc/src/accelerate_opt.txt | 4 +- doc/src/angle_charmm.txt | 2 +- doc/src/angle_class2.txt | 2 +- doc/src/angle_cosine.txt | 2 +- doc/src/angle_cosine_delta.txt | 2 +- doc/src/angle_cosine_periodic.txt | 2 +- doc/src/angle_cosine_shift.txt | 2 +- doc/src/angle_cosine_shift_exp.txt | 2 +- doc/src/angle_cosine_squared.txt | 2 +- doc/src/angle_fourier.txt | 2 +- doc/src/angle_fourier_simple.txt | 2 +- doc/src/angle_harmonic.txt | 2 +- doc/src/angle_quartic.txt | 2 +- doc/src/angle_table.txt | 2 +- doc/src/balance.txt | 2 +- doc/src/bond_class2.txt | 2 +- doc/src/bond_fene.txt | 2 +- doc/src/bond_fene_expand.txt | 2 +- doc/src/bond_harmonic.txt | 2 +- doc/src/bond_harmonic_shift.txt | 2 +- doc/src/bond_harmonic_shift_cut.txt | 2 +- doc/src/bond_morse.txt | 2 +- doc/src/bond_nonlinear.txt | 2 +- doc/src/bond_quartic.txt | 2 +- doc/src/bond_table.txt | 2 +- doc/src/compute_pressure.txt | 2 +- doc/src/compute_temp.txt | 2 +- doc/src/compute_temp_partial.txt | 2 +- doc/src/dihedral_charmm.txt | 2 +- doc/src/dihedral_class2.txt | 2 +- doc/src/dihedral_cosine_shift_exp.txt | 2 +- doc/src/dihedral_fourier.txt | 2 +- doc/src/dihedral_harmonic.txt | 2 +- doc/src/dihedral_helix.txt | 2 +- doc/src/dihedral_multi_harmonic.txt | 2 +- doc/src/dihedral_nharmonic.txt | 2 +- doc/src/dihedral_opls.txt | 2 +- doc/src/dihedral_quadratic.txt | 2 +- doc/src/echo.txt | 2 +- doc/src/fix_addforce.txt | 2 +- doc/src/fix_aveforce.txt | 2 +- doc/src/fix_deform.txt | 2 +- doc/src/fix_enforce2d.txt | 2 +- doc/src/fix_freeze.txt | 2 +- doc/src/fix_gravity.txt | 2 +- doc/src/fix_langevin.txt | 2 +- doc/src/fix_momentum.txt | 2 +- doc/src/fix_nh.txt | 2 +- doc/src/fix_nph_asphere.txt | 2 +- doc/src/fix_nph_body.txt | 2 +- doc/src/fix_nph_sphere.txt | 2 +- doc/src/fix_nphug.txt | 2 +- doc/src/fix_npt_asphere.txt | 2 +- doc/src/fix_npt_body.txt | 2 +- doc/src/fix_npt_sphere.txt | 2 +- doc/src/fix_nve.txt | 2 +- doc/src/fix_nve_asphere.txt | 2 +- doc/src/fix_nve_sphere.txt | 2 +- doc/src/fix_nvt_asphere.txt | 2 +- doc/src/fix_nvt_body.txt | 2 +- doc/src/fix_nvt_sllod.txt | 2 +- doc/src/fix_nvt_sphere.txt | 2 +- doc/src/fix_qeq_comb.txt | 2 +- doc/src/fix_qeq_reax.txt | 2 +- doc/src/fix_reax_bonds.txt | 2 +- doc/src/fix_reaxc_species.txt | 2 +- doc/src/fix_rigid.txt | 2 +- doc/src/fix_setforce.txt | 2 +- doc/src/fix_shake.txt | 2 +- doc/src/fix_wall_reflect.txt | 2 +- doc/src/improper_class2.txt | 2 +- doc/src/improper_cossq.txt | 2 +- doc/src/improper_cvff.txt | 2 +- doc/src/improper_fourier.txt | 2 +- doc/src/improper_harmonic.txt | 2 +- doc/src/improper_ring.txt | 2 +- doc/src/improper_umbrella.txt | 2 +- doc/src/jump.txt | 4 +- doc/src/log.txt | 2 +- doc/src/neb.txt | 2 +- doc/src/neighbor.txt | 2 +- doc/src/next.txt | 2 +- doc/src/package.txt | 28 +- doc/src/pair_adp.txt | 2 +- doc/src/pair_agni.txt | 2 +- doc/src/pair_airebo.txt | 2 +- doc/src/pair_beck.txt | 2 +- doc/src/pair_born.txt | 2 +- doc/src/pair_brownian.txt | 2 +- doc/src/pair_buck.txt | 2 +- doc/src/pair_buck_long.txt | 2 +- doc/src/pair_charmm.txt | 2 +- doc/src/pair_class2.txt | 2 +- doc/src/pair_colloid.txt | 2 +- doc/src/pair_comb.txt | 2 +- doc/src/pair_coul.txt | 2 +- doc/src/pair_dipole.txt | 2 +- doc/src/pair_dpd.txt | 2 +- doc/src/pair_eam.txt | 2 +- doc/src/pair_edip.txt | 2 +- doc/src/pair_eim.txt | 2 +- doc/src/pair_gayberne.txt | 2 +- doc/src/pair_gran.txt | 2 +- doc/src/pair_gromacs.txt | 2 +- doc/src/pair_hbond_dreiding.txt | 2 +- doc/src/pair_hybrid.txt | 2 +- doc/src/pair_lj.txt | 2 +- doc/src/pair_lj96.txt | 2 +- doc/src/pair_lj_cubic.txt | 2 +- doc/src/pair_lj_expand.txt | 2 +- doc/src/pair_lj_long.txt | 2 +- doc/src/pair_lj_smooth.txt | 2 +- doc/src/pair_lj_smooth_linear.txt | 2 +- doc/src/pair_lj_soft.txt | 2 +- doc/src/pair_lubricate.txt | 2 +- doc/src/pair_meam_spline.txt | 2 +- doc/src/pair_morse.txt | 2 +- doc/src/pair_nb3b_harmonic.txt | 2 +- doc/src/pair_nm.txt | 2 +- doc/src/pair_peri.txt | 2 +- doc/src/pair_reaxc.txt | 2 +- doc/src/pair_resquared.txt | 2 +- doc/src/pair_sdk.txt | 2 +- doc/src/pair_soft.txt | 2 +- doc/src/pair_sw.txt | 2 +- doc/src/pair_table.txt | 2 +- doc/src/pair_tersoff.txt | 2 +- doc/src/pair_tersoff_mod.txt | 2 +- doc/src/pair_tersoff_zbl.txt | 2 +- doc/src/pair_thole.txt | 2 +- doc/src/pair_vashishta.txt | 2 +- doc/src/pair_yukawa.txt | 2 +- doc/src/pair_yukawa_colloid.txt | 2 +- doc/src/pair_zbl.txt | 2 +- doc/src/partition.txt | 4 +- doc/src/prd.txt | 2 +- doc/src/processors.txt | 12 +- doc/src/read_data.txt | 2 +- doc/src/read_restart.txt | 2 +- doc/src/region.txt | 2 +- doc/src/restart.txt | 2 +- doc/src/run_style.txt | 6 +- doc/src/suffix.txt | 4 +- doc/src/temper.txt | 4 +- doc/src/thermo_style.txt | 2 +- doc/src/timer.txt | 2 +- doc/src/variable.txt | 8 +- doc/src/write_data.txt | 2 +- doc/src/write_restart.txt | 2 +- src/Make.py | 2378 ------------------------- 161 files changed, 237 insertions(+), 2616 deletions(-) delete mode 100755 src/Make.py diff --git a/doc/src/Manual.txt b/doc/src/Manual.txt index 36391731d0..359aa19edb 100644 --- a/doc/src/Manual.txt +++ b/doc/src/Manual.txt @@ -261,7 +261,6 @@ END_RST --> :link(start_6,Section_start.html#start_6) :link(start_7,Section_start.html#start_7) :link(start_8,Section_start.html#start_8) -:link(start_9,Section_start.html#start_9) :link(cmd_1,Section_commands.html#cmd_1) :link(cmd_2,Section_commands.html#cmd_2) diff --git a/doc/src/Section_accelerate.txt b/doc/src/Section_accelerate.txt index 64b80c1a55..8812358886 100644 --- a/doc/src/Section_accelerate.txt +++ b/doc/src/Section_accelerate.txt @@ -56,7 +56,7 @@ timings; you can simply extrapolate from short runs. For the set of runs, look at the timing data printed to the screen and log file at the end of each LAMMPS run. "This -section"_Section_start.html#start_8 of the manual has an overview. +section"_Section_start.html#start_7 of the manual has an overview. Running on one (or a few processors) should give a good estimate of the serial performance and what portions of the timestep are taking @@ -226,16 +226,16 @@ re-build LAMMPS | make machine | prepare and test a regular LAMMPS simulation | lmp_machine -in in.script; mpirun -np 32 lmp_machine -in in.script | -enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_7, | +enable specific accelerator support via '-k on' "command-line switch"_Section_start.html#start_6, | only needed for KOKKOS package | -set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_7 or "package"_package.html command, | +set any needed options for the package via "-pk" "command-line switch"_Section_start.html#start_6 or "package"_package.html command, | only if defaults need to be changed | -use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_7 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu +use accelerated styles in your input via "-sf" "command-line switch"_Section_start.html#start_6 or "suffix"_suffix.html command | lmp_machine -in in.script -sf gpu :tb(c=2,s=|) Note that the first 4 steps can be done as a single command, using the src/Make.py tool. This tool is discussed in "Section -2.4"_Section_start.html#start_4 of the manual, and its use is +4"_Section_packages.html of the manual, and its use is illustrated in the individual accelerator sections. Typically these steps only need to be done once, to create an executable that uses one or more accelerator packages. diff --git a/doc/src/Section_errors.txt b/doc/src/Section_errors.txt index 40e61a248e..408c01d52c 100644 --- a/doc/src/Section_errors.txt +++ b/doc/src/Section_errors.txt @@ -71,7 +71,7 @@ style", with ... being fix, compute, pair, etc, it means that you mistyped the style name or that the command is part of an optional package which was not compiled into your executable. The list of available styles in your executable can be listed by using "the -h -command-line argument"_Section_start.html#start_7. The installation +command-line argument"_Section_start.html#start_6. The installation and compilation of optional packages is explained in the "installation instructions"_Section_start.html#start_3. diff --git a/doc/src/Section_howto.txt b/doc/src/Section_howto.txt index f2f2561af8..6d699fe24b 100644 --- a/doc/src/Section_howto.txt +++ b/doc/src/Section_howto.txt @@ -54,7 +54,7 @@ restart files can be saved to disk using the "restart"_restart.html command. At a later time, these binary files can be read via a "read_restart"_read_restart.html command in a new script. Or they can be converted to text data files using the "-r command-line -switch"_Section_start.html#start_7 and read by a +switch"_Section_start.html#start_6 and read by a "read_data"_read_data.html command in a new script. Here we give examples of 2 scripts that read either a binary restart @@ -337,7 +337,7 @@ All of the above examples work whether you are running on 1 or multiple processors, but assumed you are running LAMMPS on a single partition of processors. LAMMPS can be run on multiple partitions via the "-partition" command-line switch as described in "this -section"_Section_start.html#start_7 of the manual. +section"_Section_start.html#start_6 of the manual. In the last 2 examples, if LAMMPS were run on 3 partitions, the same scripts could be used if the "index" and "loop" variables were @@ -387,7 +387,7 @@ for more info on packages. In all these cases, you must run with one or more processors per replica. The processors assigned to each replica are determined at run-time by using the "-partition command-line -switch"_Section_start.html#start_7 to launch LAMMPS on multiple +switch"_Section_start.html#start_6 to launch LAMMPS on multiple partitions, which in this context are the same as replicas. E.g. these commands: @@ -395,7 +395,7 @@ mpirun -np 16 lmp_linux -partition 8x2 -in in.temper mpirun -np 8 lmp_linux -partition 8x1 -in in.neb :pre would each run 8 replicas, on either 16 or 8 processors. Note the use -of the "-in command-line switch"_Section_start.html#start_7 to specify +of the "-in command-line switch"_Section_start.html#start_6 to specify the input script which is required when running in multi-replica mode. Also note that with MPI installed on a machine (e.g. your desktop), @@ -1872,7 +1872,7 @@ void lammps_free(void *) :pre The lammps_open() function is used to initialize LAMMPS, passing in a list of strings as if they were "command-line -arguments"_Section_start.html#start_7 when LAMMPS is run in +arguments"_Section_start.html#start_6 when LAMMPS is run in stand-alone mode from the command line, and a MPI communicator for LAMMPS to run under. It returns a ptr to the LAMMPS object that is created, and which is used in subsequent library calls. The diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt index 76f88b8ab8..54a2685b86 100644 --- a/doc/src/Section_packages.txt +++ b/doc/src/Section_packages.txt @@ -369,7 +369,7 @@ suffix in their style name. "Section 5.3.1"_accelerate_gpu.html gives details of what hardware and Cuda software is required on your system, and details on how to build and use this package. Its styles can be invoked at run time via the "-sf gpu" or "-suffix gpu" "command-line -switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS +switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS package, which has GPU-enabled styles. [Authors:] Mike Brown (Intel) while at Sandia and ORNL and Trung Nguyen @@ -427,8 +427,8 @@ src/GPU/README lib/gpu/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.1"_accelerate_gpu.html -"Section 2.7 -sf gpu"_Section_start.html#start_7 -"Section 2.7 -pk gpu"_Section_start.html#start_7 +"Section 2.6 -sf gpu"_Section_start.html#start_6 +"Section 2.6 -pk gpu"_Section_start.html#start_6 "package gpu"_package.html Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (g) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -529,7 +529,7 @@ style name. "Section 5.3.3"_accelerate_kokkos.html gives details of what hardware and software is required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf kk" or "-suffix kk" "command-line -switches"_Section_start.html#start_7. Also see the "GPU"_#GPU, +switches"_Section_start.html#start_6. Also see the "GPU"_#GPU, "OPT"_#OPT, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs, KNLs, and GPUs. @@ -597,9 +597,9 @@ src/KOKKOS/README lib/kokkos/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.3"_accelerate_kokkos.html -"Section 2.7 -k on ..."_Section_start.html#start_7 -"Section 2.7 -sf kk"_Section_start.html#start_7 -"Section 2.7 -pk kokkos"_Section_start.html#start_7 +"Section 2.6 -k on ..."_Section_start.html#start_6 +"Section 2.6 -sf kk"_Section_start.html#start_6 +"Section 2.6 -pk kokkos"_Section_start.html#start_6 "package kokkos"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (k) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -926,7 +926,7 @@ CHARMM, and Morse potentials. The styles have an "opt" suffix in their style name. "Section 5.3.5"_accelerate_opt.html gives details of how to build and use this package. Its styles can be invoked at run time via the "-sf opt" or "-suffix opt" "command-line -switches"_Section_start.html#start_7. See also the "KOKKOS"_#KOKKOS, +switches"_Section_start.html#start_6. See also the "KOKKOS"_#KOKKOS, "USER-INTEL"_#USER-INTEL, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPU performance. @@ -953,7 +953,7 @@ CCFLAGS: add -restrict :ul src/OPT: filenames -> commands "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.5"_accelerate_opt.html -"Section 2.7 -sf opt"_Section_start.html#start_7 +"Section 2.6 -sf opt"_Section_start.html#start_6 Pair Styles section of "Section 3.5"_Section_commands.html#cmd_5 for pair styles followed by (t) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul @@ -1863,7 +1863,7 @@ All of them have an "intel" in their style name. "Section 5.3.2"_accelerate_intel.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf intel" or -"-suffix intel" "command-line switches"_Section_start.html#start_7. +"-suffix intel" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-OMP"_#USER-OMP packages, which have styles optimized for CPUs and KNLs. @@ -1919,8 +1919,8 @@ src/USER-INTEL: filenames -> commands src/USER-INTEL/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.2"_accelerate_gpu.html -"Section 2.7 -sf intel"_Section_start.html#start_7 -"Section 2.7 -pk intel"_Section_start.html#start_7 +"Section 2.6 -sf intel"_Section_start.html#start_6 +"Section 2.6 -pk intel"_Section_start.html#start_6 "package intel"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (i) src/USER-INTEL/TEST @@ -2193,7 +2193,7 @@ via OpenMP directives. All of them have an "omp" in their style name. "Section 5.3.4"_accelerate_omp.html gives details of what hardware and compilers are required on your system, and how to build and use this package. Its styles can be invoked at run time via the "-sf omp" or -"-suffix omp" "command-line switches"_Section_start.html#start_7. +"-suffix omp" "command-line switches"_Section_start.html#start_6. Also see the "KOKKOS"_#KOKKOS, "OPT"_#OPT, and "USER-INTEL"_#USER-INTEL packages, which have styles optimized for CPUs. @@ -2226,8 +2226,8 @@ src/USER-OMP: filenames -> commands src/USER-OMP/README "Section 5.3"_Section_accelerate.html#acc_3 "Section 5.3.4"_accelerate_omp.html -"Section 2.7 -sf omp"_Section_start.html#start_7 -"Section 2.7 -pk omp"_Section_start.html#start_7 +"Section 2.6 -sf omp"_Section_start.html#start_6 +"Section 2.6 -pk omp"_Section_start.html#start_6 "package omp"_package.html Styles sections of "Section 3.5"_Section_commands.html#cmd_5 for styles followed by (o) "Benchmarks page"_http://lammps.sandia.gov/bench.html of web site :ul diff --git a/doc/src/Section_python.txt b/doc/src/Section_python.txt index 1e67fca321..f4b6bdad97 100644 --- a/doc/src/Section_python.txt +++ b/doc/src/Section_python.txt @@ -198,7 +198,7 @@ file and the shared library. 11.3 Building LAMMPS as a shared library :link(py_3),h4 Instructions on how to build LAMMPS as a shared library are given in -"Section 2.5"_Section_start.html#start_5. A shared library is one +"Section 2.4"_Section_start.html#start_4. A shared library is one that is dynamically loadable, which is what Python requires to wrap LAMMPS. On Linux this is a library file that ends in ".so", not ".a". @@ -217,7 +217,7 @@ NOTE: If you are building LAMMPS with an MPI or FFT library or other auxiliary libraries (used by various packages), then all of these extra libraries must also be shared libraries. If the LAMMPS shared-library build fails with an error complaining about this, see -"Section 2.5"_Section_start.html#start_5 for more details. +"Section 2.4"_Section_start.html#start_4 for more details. :line @@ -439,7 +439,7 @@ first importing from the lammps.py file: >>> CDLL("liblammps.so") :pre If an error occurs, carefully go thru the steps in "Section -2.5"_Section_start.html#start_5 and above about building a shared +2.4"_Section_start.html#start_4 and above about building a shared library and about insuring Python can find the necessary two files it needs. diff --git a/doc/src/Section_start.txt b/doc/src/Section_start.txt index b7a471c3fa..c798005f5e 100644 --- a/doc/src/Section_start.txt +++ b/doc/src/Section_start.txt @@ -14,11 +14,11 @@ experienced users. 2.1 "What's in the LAMMPS distribution"_#start_1 2.2 "Making LAMMPS"_#start_2 2.3 "Making LAMMPS with optional packages"_#start_3 -2.5 "Building LAMMPS as a library"_#start_4 -2.6 "Running LAMMPS"_#start_5 -2.7 "Command-line options"_#start_6 -2.8 "Screen output"_#start_7 -2.9 "Tips for users of previous versions"_#start_8 :all(b) +2.4 "Building LAMMPS as a library"_#start_4 +2.5 "Running LAMMPS"_#start_5 +2.6 "Command-line options"_#start_6 +2.7 "Screen output"_#start_7 +2.8 "Tips for users of previous versions"_#start_8 :all(b) :line @@ -714,7 +714,7 @@ type lmp_machine -h :pre to run your executable with the optional "-h command-line -switch"_#start_7 for "help", which will list the styles and commands +switch"_#start_6 for "help", which will list the styles and commands known to your executable, and immediately exit. :line diff --git a/doc/src/accelerate_gpu.txt b/doc/src/accelerate_gpu.txt index 2ac7d62f6c..68e9fa477a 100644 --- a/doc/src/accelerate_gpu.txt +++ b/doc/src/accelerate_gpu.txt @@ -54,7 +54,7 @@ specify the # of GPUs per node use GPU styles in your input script :ul The latter two steps can be done using the "-pk gpu" and "-sf gpu" -"command-line switches"_Section_start.html#start_7 respectively. Or +"command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package gpu"_package.html or "suffix gpu"_suffix.html commands respectively to your input script. @@ -75,7 +75,7 @@ This requires two steps (a,b): build the GPU library, then build LAMMPS with the GPU package. You can do both these steps in one line, using the src/Make.py script, -described in "Section 2.4"_Section_start.html#start_4 of the manual. +described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. If run from the src directory, this command will create src/lmp_gpu using src/MAKE/Makefile.mpi as the starting Makefile.machine: @@ -151,9 +151,9 @@ automatically if you create more MPI tasks/node than there are GPUs/mode. E.g. with 8 MPI tasks/node and 2 GPUs, each GPU will be shared by 4 MPI tasks. -Use the "-sf gpu" "command-line switch"_Section_start.html#start_7, +Use the "-sf gpu" "command-line switch"_Section_start.html#start_6, which will automatically append "gpu" to styles that support it. Use -the "-pk gpu Ng" "command-line switch"_Section_start.html#start_7 to +the "-pk gpu Ng" "command-line switch"_Section_start.html#start_6 to set Ng = # of GPUs/node to use. lmp_machine -sf gpu -pk gpu 1 -in in.script # 1 MPI task uses 1 GPU @@ -188,7 +188,7 @@ pair_style lj/cut/gpu 2.5 :pre You must also use the "package gpu"_package.html command to enable the GPU package, unless the "-sf gpu" or "-pk gpu" "command-line -switches"_Section_start.html#start_7 were used. It specifies the +switches"_Section_start.html#start_6 were used. It specifies the number of GPUs/node to use, as well as other options. [Speed-ups to expect:] diff --git a/doc/src/accelerate_intel.txt b/doc/src/accelerate_intel.txt index 155e29e367..74ae9d9a42 100644 --- a/doc/src/accelerate_intel.txt +++ b/doc/src/accelerate_intel.txt @@ -226,7 +226,7 @@ source /opt/intel/parallel_studio_xe_2016.3.067/psxevars.sh make intel_cpu_intelmpi :pre Alternatively, the build can be accomplished with the src/Make.py -script, described in "Section 2.4"_Section_start.html#start_4 of the +script, described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. For an example: Make.py -v -p intel omp -intel cpu -a file intel_cpu_intelmpi :pre @@ -301,7 +301,7 @@ Hyper-Threading technology disabled. To enable USER-INTEL optimizations for all available styles used in the input script, the "-sf intel" -"command-line switch"_Section_start.html#start_7 can be used without +"command-line switch"_Section_start.html#start_6 can be used without any requirement for editing the input script. This switch will automatically append "intel" to styles that support it. It also invokes a default command: "package intel 1"_package.html. This @@ -314,7 +314,7 @@ support, that 1 coprocessor per node will be used with automatic balancing of work between the CPU and the coprocessor. You can specify different options for the USER-INTEL package by using -the "-pk intel Nphi" "command-line switch"_Section_start.html#start_7 +the "-pk intel Nphi" "command-line switch"_Section_start.html#start_6 with keyword/value pairs as specified in the documentation. Here, Nphi = # of Xeon Phi coprocessors/node (ignored without offload support). Common options to the USER-INTEL package include {omp} to @@ -387,7 +387,7 @@ can performed automatically by using "-sf hybrid intel opt" or and "omp" suffixes can be appended manually in the input script. For the latter, the "package omp"_package.html command must be in the input script or the "-pk omp Nt" "command-line -switch"_Section_start.html#start_7 must be used where Nt is the +switch"_Section_start.html#start_6 must be used where Nt is the number of OpenMP threads. The number of OpenMP threads should not be set differently for the different packages. Note that the "suffix hybrid intel omp"_suffix.html command can also be used within the @@ -486,7 +486,7 @@ sorting"_atom_modify.html is changed to 1 so that the per-atom data is effectively sorted at every rebuild of the neighbor lists. All the available coprocessor threads on each Phi will be divided among MPI tasks, unless the {tptask} option of the "-pk intel" "command-line -switch"_Section_start.html#start_7 is used to limit the coprocessor +switch"_Section_start.html#start_6 is used to limit the coprocessor threads per MPI task. [Restrictions:] diff --git a/doc/src/accelerate_kokkos.txt b/doc/src/accelerate_kokkos.txt index 602c3191f6..6ccd695841 100644 --- a/doc/src/accelerate_kokkos.txt +++ b/doc/src/accelerate_kokkos.txt @@ -136,7 +136,7 @@ You must choose at build time whether to build for CPUs (OpenMP), GPUs, or Phi. You can do any of these in one line, using the src/Make.py script, -described in "Section 2.4"_Section_start.html#start_4 of the manual. +described in "Section 4"_Section_packages.html of the manual. Type "Make.py -h" for help. If run from the src directory, these commands will create src/lmp_kokkos_omp, lmp_kokkos_cuda, and lmp_kokkos_phi. Note that the OMP and PHI options use @@ -144,7 +144,7 @@ src/MAKE/Makefile.mpi as the starting Makefile.machine. The CUDA option uses src/MAKE/OPTIONS/Makefile.kokkos_cuda. The latter two steps can be done using the "-k on", "-pk kokkos" and -"-sf kk" "command-line switches"_Section_start.html#start_7 +"-sf kk" "command-line switches"_Section_start.html#start_6 respectively. Or the effect of the "-pk" or "-sf" switches can be duplicated by adding the "package kokkos"_package.html or "suffix kk"_suffix.html commands respectively to your input script. @@ -280,10 +280,10 @@ specify how many Phi coprocessors there are per node; each coprocessors is simply treated as running some number of MPI tasks. You must use the "-k on" "command-line -switch"_Section_start.html#start_7 to enable the KOKKOS package. It +switch"_Section_start.html#start_6 to enable the KOKKOS package. It takes additional arguments for hardware settings appropriate to your system. Those arguments are "documented -here"_Section_start.html#start_7. The two most commonly used +here"_Section_start.html#start_6. The two most commonly used options are: -k on t Nt g Ng :pre @@ -304,12 +304,12 @@ The "-k on" switch also issues a "package kokkos" command (with no additional arguments) which sets various KOKKOS options to default values, as discussed on the "package"_package.html command doc page. -Use the "-sf kk" "command-line switch"_Section_start.html#start_7, +Use the "-sf kk" "command-line switch"_Section_start.html#start_6, which will automatically append "kk" to styles that support it. Use -the "-pk kokkos" "command-line switch"_Section_start.html#start_7 if +the "-pk kokkos" "command-line switch"_Section_start.html#start_6 if you wish to change any of the default "package kokkos"_package.html optionns set by the "-k on" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. @@ -323,7 +323,7 @@ However, when running in MPI-only mode with 1 thread per MPI task, it will typically be faster to use "half" neighbor lists and set the Newton flag to "on", just as is the case for non-accelerated pair styles. You can do this with the "-pk" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. [Or run with the KOKKOS package by editing an input script:] @@ -332,7 +332,7 @@ appropriate thread and GPU values for host=OMP or host=MIC or device=CUDA are the same. You must still use the "-k on" "command-line -switch"_Section_start.html#start_7 to enable the KOKKOS package, and +switch"_Section_start.html#start_6 to enable the KOKKOS package, and specify its additional arguments for hardware options appropriate to your system, as documented above. @@ -343,7 +343,7 @@ pair_style lj/cut/kk 2.5 :pre You only need to use the "package kokkos"_package.html command if you wish to change any of its option defaults, as set by the "-k on" -"command-line switch"_Section_start.html#start_7. +"command-line switch"_Section_start.html#start_6. [Speed-ups to expect:] @@ -389,7 +389,7 @@ If N is the number of physical cores/node, then the number of MPI tasks/node * number of threads/task should not exceed N, and should typically equal N. Note that the default threads/task is 1, as set by the "t" keyword of the "-k" "command-line -switch"_Section_start.html#start_7. If you do not change this, no +switch"_Section_start.html#start_6. If you do not change this, no additional parallelism (beyond MPI) will be invoked on the host CPU(s). @@ -429,7 +429,7 @@ details). The -np setting of the mpirun command should set the number of MPI tasks/node to be equal to the # of physical GPUs on the node. -Use the "-k" "command-line switch"_Section_commands.html#start_7 to +Use the "-k" "command-line switch"_Section_commands.html#start_6 to specify the number of GPUs per node, and the number of threads per MPI task. As above for multi-core CPUs (and no GPU), if N is the number of physical cores/node, then the number of MPI tasks/node * number of diff --git a/doc/src/accelerate_omp.txt b/doc/src/accelerate_omp.txt index c8dd343861..81b7a5adc2 100644 --- a/doc/src/accelerate_omp.txt +++ b/doc/src/accelerate_omp.txt @@ -41,7 +41,7 @@ each MPI task running on a CPU. The lines above illustrate how to include/build with the USER-OMP package in two steps, using the "make" command. Or how to do it with one command via the src/Make.py script, described in "Section -2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for +4"_Section_packages.html of the manual. Type "Make.py -h" for help. Note that the CCFLAGS and LINKFLAGS settings in Makefile.machine must @@ -62,14 +62,14 @@ threads/task should not exceed the physical number of cores (on a node), otherwise performance will suffer. As in the lines above, use the "-sf omp" "command-line -switch"_Section_start.html#start_7, which will automatically append +switch"_Section_start.html#start_6, which will automatically append "omp" to styles that support it. The "-sf omp" switch also issues a default "package omp 0"_package.html command, which will set the number of threads per MPI task via the OMP_NUM_THREADS environment variable. You can also use the "-pk omp Nt" "command-line -switch"_Section_start.html#start_7, to explicitly set Nt = # of OpenMP +switch"_Section_start.html#start_6, to explicitly set Nt = # of OpenMP threads per MPI task to use, as well as additional options. Its syntax is the same as the "package omp"_package.html command whose doc page gives details, including the default values used if it is not diff --git a/doc/src/accelerate_opt.txt b/doc/src/accelerate_opt.txt index 704321ca07..5a2a5eac0a 100644 --- a/doc/src/accelerate_opt.txt +++ b/doc/src/accelerate_opt.txt @@ -36,7 +36,7 @@ None. The lines above illustrate how to build LAMMPS with the OPT package in two steps, using the "make" command. Or how to do it with one command via the src/Make.py script, described in "Section -2.4"_Section_start.html#start_4 of the manual. Type "Make.py -h" for +4"_Section_packages.html of the manual. Type "Make.py -h" for help. Note that if you use an Intel compiler to build with the OPT package, @@ -46,7 +46,7 @@ The Make.py command will add this automatically. [Run with the OPT package from the command line:] As in the lines above, use the "-sf opt" "command-line -switch"_Section_start.html#start_7, which will automatically append +switch"_Section_start.html#start_6, which will automatically append "opt" to styles that support it. [Or run with the OPT package by editing an input script:] diff --git a/doc/src/angle_charmm.txt b/doc/src/angle_charmm.txt index a02e604258..7ff7ef8fd4 100644 --- a/doc/src/angle_charmm.txt +++ b/doc/src/angle_charmm.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_class2.txt b/doc/src/angle_class2.txt index 74f2544cd4..71a508d691 100644 --- a/doc/src/angle_class2.txt +++ b/doc/src/angle_class2.txt @@ -94,7 +94,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine.txt b/doc/src/angle_cosine.txt index 4fb2ccaf7c..c0ce3c9301 100644 --- a/doc/src/angle_cosine.txt +++ b/doc/src/angle_cosine.txt @@ -50,7 +50,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_delta.txt b/doc/src/angle_cosine_delta.txt index 6ab214508c..830fd6db58 100644 --- a/doc/src/angle_cosine_delta.txt +++ b/doc/src/angle_cosine_delta.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_periodic.txt b/doc/src/angle_cosine_periodic.txt index c6cd57e419..b5c53b1b0f 100644 --- a/doc/src/angle_cosine_periodic.txt +++ b/doc/src/angle_cosine_periodic.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_shift.txt b/doc/src/angle_cosine_shift.txt index dc1a29a86b..6ed9fe2150 100644 --- a/doc/src/angle_cosine_shift.txt +++ b/doc/src/angle_cosine_shift.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_shift_exp.txt b/doc/src/angle_cosine_shift_exp.txt index 48af5ba76a..44a68c1087 100644 --- a/doc/src/angle_cosine_shift_exp.txt +++ b/doc/src/angle_cosine_shift_exp.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_cosine_squared.txt b/doc/src/angle_cosine_squared.txt index 23e1b150a8..065cdad542 100644 --- a/doc/src/angle_cosine_squared.txt +++ b/doc/src/angle_cosine_squared.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_fourier.txt b/doc/src/angle_fourier.txt index f58ae8e4f4..da39e7cf32 100644 --- a/doc/src/angle_fourier.txt +++ b/doc/src/angle_fourier.txt @@ -51,7 +51,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_fourier_simple.txt b/doc/src/angle_fourier_simple.txt index 9da8ffed28..5adda6cb32 100644 --- a/doc/src/angle_fourier_simple.txt +++ b/doc/src/angle_fourier_simple.txt @@ -50,7 +50,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_harmonic.txt b/doc/src/angle_harmonic.txt index 12ee805218..4c74763964 100644 --- a/doc/src/angle_harmonic.txt +++ b/doc/src/angle_harmonic.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_quartic.txt b/doc/src/angle_quartic.txt index fea2eb9e03..f7640bdfbc 100644 --- a/doc/src/angle_quartic.txt +++ b/doc/src/angle_quartic.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/angle_table.txt b/doc/src/angle_table.txt index 61dd7b041e..bd6e167bd8 100644 --- a/doc/src/angle_table.txt +++ b/doc/src/angle_table.txt @@ -136,7 +136,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/balance.txt b/doc/src/balance.txt index 79728d6569..da6f59900d 100644 --- a/doc/src/balance.txt +++ b/doc/src/balance.txt @@ -394,7 +394,7 @@ weights. It assigns the same weight to each particle owned by a processor based on the total computational time spent by that processor. See details below on what time window is used. It uses the same timing information as is used for the "MPI task timing -breakdown"_Section_start.html#start_8, namely, for sections {Pair}, +breakdown"_Section_start.html#start_7, namely, for sections {Pair}, {Bond}, {Kspace}, and {Neigh}. The time spent in those portions of the timestep are measured for each MPI rank, summed, then divided by the number of particles owned by that processor. I.e. the weight is diff --git a/doc/src/bond_class2.txt b/doc/src/bond_class2.txt index aa05412387..9687a63168 100644 --- a/doc/src/bond_class2.txt +++ b/doc/src/bond_class2.txt @@ -56,7 +56,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_fene.txt b/doc/src/bond_fene.txt index 80d2a805c5..9050c3bf5c 100644 --- a/doc/src/bond_fene.txt +++ b/doc/src/bond_fene.txt @@ -59,7 +59,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_fene_expand.txt b/doc/src/bond_fene_expand.txt index 3908c16a7e..ff687444a9 100644 --- a/doc/src/bond_fene_expand.txt +++ b/doc/src/bond_fene_expand.txt @@ -62,7 +62,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic.txt b/doc/src/bond_harmonic.txt index 1cbd897dac..c18a7e0fd4 100644 --- a/doc/src/bond_harmonic.txt +++ b/doc/src/bond_harmonic.txt @@ -54,7 +54,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic_shift.txt b/doc/src/bond_harmonic_shift.txt index 8cb2d2ce7d..bf3b3c115a 100644 --- a/doc/src/bond_harmonic_shift.txt +++ b/doc/src/bond_harmonic_shift.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_harmonic_shift_cut.txt b/doc/src/bond_harmonic_shift_cut.txt index 836d6afda4..1918ce00b6 100644 --- a/doc/src/bond_harmonic_shift_cut.txt +++ b/doc/src/bond_harmonic_shift_cut.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_morse.txt b/doc/src/bond_morse.txt index 12e51f9bef..4f6a32e341 100644 --- a/doc/src/bond_morse.txt +++ b/doc/src/bond_morse.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_nonlinear.txt b/doc/src/bond_nonlinear.txt index ac9f3369c2..434af62506 100644 --- a/doc/src/bond_nonlinear.txt +++ b/doc/src/bond_nonlinear.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_quartic.txt b/doc/src/bond_quartic.txt index e61f4f0343..4dc7ad4a36 100644 --- a/doc/src/bond_quartic.txt +++ b/doc/src/bond_quartic.txt @@ -88,7 +88,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/bond_table.txt b/doc/src/bond_table.txt index cb096fba11..906d3e5d76 100644 --- a/doc/src/bond_table.txt +++ b/doc/src/bond_table.txt @@ -133,7 +133,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_pressure.txt b/doc/src/compute_pressure.txt index 292e779f72..f0691ad207 100644 --- a/doc/src/compute_pressure.txt +++ b/doc/src/compute_pressure.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_temp.txt b/doc/src/compute_temp.txt index 0bd2d4b121..b88be79e20 100644 --- a/doc/src/compute_temp.txt +++ b/doc/src/compute_temp.txt @@ -79,7 +79,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/compute_temp_partial.txt b/doc/src/compute_temp_partial.txt index 163a00af52..fe2420b4e4 100644 --- a/doc/src/compute_temp_partial.txt +++ b/doc/src/compute_temp_partial.txt @@ -86,7 +86,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_charmm.txt b/doc/src/dihedral_charmm.txt index 73dc67cdef..06abe054e4 100644 --- a/doc/src/dihedral_charmm.txt +++ b/doc/src/dihedral_charmm.txt @@ -128,7 +128,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_class2.txt b/doc/src/dihedral_class2.txt index 91ab6f3738..cb9fc72c22 100644 --- a/doc/src/dihedral_class2.txt +++ b/doc/src/dihedral_class2.txt @@ -153,7 +153,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_cosine_shift_exp.txt b/doc/src/dihedral_cosine_shift_exp.txt index 89614a3fdb..715682affc 100644 --- a/doc/src/dihedral_cosine_shift_exp.txt +++ b/doc/src/dihedral_cosine_shift_exp.txt @@ -64,7 +64,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_fourier.txt b/doc/src/dihedral_fourier.txt index 5682309b83..da892b59da 100644 --- a/doc/src/dihedral_fourier.txt +++ b/doc/src/dihedral_fourier.txt @@ -55,7 +55,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_harmonic.txt b/doc/src/dihedral_harmonic.txt index c763dcce22..d9a48ff384 100644 --- a/doc/src/dihedral_harmonic.txt +++ b/doc/src/dihedral_harmonic.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_helix.txt b/doc/src/dihedral_helix.txt index fced983db0..1e907557b2 100644 --- a/doc/src/dihedral_helix.txt +++ b/doc/src/dihedral_helix.txt @@ -58,7 +58,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_multi_harmonic.txt b/doc/src/dihedral_multi_harmonic.txt index 5774a67685..7d3c2ea083 100644 --- a/doc/src/dihedral_multi_harmonic.txt +++ b/doc/src/dihedral_multi_harmonic.txt @@ -52,7 +52,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_nharmonic.txt b/doc/src/dihedral_nharmonic.txt index 0df28a05d4..8392d83899 100644 --- a/doc/src/dihedral_nharmonic.txt +++ b/doc/src/dihedral_nharmonic.txt @@ -52,7 +52,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_opls.txt b/doc/src/dihedral_opls.txt index afcc5d3514..d1a6ba3ff2 100644 --- a/doc/src/dihedral_opls.txt +++ b/doc/src/dihedral_opls.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/dihedral_quadratic.txt b/doc/src/dihedral_quadratic.txt index 526b469f63..ca2f5aed40 100644 --- a/doc/src/dihedral_quadratic.txt +++ b/doc/src/dihedral_quadratic.txt @@ -53,7 +53,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/echo.txt b/doc/src/echo.txt index 8ef8ad05f8..3141c7a719 100644 --- a/doc/src/echo.txt +++ b/doc/src/echo.txt @@ -26,7 +26,7 @@ command to the screen and/or log file as it is read and processed. If an input script has errors, it can be useful to look at echoed output to see the last command processed. -The "command-line switch"_Section_start.html#start_5 -echo can be used +The "command-line switch"_Section_start.html#start_6 -echo can be used in place of this command. [Restrictions:] none diff --git a/doc/src/fix_addforce.txt b/doc/src/fix_addforce.txt index da9f98a6da..1cc0a15332 100644 --- a/doc/src/fix_addforce.txt +++ b/doc/src/fix_addforce.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_aveforce.txt b/doc/src/fix_aveforce.txt index d980e9a211..5d7dec3e6a 100644 --- a/doc/src/fix_aveforce.txt +++ b/doc/src/fix_aveforce.txt @@ -77,7 +77,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_deform.txt b/doc/src/fix_deform.txt index d3254eece6..63d872eded 100644 --- a/doc/src/fix_deform.txt +++ b/doc/src/fix_deform.txt @@ -557,7 +557,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_enforce2d.txt b/doc/src/fix_enforce2d.txt index 1dce620033..5d04e96677 100644 --- a/doc/src/fix_enforce2d.txt +++ b/doc/src/fix_enforce2d.txt @@ -41,7 +41,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_freeze.txt b/doc/src/fix_freeze.txt index 6a4f6c2fcf..a63ee4cb32 100644 --- a/doc/src/fix_freeze.txt +++ b/doc/src/fix_freeze.txt @@ -45,7 +45,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_gravity.txt b/doc/src/fix_gravity.txt index 2cf1665c30..dae8ac5ed0 100644 --- a/doc/src/fix_gravity.txt +++ b/doc/src/fix_gravity.txt @@ -102,7 +102,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_langevin.txt b/doc/src/fix_langevin.txt index 534d83f6a9..93c73f5a5d 100644 --- a/doc/src/fix_langevin.txt +++ b/doc/src/fix_langevin.txt @@ -276,7 +276,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_momentum.txt b/doc/src/fix_momentum.txt index 4f94e2a857..bcf4465fb8 100644 --- a/doc/src/fix_momentum.txt +++ b/doc/src/fix_momentum.txt @@ -73,7 +73,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nh.txt b/doc/src/fix_nh.txt index c1cc3e560a..8fa30ac222 100644 --- a/doc/src/fix_nh.txt +++ b/doc/src/fix_nh.txt @@ -492,7 +492,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_asphere.txt b/doc/src/fix_nph_asphere.txt index 3d151a724b..8c35b6a1a7 100644 --- a/doc/src/fix_nph_asphere.txt +++ b/doc/src/fix_nph_asphere.txt @@ -93,7 +93,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_body.txt b/doc/src/fix_nph_body.txt index 3a273be595..1e590f1cb3 100644 --- a/doc/src/fix_nph_body.txt +++ b/doc/src/fix_nph_body.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nph_sphere.txt b/doc/src/fix_nph_sphere.txt index 9258f40c76..62b45edfd7 100644 --- a/doc/src/fix_nph_sphere.txt +++ b/doc/src/fix_nph_sphere.txt @@ -102,7 +102,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nphug.txt b/doc/src/fix_nphug.txt index ef3ffc4955..292e46f94a 100644 --- a/doc/src/fix_nphug.txt +++ b/doc/src/fix_nphug.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_asphere.txt b/doc/src/fix_npt_asphere.txt index 8fe98f1818..5f3979e36e 100644 --- a/doc/src/fix_npt_asphere.txt +++ b/doc/src/fix_npt_asphere.txt @@ -117,7 +117,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_body.txt b/doc/src/fix_npt_body.txt index 772920df61..d89bf19db2 100644 --- a/doc/src/fix_npt_body.txt +++ b/doc/src/fix_npt_body.txt @@ -116,7 +116,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_npt_sphere.txt b/doc/src/fix_npt_sphere.txt index 24a8fede57..c4cf2cb08d 100644 --- a/doc/src/fix_npt_sphere.txt +++ b/doc/src/fix_npt_sphere.txt @@ -127,7 +127,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve.txt b/doc/src/fix_nve.txt index 7ad8301877..c04c17858e 100644 --- a/doc/src/fix_nve.txt +++ b/doc/src/fix_nve.txt @@ -46,7 +46,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve_asphere.txt b/doc/src/fix_nve_asphere.txt index 03846a2558..1f31fb9679 100644 --- a/doc/src/fix_nve_asphere.txt +++ b/doc/src/fix_nve_asphere.txt @@ -57,7 +57,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nve_sphere.txt b/doc/src/fix_nve_sphere.txt index f91a41f515..21dc6cba8a 100644 --- a/doc/src/fix_nve_sphere.txt +++ b/doc/src/fix_nve_sphere.txt @@ -77,7 +77,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_asphere.txt b/doc/src/fix_nvt_asphere.txt index 77de1dea40..21b900f16a 100644 --- a/doc/src/fix_nvt_asphere.txt +++ b/doc/src/fix_nvt_asphere.txt @@ -98,7 +98,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_body.txt b/doc/src/fix_nvt_body.txt index 1f04b85c8b..6a5e09ba7f 100644 --- a/doc/src/fix_nvt_body.txt +++ b/doc/src/fix_nvt_body.txt @@ -97,7 +97,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_sllod.txt b/doc/src/fix_nvt_sllod.txt index 82631f22e3..392dbc281c 100644 --- a/doc/src/fix_nvt_sllod.txt +++ b/doc/src/fix_nvt_sllod.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_nvt_sphere.txt b/doc/src/fix_nvt_sphere.txt index fa1c97bcce..ecf0922b79 100644 --- a/doc/src/fix_nvt_sphere.txt +++ b/doc/src/fix_nvt_sphere.txt @@ -108,7 +108,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_qeq_comb.txt b/doc/src/fix_qeq_comb.txt index 30c5003e72..7f82404127 100644 --- a/doc/src/fix_qeq_comb.txt +++ b/doc/src/fix_qeq_comb.txt @@ -74,7 +74,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_qeq_reax.txt b/doc/src/fix_qeq_reax.txt index a1a19b7368..18450c7cd5 100644 --- a/doc/src/fix_qeq_reax.txt +++ b/doc/src/fix_qeq_reax.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_reax_bonds.txt b/doc/src/fix_reax_bonds.txt index aadb0a9cbc..54aa7faef8 100644 --- a/doc/src/fix_reax_bonds.txt +++ b/doc/src/fix_reax_bonds.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section_accelerate"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_reaxc_species.txt b/doc/src/fix_reaxc_species.txt index 9a588356e0..7c920791f7 100644 --- a/doc/src/fix_reaxc_species.txt +++ b/doc/src/fix_reaxc_species.txt @@ -151,7 +151,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section_accelerate"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_rigid.txt b/doc/src/fix_rigid.txt index 87021b8551..62969112f7 100644 --- a/doc/src/fix_rigid.txt +++ b/doc/src/fix_rigid.txt @@ -676,7 +676,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_setforce.txt b/doc/src/fix_setforce.txt index 90766fc5bc..f5be0f93a5 100644 --- a/doc/src/fix_setforce.txt +++ b/doc/src/fix_setforce.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_shake.txt b/doc/src/fix_shake.txt index 8b26aaa874..c187b17c6c 100644 --- a/doc/src/fix_shake.txt +++ b/doc/src/fix_shake.txt @@ -159,7 +159,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/fix_wall_reflect.txt b/doc/src/fix_wall_reflect.txt index 5b425316e0..954ec65bf6 100644 --- a/doc/src/fix_wall_reflect.txt +++ b/doc/src/fix_wall_reflect.txt @@ -142,7 +142,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_class2.txt b/doc/src/improper_class2.txt index 0b41afe2db..14ec6258de 100644 --- a/doc/src/improper_class2.txt +++ b/doc/src/improper_class2.txt @@ -99,7 +99,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_cossq.txt b/doc/src/improper_cossq.txt index e238063a8f..138a6a1650 100644 --- a/doc/src/improper_cossq.txt +++ b/doc/src/improper_cossq.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_cvff.txt b/doc/src/improper_cvff.txt index 72f346ba04..5f69eccc60 100644 --- a/doc/src/improper_cvff.txt +++ b/doc/src/improper_cvff.txt @@ -66,7 +66,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_fourier.txt b/doc/src/improper_fourier.txt index 3a5354b1fe..f9062da207 100644 --- a/doc/src/improper_fourier.txt +++ b/doc/src/improper_fourier.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_harmonic.txt b/doc/src/improper_harmonic.txt index b47b0ca41f..bb17e5a641 100644 --- a/doc/src/improper_harmonic.txt +++ b/doc/src/improper_harmonic.txt @@ -70,7 +70,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_ring.txt b/doc/src/improper_ring.txt index cba59399e7..c02d392474 100644 --- a/doc/src/improper_ring.txt +++ b/doc/src/improper_ring.txt @@ -69,7 +69,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/improper_umbrella.txt b/doc/src/improper_umbrella.txt index fafa2e7e4c..d6df9ee6cc 100644 --- a/doc/src/improper_umbrella.txt +++ b/doc/src/improper_umbrella.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/jump.txt b/doc/src/jump.txt index 1b1a209511..4e3799f7b1 100644 --- a/doc/src/jump.txt +++ b/doc/src/jump.txt @@ -40,12 +40,12 @@ lmp_g++ < in.script :pre since the SELF option invokes the C-library rewind() call, which may not be supported for stdin on some systems or by some MPI implementations. This can be worked around by using the "-in -command-line argument"_Section_start.html#start_7, e.g. +command-line argument"_Section_start.html#start_6, e.g. lmp_g++ -in in.script :pre or by using the "-var command-line -argument"_Section_start.html#start_7 to pass the script name as a +argument"_Section_start.html#start_6 to pass the script name as a variable to the input script. In the latter case, a "variable"_variable.html called "fname" could be used in place of SELF, e.g. diff --git a/doc/src/log.txt b/doc/src/log.txt index 460482ea1e..92bb12e6db 100644 --- a/doc/src/log.txt +++ b/doc/src/log.txt @@ -34,7 +34,7 @@ the same log file. The file "log.lammps" is the default log file for a LAMMPS run. The name of the initial log file can also be set by the command-line -switch -log. See "Section 2.7"_Section_start.html#start_7 for +switch -log. See "Section 2.6"_Section_start.html#start_6 for details. [Restrictions:] none diff --git a/doc/src/neb.txt b/doc/src/neb.txt index d2e8be3f03..144fe8bdef 100644 --- a/doc/src/neb.txt +++ b/doc/src/neb.txt @@ -51,7 +51,7 @@ follows the discussion in these 4 papers: "(HenkelmanA)"_#HenkelmanA, Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the manual. +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on just one or two diff --git a/doc/src/neighbor.txt b/doc/src/neighbor.txt index 7b8f499ba8..062f79a5bb 100644 --- a/doc/src/neighbor.txt +++ b/doc/src/neighbor.txt @@ -66,7 +66,7 @@ stored in the list. When a run is finished, counts of the number of neighbors stored in the pairwise list and the number of times neighbor lists were built are printed to the screen and log file. See "this -section"_Section_start.html#start_8 for details. +section"_Section_start.html#start_7 for details. [Restrictions:] none diff --git a/doc/src/next.txt b/doc/src/next.txt index fe9dc97542..08f73b896c 100644 --- a/doc/src/next.txt +++ b/doc/src/next.txt @@ -71,7 +71,7 @@ next value (for each variable) is assigned to whichever processor partition executes the command first. All processors in the partition are assigned the same value(s). Running LAMMPS on multiple partitions of processors via the "-partition" command-line switch is described in -"this section"_Section_start.html#start_7 of the manual. {Universe}- +"this section"_Section_start.html#start_6 of the manual. {Universe}- and {uloop}-style variables are incremented using the files "tmp.lammps.variable" and "tmp.lammps.variable.lock" which you will see in your directory during and after such a LAMMPS run. diff --git a/doc/src/package.txt b/doc/src/package.txt index 18a26bd55c..1b9092644f 100644 --- a/doc/src/package.txt +++ b/doc/src/package.txt @@ -115,7 +115,7 @@ their initialization, before a simulation is defined. This command can also be specified from the command-line when launching LAMMPS, using the "-pk" "command-line -switch"_Section_start.html#start_7. The syntax is exactly the same as +switch"_Section_start.html#start_6. The syntax is exactly the same as when used in an input script. Note that all of the accelerator packages require the package command @@ -126,18 +126,18 @@ a default version of the command is typically invoked by other accelerator settings. The KOKKOS package requires a "-k on" "command-line -switch"_Section_start.html#start_7 respectively, which invokes a +switch"_Section_start.html#start_6 respectively, which invokes a "package kokkos" command with default settings. For the GPU, USER-INTEL, and USER-OMP packages, if a "-sf gpu" or "-sf -intel" or "-sf omp" "command-line switch"_Section_start.html#start_7 +intel" or "-sf omp" "command-line switch"_Section_start.html#start_6 is used to auto-append accelerator suffixes to various styles in the input script, then those switches also invoke a "package gpu", "package intel", or "package omp" command with default settings. NOTE: A package command for a particular style can be invoked multiple times when a simulation is setup, e.g. by the "-c on", "-k on", "-sf", -and "-pk" "command-line switches"_Section_start.html#start_7, and by +and "-pk" "command-line switches"_Section_start.html#start_6, and by using this command in an input script. Each time it is used all of the style options are set, either to default values or to specified settings. I.e. settings from previous invocations do not persist @@ -305,7 +305,7 @@ value via their package commands, but there is only a single global invoked, you should insure the two values are consistent. If they are not, the last one invoked will take precedence, for both packages. Also note that if the "-sf hybrid intel omp" "command-line -switch"_"_Section_start.html#start_7 is used, it invokes a "package +switch"_"_Section_start.html#start_6 is used, it invokes a "package intel" command, followed by a "package omp" command, both with a setting of {Nthreads} = 0. @@ -550,7 +550,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. [Related commands:] "suffix"_suffix.html, "-pk" "command-line -setting"_Section_start.html#start_7 +setting"_Section_start.html#start_6 [Default:] @@ -558,9 +558,9 @@ For the GPU package, the default is Ngpu = 1 and the option defaults are neigh = yes, newton = off, binsize = 0.0, split = 1.0, gpuID = 0 to Ngpu-1, tpa = 1, and device = not used. These settings are made automatically if the "-sf gpu" "command-line -switch"_Section_start.html#start_7 is used. If it is not used, you +switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package gpu command in your input script or via the -"-pk gpu" "command-line switch"_Section_start.html#start_7. +"-pk gpu" "command-line switch"_Section_start.html#start_6. For the USER-INTEL package, the default is Nphi = 1 and the option defaults are omp = 0, mode = mixed, lrt = no, balance = -1, tpc = 4, @@ -569,21 +569,21 @@ style being used. This value is output to the screen in the offload report at the end of each run. Note that all of these settings, except "omp" and "mode", are ignored if LAMMPS was not built with Xeon Phi coprocessor support. These settings are made automatically -if the "-sf intel" "command-line switch"_Section_start.html#start_7 +if the "-sf intel" "command-line switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package intel command in your input script or or via the "-pk intel" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. For the KOKKOS package, the option defaults neigh = full, neigh/qeq = full, newton = off, binsize = 0.0, and comm = device. These settings are made automatically by the required "-k on" "command-line -switch"_Section_start.html#start_7. You can change them bu using the +switch"_Section_start.html#start_6. You can change them bu using the package kokkos command in your input script or via the "-pk kokkos" -"command-line switch"_Section_start.html#start_7. +"command-line switch"_Section_start.html#start_6. For the OMP package, the default is Nthreads = 0 and the option defaults are neigh = yes. These settings are made automatically if -the "-sf omp" "command-line switch"_Section_start.html#start_7 is +the "-sf omp" "command-line switch"_Section_start.html#start_6 is used. If it is not used, you must invoke the package omp command in your input script or via the "-pk omp" "command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. diff --git a/doc/src/pair_adp.txt b/doc/src/pair_adp.txt index 457a797d95..9d2a48dcbc 100644 --- a/doc/src/pair_adp.txt +++ b/doc/src/pair_adp.txt @@ -137,7 +137,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_agni.txt b/doc/src/pair_agni.txt index 06dcccb9d9..402e537dad 100644 --- a/doc/src/pair_agni.txt +++ b/doc/src/pair_agni.txt @@ -70,7 +70,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated style explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_airebo.txt b/doc/src/pair_airebo.txt index 0c03eb3267..e66ecb637f 100644 --- a/doc/src/pair_airebo.txt +++ b/doc/src/pair_airebo.txt @@ -185,7 +185,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_beck.txt b/doc/src/pair_beck.txt index 4e792754b8..e160f09b3d 100644 --- a/doc/src/pair_beck.txt +++ b/doc/src/pair_beck.txt @@ -63,7 +63,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_born.txt b/doc/src/pair_born.txt index d38d9e3191..a3cc744a22 100644 --- a/doc/src/pair_born.txt +++ b/doc/src/pair_born.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_brownian.txt b/doc/src/pair_brownian.txt index 33eed77629..79b71e91c7 100644 --- a/doc/src/pair_brownian.txt +++ b/doc/src/pair_brownian.txt @@ -85,7 +85,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "this section"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_buck.txt b/doc/src/pair_buck.txt index e705e735fb..d18b39d5d9 100644 --- a/doc/src/pair_buck.txt +++ b/doc/src/pair_buck.txt @@ -152,7 +152,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_buck_long.txt b/doc/src/pair_buck_long.txt index ba18738e4d..05e760e1b2 100644 --- a/doc/src/pair_buck_long.txt +++ b/doc/src/pair_buck_long.txt @@ -114,7 +114,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_charmm.txt b/doc/src/pair_charmm.txt index 1e78607c08..ef4ef41c95 100644 --- a/doc/src/pair_charmm.txt +++ b/doc/src/pair_charmm.txt @@ -195,7 +195,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_class2.txt b/doc/src/pair_class2.txt index 23b90aae2d..36fae5068b 100644 --- a/doc/src/pair_class2.txt +++ b/doc/src/pair_class2.txt @@ -114,7 +114,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_colloid.txt b/doc/src/pair_colloid.txt index a0df1d464e..83b15b358b 100644 --- a/doc/src/pair_colloid.txt +++ b/doc/src/pair_colloid.txt @@ -139,7 +139,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_comb.txt b/doc/src/pair_comb.txt index 3a2f380bfa..f5461b1cbc 100644 --- a/doc/src/pair_comb.txt +++ b/doc/src/pair_comb.txt @@ -124,7 +124,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_coul.txt b/doc/src/pair_coul.txt index 4a601e90c0..29e5beed3c 100644 --- a/doc/src/pair_coul.txt +++ b/doc/src/pair_coul.txt @@ -274,7 +274,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_dipole.txt b/doc/src/pair_dipole.txt index 985581cac8..2516e5eae4 100644 --- a/doc/src/pair_dipole.txt +++ b/doc/src/pair_dipole.txt @@ -198,7 +198,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_dpd.txt b/doc/src/pair_dpd.txt index 62a5faffed..9dd204ad2d 100644 --- a/doc/src/pair_dpd.txt +++ b/doc/src/pair_dpd.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_eam.txt b/doc/src/pair_eam.txt index 4d3c2b2dea..ce8495affd 100644 --- a/doc/src/pair_eam.txt +++ b/doc/src/pair_eam.txt @@ -381,7 +381,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_edip.txt b/doc/src/pair_edip.txt index 86453859d3..e5b1420b59 100644 --- a/doc/src/pair_edip.txt +++ b/doc/src/pair_edip.txt @@ -121,7 +121,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_eim.txt b/doc/src/pair_eim.txt index 3f068d4040..75ad2d4683 100644 --- a/doc/src/pair_eim.txt +++ b/doc/src/pair_eim.txt @@ -148,7 +148,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gayberne.txt b/doc/src/pair_gayberne.txt index 8639f220a4..c923578586 100644 --- a/doc/src/pair_gayberne.txt +++ b/doc/src/pair_gayberne.txt @@ -145,7 +145,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gran.txt b/doc/src/pair_gran.txt index 62a58b3504..d7e87af013 100644 --- a/doc/src/pair_gran.txt +++ b/doc/src/pair_gran.txt @@ -191,7 +191,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_gromacs.txt b/doc/src/pair_gromacs.txt index 3aca8c3cd3..ec84a2d57a 100644 --- a/doc/src/pair_gromacs.txt +++ b/doc/src/pair_gromacs.txt @@ -103,7 +103,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_hbond_dreiding.txt b/doc/src/pair_hbond_dreiding.txt index 9641e294fa..d3cf90ec14 100644 --- a/doc/src/pair_hbond_dreiding.txt +++ b/doc/src/pair_hbond_dreiding.txt @@ -178,7 +178,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_hybrid.txt b/doc/src/pair_hybrid.txt index 5166fe1f84..fc1824cf62 100644 --- a/doc/src/pair_hybrid.txt +++ b/doc/src/pair_hybrid.txt @@ -330,7 +330,7 @@ LAMMPS was built with those packages. See the You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj.txt b/doc/src/pair_lj.txt index 5c8e31ac42..058d54fb59 100644 --- a/doc/src/pair_lj.txt +++ b/doc/src/pair_lj.txt @@ -253,7 +253,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj96.txt b/doc/src/pair_lj96.txt index 6e7c3cbaec..83f6ec063d 100644 --- a/doc/src/pair_lj96.txt +++ b/doc/src/pair_lj96.txt @@ -61,7 +61,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_cubic.txt b/doc/src/pair_lj_cubic.txt index d33e3ec09b..4ca8c3c141 100644 --- a/doc/src/pair_lj_cubic.txt +++ b/doc/src/pair_lj_cubic.txt @@ -75,7 +75,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_expand.txt b/doc/src/pair_lj_expand.txt index c5f0c88a75..e0838426f6 100644 --- a/doc/src/pair_lj_expand.txt +++ b/doc/src/pair_lj_expand.txt @@ -65,7 +65,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_long.txt b/doc/src/pair_lj_long.txt index da9f37b9c3..6be4562d18 100644 --- a/doc/src/pair_lj_long.txt +++ b/doc/src/pair_lj_long.txt @@ -168,7 +168,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_smooth.txt b/doc/src/pair_lj_smooth.txt index 133773abd0..b1678cad58 100644 --- a/doc/src/pair_lj_smooth.txt +++ b/doc/src/pair_lj_smooth.txt @@ -74,7 +74,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_smooth_linear.txt b/doc/src/pair_lj_smooth_linear.txt index a48c441f54..5f7c226cee 100644 --- a/doc/src/pair_lj_smooth_linear.txt +++ b/doc/src/pair_lj_smooth_linear.txt @@ -61,7 +61,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lj_soft.txt b/doc/src/pair_lj_soft.txt index e372092cf0..2ef133da55 100644 --- a/doc/src/pair_lj_soft.txt +++ b/doc/src/pair_lj_soft.txt @@ -219,7 +219,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_lubricate.txt b/doc/src/pair_lubricate.txt index 501a043801..b39c7545c7 100644 --- a/doc/src/pair_lubricate.txt +++ b/doc/src/pair_lubricate.txt @@ -154,7 +154,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "this section"_Section_accelerate.html of the manual for more diff --git a/doc/src/pair_meam_spline.txt b/doc/src/pair_meam_spline.txt index 2295a6640b..6653b397a0 100644 --- a/doc/src/pair_meam_spline.txt +++ b/doc/src/pair_meam_spline.txt @@ -118,7 +118,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_morse.txt b/doc/src/pair_morse.txt index 5fbb6d5c0a..3eb5ac5afe 100644 --- a/doc/src/pair_morse.txt +++ b/doc/src/pair_morse.txt @@ -113,7 +113,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_nb3b_harmonic.txt b/doc/src/pair_nb3b_harmonic.txt index 3f7066c826..2395707fb4 100644 --- a/doc/src/pair_nb3b_harmonic.txt +++ b/doc/src/pair_nb3b_harmonic.txt @@ -104,7 +104,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_nm.txt b/doc/src/pair_nm.txt index 9096bdc523..81cea1a38d 100644 --- a/doc/src/pair_nm.txt +++ b/doc/src/pair_nm.txt @@ -145,7 +145,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_peri.txt b/doc/src/pair_peri.txt index 6ffd8122aa..6fef445595 100644 --- a/doc/src/pair_peri.txt +++ b/doc/src/pair_peri.txt @@ -151,7 +151,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_reaxc.txt b/doc/src/pair_reaxc.txt index cfa88673d7..b9dc6e0ed8 100644 --- a/doc/src/pair_reaxc.txt +++ b/doc/src/pair_reaxc.txt @@ -311,7 +311,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_resquared.txt b/doc/src/pair_resquared.txt index 2e0034ed3b..9ad95eb5fc 100644 --- a/doc/src/pair_resquared.txt +++ b/doc/src/pair_resquared.txt @@ -157,7 +157,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_sdk.txt b/doc/src/pair_sdk.txt index 1c348eaaf7..360136a4ea 100644 --- a/doc/src/pair_sdk.txt +++ b/doc/src/pair_sdk.txt @@ -97,7 +97,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_soft.txt b/doc/src/pair_soft.txt index ec1c06729a..08fa88c477 100644 --- a/doc/src/pair_soft.txt +++ b/doc/src/pair_soft.txt @@ -94,7 +94,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_sw.txt b/doc/src/pair_sw.txt index 6025b9b11b..6ed8f00236 100644 --- a/doc/src/pair_sw.txt +++ b/doc/src/pair_sw.txt @@ -156,7 +156,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. When using the USER-INTEL package with this style, there is an diff --git a/doc/src/pair_table.txt b/doc/src/pair_table.txt index 01c577cd98..b99491b477 100644 --- a/doc/src/pair_table.txt +++ b/doc/src/pair_table.txt @@ -229,7 +229,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff.txt b/doc/src/pair_tersoff.txt index 23a20ad0fd..918e889924 100644 --- a/doc/src/pair_tersoff.txt +++ b/doc/src/pair_tersoff.txt @@ -191,7 +191,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff_mod.txt b/doc/src/pair_tersoff_mod.txt index ff703063b3..e0c2b5a5cb 100644 --- a/doc/src/pair_tersoff_mod.txt +++ b/doc/src/pair_tersoff_mod.txt @@ -143,7 +143,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_tersoff_zbl.txt b/doc/src/pair_tersoff_zbl.txt index 18e54749aa..21d57e4e88 100644 --- a/doc/src/pair_tersoff_zbl.txt +++ b/doc/src/pair_tersoff_zbl.txt @@ -201,7 +201,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_thole.txt b/doc/src/pair_thole.txt index 61ca0b5c35..41a4059cee 100644 --- a/doc/src/pair_thole.txt +++ b/doc/src/pair_thole.txt @@ -142,7 +142,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_vashishta.txt b/doc/src/pair_vashishta.txt index 9c275a61d3..d9c66d45c0 100644 --- a/doc/src/pair_vashishta.txt +++ b/doc/src/pair_vashishta.txt @@ -183,7 +183,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_yukawa.txt b/doc/src/pair_yukawa.txt index 26acdb2ccb..61d6bde6a9 100644 --- a/doc/src/pair_yukawa.txt +++ b/doc/src/pair_yukawa.txt @@ -60,7 +60,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_yukawa_colloid.txt b/doc/src/pair_yukawa_colloid.txt index ecdc1496ab..2037a9451f 100644 --- a/doc/src/pair_yukawa_colloid.txt +++ b/doc/src/pair_yukawa_colloid.txt @@ -92,7 +92,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/pair_zbl.txt b/doc/src/pair_zbl.txt index 154fdc1c13..5ab672171b 100644 --- a/doc/src/pair_zbl.txt +++ b/doc/src/pair_zbl.txt @@ -82,7 +82,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/partition.txt b/doc/src/partition.txt index 9c1d560c83..610eee99b3 100644 --- a/doc/src/partition.txt +++ b/doc/src/partition.txt @@ -27,7 +27,7 @@ partition yes 6* fix all nvt temp 1.0 1.0 0.1 :pre This command invokes the specified command on a subset of the partitions of processors you have defined via the -partition -command-line switch. See "Section 2.6"_Section_start.html#start_7 +command-line switch. See "Section 2.6"_Section_start.html#start_6 for an explanation of the switch. Normally, every input script command in your script is invoked by @@ -49,7 +49,7 @@ argument. Partitions are numbered from 1 to Np, where Np is the number of partitions specified by the "-partition command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. {N} can be specified in one of two ways. An explicit numeric value can be used, as in the 1st example above. Or a wild-card asterisk can diff --git a/doc/src/prd.txt b/doc/src/prd.txt index 247d422b1c..3c0305e316 100644 --- a/doc/src/prd.txt +++ b/doc/src/prd.txt @@ -63,7 +63,7 @@ event to occur. Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the manual. +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on one or two diff --git a/doc/src/processors.txt b/doc/src/processors.txt index 781049af9c..e54b2cede3 100644 --- a/doc/src/processors.txt +++ b/doc/src/processors.txt @@ -82,7 +82,7 @@ sub-domain. Also note that if multiple partitions are being used then P is the number of processors in this partition; see "this -section"_Section_start.html#start_7 for an explanation of the +section"_Section_start.html#start_6 for an explanation of the -partition command-line switch. Also note that you can prefix the processors command with the "partition"_partition.html command to easily specify different Px,Py,Pz values for different partitions. @@ -249,7 +249,7 @@ partition {Precv} which is enforced when each is setting up their own mapping of their processors to the simulation box. Each of {Psend} and {Precv} must be integers from 1 to Np, where Np is the number of partitions you have defined via the "-partition command-line -switch"_Section_start.html#start_7. +switch"_Section_start.html#start_6. A "dependency" means that the sending partition will create its regular 3d grid as Px by Py by Pz and after it has done this, it will @@ -286,7 +286,7 @@ processors and their mapping to the 3d grid to the specified file processors in the manner you desired, which can be tricky to figure out, especially when running on multiple partitions or on, a multicore machine or when the processor ranks were reordered by use of the -"-reorder command-line switch"_Section_start.html#start_7 or due to +"-reorder command-line switch"_Section_start.html#start_6 or due to use of MPI-specific launch options such as a config file. If you have multiple partitions you should insure that each one writes @@ -300,9 +300,9 @@ The IDs are the processor's rank in this simulation (the world), the universe (of multiple simulations), and the original MPI communicator used to instantiate LAMMPS, respectively. The world and universe IDs will only be different if you are running on more than one partition; -see the "-partition command-line switch"_Section_start.html#start_7. +see the "-partition command-line switch"_Section_start.html#start_6. The universe and original IDs will only be different if you used the -"-reorder command-line switch"_Section_start.html#start_7 to reorder +"-reorder command-line switch"_Section_start.html#start_6 to reorder the processors differently than their rank in the original communicator LAMMPS was instantiated with. @@ -332,7 +332,7 @@ The {part} keyword (for the receiving partition) only works with the [Related commands:] -"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_7 +"partition"_partition.html, "-reorder command-line switch"_Section_start.html#start_6 [Default:] diff --git a/doc/src/read_data.txt b/doc/src/read_data.txt index 6785eb1066..a8aca53693 100644 --- a/doc/src/read_data.txt +++ b/doc/src/read_data.txt @@ -62,7 +62,7 @@ simulation. The file can be ASCII text or a gzipped text file atom coordinates; see the "read_restart"_read_restart.html and "create_atoms"_create_atoms.html commands for alternative methods. Also see the explanation of the "-restart command-line -switch"_Section_start.html#start_7 which can convert a restart file to +switch"_Section_start.html#start_6 which can convert a restart file to a data file. This command can be used multiple times to add new atoms and their diff --git a/doc/src/read_restart.txt b/doc/src/read_restart.txt index d0f4b16175..d1091542b8 100644 --- a/doc/src/read_restart.txt +++ b/doc/src/read_restart.txt @@ -81,7 +81,7 @@ wrong. Because restart files are binary, they may not be portable to other machines. In this case, you can use the "-restart command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. Similar to how restart files are written (see the diff --git a/doc/src/region.txt b/doc/src/region.txt index 885e5e45f8..5039e4a516 100644 --- a/doc/src/region.txt +++ b/doc/src/region.txt @@ -375,7 +375,7 @@ LAMMPS"_Section_start.html#start_3 section for more info. You can specify the accelerated styles explicitly in your input script by including their suffix, or you can use the "-suffix command-line -switch"_Section_start.html#start_7 when you invoke LAMMPS, or you can +switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. See "Section 5"_Section_accelerate.html of the manual for diff --git a/doc/src/restart.txt b/doc/src/restart.txt index 5e0c2a9ea5..7c39ae1404 100644 --- a/doc/src/restart.txt +++ b/doc/src/restart.txt @@ -125,7 +125,7 @@ Restart files can be read by a "read_restart"_read_restart.html command to restart a simulation from a particular state. Because the file is binary (to enable exact restarts), it may not be readable on another machine. In this case, you can use the "-r command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. NOTE: Although the purpose of restart files is to enable restarting a diff --git a/doc/src/run_style.txt b/doc/src/run_style.txt index a67899420b..ba836a07dd 100644 --- a/doc/src/run_style.txt +++ b/doc/src/run_style.txt @@ -69,7 +69,7 @@ The {verlet} style is a standard velocity-Verlet integrator. The {verlet/split} style is also a velocity-Verlet integrator, but it splits the force calculation within each timestep over 2 partitions of -processors. See "Section 2.7"_Section_start.html#start_7 for an +processors. See "Section 2.6"_Section_start.html#start_6 for an explanation of the -partition command-line switch. Specifically, this style performs all computation except the @@ -115,7 +115,7 @@ When you run in 2-partition mode with the {verlet/split} style, the thermodynamic data for the entire simulation will be output to the log and screen file of the 1st partition, which are log.lammps.0 and screen.0 by default; see the "-plog and -pscreen command-line -switches"_Section_start.html#start_7 to change this. The log and +switches"_Section_start.html#start_6 to change this. The log and screen file for the 2nd partition will not contain thermodynamic output beyond the 1st timestep of the run. @@ -259,7 +259,7 @@ Accelerated styles take the same arguments and should produce the same results, except for round-off and precision issues. You can specify {respa/omp} explicitly in your input script, or -you can use the "-suffix command-line switch"_Section_start.html#start_7 +you can use the "-suffix command-line switch"_Section_start.html#start_6 when you invoke LAMMPS, or you can use the "suffix"_suffix.html command in your input script. diff --git a/doc/src/suffix.txt b/doc/src/suffix.txt index 127719cdb5..7a4adb50b6 100644 --- a/doc/src/suffix.txt +++ b/doc/src/suffix.txt @@ -28,7 +28,7 @@ suffix kk :pre This command allows you to use variants of various styles if they exist. In that respect it operates the same as the "-suffix -command-line switch"_Section_start.html#start_7. It also has options +command-line switch"_Section_start.html#start_6. It also has options to turn off or back on any suffix setting made via the command line. The specified style can be {gpu}, {intel}, {kk}, {omp}, {opt} or @@ -105,6 +105,6 @@ input script. [Related commands:] -"Command-line switch -suffix"_Section_start.html#start_7 +"Command-line switch -suffix"_Section_start.html#start_6 [Default:] none diff --git a/doc/src/temper.txt b/doc/src/temper.txt index be7edfba43..b1c47c8076 100644 --- a/doc/src/temper.txt +++ b/doc/src/temper.txt @@ -32,7 +32,7 @@ replicas (ensembles) of a system. Two or more replicas must be used. Each replica runs on a partition of one or more processors. Processor partitions are defined at run-time using the -partition command-line -switch; see "Section 2.7"_Section_start.html#start_7 of the +switch; see "Section 2.6"_Section_start.html#start_6 of the manual. Note that if you have MPI installed, you can run a multi-replica simulation with more replicas (partitions) than you have physical processors, e.g you can run a 10-replica simulation on one or @@ -70,7 +70,7 @@ As a tempering run proceeds, multiple log files and screen output files are created, one per replica. By default these files are named log.lammps.M and screen.M where M is the replica number from 0 to N-1, with N = # of replicas. See the "section on command-line -switches"_Section_start.html#start_7 for info on how to change these +switches"_Section_start.html#start_6 for info on how to change these names. The main screen and log file (log.lammps) will list information about diff --git a/doc/src/thermo_style.txt b/doc/src/thermo_style.txt index 36ec7bf12e..6102169ee3 100644 --- a/doc/src/thermo_style.txt +++ b/doc/src/thermo_style.txt @@ -255,7 +255,7 @@ The {part} keyword is useful for multi-replica or multi-partition simulations to indicate which partition this output and this file corresponds to, or for use in a "variable"_variable.html to append to a filename for output specific to this partition. See "Section -2.7"_Section_start.html#start_7 of the manual for details on running +2.6"_Section_start.html#start_6 of the manual for details on running in multi-partition mode. The {timeremain} keyword returns the remaining seconds when a diff --git a/doc/src/timer.txt b/doc/src/timer.txt index 39a6c542b7..768c3e1353 100644 --- a/doc/src/timer.txt +++ b/doc/src/timer.txt @@ -40,7 +40,7 @@ time is spent in different sections of the code and thus can provide information for determining performance and load imbalance problems. This can be done at different levels of detail and accuracy. For more information about the timing output, see this "discussion of screen -output in Section 2.8"_Section_start.html#start_8. +output in Section 2.7"_Section_start.html#start_7. The {off} setting will turn all time measurements off. The {loop} setting will only measure the total time for a run and not collect any diff --git a/doc/src/variable.txt b/doc/src/variable.txt index e32e82ef4d..e3b7c5de0d 100644 --- a/doc/src/variable.txt +++ b/doc/src/variable.txt @@ -178,7 +178,7 @@ This means variables can NOT be re-defined in an input script (with two exceptions, read further). This is to allow an input script to be processed multiple times without resetting the variables; see the "jump"_jump.html or "include"_include.html commands. It also means -that using the "command-line switch"_Section_start.html#start_7 -var +that using the "command-line switch"_Section_start.html#start_6 -var will override a corresponding index variable setting in the input script. @@ -248,7 +248,7 @@ variable. {Index} style variables with a single string value can also be set by using the command-line switch -var; see "this -section"_Section_start.html#start_7 for details. +section"_Section_start.html#start_6 for details. The {loop} style is identical to the {index} style except that the strings are the integers from 1 to N inclusive, if only one argument N @@ -264,7 +264,7 @@ N1 <= N2 and N2 >= 0 is required. For the {world} style, one or more strings are specified. There must be one string for each processor partition or "world". See "this -section"_Section_start.html#start_7 of the manual for information on +section"_Section_start.html#start_6 of the manual for information on running LAMMPS with multiple partitions via the "-partition" command-line switch. This variable command assigns one string to each world. All processors in the world are assigned the same string. The @@ -277,7 +277,7 @@ different partitions. For the {universe} style, one or more strings are specified. There must be at least as many strings as there are processor partitions or -"worlds". See "this page"_Section_start.html#start_7 for information +"worlds". See "this page"_Section_start.html#start_6 for information on running LAMMPS with multiple partitions via the "-partition" command-line switch. This variable command initially assigns one string to each world. When a "next"_next.html command is encountered diff --git a/doc/src/write_data.txt b/doc/src/write_data.txt index 033199e98b..39e5a7f811 100644 --- a/doc/src/write_data.txt +++ b/doc/src/write_data.txt @@ -59,7 +59,7 @@ If you want to do more exact restarts, using binary files, see the "restart"_restart.html, "write_restart"_write_restart.html, and "read_restart"_read_restart.html commands. You can also convert binary restart files to text data files, after a simulation has run, -using the "-r command-line switch"_Section_start.html#start_7. +using the "-r command-line switch"_Section_start.html#start_6. NOTE: Only limited information about a simulation is stored in a data file. For example, no information about atom "groups"_group.html and diff --git a/doc/src/write_restart.txt b/doc/src/write_restart.txt index 8160eec3df..ff3b652dba 100644 --- a/doc/src/write_restart.txt +++ b/doc/src/write_restart.txt @@ -66,7 +66,7 @@ Restart files can be read by a "read_restart"_read_restart.html command to restart a simulation from a particular state. Because the file is binary (to enable exact restarts), it may not be readable on another machine. In this case, you can use the "-r command-line -switch"_Section_start.html#start_7 to convert a restart file to a data +switch"_Section_start.html#start_6 to convert a restart file to a data file. NOTE: Although the purpose of restart files is to enable restarting a diff --git a/src/Make.py b/src/Make.py deleted file mode 100755 index 3030183e1a..0000000000 --- a/src/Make.py +++ /dev/null @@ -1,2378 +0,0 @@ -#!/usr/bin/env python2 - -# Make.py tool for managing packages and their auxiliary libs, -# auto-editing machine Makefiles, and building LAMMPS -# Syntax: Make.py -h (for help) -# Notes: should be compatible with python 2.7 and 3.x thanks to 'futurize' - -from __future__ import print_function -import sys,os,re,copy,subprocess,platform - -# switch abbrevs -# switch classes = created class for each switch -# lib classes = auxiliary package libs -# build classes = build options with defaults -# make classes = makefile options with no defaults -# setargs = makefile settings -# actionargs = allowed actions (also lib-dir and machine) -# lib build flags are set if lib is built, for use with zoutput - -abbrevs = "adhjmoprsvz" - -switchclasses = ("actions","dir","help","jmake","makefile", - "output","packages","redo","settings","verbose","zoutput") -libclasses = ("atc","awpmd","colvars","cuda","gpu","h5md", - "meam","poems","python","qmmm","reax","voronoi") -buildclasses = ("intel","kokkos") -makeclasses = ("cc","flags","mpi","fft","jpg","png") - -setargs = ("gzip","#gzip","ffmpeg","#ffmpeg","smallbig","bigbig", - "smallsmall","exceptions","#exceptions") -actionargs = ("lib-all","file","clean","exe") - -gpubuildflag = 0 - -# ---------------------------------------------------------------- -# functions -# ---------------------------------------------------------------- - -# if flag = 1, print txt and exit -# if flag = 0, print txt as warning and do not exit - -def error(txt,flag=1): - if flag: - print("ERROR:",txt) - sys.exit() - else: - print("WARNING:",txt) - -# store command-line args as sw = dict of key/value -# key = switch word, value = list of following args -# order = list of switches in order specified -# enforce no switch more than once - -def parse_args(args): - narg = len(args) - sw = {} - order = [] - iarg = 0 - while iarg < narg: - if args[iarg][0] != '-': error("Arg %s is not a switch" % args[iarg]) - switch = args[iarg][1:] - if switch in sw: error("Duplicate switch %s" % args[iarg]) - order.append(switch) - first = iarg+1 - last = first - while last < narg and args[last][0] != '-': last += 1 - sw[switch] = args[first:last] - iarg = last - return sw,order - -# convert info in switches dict back to a string, in switch_order - -def switch2str(switches,switch_order): - txt = "" - for switch in switch_order: - if txt: txt += ' ' - txt += "-%s" % switch - txt += ' ' + ' '.join(switches[switch]) - return txt - -# check if compiler works with ccflags on dummy one-line tmpauto.cpp file -# return 1 if successful, else 0 -# warn = 1 = print warning if not successful, warn = 0 = no warning -# NOTE: unrecognized -override-limits can leave verride-limits file - -def compile_check(compiler,ccflags,warn): - open("tmpauto.cpp",'w').write("int main(int, char **) {}\n") - tmp = "%s %s -c tmpauto.cpp" % (compiler,ccflags) - try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT, - shell=True).decode() - except subprocess.CalledProcessError as e: txt = e.output - flag = 1 - if txt or not os.path.isfile("tmpauto.o"): - flag = 0 - if warn: - print(tmp) - if txt: print(txt) - else: print("compile produced no output") - os.remove("tmpauto.cpp") - if os.path.isfile("tmpauto.o"): os.remove("tmpauto.o") - return flag - -# check if linker works with linkflags and libs on tmpauto.o file -# return 1 if successful, else 0 -# warn = 1 = print warning if not successful, warn = 0 = no warning - -def link_check(linker,linkflags,libs,warn): - open("tmpauto.cpp",'w').write("int main(int, char **) {}\n") - tmp = "%s %s -o tmpauto tmpauto.cpp %s" % (linker,linkflags,libs) - try: txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT, - shell=True).decode() - except subprocess.CalledProcessError as e: txt = e.output - flag = 1 - if txt or not os.path.isfile("tmpauto"): - flag = 0 - if warn: - print(tmp) - if txt: print(txt) - else: print("link produced no output") - os.remove("tmpauto.cpp") - if os.path.isfile("tmpauto"): os.remove("tmpauto") - return flag - -# ---------------------------------------------------------------- -# switch classes, one per single-letter switch -# ---------------------------------------------------------------- - -# actions - -class Actions(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --a action1 action2 ... - possible actions = lib-all, lib-dir, file, clean, exe or machine - machine is a Makefile.machine suffix - actions can be specified in any order - each action can appear only once - lib-dir can appear multiple times for different dirs - some actions depend on installed packages - installed packages = currently installed + result of -p switch - actions are invoked in this order, independent of specified order - (1) lib-all or lib-dir = build auxiliary libraries - lib-all builds all auxiliary libs needed by installed packages - lib-dir builds a specific lib whether package installed or not - dir is any dir in lib directory (atc, cuda, meam, etc) except linalg - (2) file = create a new src/MAKE/MINE/Makefile.auto - if file not specified, existing Makefile.auto is NOT changed - except by -m switch, which will copy Makefile.machine to Makefile.auto - note that exe action can add an -m switch, as described below - if file is specified, new Makefile.auto is created - if "-m machine" specified (or added by exe), - start with existing Makefile.machine, else existing Makefile.auto - if "-m none" specified, start Makefile.auto from scratch - must use -cc and -mpi switches to specify compiler and MPI - settings for these switches will alter Makefile.auto - -s, -intel, -kokkos, -cc, -mpi, -fft, -jpg, -png - if these accelerator packages are installed, they induce settings - that will alter Makefile.auto: opt, user-omp, user-intel, kokkos - use -z switch to copy final Makefile.auto to new filename - (3) clean = invoke "make clean-auto" to insure clean build on current files - useful if compiler flags have changed - (4) exe or machine = build LAMMPS - machine can be any existing Makefile.machine suffix - machine is converted to "exe" action, and additionally: - "-m machine" is added if -m switch is not specified - "-o machine" is added if -o switch is not specified - if either "-m" or "-o" are specified, they are not overridden - does not invoke any lib builds, since libs could be previously built - exe ALWAYS builds using src/MAKE/MINE/Makefile.auto - if file action also specified, it creates a new Makefile.auto - else if -m switch specified, - existing Makefile.machine is copied to create Makefile.auto - else Makefile.auto must already exist and is not changed - build produces src/lmp_auto, or error message if unsuccessful - use -o switch to copy src/lmp_auto to new filename - use -z switch to copy src/MAKE/MINE/Makefile.auto to new filename -""" - - def check(self): - if not self.inlist: error("-a args are invalid") - libs = [] - cleans = [] - files = [] - exes = [] - for one in self.inlist: - if one.startswith("lib-"): - lib = one[4:] - if lib != "all" and lib not in libclasses: error("Actions are invalid") - libs.append(one) - elif one == "file": - files.append(one) - elif one == "clean": - cleans.append(one) - elif one == "exe": - exes.append(one) - # one action can be unknown, must be a machine (checked in setup) - else: - exes.append(one) - if len(set(libs)) != len(libs) or \ - len(cleans) > 1 or len(files) > 1 or len(exes) > 1: - error("Actions are invalid") - self.alist = [action for actions in [libs,cleans,files,exes] \ - for action in actions] - - # dedup list of actions concatenated from two lists - # current self.inlist = specified -a switch + redo command -a switch - # specified exe/machine action replaces redo exe/machine action - # operates on and replaces self.inlist - - def dedup(self): - alist = [] - exemachine = 0 - for one in self.inlist: - if one == "exe" or (one not in actionargs and not one.startswith("lib-")): - if exemachine: continue - exemachine = 1 - if one not in alist: alist.append(one) - self.inlist = alist - - # if last action is unknown, assume machine and convert to exe - # only done if action is a suffix for an existing Makefile.machine - # return machine if conversion done, else None - - def setup(self): - machine = self.alist[-1] - if machine in actionargs or machine.startswith("lib-"): return None - make = MakeReader(machine,2) - self.alist[-1] = "exe" - return machine - - # build one or more auxiliary package libraries - - def lib(self,suffix): - if suffix != "all": - print("building",suffix,"library ...") - txt = "%s.build()" % suffix - exec(txt) - else: - final = packages.final - for one in packages.lib: - if final[one]: - if "user" in one: pkg = one[5:] - else: pkg = one - print("building",pkg,"library ...") - txt = "%s.build()" % pkg - exec(txt) - - # read Makefile.machine - # if caller = "file", edit via switches - # if caller = "exe", just read - # write out new Makefile.auto - - def file(self,caller): - - # if caller="file", create from mpi or read from Makefile.machine or auto - # if caller="exe" and "file" action already invoked, read from auto - # if caller="exe" and no "file" action, read from Makefile.machine or auto - - if caller == "file": - if makefile and makefile.machine == "none": - if cc and mpi: machine = "mpi" - else: error("Cannot create makefile unless -cc and -mpi are used") - elif makefile: machine = makefile.machine - else: machine = "auto" - elif caller == "exe" and "file" in self.alist: - machine = "auto" - elif caller == "exe" and "file" not in self.alist: - if makefile and makefile.machine == "none": - error("Cannot build with makefile = none") - elif makefile: machine = makefile.machine - else: machine = "auto" - - make = MakeReader(machine,1) - - # change makefile settings to user specifications - - precompiler = "" - if caller == "file": - - # add compiler/linker and default CCFLAGS,LINKFLAGS - # if cc.wrap, add wrapper setting for mpi = ompi/mpich - # precompiler = env variable setting for OpenMPI wrapper compiler - - if cc: - make.setvar("CC",cc.compiler) - make.setvar("LINK",cc.compiler) - if cc.wrap: - if cc.wrap == "nvcc": - wrapper = os.path.abspath("../lib/kokkos/config/nvcc_wrapper") - else: wrapper = cc.wrap - abbrev = cc.abbrev - if abbrev == "mpi": - if cc.parent == "mpich": - make.addvar("CC","-cxx=%s" % wrapper) - make.addvar("LINK","-cxx=%s" % wrapper) - elif cc.parent == "openmpi": - make.addvar("export OMPI_CXX",wrapper,"cc") - precompiler = "env OMPI_CXX=%s " % wrapper - else: error("Could not add MPI wrapper compiler, " + - "did not recognize OpenMPI or MPICH") - make.setvar("CCFLAGS","-g") - make.addvar("CCFLAGS","-O3") - make.setvar("LINKFLAGS","-g") - make.addvar("LINKFLAGS","-O") - - # add MPI settings - - if mpi: - make.delvar("MPI_INC","*") - make.delvar("MPI_PATH","*") - make.delvar("MPI_LIB","*") - if mpi.style == "mpi": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - elif mpi.style == "mpich": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir) - if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir) - make.addvar("MPI_LIB","-lmpich") - make.addvar("MPI_LIB","-lmpl") - make.addvar("MPI_LIB","-lpthread") - elif mpi.style == "ompi": - make.addvar("MPI_INC","-DMPICH_SKIP_MPICXX") - make.addvar("MPI_INC","-DOMPI_SKIP_MPICXX=1") - if mpi.dir: make.addvar("MPI_INC","-I%s/include" % mpi.dir) - if mpi.dir: make.addvar("MPI_PATH","-L%s/lib" % mpi.dir) - make.addvar("MPI_LIB","-lmpi") - make.addvar("MPI_LIB","-lmpi_cxx") - elif mpi.style == "serial": - make.addvar("MPI_INC","-I../STUBS") - make.addvar("MPI_PATH","-L../STUBS") - make.addvar("MPI_LIB","-lmpi_stubs") - - # add accelerator package CCFLAGS and LINKFLAGS and variables - - compiler = precompiler + ' '.join(make.getvar("CC")) - linker = precompiler + ' '.join(make.getvar("LINK")) - - final = packages.final - if final["opt"]: - if compile_check(compiler,"-restrict",0): - make.addvar("CCFLAGS","-restrict") - - if final["user-omp"]: - if compile_check(compiler,"-fopenmp",1): - make.addvar("CCFLAGS","-fopenmp") - make.addvar("LINKFLAGS","-fopenmp") - if compile_check(compiler,"-restrict",0): - make.addvar("CCFLAGS","-restrict") - - if final["user-intel"]: - if intel.mode == "cpu": - make.delvar("CCFLAGS","-O*") - make.addvar("CCFLAGS","-O2") - if compile_check(compiler,"-openmp",1): - make.addvar("CCFLAGS","-openmp") - if compile_check(compiler,"-restrict",1): - make.addvar("CCFLAGS","-restrict") - if compile_check(compiler,"-no-offload",1): - make.addvar("CCFLAGS","-no-offload") - if compile_check(compiler,"-fno-alias",1): - make.addvar("CCFLAGS","-fno-alias") - if compile_check(compiler,"-ansi-alias",1): - make.addvar("CCFLAGS","-ansi-alias") - if compile_check(compiler,"-xAVX",1): - make.addvar("CCFLAGS","-xAVX") - if compile_check(compiler,"-fp-model fast=2",1): - make.addvar("CCFLAGS","-fp-model fast=2") - if compile_check(compiler,"-no-prec-div",1): - make.addvar("CCFLAGS","-no-prec-div") - if compile_check(compiler,"-override-limits",1): - make.addvar("CCFLAGS","-override-limits") - make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64") - make.delvar("CCFLAGS","-DLMP_INTEL_OFFLOAD") - - make.delvar("LINKFLAGS","-O*") - make.addvar("LINKFLAGS","-O2") - if link_check(linker,"-openmp","",1): - make.addvar("LINKFLAGS","-openmp") - if link_check(linker,"-xAVX","",1): - make.addvar("LINKFLAGS","-xAVX") - if link_check(linker,"-fpmodel fast=2","",1): - make.addvar("LINKFLAGS","-fpmodel fast=2") - if link_check(linker,"-no-prec-div","",1): - make.addvar("LINKFLAGS","-no-prec-div") - if link_check(linker,"-override-limits","",1): - make.addvar("LINKFLAGS","-override-limits") - make.delvar("LINKFLAGS","-offload") - - if link_check(linker,"","-ltbbmalloc",1): - make.addvar("LIB","-ltbbmalloc") - if link_check(linker,"","-ltbbmalloc_proxy",1): - make.addvar("LIB","-ltbbmalloc_proxy") - - elif intel.mode == "phi": - if compile_check(compiler,"-fopenmp",1): - make.addvar("CCFLAGS","-fopenmp") - make.addvar("LINKFLAGS","-fopenmp") - make.addvar("CCFLAGS","-DLAMMPS_MEMALIGN=64") - if compile_check(compiler,"-restrict",1): - make.addvar("CCFLAGS","-restrict") - if compile_check(compiler,"-xHost",1): - make.addvar("CCFLAGS","-xHost") - make.addvar("CCFLAGS","-DLMP_INTEL_OFFLOAD") - if compile_check(compiler,"-fno-alias",1): - make.addvar("CCFLAGS","-fno-alias") - if compile_check(compiler,"-ansi-alias",1): - make.addvar("CCFLAGS","-ansi-alias") - if compile_check(compiler,"-override-limits",1): - make.addvar("CCFLAGS","-override-limits") - if compile_check(compiler,'-offload-option,mic,compiler,' + - '"-fp-model fast=2 -mGLOB_default_function_attrs=' + - '\\"gather_scatter_loop_unroll=4\\""',1): - make.addvar("CCFLAGS",'-offload-option,mic,compiler,' + - '"-fp-model fast=2 -mGLOB_default_function_attrs=' + - '\\"gather_scatter_loop_unroll=4\\""') - if link_check(linker,"-offload","",1): - make.addvar("LINKFLAGS","-offload") - - if final["kokkos"]: - if kokkos.mode == "omp": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","OpenMP","lmp") - if kokkos.archcpu: - make.addvar("KOKKOS_ARCH",kokkos.archcpu,"lmp") - elif kokkos.mode == "cuda": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","Cuda, OpenMP","lmp") - if kokkos.archgpu: - if kokkos.archgpu[0] == "3": value = "Kepler" + kokkos.archgpu - elif kokkos.archgpu[0] == "2": value = "Fermi" + kokkos.archgpu - else: error("Unrecognized Kokkos archgpu setting") - if kokkos.archcpu: value += ", %s" % kokkos.archcpu - make.addvar("KOKKOS_ARCH",value,"lmp") - elif kokkos.mode == "phi": - make.delvar("KOKKOS_DEVICES","*") - make.delvar("KOKKOS_ARCH","*") - make.addvar("KOKKOS_DEVICES","OpenMP","lmp") - make.addvar("KOKKOS_ARCH","KNC","lmp") - - # add LMP_INC ifdef settings - - if settings: - list = settings.inlist - for one in list: - if one == "gzip": make.addvar("LMP_INC","-DLAMMPS_GZIP") - elif one == "#gzip": make.delvar("LMP_INC","-DLAMMPS_GZIP") - elif one == "ffmpeg": make.addvar("LMP_INC","-DLAMMPS_FFMPEG") - elif one == "#ffmpeg": make.delvar("LMP_INC","-DLAMMPS_FFMPEG") - elif one == "smallbig": - make.delvar("LMP_INC","-DLAMMPS_BIGBIG") - make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL") - elif one == "bigbig": - make.delvar("LMP_INC","-DLAMMPS_SMALLBIG") - make.delvar("LMP_INC","-DLAMMPS_SMALLSMALL") - make.addvar("LMP_INC","-DLAMMPS_BIGBIG") - elif one == "smallsmall": - make.delvar("LMP_INC","-DLAMMPS_SMALLBIG") - make.delvar("LMP_INC","-DLAMMPS_BIGBIG") - make.addvar("LMP_INC","-DLAMMPS_SMALLSMALL") - elif one == "exceptions": make.addvar("LMP_INC","-DLAMMPS_EXCEPTIONS") - elif one == "#exception": make.delvar("LMP_INC","-DLAMMPS_EXCEPTIONS") - - # add FFT, JPG, PNG settings - - if fft: - make.delvar("FFT_INC","*") - make.delvar("FFT_PATH","*") - make.delvar("FFT_LIB","*") - if fft.mode == "none": make.addvar("FFT_INC","-DFFT_NONE") - else: - make.addvar("FFT_INC","-DFFT_%s" % fft.mode.upper()) - make.addvar("FFT_LIB",fft.lib) - if fft.dir: - make.addvar("FFT_INC","-I%s/include" % fft.dir) - make.addvar("FFT_PATH","-L%s/lib" % fft.dir) - else: - if fft.incdir: make.addvar("FFT_INC","-I%s" % fft.incdir) - if fft.libdir: make.addvar("FFT_PATH","-L%s" % fft.libdir) - - if jpg: - if jpg.on == 0: - make.delvar("LMP_INC","-DLAMMPS_JPEG") - make.delvar("JPG_LIB","-ljpeg") - else: - make.addvar("LMP_INC","-DLAMMPS_JPEG") - make.addvar("JPG_LIB","-ljpeg") - if jpg.dir: - make.addvar("JPG_INC","-I%s/include" % jpg.dir) - make.addvar("JPG_PATH","-L%s/lib" % jpg.dir) - else: - if jpg.incdir: make.addvar("JPG_INC","-I%s" % jpg.incdir) - if jpg.libdir: make.addvar("JPG_PATH","-L%s" % jpg.libdir) - - if png: - if png.on == 0: - make.delvar("LMP_INC","-DLAMMPS_PNG") - make.delvar("JPG_LIB","-lpng") - else: - make.addvar("LMP_INC","-DLAMMPS_PNG") - make.addvar("JPG_LIB","-lpng") - if png.dir: - make.addvar("JPG_INC","-I%s/include" % png.dir) - make.addvar("JPG_PATH","-L%s/lib" % png.dir) - else: - if png.incdir: make.addvar("JPG_INC","-I%s" % png.incdir) - if png.libdir: make.addvar("JPG_PATH","-L%s" % png.libdir) - - # finally after all other settings, add explicit flags - - if flags: - for var,action,flist in flags.flags: - values = make.getvar(var) - if values == None: - error("Flags for a non-existent Makefile.auto variable") - for flag in flist: - flag = "-" + flag - if action == "add": make.addvar(var,flag) - elif action == "del": make.delvar(var,flag) - - # set self.stubs if Makefile.auto uses STUBS lib in MPI settings - - if make.getvar("MPI_LIB") and "-lmpi_stubs" in make.getvar("MPI_LIB"): - self.stubs = 1 - else: self.stubs = 0 - - # write out Makefile.auto - # unless caller = "exe" and "file" action already invoked - - if caller == "file" or "file" not in self.alist: - # make certain that 'MAKE/MINE' folder exists. - subprocess.check_output("mkdir -p %s/MAKE/MINE" % dir.src, - stderr=subprocess.STDOUT,shell=True) - make.write("%s/MAKE/MINE/Makefile.auto" % dir.src,1) - print("Created src/MAKE/MINE/Makefile.auto") - - # test full compile and link - # unless caller = "file" and "exe" action will be invoked later - - if caller == "file" and "exe" in self.alist: return - compiler = precompiler + ' '.join(make.getvar("CC")) - ccflags = ' '.join(make.getvar("CCFLAGS")) - linker = precompiler + ' '.join(make.getvar("LINK")) - linkflags = ' '.join(make.getvar("LINKFLAGS")) - libs = ' '.join(make.getvar("LIB")) - if not compile_check(compiler,ccflags,1): - error("Test of compilation failed") - if not link_check(linker,linkflags,libs,1): error("Test of link failed") - - # invoke "make clean-auto" to force clean before build - - def clean(self): - txt = "cd %s; make clean-auto" % dir.src - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Performed make clean-auto") - - # build LAMMPS using Makefile.auto and -j setting - # invoke self.file() first, to test makefile compile/link - # delete existing lmp_auto, so can detect if build fails - # build STUBS lib (if unbuilt) if Makefile.auto MPI settings need it - - def exe(self): - self.file("exe") - subprocess.check_output("cd %s; rm -f lmp_auto" % dir.src,stderr=subprocess.STDOUT,shell=True) - if self.stubs and not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src): - print("building serial STUBS library ...") - tmp = "cd %s/STUBS; make clean; make" % dir.src - txt = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode() - if not os.path.isfile("%s/STUBS/libmpi_stubs.a" % dir.src): - print(txt) - error('Unsuccessful "make stubs"') - print("Created src/STUBS/libmpi_stubs.a") - - # special hack for shannon GPU cluster - # must use "srun make" if on it and building w/ GPU package, else just make - # this is b/c Cuda libs are not all available on host - - make = "make" - if "shannon" == platform.node() and packages.final["gpu"]: - make = "srun make" - - if jmake: tmp = "cd %s; %s -j %d auto" % (dir.src,make,jmake.n) - else: tmp = "cd %s; %s auto" % (dir.src,make) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(tmp,shell=True) - else: - print(tmp) - try: subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/lmp_auto" % dir.src): - error('Unsuccessful "make auto"') - elif not output: print("Created src/lmp_auto") - -# dir switch - -class Dir(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --d dir - dir = LAMMPS home dir - if -d not specified, working dir must be lammps/src -""" - - def check(self): - if self.inlist != None and len(self.inlist) != 1: - error("-d args are invalid") - - # if inlist = None, check that cwd = lammps/src - # store cwd and lammps dir - # derive src,make,lib dirs from lammps dir - # check that they all exist - - def setup(self): - self.cwd = os.getcwd() - if self.inlist == None: self.lammps = ".." - else: self.lammps = self.inlist[0] - self.lammps = os.path.realpath(self.lammps) - self.src = self.lammps + "/src" - self.make = self.lammps + "/src/MAKE" - self.lib = self.lammps + "/lib" - if not os.path.isdir(self.lammps): error("LAMMPS home dir is invalid") - if not os.path.isdir(self.src): error("LAMMPS src dir is invalid") - if not os.path.isdir(self.lib): error("LAMMPS lib dir is invalid") - -# help switch - -class Help(object): - def __init__(self,list): pass - - def help(self): - return """ -Syntax: Make.py switch args ... - switches can be listed in any order - help switch: - -h prints help and syntax for all other specified switches - switch for actions: - -a lib-all, lib-dir, clean, file, exe or machine - list one or more actions, in any order - machine is a Makefile.machine suffix - one-letter switches: - -d (dir), -j (jmake), -m (makefile), -o (output), -p (packages), - -r (redo), -s (settings), -v (verbose), -z (makefile output) - switches for libs: - -atc, -awpmd, -colvars, -cuda, -gpu, -h5md, - -meam, -poems, -python, -qmmm, -reax, -voronoi - switches for build and makefile options: - -intel, -kokkos, -cc, -flags, -mpi, -fft, -jpg, -png -""" - -# jmake switch - -class Jmake(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --j N - use N procs for performing parallel make commands - used when building a lib or LAMMPS itself - if -j not specified, serial make commands run on single core -""" - - def check(self): - if len(self.inlist) != 1: error("-j args are invalid") - if not self.inlist[0].isdigit(): error("-j args are invalid") - n = int(self.inlist[0]) - if n <= 0: error("-j args are invalid") - self.n = n - -# makefile switch - -class Makefile(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --m machine - use Makefile.machine under src/MAKE as starting point to create Makefile.auto - if machine = "none", file action will create Makefile.auto from scratch - must use -cc and -mpi switches to specify compiler and MPI - if -m not specified, file/exe actions alter existing Makefile.auto -""" - - def check(self): - if len(self.inlist) != 1: error("-m args are invalid") - self.machine = self.inlist[0] - -# output switch - -class Output(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --o machine - copy final src/lmp_auto to lmp_machine in working dir - if -o not specified, exe action only produces src/lmp_auto -""" - - def check(self): - if len(self.inlist) != 1: error("-o args are invalid") - self.machine = self.inlist[0] - -# packages switch - -class Packages(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --p = package1 package2 ... - list of packages to install or uninstall in order specified - operates on set of packages currently installed - valid package names: - any LAMMPS standard or user package (type "make package" to see list) - prefix by yes/no to install/uninstall (see abbrevs) - yes-molecule, yes-user-atc, no-molecule, no-user-atc - can use LAMMPS categories (type "make package" to see list) - all = all standard and user packages (also none = no-all) - std (or standard) = all standard packages - user = all user packages - lib = all standard and user packages with auxiliary libs - can abbreviate package names and yes/no - omp = user-omp = yes-user-omp - ^omp = ^user-omp = no-user-omp - user = yes-user, ^user = no-user - all = yes-all, ^all = none = no-all - when action performed, list is processed in order, - as if typed "make yes/no" for each - if "orig" or "original" is last package in list, - set of installed packages will be restored to original (current) list - after "build" action is performed - if -p not specified, currently installed packages are not changed -""" - - def check(self): - if self.inlist != None and not self.inlist: error("-p args are invalid") - - def setup(self): - - # extract package lists from src/Makefile - # remove names from lib that there are not Make.py lib-classes for - # most don't actually have libs, so nothing to control from Make.py - - make = MakeReader("%s/Makefile" % dir.src) - std = make.getvar("PACKAGE") - user = make.getvar("PACKUSER") - lib = make.getvar("PACKLIB") - lib.remove("kim") - lib.remove("kokkos") - lib.remove("user-molfile") - lib.remove("python") - lib.remove("user-quip") - all = std + user - - # plist = command line args expanded to yes-package or no-package - - plist = [] - if self.inlist: - for one in self.inlist: - if one in std: - plist.append("yes-%s" % one) - elif one in user: - plist.append("yes-%s" % one) - elif "user-"+one in user: - plist.append("yes-user-%s" % one) - elif one == "std" or one == "standard" or one == "user" or \ - one == "lib" or one == "all": plist.append("yes-%s" % one) - elif one.startswith("yes-"): - if one[4:] in std: plist.append("yes-%s" % one[4:]) - elif one[4:] in user: plist.append("yes-%s" % one[4:]) - elif "user-"+one[4:] in user: plist.append("yes-user-%s" % one[4:]) - elif one == "yes-std" or one == "yes-standard" or \ - one == "yes-user" or one == "yes-lib" or one == "yes-all": - plist.append("yes-%s" % one[4:]) - else: error("Invalid package name %s" % one) - elif one.startswith("no-"): - if one[3:] in std: plist.append("no-%s" % one[3:]) - elif one[3:] in user: plist.append("no-%s" % one[3:]) - elif "user-"+one[3:] in user: plist.append("no-user-%s" % one[3:]) - elif one == "no-std" or one == "no-standard" or one == "no-user" or \ - one == "no-lib" or one == "no-all": - plist.append("no-%s" % one[3:]) - else: error("Invalid package name %s" % one) - elif one.startswith('^'): - if one[1:] in std: plist.append("no-%s" % one[1:]) - elif one[1:] in user: plist.append("no-%s" % one[1:]) - elif "user-"+one[1:] in user: plist.append("no-user-%s" % one[1:]) - elif one == "^std" or one == "^standard" or one == "^user" or \ - one == "^lib" or one == "^all": plist.append("no-%s" % one[1:]) - else: error("Invalid package name %s" % one) - elif one == "none": plist.append("no-all") - elif one == "orig": plist.append(one) - else: error("Invalid package name %s" % one) - if "orig" in plist and plist.index("orig") != len(plist)-1: - error('-p orig arg must be last') - if plist.count("orig") > 1: error('-p orig arg must be last') - - # original = dict of all packages - # key = package name, value = 1 if currently installed, else 0 - - original = {} - tmp = "cd %s; make ps" % dir.src - output = subprocess.check_output(tmp,stderr=subprocess.STDOUT,shell=True).decode().split('\n') - pattern = "Installed\s+(\w+): package (\S+)" - for line in output: - m = re.search(pattern,line) - if not m: continue - pkg = m.group(2).lower() - if pkg not in all: error('Package list does not match "make ps" results') - if m.group(1) == "NO": original[pkg] = 0 - elif m.group(1) == "YES": original[pkg] = 1 - - # final = dict of all packages after plist applied to original - # key = package name, value = 1 if installed, else 0 - - final = copy.deepcopy(original) - for i,one in enumerate(plist): - if "yes" in one: - pkg = one[4:] - yes = 1 - else: - pkg = one[3:] - yes = 0 - if pkg in all: - final[pkg] = yes - elif pkg == "std" or pkg == "standard": - for pkg in std: final[pkg] = yes - elif pkg == "user": - for pkg in user: final[pkg] = yes - elif pkg == "lib": - for pkg in lib: final[pkg] = yes - elif pkg == "all": - for pkg in all: final[pkg] = yes - - self.std = std - self.user = user - self.lib = lib - self.all = all - self.plist = plist - self.original = original - self.final = final - - # install packages in plist - - def install(self): - if self.plist: print("Installing packages ...") - for one in self.plist: - if one == "orig": continue - subprocess.check_output("cd %s; make %s" % (dir.src,one), - stderr=subprocess.STDOUT,shell=True) - if self.plist and verbose: - txt = subprocess.check_output("cd %s; make ps" % dir.src, - stderr=subprocess.STDOUT, - shell=True).decode() - print("Package status after installation:") - print(txt) - - # restore packages to original list if requested - # order of re-install should not matter matter b/c of Depend.sh - - def uninstall(self): - if not self.plist or self.plist[-1] != "orig": return - print("Restoring packages to original state ...") - subprocess.check_output("cd %s; make no-all" % dir.src, - stderr=subprocess.STDOUT,shell=True) - for one in self.all: - if self.original[one]: - subprocess.check_output("cd %s; make yes-%s" % (dir.src,one), - stderr=subprocess.STDOUT,shell=True) - if verbose: - txt = subprocess.check_output("cd %s; make ps" % dir.src, - stderr=subprocess.STDOUT, - shell=True).decode() - print("Restored package status:") - print(txt) - -# redo switch - -class Redo(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --r file label1 label2 ... - all args are optional - invoke Make.py commands from a file - other specified switches are merged with file commands (see below) - redo file format: - blank lines and lines starting with "#" are skipped - other lines are treated as commands - each command is a list of Make.py args, as if typed at command-line - commands can have leading label, followed by ":" - commands cannot contain a "-r" switch - if no args, execute previous command, which is stored in src/Make.py.last - if one arg, execute all commands from specified file - unlabeled or labeled commands are all executed - if multiple args, execute only matching labeled commands from file - if other switches are specified, - if file command does not have the switch, it is added - if file command has the switch, the specified switch replaces it - except if -a (action) switch is both specified and in the file command, - two sets of actions are merged and duplicates removed - if both switches have "exe or machine" action, - the specified exe/machine overrides the file exe/machine -""" - - def check(self): - if len(self.inlist) == 0: - self.dir = 1 - self.file = "Make.py.last" - self.labels = [] - else: - self.dir = 0 - self.file = self.inlist[0] - self.labels = self.inlist[1:] - - # read redo file - # self.commands = list of commands to execute - - def setup(self): - file = self.file - if not os.path.isfile(file): error("Redo file %s does not exist" % file) - lines = open(file,'r').readlines() - - cmdlines = [] - for line in lines: - line = line.strip() - if not line or line[0] == '#' : continue - cmdlines.append(line) - - # if no labels, add all file commands to command list - # if labels, make a dict with key = label, value = command - # and discard unlabeled commands - - dict = {} - commands = [] - for line in cmdlines: - words = line.split() - if "-r" in words: error("Redo command cannot contain -r switch") - if words[0][-1] == ':': label = words[0][:-1] - else: label = None - if not self.labels: - if label: subprocess.append(' '.join(words[1:])) - else: subprocess.append(line) - else: - if not label: continue - dict[label] = ' '.join(words[1:]) - - # extract labeled commands from dict and add to command list - - for label in self.labels: - if label not in dict: error("Redo label not in redo file") - subprocess.append(dict[label]) - - self.commands = commands - -# settings switch - -class Settings(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --s set1 set2 ... - possible settings = gzip #gzip ffmpeg #ffmpeg - smallbig bigbig smallsmall exceptions #exceptions - alter LAMMPS ifdef settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - gzip and #gzip turn on/off LAMMPS_GZIP setting - ffmpeg and #ffmpeg turn on/off LAMMPS_FFMPEG setting - smallbig, bigbig, smallsmall turn on LAMMPS_SMALLBIG, etc - and turn off other two - exceptions and #exceptions turn on/off LAMMPS_EXCEPTIONS setting -""" - - def check(self): - if not self.inlist: error("-s args are invalid") - for one in self.inlist: - if one not in setargs: error("-s args are invalid") - -# verbose switch - -class Verbose(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --v (no arguments) - produce verbose output as Make.py executes - if -v not specified, minimal output is produced -""" - - def check(self): - if len(self.inlist): error("-v args are invalid") - -# zoutput switch for making copy of final Makefile.auto - -class Zoutput(object): - def __init__(self,list): - self.inlist = copy.copy(list) - - def help(self): - return """ --z machine - copy created/used src/MAKE/MINE/Makefile.auto to Makefile.machine in same dir - copy created/used lib/*/Makefile.auto and lib/*/Makefile.lammps to - Makefile_lib.machine and Makefile_lib_lammps.machine in same dir - this can be used to preserve the machine Makefile and lib Makefiles -""" - - def check(self): - if len(self.inlist) != 1: error("-z args are invalid") - self.machine = self.inlist[0] - -# ---------------------------------------------------------------- -# lib classes, one per LAMMPS auxiliary lib -# ---------------------------------------------------------------- - -# ATC lib - -class ATC(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --atc make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-atc args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-atc args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-atc args are invalid") - - def build(self): - libdir = dir.lib + "/atc" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libatc.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/atc library") - else: print("Created lib/atc library") - -# AWPMD lib - -class AWPMD(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "mpicc" - self.lammpsflag = 0 - - def help(self): - return """ --awpmd make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = mpicc) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-awpmd args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-awpmd args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-awpmd args are invalid") - - def build(self): - libdir = dir.lib + "/awpmd" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libawpmd.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/awpmd library") - else: print("Created lib/awpmd library") - -# COLVARS lib - -class COLVARS(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --colvars make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-colvars args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-colvars args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-colvars args are invalid") - - def build(self): - libdir = dir.lib + "/colvars" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libcolvars.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/colvars library") - else: print("Created lib/colvars library") - -# CUDA lib - -class CUDA(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "double" - self.arch = "35" - - def help(self): - return """ --cuda mode=double arch=35 - all args are optional and can be in any order - mode = double or mixed or single (def = double) - arch = M (def = 35) - M = 31,35,37,etc for Kepler - M = 20 for CC2.0 (GF100/110, e.g. C2050,GTX580,GTX470) - M = 21 for CC2.1 (GF104/114, e.g. GTX560, GTX460, GTX450) - M = 13 for CC1.3 (GF200, e.g. C1060, GTX285) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-cuda args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-cuda args are invalid") - if words[0] == "mode": self.mode = words[1] - elif words[0] == "arch": self.arch = words[1] - else: error("-cuda args are invalid") - if self.mode != "double" and self.mode != "mixed" and \ - self.mode != "single": - error("-cuda args are invalid") - if not self.arch.isdigit(): error("-cuda args are invalid") - - def build(self): - libdir = dir.lib + "/cuda" - subprocess.check_output("cd %s; make clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - if self.mode == "double": n = 2 - elif self.mode == "mixed": n = 3 - elif self.mode == "single": n = 1 - if jmake: txt = "cd %s; make -j %d precision=%d arch=%s" % \ - (libdir,jmake.n,n,self.arch) - else: txt = "cd %s; make precision=%d arch=%s" % \ - (libdir,n,self.arch) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/liblammpscuda.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/cuda library") - else: print("Created lib/cuda library") - -# GPU lib - -class GPU(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "linux.double" - self.lammpsflag = self.modeflag = self.archflag = self.homeflag = 0 - - def help(self): - return """ --gpu make=suffix lammps=suffix2 mode=double arch=N home=path - all args are optional and can be in any order - make = use Makefile.suffix (def = linux.double) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) - mode = double or mixed or single (def = CUDA_PREC in makefile) - arch = 3x (x = digit for Kepler) or 2x (x = digit for Fermi) - (def = CUDA_ARCH in makefile) - home = path to Cuda, e.g. /usr/local/cuda (def = CUDA_HOME in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-gpu args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-gpu args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - elif words[0] == "mode": - self.mode = words[1] - self.modeflag = 1 - elif words[0] == "arch": - self.arch = words[1] - self.archflag = 1 - elif words[0] == "home": - self.home = words[1] - self.homeflag = 1 - else: error("-gpu args are invalid") - if self.modeflag and (self.mode != "double" and - self.mode != "mixed" and - self.mode != "single"): - error("-gpu args are invalid") - if self.archflag and not self.arch.isdigit(): - error("-gpu args are invalid") - - def build(self): - global gpubuildflag - gpubuildflag = 1 - libdir = dir.lib + "/gpu" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.modeflag: - if self.mode == "double": - make.setvar("CUDA_PRECISION","-D_DOUBLE_DOUBLE") - elif self.mode == "mixed": - make.setvar("CUDA_PRECISION","-D_SINGLE_DOUBLE") - elif self.mode == "single": - make.setvar("CUDA_PRECISION","-D_SINGLE_SINGLE") - if self.archflag: - make.setvar("CUDA_ARCH","-arch=sm_%s" % self.arch) - if self.homeflag: - make.setvar("CUDA_HOME",self.home) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - # special hack for shannon GPU cluster - # must use "srun make" if on it, else just make - # this is b/c Cuda libs are not all available on host - - make = "make" - if "shannon" == platform.node(): make = "srun make" - - subprocess.check_output("cd %s; %s -f Makefile.auto clean" % - (libdir,make),stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; %s -j %d -f Makefile.auto" % (libdir,make,jmake.n) - else: txt = "cd %s; %s -f Makefile.auto" % (libdir,make) - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libgpu.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/gpu library") - else: print("Created lib/gpu library") - -# H5MD lib - -class H5MD(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "h5cc" - self.lammpsflag = 0 - - def help(self): - return """ --h5md make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = h5cc) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-h5md args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-h5md args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-h5md args are invalid") - - def build(self): - libdir = dir.lib + "/h5md" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - txt = "cd %s; make" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libch5md.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/h5md library") - else: print("Created lib/h5md library") - -# MEAM lib - -class MEAM(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --meam make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-meam args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-meam args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-meam args are invalid") - - def build(self): - libdir = dir.lib + "/meam" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - # do not use -j for MEAM build, parallel build does not work - txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libmeam.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/meam library") - else: print("Created lib/meam library") - -# POEMS lib - -class POEMS(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --poems make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = g++) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-poems args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-poems args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-poems args are invalid") - - def build(self): - libdir = dir.lib + "/poems" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % libdir, - stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libpoems.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/poems library") - else: print("Created lib/poems library") - -# PYTHON lib - -class PYTHON(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "g++" - self.lammpsflag = 0 - - def help(self): - return """ --python lammps=suffix - arg is optional, use Makefile.lammps if not specified - lammps = use Makefile.lammps.suffix -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-python args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-python args are invalid") - if words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-python args are invalid") - - def build(self): - libdir = dir.lib + "/python" - if self.lammpsflag: - subprocess.check_output("cd %s; cp Makefile.lammps.%s Makefile.lammps" % - (libdir,self.lammps)) - if not os.path.isfile("%s/Makefile.lammps.%s" % (libdir,self.lammps)): - error("Unsuccessful creation of lib/python/Makefile.lammps.%s file" % - self.lammps) - else: print("Created lib/python/Makefile.lammps file") - -# QMMM lib - -class QMMM(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --qmmm make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-qmmm args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-qmmm args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-qmmm args are invalid") - - def build(self): - libdir = dir.lib + "/qmmm" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - subprocess.check_output("cd %s; make -f Makefile.auto clean" % - libdir,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libqmmm.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/qmmm library") - else: print("Created lib/qmmm library") - -# REAX lib - -class REAX(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.make = "gfortran" - self.lammpsflag = 0 - - def help(self): - return """ --reax make=suffix lammps=suffix2 - all args are optional and can be in any order - make = use Makefile.suffix (def = gfortran) - lammps = use Makefile.lammps.suffix2 (def = EXTRAMAKE in makefile) -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-reax args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-reax args are invalid") - if words[0] == "make": self.make = words[1] - elif words[0] == "lammps": - self.lammps = words[1] - self.lammpsflag = 1 - else: error("-reax args are invalid") - - def build(self): - libdir = dir.lib + "/reax" - make = MakeReader("%s/Makefile.%s" % (libdir,self.make)) - if self.lammpsflag: - make.setvar("EXTRAMAKE","Makefile.lammps.%s" % self.lammps) - make.write("%s/Makefile.auto" % libdir) - - cmd = "cd %s; make -f Makefile.auto clean" % libdir - subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) - if jmake: txt = "cd %s; make -j %d -f Makefile.auto" % (libdir,jmake.n) - else: txt = "cd %s; make -f Makefile.auto" % libdir - - # if verbose, print output as build proceeds, else only print if fails - - if verbose: subprocess.call(txt,shell=True) - else: - try: subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - except subprocess.CalledProcessError as e: print(e.output) - - if not os.path.isfile("%s/libreax.a" % libdir) or \ - not os.path.isfile("%s/Makefile.lammps" % libdir): - error("Unsuccessful build of lib/reax library") - else: print("Created lib/reax library") - -# VORONOI lib - -class VORONOI(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.install = "" - - def help(self): - return """ --voronoi install="-d dir -v version -g -b -i installdir -l incdir libdir" - arg is optional, only needed if want to run install.py script - install = args to use with lib/voronoi/install.py script - must enclose in quotes since install.py args have switches - install.py can download, build, install, setup links to the Voro++ library - see lib/voronoi/README for details on Voro++ and using install.py -""" - - def check(self): - if self.inlist != None and len(self.inlist) == 0: - error("-voronoi args are invalid") - for one in self.inlist: - words = one.split('=') - if len(words) != 2: error("-voronoi args are invalid") - if words[0] == "install": self.install = words[1] - else: error("-voronoi args are invalid") - - def build(self): - if not self.install: return - libdir = dir.lib + "/voronoi" - cmd = "cd %s; python install.py %s" % (libdir,self.install) - txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT, - shell=True).decode() - if verbose: print(txt) - print("Created lib/voronoi library") - -# ---------------------------------------------------------------- -# build classes for intel, kokkos build options -# ---------------------------------------------------------------- - -# Intel class - -class Intel(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "cpu" - - def help(self): - return """ --intel mode - mode = cpu or phi (def = cpu) - build Intel package for CPU or Xeon Phi -""" - - def check(self): - if self.inlist == None: return - if len(self.inlist) != 1: error("-intel args are invalid") - self.mode = self.inlist[0] - if self.mode != "cpu" and self.mode != "phi": - error("-intel args are invalid") - -# Kokkos class - -class Kokkos(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.mode = "" - self.archgpu = None - self.archcpu = None - - def help(self): - return """ --kokkos mode archgpu=N archcpu=SNB - mode is not optional, arch is optional - mode = omp or cuda or phi (def = KOKKOS_DEVICES setting in Makefile ) - build Kokkos package for omp or cuda or phi - sets KOKKOS_DEVICES to "OpenMP" (omp, phi) or "Cuda, OpenMP" (cuda) - archgpu = number like 35 (Kepler) or 21 (Fermi) (def = none) - sets KOKKOS_ARCH for GPU to appropriate value - archcpu = SNB or HSW or BGQ or Power7 or Power8 (def = none) - for CPU = SandyBridge, Haswell, BGQ, Power7, Power8 - sets KOKKOS_ARCH for GPU to appropriate value -""" - - def check(self): - print(self.inlist) - if self.inlist != None and len(self.inlist) == 0: - error("-kokkos args are invalid") - - if self.inlist == None: return - if len(self.inlist) < 1: error("-kokkos args are invalid") - self.mode = self.inlist[0] - if self.mode != "omp" and self.mode != "cuda" and self.mode != "phi": - error("-kokkos args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-kokkos args are invalid") - if words[0] == "archgpu": self.archgpu = words[1] - elif words[0] == "archcpu": self.archcpu = words[1] - else: error("-kokkos args are invalid") - -# ---------------------------------------------------------------- -# makefile classes for CC, FLAGS, MPI, JPG, PNG, FFT settings -# ---------------------------------------------------------------- - -# Cc class - -class Cc(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.compiler = self.abbrev = "" - self.wrap = "" - self.parent = "" - - def help(self): - return """ --cc compiler wrap=wcompiler,parent - alter CC setting in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - compiler is required, all other args are optional - compiler = any string with g++ or icc or icpc - or mpi (or mpicxx, mpiCC, mpiicpc, etc) - can be compiler name or full path to compiler - mpi by itself is changed to mpicxx - wcompiler = compiler for mpi wrapper to use - use nvcc for building for Kokkos/cuda with provided nvcc_wrapper - parent = openmpi or mpich - parent style determines syntax for setting low-level compiler -""" - - def check(self): - if len(self.inlist) < 1: error("-cc args are invalid") - self.compiler = self.inlist[0] - if self.compiler == "mpi": - self.compiler = "mpicxx" - self.abbrev = "mpi" - elif self.compiler.startswith("mpi"): - self.abbrev = "mpi" - elif self.compiler == "g++" or self.compiler == "icc" or \ - self.compiler == "icpc": - self.abbrev = self.compiler - elif "mpi" in self.compiler: self.abbrev = "mpi" - elif "g++" in self.compiler: self.abbrev = "g++" - elif "icc" in self.compiler: self.abbrev = "icc" - elif "icpc" in self.compiler: self.abbrev = "icpc" - else: error("-cc args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-cc args are invalid") - args = words[1].split(',') - if len(args) != 2: error("-cc args are invalid") - if words[0] == "wrap": - if self.abbrev != "mpi": error("-cc compiler is not a wrapper") - self.wrap = args[0] - self.parent = args[1] - else: error("-cc args are invalid") - -# Flags class - -class Flags(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.flags = [] - - def help(self): - return """ --flags var action N f1 f2 ... var action N f1 f2 ... - alter variable settings (flags) in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - var = CCFLAGS, LINKFLAGS, LIB, etc - any variable in Makefile.auto, must already exist - action = add or del - N = # of flags to follow - f1,f2,etc = flag to add or delete - "-" char will be prepended to each flag - for example: add 4 g O3 xHost "fp-model fast=2" - will add: -g -O3 -xHost -fp-model fast=2 - for add: if flag already exists, no change is made - for delete: flag of form "-O*", will delete any wildcard match - for -O,-O2,-O3,etc: existing -O* will first be removed -""" - - def check(self): - if len(self.inlist) < 1: error("-flags args are invalid") - narg = len(self.inlist) - i = 0 - while i < narg: - if i+3 > narg: error("-flags args are invalid") - var = self.inlist[i] - action = self.inlist[i+1] - if action != "add" and action != "del": error("-flags args are invalid") - nflag = int(self.inlist[i+2]) - i += 3 - if i+nflag > narg: error("-flags args are invalid") - flags = self.inlist[i:i+nflag] - self.flags.append([var,action,flags]) - i += nflag - -# Mpi class - -class Mpi(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.style = self.dir = "" - - def help(self): - return """ --mpi style dir=path - alter MPI settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - style is required, all other args are optional - style = mpi or mpich or ompi or serial - mpi = no MPI settings (assume compiler is MPI wrapper) - mpich = use explicit settings for MPICH - ompi = use explicit settings for OpenMPI - serial = use settings for src/STUBS library - dir = path for MPICH or OpenMPI directory - add -I and -L settings for include and lib sub-dirs -""" - - def check(self): - if len(self.inlist) < 1: error("-mpi args are invalid") - self.style = self.inlist[0] - if self.style != "mpi" and self.style != "mpich" and \ - self.style != "ompi" and self.style != "serial": - error("-mpi args are invalid") - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-mpi args are invalid") - if words[0] == "dir": self.dir = words[1] - else: error("-mpi args are invalid") - -# Fft class - -class Fft(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --fft mode lib=libname dir=homedir idir=incdir ldir=libdir - alter FFT settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - mode is required, all other args are optional - first removes all current FFT variable settings - mode = none or fftw or fftw3 or ... - adds -DFFT_MODE setting - lib = name of FFT library to link with (def is libname = mode) - adds -llib{libname} setting, e.g. -llibfftw3 - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - if not len(self.inlist): error("-fft args are invalid") - self.mode = self.inlist[0] - self.lib = "-l%s" % self.mode - for one in self.inlist[1:]: - words = one.split('=') - if len(words) != 2: error("-fft args are invalid") - if words[0] == "lib": self.lib = "-l%s" % words[1] - elif words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-fft args are invalid") - -# Jpg class - -class Jpg(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.on = 1 - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --jpg flag dir=homedir idir=incdir ldir=libdir - alter JPG settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - change JPG settings in makefile - all args are optional, flag must come first if specified - flag = yes or no (def = yes) - include or exclude JPEG support - adds/removes -DLAMMPS_JPEG and -ljpeg settings - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - for i,one in enumerate(self.inlist): - if one == "no" and i == 0: self.on = 0 - elif one == "yes" and i == 0: self.on = 1 - else: - words = one.split('=') - if len(words) != 2: error("-jpeg args are invalid") - if words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-jpeg args are invalid") - -# Png class - -class Png(object): - def __init__(self,list): - self.inlist = copy.copy(list) - self.on = 1 - self.dir = self.incdir = self.libdir = "" - - def help(self): - return """ --png flag dir=homedir idir=incdir ldir=libdir - alter PNG settings in Makefile.auto - only happens if new Makefile.auto is created by use of "file" action - all args are optional, flag must come first if specified - flag = yes or no (def = yes) - include or exclude PNG support - adds/removes -DLAMMPS_PNG and -lpng settings - dir = home dir for include and library files (def = none) - adds -Idir/include and -Ldir/lib settings - if set, overrides idir and ldir args - idir = dir for include file (def = none) - adds -Iidir setting - ldir = dir for library file (def = none) - adds -Lldir setting -""" - - def check(self): - for i,one in enumerate(self.inlist): - if one == "no" and i == 0: self.on = 0 - elif one == "yes" and i == 0: self.on = 1 - else: - words = one.split('=') - if len(words) != 2: error("-png args are invalid") - if words[0] == "dir": self.dir = words[1] - elif words[0] == "idir": self.incdir = words[1] - elif words[0] == "ldir": self.libdir = words[1] - else: error("-png args are invalid") - -# ---------------------------------------------------------------- -# auxiliary classes -# ---------------------------------------------------------------- - -# read, tweak, and write a Makefile - -class MakeReader(object): - - # read a makefile - # flag = 0 if file is full path name - # flag = 1,2 if file is suffix for any Makefile.machine under src/MAKE - # look for this file in same order that src/Makefile does - # if flag = 1, read the file - # if flag = 2, just check if file exists - - def __init__(self,file,flag=0): - if flag == 0: - if not os.path.isfile(file): error("Makefile %s does not exist" % file) - lines = open(file,'r').readlines() - else: - mfile = "%s/MAKE/MINE/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/OPTIONS/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - mfile = "%s/MAKE/MACHINES/Makefile.%s" % (dir.src,file) - if not os.path.isfile(mfile): - error("Makefile.%s does not exist" % file) - if flag == 1: lines = open(mfile,'r').readlines() - else: return - - # scan lines of makefile - # if not a variable line, just copy to newlines - # if a variable line, concatenate any continuation lines - # convert variable to var dict entry: key = name, value = list of words - # discard any portion of value string with a comment char - # varinfo = list of variable info: (name, name with whitespace for print) - # add index into varinfo to newlines - # ccindex = index of "CC =" line, to add OMPI var before it - # lmpindex = index of "LAMMPS-specific settings" - # line to add KOKKOS vars before it - - var = {} - varinfo = [] - newlines = [] - pattern = "(\S+\s+=\s+)(.*)" - conditional = 0 - multiline = 0 - self.ccindex = self.lmpindex = 0 - - for line in lines: - line = line[:-1] - if "CC =" in line: self.ccindex = len(newlines) - if "LAMMPS-specific settings" in line: self.lmpindex = len(newlines) - if "ifeq" in line: - conditional = 1 - continue - if conditional: - if "endif" in line: - conditional = 0 - continue - if multiline: - if '#' in line: line = line[:line.find('#')] - morevalues = line.split() - values = values[:-1] + morevalues - if values[-1] != '\\': - var[name] = values - multiline = 0 - newlines.append(str(len(varinfo))) - varinfo.append((name,namewhite)) - continue - varflag = 1 - if len(line.strip()) == 0: varflag = 0 - elif line.lstrip()[0] == '#': varflag = 0 - else: - m = re.match(pattern,line) - if not m: varflag = 0 - if varflag: - namewhite = m.group(1) - name = namewhite.split()[0] - if name in var: - error("Makefile variable %s appears more than once" % name) - remainder = m.group(2) - if '#' in remainder: remainder = remainder[:remainder.find('#')] - values = remainder.split() - if values and values[-1] == '\\': multiline = 1 - else: - var[name] = values - newlines.append(str(len(varinfo))) - varinfo.append((name,namewhite)) - else: - newlines.append(line) - - self.var = var - self.varinfo = varinfo - self.lines = newlines - - # return list of values associated with var - # return None if var not defined - - def getvar(self,var): - if var in self.var: return self.var[var] - else: return None - - # set var to single value - # if var not defined, error - - def setvar(self,var,value): - if var not in self.var: error("Variable %s not in makefile" % var) - self.var[var] = [value] - - # add value to var - # do not add if value already defined by var - # if var not defined, - # create new variable using "where" - # where="cc", line before "CC =" line, use ":=" - # where="lmp", 2 lines before "LAMMPS-specific settings" line, use "=" - - def addvar(self,var,value,where=""): - if var in self.var: - if value not in self.var[var]: self.var[var].append(value) - else: - if not where: - error("Variable %s with value %s is not in makefile" % (var,value)) - if where == "cc": - if not self.ccindex: error("No 'CC =' line in makefile to add variable") - index = self.ccindex - varwhite = "%s :=\t\t" % var - elif where == "lmp": - if not self.lmpindex: error("No 'LAMMPS-specific settings line' " + - "in makefile to add variable") - index = self.lmpindex - 2 - varwhite = "%s =\t\t" % var - self.var[var] = [value] - varwhite = "%s =\t\t" % var - self.lines.insert(index,str(len(self.varinfo))) - self.varinfo.append((var,varwhite)) - - # if value = None, remove entire var - # no need to update lines or varinfo, write() will ignore deleted vars - # else remove value from var - # value can have trailing '*' to remove wildcard match - # if var or value not defined, ignore it - - def delvar(self,var,value=None): - #if var == "KOKKOS_DEVICES": - # print self.var,value - if var not in self.var: return - if not value: - del self.var[var] - #print "AGAIN",self.var - elif value and value[-1] != '*': - if value not in self.var[var]: return - self.var[var].remove(value) - else: - value = value[:-1] - values = self.var[var] - dellist = [] - for i,one in enumerate(values): - if one.startswith(value): dellist.append(i) - while dellist: values.pop(dellist.pop()) - self.var[var] = values - - # write stored makefile lines to file, using vars that may have been updated - # do not write var if not in dict, since has been deleted - # wrap var values into multiple lines if needed - # file = 1 if this is Makefile.auto, change 1st line to use "auto" - - def write(self,file,flag=0): - fp = open(file,'w') - for i,line in enumerate(self.lines): - if not line.isdigit(): - if flag and i == 0: - line = "# auto = makefile auto-generated by Make.py" - print(line, file=fp) - else: - index = int(line) - name = self.varinfo[index][0] - txt = self.varinfo[index][1] - if name not in self.var: continue - values = self.var[name] - print("%s%s" % (txt,' '.join(values)), file=fp) - -# ---------------------------------------------------------------- -# main program -# ---------------------------------------------------------------- - -# parse command-line args -# switches dict: key = switch letter, value = list of args -# switch_order = list of switches in order -# will possibly be merged with redo file args below - -cmd_switches,cmd_switch_order = parse_args(sys.argv[1:]) - -if "v" in cmd_switches: - # debug - #print "Command-line parsing:" - #for switch in cmd_switch_order: - # print " %s: %s" % (switch,' '.join(cmd_switches[switch])) - pass - -# check for redo switch, process redo file -# redolist = list of commands to execute - -redoflag = 0 -redolist = [] - -if 'r' in cmd_switches and 'h' not in cmd_switches: - redoflag = 1 - redo = Redo(cmd_switches['r']) - redo.check() - redo.setup() - redolist = redo.commands - redoindex = 0 - del redo - if not redolist: error("No commands to execute from redo file") - -# loop over Make.py commands -# if no redo switch, loop once for command-line command -# if redo, loop over one or more commands from redo file - -while 1: - - # if redo: - # parse next command from redo file - # use command-line switches to add/replace file command switches - # do not add -r, since already processed - # and don't want -r swtich to appear in Make.py.last file - # if -a in both: concatenate, de-dup, - # specified exe/machine action replaces file exe/machine action - # print resulting new command - # else just use command-line switches - - if redoflag: - if redoindex == len(redolist): break - args = redolist[redoindex].split() - switches,switch_order = parse_args(args) - redoindex += 1 - - for switch in cmd_switches: - if switch == 'r': continue - if switch == 'a' and switch in switches: - tmp = Actions(cmd_switches[switch] + switches[switch]) - tmp.dedup() - switches[switch] = tmp.inlist - continue - if switch not in switches: switch_order.append(switch) - switches[switch] = cmd_switches[switch] - - argstr = switch2str(switches,switch_order) - print("Redo command: Make.py",argstr) - else: - switches = cmd_switches - switch_order = cmd_switch_order - - # initialize all class variables to None - - for one in switchclasses: exec("%s = None" % one) - for one in libclasses: exec("%s = None" % one) - for one in buildclasses: exec("%s = None" % one) - for one in makeclasses: exec("%s = None" % one) - - # classes = dictionary of created classes - # key = switch, value = class instance - - classes = {} - for switch in switches: - if len(switch) == 1 and switch in abbrevs: - i = abbrevs.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (switchclasses[i],switch,switchclasses[i].capitalize(),switch) - exec(txt) - elif switch in libclasses: - i = libclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (libclasses[i],switch,libclasses[i].upper(),switch) - exec(txt) - elif switch in buildclasses: - i = buildclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (buildclasses[i],switch,buildclasses[i].capitalize(),switch) - exec(txt) - elif switch in makeclasses: - i = makeclasses.index(switch) - txt = '%s = classes["%s"] = %s(switches["%s"])' % \ - (makeclasses[i],switch,makeclasses[i].capitalize(),switch) - exec(txt) - else: error("Unknown command-line switch -%s" % switch) - - # print help messages and exit - - if help or (actions and "-h" in actions.inlist) or not switches: - if not help: help = Help(None) - print(help.help()) - for switch in switch_order: - if switch == "h": continue - print(classes[switch].help()[1:]) - sys.exit() - - # create needed default classes if not specified with switch - # dir and packages plus lib and build classes so defaults are set - - if not dir: dir = Dir(None) - if not packages: packages = Packages(None) - - for one in libclasses: - txt = "if not %s: %s = %s(None)" % (one,one,one.upper()) - exec(txt) - - for one in buildclasses: - txt = "if not %s: %s = %s(None)" % (one,one,one.capitalize()) - exec(txt) - - # error check on args for all classes - - for switch in classes: classes[switch].check() - - # prep for action - # actions.setup() detects if last action = machine - # if yes, induce addition of "-m" and "-o" switches - - dir.setup() - packages.setup() - - if actions: - machine = actions.setup() - if machine: - switches['a'][-1] = "exe" - if 'm' not in switches: - switches['m'] = [machine] - switch_order.insert(-1,'m') - makefile = classes['m'] = Makefile(switches['m']) - makefile.check() - if 'o' not in switches: - switches['o'] = [machine] - switch_order.insert(-1,'o') - output = classes['o'] = Output(switches['o']) - output.check() - - # perform actions - - packages.install() - - if actions: - for action in actions.alist: - print("Action %s ..." % action) - if action.startswith("lib-"): actions.lib(action[4:]) - elif action == "file": actions.file("file") - elif action == "clean": actions.clean() - elif action == "exe": actions.exe() - - packages.uninstall() - - # create copy of executable if requested, and exe action performed - - if output and actions and "exe" in actions.alist: - txt = "cp %s/lmp_auto %s/lmp_%s" % (dir.src,dir.cwd,output.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created lmp_%s in %s" % (output.machine,dir.cwd)) - - # create copy of Makefile.auto if requested, and file or exe action performed - # ditto for library Makefile.auto and Makefile.lammps files - - if zoutput and actions and \ - ("file" in actions.alist or "exe" in actions.alist): - txt = "cp %s/MAKE/MINE/Makefile.auto %s/MAKE/MINE/Makefile.%s" % \ - (dir.src,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile.%s in %s/MAKE/MINE" % (zoutput.machine,dir.src)) - if gpubuildflag: - txt = "cp %s/gpu/Makefile.auto %s/MAKE/MINE/Makefile_gpu.%s" % \ - (dir.lib,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile_gpu.%s in %s/MAKE/MINE" % \ - (zoutput.machine,dir.src)) - txt = "cp %s/gpu/Makefile.lammps %s/MAKE/MINE/Makefile_gpu_lammps.%s" % \ - (dir.lib,dir.src,zoutput.machine) - subprocess.check_output(txt,stderr=subprocess.STDOUT,shell=True) - print("Created Makefile_gpu_lammps.%s in %s/MAKE/MINE" % \ - (zoutput.machine,dir.src)) - - # write current Make.py command to src/Make.py.last - - fp = open("%s/Make.py.last" % dir.src,'w') - print("# last invoked Make.py command", file=fp) - print(switch2str(switches,switch_order), file=fp) - fp.close() - - # if not redoflag, done - - if not redoflag: break From bdd2f3a6b2c70498c08c1c1b552f9c4ecc9742e0 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 18 Jul 2017 13:24:32 -0400 Subject: [PATCH 180/293] remove references to Make.py and USER-CUDA --- bench/FERMI/README | 66 ++++---------------------------------- bench/README | 46 +++++++++----------------- examples/README | 11 +------ examples/accelerate/README | 64 ++++-------------------------------- 4 files changed, 29 insertions(+), 158 deletions(-) diff --git a/bench/FERMI/README b/bench/FERMI/README index db3f527bdc..b66e560775 100644 --- a/bench/FERMI/README +++ b/bench/FERMI/README @@ -1,55 +1,21 @@ These are input scripts used to run versions of several of the -benchmarks in the top-level bench directory using the GPU and -USER-CUDA accelerator packages. The results of running these scripts -on two different machines (a desktop with 2 Tesla GPUs and the ORNL -Titan supercomputer) are shown on the "GPU (Fermi)" section of the -Benchmark page of the LAMMPS WWW site: lammps.sandia.gov/bench. +benchmarks in the top-level bench directory using the GPU accelerator +package. The results of running these scripts on two different machines +(a desktop with 2 Tesla GPUs and the ORNL Titan supercomputer) are shown +on the "GPU (Fermi)" section of the Benchmark page of the LAMMPS WWW +site: lammps.sandia.gov/bench. Examples are shown below of how to run these scripts. This assumes -you have built 3 executables with both the GPU and USER-CUDA packages +you have built 3 executables with the GPU package installed, e.g. lmp_linux_single lmp_linux_mixed lmp_linux_double -The precision (single, mixed, double) refers to the GPU and USER-CUDA -package precision. See the README files in the lib/gpu and lib/cuda -directories for instructions on how to build the packages with -different precisions. The GPU and USER-CUDA sub-sections of the -doc/Section_accelerate.html file also describes this process. - -Make.py -d ~/lammps -j 16 -p #all orig -m linux -o cpu -a exe -Make.py -d ~/lammps -j 16 -p #all opt orig -m linux -o opt -a exe -Make.py -d ~/lammps -j 16 -p #all omp orig -m linux -o omp -a exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=double arch=20 -o gpu_double -a libs exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=mixed arch=20 -o gpu_mixed -a libs exe -Make.py -d ~/lammps -j 16 -p #all gpu orig -m linux \ - -gpu mode=single arch=20 -o gpu_single -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=double arch=20 -o cuda_double -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=mixed arch=20 -o cuda_mixed -a libs exe -Make.py -d ~/lammps -j 16 -p #all cuda orig -m linux \ - -cuda mode=single arch=20 -o cuda_single -a libs exe -Make.py -d ~/lammps -j 16 -p #all intel orig -m linux -o intel_cpu -a exe -Make.py -d ~/lammps -j 16 -p #all kokkos orig -m linux -o kokkos_omp -a exe -Make.py -d ~/lammps -j 16 -p #all kokkos orig -kokkos cuda arch=20 \ - -m cuda -o kokkos_cuda -a exe - -Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \ - -gpu mode=double arch=20 -cuda mode=double arch=20 -m linux \ - -o all -a libs exe - -Make.py -d ~/lammps -j 16 -p #all opt omp gpu cuda intel kokkos orig \ - -kokkos cuda arch=20 -gpu mode=double arch=20 \ - -cuda mode=double arch=20 -m cuda -o all_cuda -a libs exe - ------------------------------------------------------------------------ -To run on just CPUs (without using the GPU or USER-CUDA styles), +To run on just CPUs (without using the GPU styles), do something like the following: mpirun -np 1 lmp_linux_double -v x 8 -v y 8 -v z 8 -v t 100 < in.lj @@ -81,23 +47,5 @@ node via a "-ppn" setting. ------------------------------------------------------------------------ -To run with the USER-CUDA package, do something like the following: - -mpirun -np 1 lmp_linux_single -c on -sf cuda -v x 16 -v y 16 -v z 16 -v t 100 < in.lj -mpirun -np 2 lmp_linux_double -c on -sf cuda -pk cuda 2 -v x 32 -v y 64 -v z 64 -v t 100 < in.eam - -The "xyz" settings determine the problem size. The "t" setting -determines the number of timesteps. The "np" setting determines how -many MPI tasks (per node) the problem will run on. The numeric -argument to the "-pk" setting is the number of GPUs (per node); 1 GPU -is the default. Note that the number of MPI tasks must equal the -number of GPUs (both per node) with the USER-CUDA package. - -These mpirun commands run on a single node. To run on multiple nodes, -scale up the "-np" setting, and control the number of MPI tasks per -node via a "-ppn" setting. - ------------------------------------------------------------------------- - If the script has "titan" in its name, it was run on the Titan supercomputer at ORNL. diff --git a/bench/README b/bench/README index 85d71cbb5d..0806fcded6 100644 --- a/bench/README +++ b/bench/README @@ -71,49 +71,33 @@ integration ---------------------------------------------------------------------- -Here is a src/Make.py command which will perform a parallel build of a -LAMMPS executable "lmp_mpi" with all the packages needed by all the -examples. This assumes you have an MPI installed on your machine so -that "mpicxx" can be used as the wrapper compiler. It also assumes -you have an Intel compiler to use as the base compiler. You can leave -off the "-cc mpi wrap=icc" switch if that is not the case. You can -also leave off the "-fft fftw3" switch if you do not have the FFTW -(v3) installed as an FFT package, in which case the default KISS FFT -library will be used. - -cd src -Make.py -j 16 -p none molecule manybody kspace granular rigid orig \ - -cc mpi wrap=icc -fft fftw3 -a file mpi - ----------------------------------------------------------------------- - Here is how to run each problem, assuming the LAMMPS executable is named lmp_mpi, and you are using the mpirun command to launch parallel runs: Serial (one processor runs): -lmp_mpi < in.lj -lmp_mpi < in.chain -lmp_mpi < in.eam -lmp_mpi < in.chute -lmp_mpi < in.rhodo +lmp_mpi -in in.lj +lmp_mpi -in in.chain +lmp_mpi -in in.eam +lmp_mpi -in in.chute +lmp_mpi -in in.rhodo Parallel fixed-size runs (on 8 procs in this case): -mpirun -np 8 lmp_mpi < in.lj -mpirun -np 8 lmp_mpi < in.chain -mpirun -np 8 lmp_mpi < in.eam -mpirun -np 8 lmp_mpi < in.chute -mpirun -np 8 lmp_mpi < in.rhodo +mpirun -np 8 lmp_mpi -in in.lj +mpirun -np 8 lmp_mpi -in in.chain +mpirun -np 8 lmp_mpi -in in.eam +mpirun -np 8 lmp_mpi -in in.chute +mpirun -np 8 lmp_mpi -in in.rhodo Parallel scaled-size runs (on 16 procs in this case): -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.lj -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.chain.scaled -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.eam -mpirun -np 16 lmp_mpi -var x 4 -var y 4 < in.chute.scaled -mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 < in.rhodo.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.lj +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.chain.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.eam +mpirun -np 16 lmp_mpi -var x 4 -var y 4 -in in.chute.scaled +mpirun -np 16 lmp_mpi -var x 2 -var y 2 -var z 4 -in in.rhodo.scaled For each of the scaled-size runs you must set 3 variables as -var command line switches. The variables x,y,z are used in the input diff --git a/examples/README b/examples/README index e4312e2598..702ada790b 100644 --- a/examples/README +++ b/examples/README @@ -105,20 +105,11 @@ tad: temperature-accelerated dynamics of vacancy diffusion in bulk Si vashishta: models using the Vashishta potential voronoi: Voronoi tesselation via compute voronoi/atom command -Here is a src/Make.py command which will perform a parallel build of a -LAMMPS executable "lmp_mpi" with all the packages needed by all the -examples, with the exception of the accelerate sub-directory. See the -accelerate/README for Make.py commands suitable for its example -scripts. - -cd src -Make.py -j 16 -p none std no-lib reax meam poems reaxc orig -a lib-all mpi - Here is how you might run and visualize one of the sample problems: cd indent cp ../../src/lmp_mpi . # copy LAMMPS executable to this dir -lmp_mpi < in.indent # run the problem +lmp_mpi -in in.indent # run the problem Running the simulation produces the files {dump.indent} and {log.lammps}. You can visualize the dump file as follows: diff --git a/examples/accelerate/README b/examples/accelerate/README index 1fab296a53..c4eb5dcc8d 100644 --- a/examples/accelerate/README +++ b/examples/accelerate/README @@ -1,14 +1,11 @@ These are example scripts that can be run with any of the acclerator packages in LAMMPS: -USER-CUDA, GPU, USER-INTEL, KOKKOS, USER-OMP, OPT +GPU, USER-INTEL, KOKKOS, USER-OMP, OPT The easiest way to build LAMMPS with these packages -is via the src/Make.py tool described in Section 2.4 -of the manual. You can also type "Make.py -h" to see -its options. The easiest way to run these scripts -is by using the appropriate - +is via the flags described in Section 4 of the manual. +The easiest way to run these scripts is by using the appropriate Details on the individual accelerator packages can be found in doc/Section_accelerate.html. @@ -16,21 +13,6 @@ can be found in doc/Section_accelerate.html. Build LAMMPS with one or more of the accelerator packages -The following command will invoke the src/Make.py tool with one of the -command-lines from the Make.list file: - -../../src/Make.py -r Make.list target - -target = one or more of the following: - cpu, omp, opt - cuda_double, cuda_mixed, cuda_single - gpu_double, gpu_mixed, gpu_single - intel_cpu, intel_phi - kokkos_omp, kokkos_cuda, kokkos_phi - -If successful, the build will produce the file lmp_target in this -directory. - Note that in addition to any accelerator packages, these packages also need to be installed to run all of the example scripts: ASPHERE, MOLECULE, KSPACE, RIGID. @@ -38,39 +20,11 @@ MOLECULE, KSPACE, RIGID. These two targets will build a single LAMMPS executable with all the CPU accelerator packages installed (USER-INTEL for CPU, KOKKOS for OMP, USER-OMP, OPT) or all the GPU accelerator packages installed -(USER-CUDA, GPU, KOKKOS for CUDA): +(GPU, KOKKOS for CUDA): -target = all_cpu, all_gpu - -Note that the Make.py commands in Make.list assume an MPI environment -exists on your machine and use mpicxx as the wrapper compiler with -whatever underlying compiler it wraps by default. If you add "-cc mpi -wrap=g++" or "-cc mpi wrap=icc" after the target, you can choose the -underlying compiler for mpicxx to invoke. E.g. - -../../src/Make.py -r Make.list intel_cpu -cc mpi wrap=icc - -You should do this for any build that includes the USER-INTEL -package, since it will perform best with the Intel compilers. - -Note that for kokkos_cuda, it needs to be "-cc nvcc" instead of "mpi", -since a KOKKOS for CUDA build requires NVIDIA nvcc as the wrapper -compiler. - -Also note that the Make.py commands in Make.list use the default -FFT support which is via the KISS library. If you want to -build with another FFT library, e.g. FFTW3, then you can add -"-fft fftw3" after the target, e.g. - -../../src/Make.py -r Make.list gpu -fft fftw3 - -For any build with USER-CUDA, GPU, or KOKKOS for CUDA, be sure to set +For any build with GPU, or KOKKOS for CUDA, be sure to set the arch=XX setting to the appropriate value for the GPUs and Cuda -environment on your system. What is defined in the Make.list file is -arch=21 for older Fermi GPUs. This can be overridden as follows, -e.g. for Kepler GPUs: - -../../src/Make.py -r Make.list gpu_double -gpu mode=double arch=35 +environment on your system. --------------------- @@ -118,12 +72,6 @@ Note that when running in.lj.5.0 (which has a long cutoff) with the GPU package, the "-pk tpa" setting should be > 1 (e.g. 8) for best performance. -** USER-CUDA package - -lmp_machine -c on -sf cuda < in.lj -mpirun -np 1 lmp_machine -c on -sf cuda < in.lj # 1 MPI, 1 MPI/GPU -mpirun -np 2 lmp_machine -c on -sf cuda -pk cuda 2 < in.lj # 2 MPI, 1 MPI/GPU - ** KOKKOS package for OMP lmp_kokkos_omp -k on t 1 -sf kk -pk kokkos neigh half < in.lj From 84065dde2112eb1094ffb40ef39bf8ee62caf26c Mon Sep 17 00:00:00 2001 From: "Ryan S. Elliott" Date: Thu, 20 Jul 2017 12:02:50 -0500 Subject: [PATCH 181/293] Refactor lib/kim/Install.py; works with phtyon 3 2.7 --- lib/kim/Install.py | 100 ++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 46 deletions(-) diff --git a/lib/kim/Install.py b/lib/kim/Install.py index 1405cc5fad..1d022a5875 100644 --- a/lib/kim/Install.py +++ b/lib/kim/Install.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# install.pa tool to setup the kim-api library +# install.py tool to setup the kim-api library # used to automate the steps described in the README file in this dir from __future__ import print_function import sys,os,re,subprocess @@ -8,28 +8,25 @@ try: from urllib.request import urlretrieve as geturl except: from urllib import urlretrieve as geturl help = """ -Syntax from src dir: make lib-kim args="-v version -b kim-install-dir kim-name -a kim-name" -Syntax from lib dir: python Install.py -v version -b kim-install-dir kim-name -a kim-name +Syntax from src dir: make lib-kim args="-v version -b -a kim-name" +Syntax from lib dir: python Install.py -v version -b -a kim-name specify one or more options, order does not matter -v = version of KIM API library to use default = kim-api-v1.8.2 (current as of June 2017) - -b = download and build KIM API library with KIM models - kim-dir = where to install/build the KIM API library - use "." to install in lib/kim - kim-name = none to install only the example KIM models - kim-name = KIM model name (see example below) + examples - kim-name = OpenKIM to install all models - from the openkim.org site (this can take 30 minutes or more) + -b = download and build KIM API library with example Models -a = add single KIM model or model driver with kim-name - to existing KIM API lib (see example below) + to existing KIM API lib (see example below). + If kim-name = everything, then rebuild KIM API library with + all available OpenKIM Models (this implies -b). + -vv = be more verbose about what is happening while the script runs Examples: -make lib-kim args="-b . none" # install KIM API lib with only example models -make lib-kim args="-b . Glue_Ercolessi_Adams_Al__MO_324507536345_001" # ditto plus one model -make lib-kim args="-b . OpenKIM" # install KIM API lib with all models +make lib-kim args="-b" # install KIM API lib with only example models +make lib-kim args="-b -a Glue_Ercolessi_Adams_Al__MO_324507536345_001" # Ditto plus one model +make lib-kim args="-b -a everything" # install KIM API lib with all models make lib-kim args="-a EAM_Dynamo_Ackland_W__MO_141627196590_002" # add one model or model driver See the list of KIM model drivers here: @@ -57,7 +54,9 @@ thisdir = os.environ['PWD'] version = "kim-api-v1.8.2" buildflag = False +everythingflag = False addflag = False +verboseflag = False iarg = 0 while iarg < len(args): @@ -67,15 +66,19 @@ while iarg < len(args): iarg += 2 elif args[iarg] == "-b": buildflag = True - if iarg+3 > len(args): error() - dir = args[iarg+1] - modelname = args[iarg+2] - iarg += 3 + iarg += 1 elif args[iarg] == "-a": addflag = True if iarg+2 > len(args): error() addmodelname = args[iarg+1] + if addmodelname == "everything": + buildflag = True + everythingflag = True + addflag = False iarg += 2 + elif args[iarg] == "-vv": + verboseflag = True + iarg += 1 else: error() thisdir = os.path.abspath(thisdir) @@ -88,14 +91,14 @@ if buildflag: # set install directory - dir = os.path.join(os.path.abspath(dir), "installed-" + version) + dir = os.path.join(os.path.abspath(thisdir), "installed-" + version) # check to see if an installed kim-api already exists and wipe it out. if os.path.isdir(dir): print("kim-api is already installed at %s.\nRemoving it for re-install" % dir) cmd = "rm -rf %s" % dir - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # configure LAMMPS to use kim-api to be installed @@ -116,44 +119,48 @@ if buildflag: geturl(url,"%s/%s.tgz" % (thisdir,version)) print("Unpacking kim-api tarball ...") cmd = "cd %s; rm -rf %s; tar zxvf %s.tgz" % (thisdir,version,version) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # configure kim-api print("Configuring kim-api ...") cmd = "cd %s/%s; ./configure --prefix='%s'" % (thisdir,version,dir) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # build kim-api - print("Configuring model : %s" % modelname) - if modelname == "none": - cmd = "cd %s/%s; make add-examples" % (thisdir,version) - else: - if modelname == "OpenKIM": - print("configuring all OpenKIM models, this will take a while ...") - cmd = "cd %s/%s; make add-examples; make add-%s" % \ - (thisdir,version,modelname) - subprocess.check_output(cmd,shell=True) + print("Configuring example Models") + cmd = "cd %s/%s; make add-examples" % (thisdir,version) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print (txt.decode("UTF-8")) + + if everythingflag: + print("Configuring all OpenKIM models, this will take a while ...") + cmd = "cd %s/%s; make add-OpenKIM" % (thisdir,version) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) print("Building kim-api ...") cmd = "cd %s/%s; make" % (thisdir,version) - subprocess.check_output(cmd,shell=True) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) # install kim-api print("Installing kim-api ...") cmd = "cd %s/%s; make install" % (thisdir,version) - subprocess.check_output(cmd,shell=True) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) cmd = "cd %s/%s; make install-set-default-to-v1" %(thisdir,version) - subprocess.check_output(cmd,shell=True) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + if verboseflag: print(txt.decode("UTF-8")) # remove source files print("Removing kim-api source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" % (thisdir,version,version) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) # add a single model (and possibly its driver) to existing KIM installation @@ -166,19 +173,18 @@ if addflag: error() else: cmd = "cd %s; make -f Makefile.KIM_DIR print_dir" % thisdir - dir = subprocess.check_output(cmd,shell=True)[1] + dir = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True)[1] # download single model # try first via urllib - # if fails (probably due to no SSL support), use wget - print("Downloading item tarball ...") + print("Downloading tarball for %s..." % addmodelname) url = "https://openkim.org/download/%s.tgz" % addmodelname geturl(url,"%s/%s.tgz" % (thisdir,addmodelname)) print("Unpacking item tarball ...") cmd = "cd %s; tar zxvf %s.tgz" % (thisdir,addmodelname) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) print("Building item ...") cmd = "cd %s/%s; make; make install" %(thisdir,addmodelname) @@ -187,19 +193,19 @@ if addflag: except subprocess.CalledProcessError as e: # Error: but first, check to see if it needs a driver - firstRunOutput = e.output.decode() + firstRunOutput = e.output.decode("UTF-8") cmd = "cd %s/%s; make kim-item-type" % (thisdir,addmodelname) txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) - txt = txt.decode().strip() + txt = txt.decode("UTF-8") if txt == "ParameterizedModel": # Get and install driver cmd = "cd %s/%s; make model-driver-name" % (thisdir,addmodelname) txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) - adddrivername = txt.decode().strip() - print("First installing model driver: %s" % adddrivername) + adddrivername = txt.decode("UTF-8").strip() + print("First installing model driver: %s..." % adddrivername) cmd = "cd %s; python Install.py -a %s" % (thisdir,adddrivername) try: txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) @@ -207,6 +213,8 @@ if addflag: print(e.output) sys.exit() + if verboseflag: print(txt.decode("UTF-8")) + # now install the model that needed the driver print("Now installing model : %s" % addmodelname) @@ -216,7 +224,7 @@ if addflag: except subprocess.CalledProcessError as e: print(e.output) sys.exit() - print(txt.decode()) + print(txt.decode("UTF-8")) sys.exit() else: print(firstRunOutput) @@ -226,7 +234,7 @@ if addflag: # success the first time - print(txt) + if verboseflag: print(txt.decode("UTF-8")) print("Removing kim item source and build files ...") cmd = "cd %s; rm -rf %s; rm -rf %s.tgz" %(thisdir,addmodelname,addmodelname) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) From 66154e8a8b31fcfa1ce512908a249d4175257a28 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 15:05:58 -0400 Subject: [PATCH 182/293] avoid makefile failure, if LAMMPS has not been configured yet --- lib/colvars/Makefile.common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/colvars/Makefile.common b/lib/colvars/Makefile.common index 818373abe1..6e05ca93f5 100644 --- a/lib/colvars/Makefile.common +++ b/lib/colvars/Makefile.common @@ -1,7 +1,7 @@ # Shared -*- makefile -*- for multiple architectures # Detect settings from PYTHON package (if defined) -include ../../src/Makefile.package.settings +sinclude ../../src/Makefile.package.settings ifeq ($(python_SYSINC),) COLVARS_PYTHON_INCFLAGS = else From 9d0d90c038604893c20f2737331d548f4fb188c7 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 15:25:27 -0400 Subject: [PATCH 183/293] README clarification from giacomo --- lib/colvars/README | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lib/colvars/README b/lib/colvars/README index a4f04221b3..ce1d319974 100644 --- a/lib/colvars/README +++ b/lib/colvars/README @@ -18,13 +18,17 @@ For a brief description see: This directory has source files to build a library that LAMMPS links against when using the USER-COLVARS package. -This library must be built with a C++ compiler, *before* LAMMPS is built, so -that LAMMPS can link against it. You can use the provided Makefile.* files or -create your own, specific to your compiler and system. For example: +This library must be built with a C++ compiler, *before* LAMMPS is built and +*after* packages are configured, so that LAMMPS can link against it. +You can use the provided Makefile.* files or create your own, specific to your +compiler and system. For example: + cd src + make yes-user-colvars + cd ../lib/colvars make -f Makefile.g++ -will use the GNU C++ compiler and is a good template to start. +where Makefile.g++ uses the GNU C++ compiler and is a good template to start. **Optional**: if you use the Install.py script provided in this folder, you can give the machine name as the '-m' argument. This can be the suffix of one From 5031f5b8079cb285b0cae910c32caab96e382b68 Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 20 Jul 2017 15:46:58 -0400 Subject: [PATCH 184/293] Comment out use by Colvars of Makefile.lammps from other packages --- lib/colvars/Makefile.common | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/colvars/Makefile.common b/lib/colvars/Makefile.common index 818373abe1..f47403f771 100644 --- a/lib/colvars/Makefile.common +++ b/lib/colvars/Makefile.common @@ -1,12 +1,12 @@ # Shared -*- makefile -*- for multiple architectures -# Detect settings from PYTHON package (if defined) -include ../../src/Makefile.package.settings -ifeq ($(python_SYSINC),) -COLVARS_PYTHON_INCFLAGS = -else -COLVARS_PYTHON_INCFLAGS = -DCOLVARS_PYTHON $(python_SYSINC) -endif +# # Detect settings from PYTHON package (if defined) +# sinclude ../../src/Makefile.package.settings +# ifeq ($(python_SYSINC),) +# COLVARS_PYTHON_INCFLAGS = +# else +# COLVARS_PYTHON_INCFLAGS = -DCOLVARS_PYTHON $(python_SYSINC) +# endif # Detect debug settings ifeq ($(COLVARS_DEBUG),) From c98f6140e7555a0e6c2c5f5e429fc149ee52520c Mon Sep 17 00:00:00 2001 From: Giacomo Fiorin Date: Thu, 20 Jul 2017 15:49:31 -0400 Subject: [PATCH 185/293] Change order of targets in Makefiles for Colvars --- lib/colvars/Makefile.g++ | 4 ++-- lib/colvars/Makefile.mingw32-cross | 4 ++-- lib/colvars/Makefile.mingw64-cross | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/colvars/Makefile.g++ b/lib/colvars/Makefile.g++ index cd7f72a833..556e39d070 100644 --- a/lib/colvars/Makefile.g++ +++ b/lib/colvars/Makefile.g++ @@ -11,12 +11,12 @@ AR = ar ARFLAGS = -rscv SHELL = /bin/sh -include Makefile.common - .PHONY: default clean default: $(COLVARS_LIB) Makefile.lammps +include Makefile.common + clean: -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) diff --git a/lib/colvars/Makefile.mingw32-cross b/lib/colvars/Makefile.mingw32-cross index e2873ecdad..29c64b26a2 100644 --- a/lib/colvars/Makefile.mingw32-cross +++ b/lib/colvars/Makefile.mingw32-cross @@ -14,12 +14,12 @@ AR = i686-w64-mingw32-ar ARFLAGS = -rscv SHELL = /bin/sh -include Makefile.common - .PHONY: default clean default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps +include Makefile.common + $(COLVARS_OBJ_DIR): mkdir $(COLVARS_OBJ_DIR) diff --git a/lib/colvars/Makefile.mingw64-cross b/lib/colvars/Makefile.mingw64-cross index 09d6bd4fa9..2fd1c6fc67 100644 --- a/lib/colvars/Makefile.mingw64-cross +++ b/lib/colvars/Makefile.mingw64-cross @@ -14,12 +14,12 @@ AR = x86_64-w64-mingw32-ar ARFLAGS = -rscv SHELL = /bin/sh -include Makefile.common - .PHONY: default clean default: $(COLVARS_OBJ_DIR) $(COLVARS_LIB) Makefile.lammps +include Makefile.common + $(COLVARS_OBJ_DIR): mkdir $(COLVARS_OBJ_DIR) From f037f89f5f4de24f760b608778bb232c8312dc66 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 20 Jul 2017 14:12:17 -0600 Subject: [PATCH 186/293] fix GPU + BUILD_SHARED_LIBS X-Thanks: Robert Maynard --- cmake/CMakeLists.txt | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index e8afb6fb56..bbf6048460 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -439,11 +439,12 @@ if(ENABLE_GPU) if(NOT BIN2C) message(FATAL_ERROR "Couldn't find bin2c") endif() - include_directories(${CUDA_TOOLKIT_INCLUDE}) + include_directories(${CUDA_INCLUDE_DIRS}) + list(APPEND LAMMPS_LINK_LIBS ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) set(GPU_PREC "SINGLE_DOUBLE" CACHE STRING "Lammps gpu precision size") set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) add_definitions(-D_${GPU_PREC}) - add_definitions(-DNV_KERNEL -DUSE_CUDPP -DUCL_CUDADR) + add_definitions(-DNV_KERNEL -DUCL_CUDADR) set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) @@ -455,12 +456,13 @@ if(ENABLE_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) - file(GLOB_RECURSE GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp) - file(GLOB_RECURSE GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu ${CMAKE_SOURCE_DIR}/gpu/*.cu) + file(GLOB GPU_LIB_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cpp) + file(GLOB GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu ${CMAKE_SOURCE_DIR}/gpu/*.cu) file(GLOB_RECURSE GPU_NOT_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/lal_pppm.cu) list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) - add_custom_target(gpu_objs) - cuda_wrap_srcs(gpu_objs OBJ GPU_OBJS ${GPU_LIB_CU}) + include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu + ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) + cuda_compile(GPU_OBJS ${GPU_LIB_CU} OPTIONS $<$:-Xcompiler=-fPIC>) file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) foreach(CU_OBJ ${GPU_OBJS}) get_filename_component(CU_NAME ${CU_OBJ} NAME_WE) @@ -470,10 +472,12 @@ if(ENABLE_GPU) DEPENDS ${CU_OBJ} COMMENT "Generating ${CU_NAME}_cubin.h") list(APPEND LIB_SOURCES ${LAMMPS_LIB_BINARY_DIR}/gpu/${CU_NAME}_cubin.h) + if(${CU_NAME} STREQUAL "pppm_d") #pppm_d doesn't get linked into the lib + set(CU_FORBIDDEN_OBJ "${CU_OBJ}") + endif() endforeach() + list(REMOVE_ITEM GPU_OBJS "${CU_FORBIDDEN_OBJ}") list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES} ${GPU_OBJS}) - include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu - ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu/*_cubin.h") endif() From 1749d643c7205ec05655818d2d5b2295bd37b171 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 20 Jul 2017 14:30:52 -0600 Subject: [PATCH 187/293] GPU: bring back CUDPP_OPT --- cmake/CMakeLists.txt | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index bbf6048460..4304a8078f 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -445,6 +445,7 @@ if(ENABLE_GPU) set_property(CACHE GPU_PREC PROPERTY STRINGS SINGLE_DOUBLE SINGLE_SINGLE DOUBLE_DOUBLE) add_definitions(-D_${GPU_PREC}) add_definitions(-DNV_KERNEL -DUCL_CUDADR) + option(CUDPP_OPT "Enable CUDPP_OPT" ON) set(GPU_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/GPU) set(GPU_SOURCES ${GPU_SOURCES_DIR}/gpu_extra.h) @@ -460,9 +461,14 @@ if(ENABLE_GPU) file(GLOB GPU_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/*.cu ${CMAKE_SOURCE_DIR}/gpu/*.cu) file(GLOB_RECURSE GPU_NOT_LIB_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/lal_pppm.cu) list(REMOVE_ITEM GPU_LIB_CU ${GPU_NOT_LIB_CU}) - include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu - ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini ${LAMMPS_LIB_BINARY_DIR}/gpu) - cuda_compile(GPU_OBJS ${GPU_LIB_CU} OPTIONS $<$:-Xcompiler=-fPIC>) + include_directories(${GPU_SOURCES_DIR} ${LAMMPS_LIB_SOURCE_DIR}/gpu ${LAMMPS_LIB_BINARY_DIR}/gpu) + if(CUDPP_OPT) + include_directories(${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini) + add_definitions(-DCUDPP_OPT) + file(GLOB GPU_LIB_CUDPP_SOURCES ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini/*.cpp) + file(GLOB GPU_LIB_CUDPP_CU ${LAMMPS_LIB_SOURCE_DIR}/gpu/cudpp_mini/*.cu) + endif() + cuda_compile(GPU_OBJS ${GPU_LIB_CU} ${GPU_LIB_CUDPP_CU} OPTIONS $<$:-Xcompiler=-fPIC>) file(MAKE_DIRECTORY ${LAMMPS_LIB_BINARY_DIR}/gpu) foreach(CU_OBJ ${GPU_OBJS}) get_filename_component(CU_NAME ${CU_OBJ} NAME_WE) @@ -477,7 +483,7 @@ if(ENABLE_GPU) endif() endforeach() list(REMOVE_ITEM GPU_OBJS "${CU_FORBIDDEN_OBJ}") - list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES} ${GPU_OBJS}) + list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES} ${GPU_LIB_CUDPP_SOURCES} ${GPU_OBJS}) set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu/*_cubin.h") endif() From 59db5f6a1782b0cacdb28a36ffbfab6940f48afb Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Thu, 20 Jul 2017 14:40:35 -0600 Subject: [PATCH 188/293] update of Fortran-DFTB interface to be compatible with fix msst --- doc/src/fix_msst.txt | 46 ++++--- doc/src/pair_kim.txt | 33 ++++- examples/COUPLE/README | 4 +- .../LAMMPS-wrapper.cpp | 0 .../LAMMPS-wrapper.h | 0 .../LAMMPS-wrapper2.cpp | 26 +++- .../LAMMPS-wrapper2.h | 3 + .../{fortran3 => fortran_dftb}/LAMMPS.F90 | 30 +++- .../COUPLE/{fortran3 => fortran_dftb}/README | 12 +- .../{fortran3 => fortran_dftb}/data.diamond | 0 examples/COUPLE/fortran_dftb/dftb_in.hsd | 40 ++++++ examples/COUPLE/fortran_dftb/dftb_pin.hsd | 129 ++++++++++++++++++ .../{fortran3 => fortran_dftb}/in.simple | 0 examples/COUPLE/fortran_dftb/log.simple | 71 ++++++++++ .../{fortran3 => fortran_dftb}/makefile | 2 +- .../{fortran3 => fortran_dftb}/simple.f90 | 26 ++-- lib/colvars/Install.py | 110 ++++----------- 17 files changed, 397 insertions(+), 135 deletions(-) rename examples/COUPLE/{fortran3 => fortran_dftb}/LAMMPS-wrapper.cpp (100%) rename examples/COUPLE/{fortran3 => fortran_dftb}/LAMMPS-wrapper.h (100%) rename examples/COUPLE/{fortran3 => fortran_dftb}/LAMMPS-wrapper2.cpp (71%) rename examples/COUPLE/{fortran3 => fortran_dftb}/LAMMPS-wrapper2.h (89%) rename examples/COUPLE/{fortran3 => fortran_dftb}/LAMMPS.F90 (97%) rename examples/COUPLE/{fortran3 => fortran_dftb}/README (78%) rename examples/COUPLE/{fortran3 => fortran_dftb}/data.diamond (100%) create mode 100644 examples/COUPLE/fortran_dftb/dftb_in.hsd create mode 100644 examples/COUPLE/fortran_dftb/dftb_pin.hsd rename examples/COUPLE/{fortran3 => fortran_dftb}/in.simple (100%) create mode 100644 examples/COUPLE/fortran_dftb/log.simple rename examples/COUPLE/{fortran3 => fortran_dftb}/makefile (95%) rename examples/COUPLE/{fortran3 => fortran_dftb}/simple.f90 (91%) diff --git a/doc/src/fix_msst.txt b/doc/src/fix_msst.txt index 43f35d6880..025c733897 100644 --- a/doc/src/fix_msst.txt +++ b/doc/src/fix_msst.txt @@ -25,7 +25,7 @@ keyword = {q} or {mu} or {p0} or {v0} or {e0} or {tscale} or {beta} or {dftb} :l {e0} value = initial total energy (energy units) {tscale} value = reduction in initial temperature (unitless fraction between 0.0 and 1.0) {dftb} value = {yes} or {no} for whether using MSST in conjunction with DFTB+ - {beta} value = scale factor on energy contribution of DFTB+ :pre + {beta} value = scale factor for improved energy conservation :pre :ule [Examples:] @@ -72,6 +72,14 @@ be calculated on the first step, after the energy specified by {tscale} is removed. The value of {e0} is not used in the dynamical equations, but is used in calculating the deviation from the Hugoniot. +The keyword {beta} is a scaling term that can be added to the MSST +ionic equations of motion to account for drift in the conserved +quantity during long timescale simulations, similar to a Berendson +thermostat. See "(Reed)"_#Reed and "(Goldman)"_#Goldman for more +details. The value of {beta} must be between 0.0 and 1.0 inclusive. +A value of 0.0 means no contribution, a value of 1.0 means a full +contribution. + Values of shockvel less than a critical value determined by the material response will not have compressive solutions. This will be reflected in lack of significant change of the volume in the MSST. @@ -95,23 +103,15 @@ or "_MSST_pe". The group for the new computes is "all". :line -The {dftb} and {beta} keywords are to allow this fix to be used when -LAMMPS is being driven by DFTB+, a density-functional tight-binding -code. - -If the keyword {dftb} is used with a value of {yes}, then the MSST -equations are altered to account for an energy contribution compute by -DFTB+. In this case, you must define a "fix -external"_fix_external.html command in your input script, which is -used to callback to DFTB+ during the LAMMPS timestepping. DFTB+ will -communicate its info to LAMMPS via that fix. - -The keyword {beta} is a scale factor on the DFTB+ energy contribution. -The value of {beta} must be between 0.0 and 1.0 inclusive. A value of -0.0 means no contribution, a value of 1.0 means a full contribution. - -(July 2017) More information about these keywords and the use of -LAMMPS with DFTB+ will be added to the LAMMMPS documention soon. +The {dftb} keyword is to allow this fix to be used when LAMMPS is +being driven by DFTB+, a density-functional tight-binding code. If the +keyword {dftb} is used with a value of {yes}, then the MSST equations +are altered to account for the electron entropy contribution to the +Hugonio relations and total energy. See "(Reed2)"_#Reed2 and +"(Goldman)"_#Goldman for details on this contribution. In this case, +you must define a "fix external"_fix_external.html command in your +input script, which is used to callback to DFTB+ during the LAMMPS +timestepping. DFTB+ will communicate its info to LAMMPS via that fix. :line @@ -182,4 +182,12 @@ timestep. :line :link(Reed) -[(Reed)] Reed, Fried, and Joannopoulos, Phys. Rev. Lett., 90, 235503 (2003). +[(Reed)] Reed, Fried, and Joannopoulos, Phys. Rev. Lett., 90, 235503 +(2003). + +:link(Reed2) +[(Reed2)] Reed, J. Phys. Chem. C, 116, 2205 (2012). + +:link(Goldman) +[(Goldman)] Goldman, Srinivasan, Hamel, Fried, Gaus, and Elstner, +J. Phys. Chem. C, 117, 7885 (2013). diff --git a/doc/src/pair_kim.txt b/doc/src/pair_kim.txt index 5a623e5ece..5ee607c2b0 100644 --- a/doc/src/pair_kim.txt +++ b/doc/src/pair_kim.txt @@ -27,13 +27,34 @@ pair_coeff * * Ar Ar :pre [Description:] This pair style is a wrapper on the "Knowledge Base for Interatomic -Models (KIM)"_https://openkim.org repository of interatomic potentials, -so that they can be used by LAMMPS scripts. +Models (OpenKIM)"_https://openkim.org repository of interatomic +potentials, so that they can be used by LAMMPS scripts. -In KIM lingo, a potential is a "model" and a model contains both the -analytic formulas that define the potential as well as the parameters -needed to run it for one or more materials, including coefficients and -cutoffs. +Note that in LAMMPS lingo, a KIM model driver is a pair style +(e.g. EAM or Tersoff). A KIM model is a pair style for a particular +element or alloy and set of parameters, e.g. EAM for Cu with a +specific EAM potential file. + +See the current list of "KIM model +drivers"_https://openkim.org/kim-items/model-drivers/alphabetical. + +See the current list of all "KIM +models"_https://openkim.org/kim-items/models/by-model-drivers + +See the list of "example KIM models"_https://openkim.org/kim-api which +are included in the KIM library by default, in the "What is in the KIM +API source package?" section. + +To use this pair style, you must first download and install the KIM +API library from the "OpenKIM website"_https://openkim.org. The "KIM +section of Section packages"_Section_packages.html#kim-package has +instructions on how to do this with a simple make command, when +building LAMMPS. + +See the examples/kim dir for an input script that uses a KIM model +(potential) for Lennard-Jones. + +:line The argument {virialmode} determines how the global virial is calculated. If {KIMvirial} is specified, the KIM model performs the diff --git a/examples/COUPLE/README b/examples/COUPLE/README index c8c9e0e31b..83e7463531 100644 --- a/examples/COUPLE/README +++ b/examples/COUPLE/README @@ -41,8 +41,8 @@ fortran a simple wrapper on the LAMMPS library API that can be called from Fortran fortran2 a more sophisticated wrapper on the LAMMPS library API that can be called from Fortran -fortran3 wrapper written by Nir Goldman (LLNL), as an +fortran_dftb wrapper written by Nir Goldman (LLNL), as an extension to fortran2, used for calling LAMMPS - from Fortran DFTB+ code + from Fortran DFTB+ tight-binding code Each sub-directory has its own README with more details. diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper.cpp b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper.cpp similarity index 100% rename from examples/COUPLE/fortran3/LAMMPS-wrapper.cpp rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper.cpp diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper.h b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper.h similarity index 100% rename from examples/COUPLE/fortran3/LAMMPS-wrapper.h rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper.h diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp similarity index 71% rename from examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp index f245c44d79..d16b49cc50 100644 --- a/examples/COUPLE/fortran3/LAMMPS-wrapper2.cpp +++ b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.cpp @@ -47,11 +47,35 @@ void lammps_set_callback (void *ptr) { return; } +void lammps_set_external_vector_length (void *ptr, int n) { + class LAMMPS *lmp = (class LAMMPS *) ptr; + int ifix = lmp->modify->find_fix_by_style("external"); + FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix]; + fix->set_vector_length(n); + return; +} + +void lammps_set_external_vector (void *ptr, int n, double val) { + class LAMMPS *lmp = (class LAMMPS *) ptr; + int ifix = lmp->modify->find_fix_by_style("external"); + FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix]; + fix->set_vector (n, val); + return; +} + void lammps_set_user_energy (void *ptr, double energy) { class LAMMPS *lmp = (class LAMMPS *) ptr; int ifix = lmp->modify->find_fix_by_style("external"); FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix]; - fix->set_energy(energy); + fix->set_energy_global(energy); + return; +} + +void lammps_set_user_virial (void *ptr, double *virial) { + class LAMMPS *lmp = (class LAMMPS *) ptr; + int ifix = lmp->modify->find_fix_by_style("external"); + FixExternal *fix = (FixExternal *) lmp->modify->fix[ifix]; + fix->set_virial_global(virial); return; } diff --git a/examples/COUPLE/fortran3/LAMMPS-wrapper2.h b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h similarity index 89% rename from examples/COUPLE/fortran3/LAMMPS-wrapper2.h rename to examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h index 794006e3af..ed79015e78 100644 --- a/examples/COUPLE/fortran3/LAMMPS-wrapper2.h +++ b/examples/COUPLE/fortran_dftb/LAMMPS-wrapper2.h @@ -26,6 +26,9 @@ extern "C" { /* Prototypes for auxiliary functions */ void lammps_set_callback (void *); void lammps_set_user_energy (void*, double); +void lammps_set_user_virial (void*, double*); +void lammps_set_external_vector_length (void*, int); +void lammps_set_external_vector (void*, int, double); #ifdef __cplusplus } diff --git a/examples/COUPLE/fortran3/LAMMPS.F90 b/examples/COUPLE/fortran_dftb/LAMMPS.F90 similarity index 97% rename from examples/COUPLE/fortran3/LAMMPS.F90 rename to examples/COUPLE/fortran_dftb/LAMMPS.F90 index eb5b7f825b..9b18bbfa5f 100644 --- a/examples/COUPLE/fortran3/LAMMPS.F90 +++ b/examples/COUPLE/fortran_dftb/LAMMPS.F90 @@ -52,12 +52,16 @@ module LAMMPS C_NULL_CHAR, C_loc, C_F_pointer, lammps_instance => C_ptr implicit none private + public :: lammps_set_user_virial + public :: lammps_set_external_vector_length + public :: lammps_set_external_vector + public :: lammps_set_user_energy public :: lammps_open, lammps_open_no_mpi, lammps_close, lammps_file, & lammps_command, lammps_free, lammps_extract_global, & lammps_extract_atom, lammps_extract_compute, lammps_extract_fix, & lammps_extract_variable, lammps_get_natoms, lammps_gather_atoms, & - lammps_scatter_atoms, lammps_set_callback, lammps_set_user_energy - public :: lammps_instance, C_ptr, C_double, C_int + lammps_set_callback + public :: lammps_scatter_atoms, lammps_instance, C_ptr, C_double, C_int !! Functions supplemental to the prototypes in library.h. {{{1 !! The function definitions (in C++) are contained in LAMMPS-wrapper.cpp. @@ -218,6 +222,28 @@ module LAMMPS real(C_double), value :: energy end subroutine lammps_set_user_energy + subroutine lammps_set_user_virial (ptr, virial) & + bind (C, name='lammps_set_user_virial') + import :: C_ptr, C_double + type (C_ptr), value :: ptr + real(C_double) :: virial(6) + end subroutine lammps_set_user_virial + + subroutine lammps_set_external_vector_length (ptr, n) & + bind (C, name='lammps_set_external_vector_length') + import :: C_ptr, C_double, C_int + type(C_ptr), value :: ptr + integer (C_int), value :: n + end subroutine lammps_set_external_vector_length + + subroutine lammps_set_external_vector (ptr, n, val) & + bind (C, name='lammps_set_external_vector') + import :: C_ptr, C_int, C_double + type (C_ptr), value :: ptr + integer (C_int), value :: n + real(C_double), value :: val + end subroutine lammps_set_external_vector + subroutine lammps_actual_gather_atoms (ptr, name, type, count, data) & bind (C, name='lammps_gather_atoms') import :: C_ptr, C_int, C_char diff --git a/examples/COUPLE/fortran3/README b/examples/COUPLE/fortran_dftb/README similarity index 78% rename from examples/COUPLE/fortran3/README rename to examples/COUPLE/fortran_dftb/README index 9effa35ec4..39a2f18169 100644 --- a/examples/COUPLE/fortran3/README +++ b/examples/COUPLE/fortran_dftb/README @@ -3,8 +3,9 @@ forces from a fortran code for a LAMMPS simulation. The reader should refer to the README file in COUPLE/fortran2 before proceeding. Here, the LAMMPS.F90 file has been modified slightly and additional files named LAMMPS-wrapper2.h and LAMMPS-wrapper2.cpp have been included in -order to supply wrapper functions to set the LAMMPS callback function -and total energy. +order to supply wrapper functions to set the LAMMPS callback function, +total energy, virial, and electronic entropy contribution (needed for +MSST simulations with a quantum code). In this example, the callback function is set to run the semi-empirical quantum code DFTB+ in serial and then read in the total @@ -20,11 +21,14 @@ etc. A few more important notes: --The stress tensor from DFTB+ is passed in to LAMMPS via pointer. -Calling the subroutine lammps_set_callback() is required in order to set a pointer to the callback function in LAMMPS. -The subroutine lammps_set_user_energy() passes in the potential energy - from DFTB+ to LAMMPS. + from DFTB+ to LAMMPS. Similarly, lammps_set_user_virial passes the stress tensor. + +-The electronic entropy contribution is set via lammps_set_external_vector(). Their needs + to be a call to lammps_set_external_vector_length() before this value can be + passed to LAMMPS. This example was created by Nir Goldman, whom you can contact with questions: diff --git a/examples/COUPLE/fortran3/data.diamond b/examples/COUPLE/fortran_dftb/data.diamond similarity index 100% rename from examples/COUPLE/fortran3/data.diamond rename to examples/COUPLE/fortran_dftb/data.diamond diff --git a/examples/COUPLE/fortran_dftb/dftb_in.hsd b/examples/COUPLE/fortran_dftb/dftb_in.hsd new file mode 100644 index 0000000000..104a4c04ce --- /dev/null +++ b/examples/COUPLE/fortran_dftb/dftb_in.hsd @@ -0,0 +1,40 @@ +#sample DFTB+ script to run this test code +Geometry = GenFormat { +<<< "lammps.gen" +} + +Driver = { +} + +Hamiltonian = DFTB { + LAMMPS = Yes # keyword to print energy, forces, and stress tensor to file(results.out) + SCC = No + MaxAngularMomentum = { + C = "p" + } + Charge = 0.0 + Eigensolver = Standard {} + Filling = Fermi { + Temperature [Kelvin] = 298.0 + } + SlaterKosterFiles = Type2FileNames { + Prefix = "~/slako/mio-1-1/" # the user must define the location of the skf files + Separator = "-" + Suffix = ".skf" + LowerCaseTypeName = No + } + KPointsAndWeights = { + 0.0000000000000 0.0000000000000 0.0000000000000 1.00000000000000 + } +} + +Options = { + CalculateForces = Yes + WriteDetailedOut = No + WriteBandOut = No + RandomSeed = 12345 +} + +ParserOptions = { + ParserVersion = 3 +} diff --git a/examples/COUPLE/fortran_dftb/dftb_pin.hsd b/examples/COUPLE/fortran_dftb/dftb_pin.hsd new file mode 100644 index 0000000000..6d9dea4a15 --- /dev/null +++ b/examples/COUPLE/fortran_dftb/dftb_pin.hsd @@ -0,0 +1,129 @@ +Geometry = GenFormat { +64 S +C +1 1 7.099007 7.117657 7.119139 +2 1 0.858709 0.867233 0.882294 +3 1 1.772527 1.811776 7.120239 +4 1 2.702145 2.681271 0.901362 +5 1 0.017539 1.794455 1.788454 +6 1 0.885593 2.694118 2.707994 +7 1 1.795055 7.120787 1.777896 +8 1 2.642849 0.868278 2.670699 +9 1 0.016060 0.017156 3.568644 +10 1 0.891891 0.896406 4.439286 +11 1 1.766086 1.764402 3.550134 +12 1 2.677349 2.648926 4.427174 +13 1 0.010133 1.771283 5.342173 +14 1 0.858153 2.653565 6.241596 +15 1 1.804087 0.020636 5.353268 +16 1 2.689680 0.907188 6.224575 +17 1 0.017845 3.577563 7.113016 +18 1 0.910027 4.459286 0.910286 +19 1 1.766394 5.376046 0.015526 +20 1 2.683727 6.220728 0.898553 +21 1 0.003357 5.363423 1.774139 +22 1 0.856735 6.238324 2.660213 +23 1 1.761079 3.549776 1.797054 +24 1 2.667227 4.463441 2.646074 +25 1 7.132499 3.551558 3.599764 +26 1 0.920387 4.482191 4.479257 +27 1 1.772194 5.337132 3.555569 +28 1 2.675010 6.251629 4.483124 +29 1 0.005702 5.371095 5.351147 +30 1 0.880807 6.249819 6.264231 +31 1 1.793177 3.592396 5.369939 +32 1 2.653179 4.463595 6.274044 +33 1 3.557243 7.118913 0.026006 +34 1 4.458971 0.889331 0.904950 +35 1 5.367903 1.759757 7.104941 +36 1 6.271565 2.658454 0.890168 +37 1 3.591915 1.768681 1.793880 +38 1 4.435612 2.662184 2.676722 +39 1 5.371040 0.000196 1.783464 +40 1 6.226453 0.886640 2.653384 +41 1 3.583339 0.005449 3.600177 +42 1 4.453692 0.909417 4.459713 +43 1 5.314554 1.805409 3.584215 +44 1 6.210181 2.642660 4.486206 +45 1 3.545704 1.802745 5.365369 +46 1 4.476660 2.701226 6.220451 +47 1 5.332820 0.029557 5.347965 +48 1 6.215725 0.915081 6.230289 +49 1 3.536446 3.551469 7.106600 +50 1 4.451181 4.426439 0.900180 +51 1 5.368735 5.377996 7.109524 +52 1 6.230666 6.220985 0.862175 +53 1 3.596626 5.372822 1.797613 +54 1 4.485613 6.221252 2.699652 +55 1 5.364421 3.549838 1.796281 +56 1 6.261739 4.459046 2.648152 +57 1 3.588752 3.581054 3.581755 +58 1 4.462342 4.467270 4.478800 +59 1 5.355202 5.318323 3.556531 +60 1 6.268570 6.259831 4.465795 +61 1 3.588636 5.354278 5.362327 +62 1 4.475747 6.263866 6.227803 +63 1 5.331158 3.554349 5.318368 +64 1 6.254581 4.436344 6.209681 +0.0 0.0 0.0 +7.13400000000000 0 0 +0 7.13400000000000 0 +0 0 7.13400000000000 +} +Driver = {} +Hamiltonian = DFTB { + LAMMPS = Yes + SCC = No + MaxAngularMomentum = { + C = "p" + } + Charge = 0.0 + Eigensolver = Standard {} + Filling = Fermi { + Temperature [Kelvin] = 298.0 + IndependentKFilling = No + } + SlaterKosterFiles = Type2FileNames { + Prefix = "~/slako/mio-1-1/" + Separator = "-" + Suffix = ".skf" + LowerCaseTypeName = No + } + KPointsAndWeights = { +0.0000000000000 0.0000000000000 0.0000000000000 1.00000000000000 + } + PolynomialRepulsive = {} + OldRepulsiveSum = No + OrbitalResolvedSCC = No + OldSKInterpolation = No + NoErep = No + Dispersion = {} + ThirdOrder = No + ThirdOrderFull = No +} +Options = { + CalculateForces = Yes + WriteDetailedOut = No + WriteBandOut = No + RandomSeed = 12345 + MullikenAnalysis = No + WriteEigenvectors = No + WriteAutotestTag = No + WriteDetailedXML = No + WriteResultsTag = No + AtomResolvedEnergies = No + WriteHS = No + WriteRealHS = No + MinimiseMemoryUsage = No + ShowFoldedCoords = No +} +ParserOptions = { + ParserVersion = 3 + WriteHSDInput = Yes + WriteXMLInput = No + StopAfterParsing = No + IgnoreUnprocessedNodes = No +} +Analysis = { + ProjectStates = {} +} diff --git a/examples/COUPLE/fortran3/in.simple b/examples/COUPLE/fortran_dftb/in.simple similarity index 100% rename from examples/COUPLE/fortran3/in.simple rename to examples/COUPLE/fortran_dftb/in.simple diff --git a/examples/COUPLE/fortran_dftb/log.simple b/examples/COUPLE/fortran_dftb/log.simple new file mode 100644 index 0000000000..3496e94ebe --- /dev/null +++ b/examples/COUPLE/fortran_dftb/log.simple @@ -0,0 +1,71 @@ +LAMMPS (6 Jul 2017) +units real +atom_style charge +atom_modify map array +atom_modify sort 0 0.0 +read_data data.diamond + triclinic box = (0 0 0) to (7.134 7.134 7.134) with tilt (0 0 0) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 64 atoms + reading velocities ... + 64 velocities +neighbor 1.0 bin +neigh_modify delay 0 every 5 check no +fix 1 all nve +fix 2 all external pf/callback 1 1 + +fix_modify 2 energy yes +thermo_style custom step temp etotal ke pe lx ly lz pxx pyy pzz press + +thermo 1 +timestep 0.5 + +run 10 +Neighbor list info ... + update every 5 steps, delay 0 steps, check no + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 0 + ghost atom cutoff = 0 + binsize = 7.134, bins = 1 1 1 + 0 neighbor lists, perpetual/occasional/extra = 0 0 0 +Per MPI rank memory allocation (min/avg/max) = 2.3 | 2.3 | 2.3 Mbytes +Step Temp TotEng KinEng PotEng Lx Ly Lz Pxx Pyy Pzz Press + 0 298.24835 -69593.587 56.008365 -69649.595 7.134 7.134 7.134 -19980.19 -21024.038 -21097.458 -20700.562 + 1 295.24358 -69593.585 55.444098 -69649.029 7.134 7.134 7.134 -19778.833 -20799.657 -20854.156 -20477.549 + 2 286.37211 -69593.58 53.778115 -69647.358 7.134 7.134 7.134 -19227.52 -20177.28 -20176.12 -19860.306 + 3 272.062 -69593.572 51.090804 -69644.663 7.134 7.134 7.134 -18360.869 -19189.684 -19100.021 -18883.525 + 4 253.01834 -69593.561 47.514575 -69641.075 7.134 7.134 7.134 -17198.143 -17855.03 -17652.036 -17568.403 + 5 230.19242 -69593.547 43.228073 -69636.775 7.134 7.134 7.134 -15750.247 -16183.764 -15854.145 -15929.386 + 6 204.71787 -69593.533 38.44418 -69631.977 7.134 7.134 7.134 -14083.498 -14247.434 -13789.835 -14040.256 + 7 177.82397 -69593.518 33.393748 -69626.911 7.134 7.134 7.134 -12340.963 -12202.878 -11623.171 -12055.671 + 8 150.76736 -69593.503 28.312758 -69621.816 7.134 7.134 7.134 -10637.824 -10180.827 -9495.0496 -10104.567 + 9 124.7737 -69593.49 23.431383 -69616.921 7.134 7.134 7.134 -9113.3842 -8339.0492 -7572.8076 -8341.747 + 10 100.98183 -69593.478 18.963481 -69612.442 7.134 7.134 7.134 -7833.9349 -6756.9749 -5945.8968 -6845.6022 +Loop time of 2.20497 on 1 procs for 10 steps with 64 atoms + +Performance: 0.196 ns/day, 122.499 hours/ns, 4.535 timesteps/s +0.2% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0 | 0 | 0 | 0.0 | 0.00 +Neigh | 1.4305e-06 | 1.4305e-06 | 1.4305e-06 | 0.0 | 0.00 +Comm | 4.22e-05 | 4.22e-05 | 4.22e-05 | 0.0 | 0.00 +Output | 0.00067687 | 0.00067687 | 0.00067687 | 0.0 | 0.03 +Modify | 2.2042 | 2.2042 | 2.2042 | 0.0 | 99.96 +Other | | 6.533e-05 | | | 0.00 + +Nlocal: 64 ave 64 max 64 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 0 +Ave neighs/atom = 0 +Neighbor list builds = 2 +Dangerous builds not checked +Total wall time: 0:00:02 diff --git a/examples/COUPLE/fortran3/makefile b/examples/COUPLE/fortran_dftb/makefile similarity index 95% rename from examples/COUPLE/fortran3/makefile rename to examples/COUPLE/fortran_dftb/makefile index 86dea30850..225bd0025a 100644 --- a/examples/COUPLE/fortran3/makefile +++ b/examples/COUPLE/fortran_dftb/makefile @@ -21,7 +21,7 @@ liblammps_fortran.so : LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o $(FC) $(FFLAGS) -shared -o $@ $^ simpleF.x: simple.o LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o - $(FC) $(FFLAGS) simple.o -o simpleF.x liblammps_fortran.a $(LAMMPS_SRC)/liblammps_mvapich.a -lstdc++ /usr/local/tools/fftw/lib/libfftw.a + $(FC) $(FFLAGS) simple.o -o simpleF.x liblammps_fortran.a $(LAMMPS_SRC)/liblammps_mvapich.a -lstdc++ /usr/lib64/libfftw3.a liblammps_fortran.a : LAMMPS.o LAMMPS-wrapper.o LAMMPS-wrapper2.o $(AR) rs $@ $^ diff --git a/examples/COUPLE/fortran3/simple.f90 b/examples/COUPLE/fortran_dftb/simple.f90 similarity index 91% rename from examples/COUPLE/fortran3/simple.f90 rename to examples/COUPLE/fortran_dftb/simple.f90 index 40f8bf8b86..4604b4e4a9 100644 --- a/examples/COUPLE/fortran3/simple.f90 +++ b/examples/COUPLE/fortran_dftb/simple.f90 @@ -13,7 +13,7 @@ type(c_ptr) :: c_pos, c_fext, c_ids double precision, pointer :: fext(:,:), pos(:,:) integer, intent(in) :: ids(nlocal) - real (C_double), dimension(:), pointer :: virial => NULL() + real(C_double) :: virial(6) real (C_double) :: etot real(C_double), pointer :: ts_lmp double precision :: stress(3,3), ts_dftb @@ -61,26 +61,21 @@ read(10,*)stress(i,:) enddo stress (:,:) = stress(:,:)*autoatm - etot = etot*econv - call lammps_extract_global(ts_lmp, lmp, 'TS_dftb') - ts_lmp = ts_dftb - do i = 1, nlocal - read(10,*)fext(:,ids(i)) - fext(:,ids(i)) = fext(:,ids(i))*fconv - enddo - close(10) - call lammps_set_user_energy (lmp, etot) - call lammps_extract_atom (virial, lmp, 'virial') - if (.not. associated(virial)) then - print*,'virial pointer not associated.' - STOP - endif virial(1) = stress(1,1)/(nktv2p/volume) virial(2) = stress(2,2)/(nktv2p/volume) virial(3) = stress(3,3)/(nktv2p/volume) virial(4) = stress(1,2)/(nktv2p/volume) virial(5) = stress(1,3)/(nktv2p/volume) virial(6) = stress(2,3)/(nktv2p/volume) + etot = etot*econv + call lammps_set_external_vector(lmp,1,ts_dftb*econv) + do i = 1, nlocal + read(10,*)fext(:,ids(i)) + fext(:,ids(i)) = fext(:,ids(i))*fconv + enddo + close(10) + call lammps_set_user_energy (lmp, etot) + call lammps_set_user_virial (lmp, virial) end subroutine end module callback @@ -103,6 +98,7 @@ program simple_fortran_callback call lammps_open_no_mpi ('lmp -log log.simple', lmp) call lammps_file (lmp, 'in.simple') call lammps_set_callback(lmp) + call lammps_set_external_vector_length(lmp,2) call lammps_command (lmp, 'run 10') call lammps_close (lmp) diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index af658fa26c..18b426f928 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -1,34 +1,27 @@ #!/usr/bin/env python -# Install.py tool to do automate build of Colvars +# install.py tool to do a generic build of a library +# soft linked to by many of the lib/Install.py files +# used to automate the steps described in the corresponding lib/README -from __future__ import print_function -import sys,os,subprocess +import sys,commands,os # help message help = """ -Syntax from src dir: make lib-colvars args="-m machine -e suffix" -Syntax from lib/colvars dir: python Install.py -m machine -e suffix - -specify -m and optionally -e, order does not matter - +Syntax: python Install.py -m machine -e suffix + specify -m and optionally -e, order does not matter -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/colvars/Makefile.* or of a - src/MAKE/MACHINES/Makefile.* file + machine = suffix of a lib/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine - -Examples: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler """ # print error message or help def error(str=None): - if not str: print(help) - else: print("ERROR"),str + if not str: print help + else: print "ERROR",str sys.exit() # parse args @@ -38,17 +31,17 @@ nargs = len(args) if nargs == 0: error() machine = None -extraflag = False +extraflag = 0 iarg = 0 while iarg < nargs: if args[iarg] == "-m": - if iarg+2 > len(args): error() + if iarg+2 > nargs: error() machine = args[iarg+1] iarg += 2 elif args[iarg] == "-e": - if iarg+2 > len(args): error() - extraflag = True + if iarg+2 > nargs: error() + extraflag = 1 suffix = args[iarg+1] iarg += 2 else: error() @@ -58,85 +51,32 @@ while iarg < nargs: cwd = os.getcwd() lib = os.path.basename(cwd) -def get_lammps_machine_flags(machine): - """Parse Makefile.machine from LAMMPS, return dictionary of compiler flags""" - if not os.path.exists("../../src/MAKE/MACHINES/Makefile.%s" % machine): - error("Cannot locate src/MAKE/MACHINES/Makefile.%s" % machine) - lines = open("../../src/MAKE/MACHINES/Makefile.%s" % machine, - 'r').readlines() - machine_flags = {} - for line in lines: - line = line.partition('#')[0] - line = line.rstrip() - words = line.split() - if (len(words) > 2): - if ((words[0] == 'CC') or (words[0] == 'CCFLAGS') or - (words[0] == 'SHFLAGS') or (words[0] == 'ARCHIVE') or - (words[0] == 'ARFLAGS') or (words[0] == 'SHELL')): - machine_flags[words[0]] = ' '.join(words[2:]) - return machine_flags - -def gen_colvars_makefile_machine(machine, machine_flags): - """Generate Makefile.machine for Colvars given the compiler flags""" - machine_makefile = open("Makefile.%s" % machine, 'w') - machine_makefile.write('''# -*- makefile -*- to build Colvars module with %s - -COLVARS_LIB = libcolvars.a -COLVARS_OBJ_DIR = - -CXX = %s -CXXFLAGS = %s %s -AR = %s -ARFLAGS = %s -SHELL = %s - -include Makefile.common - -.PHONY: default clean - -default: $(COLVARS_LIB) Makefile.lammps - -clean: - -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) -''' % (machine, machine_flags['CC'], - machine_flags['CCFLAGS'], machine_flags['SHFLAGS'] , - machine_flags['ARCHIVE'], machine_flags['ARFLAGS'], - machine_flags['SHELL'])) - -if not os.path.exists("Makefile.%s" % machine): - machine_flags = get_lammps_machine_flags(machine) - gen_colvars_makefile_machine(machine, machine_flags) +# create Makefile.auto as copy of Makefile.machine +# reset EXTRAMAKE if requested + if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - lines = open("Makefile.%s" % machine,'r').readlines() fp = open("Makefile.auto",'w') + for line in lines: words = line.split() if len(words) == 3 and extraflag and \ words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - fp.write(line) + print >>fp,line, + fp.close() # make the library via Makefile.auto -try: - import multiprocessing - n_cpus = multiprocessing.cpu_count() -except: - n_cpus = 1 +print "Building lib%s.a ..." % lib +cmd = "make -f Makefile.auto clean; make -f Makefile.auto" +txt = commands.getoutput(cmd) +print txt -print("Building lib%s.a ..." % lib) -cmd = ["make -f Makefile.auto clean"] -print(subprocess.check_output(cmd, shell=True).decode()) -cmd = ["make -f Makefile.auto -j%d" % n_cpus] -print(subprocess.check_output(cmd, shell=True).decode()) - -if os.path.exists("lib%s.a" % lib): print("Build was successful") +if os.path.exists("lib%s.a" % lib): print "Build was successful" else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): - print("lib/%s/Makefile.lammps was NOT created" % lib) + print "lib/%s/Makefile.lammps was NOT created" % lib From 427ca88dd44dc7638de9f9131e120c85a298942e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 20 Jul 2017 15:02:41 -0600 Subject: [PATCH 189/293] cmake: error for POEMS + BODY package --- cmake/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4304a8078f..8f375e91bb 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -102,6 +102,10 @@ pkg_depends(USER-LB MPI) pkg_depends(USER-MISC MANYBODY) pkg_depends(USER-PHONON KSPACE) +if(ENABLE_BODY AND ENABLE_POEMS) + message(FATAL_ERROR "BODY and POEMS cannot be enabled at the same time") +endif() + ###################################################### # packages with special compiler needs or external libs ###################################################### From 5dbe2df85455ee6c705f4bbdd835afdae4d3f93b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 17:07:31 -0400 Subject: [PATCH 190/293] revert change that accidentally undoes part of PRs #583 and #588 --- lib/colvars/Install.py | 110 +++++++++++++++++++++++++++++++---------- 1 file changed, 85 insertions(+), 25 deletions(-) diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index 18b426f928..af658fa26c 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -1,27 +1,34 @@ #!/usr/bin/env python -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README +# Install.py tool to do automate build of Colvars -import sys,commands,os +from __future__ import print_function +import sys,os,subprocess # help message help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter +Syntax from src dir: make lib-colvars args="-m machine -e suffix" +Syntax from lib/colvars dir: python Install.py -m machine -e suffix + +specify -m and optionally -e, order does not matter + -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file + machine = suffix of a lib/colvars/Makefile.* or of a + src/MAKE/MACHINES/Makefile.* file -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine + +Examples: + +make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler """ # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR"),str sys.exit() # parse args @@ -31,17 +38,17 @@ nargs = len(args) if nargs == 0: error() machine = None -extraflag = 0 +extraflag = False iarg = 0 while iarg < nargs: if args[iarg] == "-m": - if iarg+2 > nargs: error() + if iarg+2 > len(args): error() machine = args[iarg+1] iarg += 2 elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 + if iarg+2 > len(args): error() + extraflag = True suffix = args[iarg+1] iarg += 2 else: error() @@ -51,32 +58,85 @@ while iarg < nargs: cwd = os.getcwd() lib = os.path.basename(cwd) -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - +def get_lammps_machine_flags(machine): + """Parse Makefile.machine from LAMMPS, return dictionary of compiler flags""" + if not os.path.exists("../../src/MAKE/MACHINES/Makefile.%s" % machine): + error("Cannot locate src/MAKE/MACHINES/Makefile.%s" % machine) + lines = open("../../src/MAKE/MACHINES/Makefile.%s" % machine, + 'r').readlines() + machine_flags = {} + for line in lines: + line = line.partition('#')[0] + line = line.rstrip() + words = line.split() + if (len(words) > 2): + if ((words[0] == 'CC') or (words[0] == 'CCFLAGS') or + (words[0] == 'SHFLAGS') or (words[0] == 'ARCHIVE') or + (words[0] == 'ARFLAGS') or (words[0] == 'SHELL')): + machine_flags[words[0]] = ' '.join(words[2:]) + return machine_flags + +def gen_colvars_makefile_machine(machine, machine_flags): + """Generate Makefile.machine for Colvars given the compiler flags""" + machine_makefile = open("Makefile.%s" % machine, 'w') + machine_makefile.write('''# -*- makefile -*- to build Colvars module with %s + +COLVARS_LIB = libcolvars.a +COLVARS_OBJ_DIR = + +CXX = %s +CXXFLAGS = %s %s +AR = %s +ARFLAGS = %s +SHELL = %s + +include Makefile.common + +.PHONY: default clean + +default: $(COLVARS_LIB) Makefile.lammps + +clean: + -rm -f $(COLVARS_OBJS) $(COLVARS_LIB) +''' % (machine, machine_flags['CC'], + machine_flags['CCFLAGS'], machine_flags['SHFLAGS'] , + machine_flags['ARCHIVE'], machine_flags['ARFLAGS'], + machine_flags['SHELL'])) + +if not os.path.exists("Makefile.%s" % machine): + machine_flags = get_lammps_machine_flags(machine) + gen_colvars_makefile_machine(machine, machine_flags) if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) +# create Makefile.auto as copy of Makefile.machine +# reset EXTRAMAKE if requested + lines = open("Makefile.%s" % machine,'r').readlines() fp = open("Makefile.auto",'w') - for line in lines: words = line.split() if len(words) == 3 and extraflag and \ words[0] == "EXTRAMAKE" and words[1] == '=': line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - + fp.write(line) fp.close() # make the library via Makefile.auto -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt +try: + import multiprocessing + n_cpus = multiprocessing.cpu_count() +except: + n_cpus = 1 -if os.path.exists("lib%s.a" % lib): print "Build was successful" +print("Building lib%s.a ..." % lib) +cmd = ["make -f Makefile.auto clean"] +print(subprocess.check_output(cmd, shell=True).decode()) +cmd = ["make -f Makefile.auto -j%d" % n_cpus] +print(subprocess.check_output(cmd, shell=True).decode()) + +if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib + print("lib/%s/Makefile.lammps was NOT created" % lib) From 551001f172a36790b7ff53453383d381b9e66ea5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 17:08:19 -0400 Subject: [PATCH 191/293] revert change, that is part of the kim-install branch and changeset --- doc/src/pair_kim.txt | 33 ++++++--------------------------- 1 file changed, 6 insertions(+), 27 deletions(-) diff --git a/doc/src/pair_kim.txt b/doc/src/pair_kim.txt index 5ee607c2b0..5a623e5ece 100644 --- a/doc/src/pair_kim.txt +++ b/doc/src/pair_kim.txt @@ -27,34 +27,13 @@ pair_coeff * * Ar Ar :pre [Description:] This pair style is a wrapper on the "Knowledge Base for Interatomic -Models (OpenKIM)"_https://openkim.org repository of interatomic -potentials, so that they can be used by LAMMPS scripts. +Models (KIM)"_https://openkim.org repository of interatomic potentials, +so that they can be used by LAMMPS scripts. -Note that in LAMMPS lingo, a KIM model driver is a pair style -(e.g. EAM or Tersoff). A KIM model is a pair style for a particular -element or alloy and set of parameters, e.g. EAM for Cu with a -specific EAM potential file. - -See the current list of "KIM model -drivers"_https://openkim.org/kim-items/model-drivers/alphabetical. - -See the current list of all "KIM -models"_https://openkim.org/kim-items/models/by-model-drivers - -See the list of "example KIM models"_https://openkim.org/kim-api which -are included in the KIM library by default, in the "What is in the KIM -API source package?" section. - -To use this pair style, you must first download and install the KIM -API library from the "OpenKIM website"_https://openkim.org. The "KIM -section of Section packages"_Section_packages.html#kim-package has -instructions on how to do this with a simple make command, when -building LAMMPS. - -See the examples/kim dir for an input script that uses a KIM model -(potential) for Lennard-Jones. - -:line +In KIM lingo, a potential is a "model" and a model contains both the +analytic formulas that define the potential as well as the parameters +needed to run it for one or more materials, including coefficients and +cutoffs. The argument {virialmode} determines how the global virial is calculated. If {KIMvirial} is specified, the KIM model performs the From c88d1e5510a1999d64604d97df406cf212f14d24 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 20 Jul 2017 15:15:29 -0600 Subject: [PATCH 192/293] make ENABLE_ALL work out of the box --- cmake/CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 8f375e91bb..c9e973e212 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -71,20 +71,21 @@ add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) -option(ENABLE_ALL "Build all packages" OFF) -set(PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR - KIM KSPACE MANYBODY MC MEAM MISC MOLECULE MSCG MPIIO PERI POEMS PYTHON QEQ - REAX REPLICA RIGID SHOCK SNAP SRD VORONOI) -set(USER-PACKAGES USER-ATC USER-AWPMD USER-CGDNA +option(ENABLE_ALL "Build all default packages" OFF) +set(DEFAULT_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR + KSPACE MANYBODY MC MEAM MISC MOLECULE PERI QEQ + REAX REPLICA RIGID SHOCK SNAP SRD) +set(OTHER_PACKAGES KIM PYTHON MSCG MPIIO VORONOI POEMS + USER-ATC USER-AWPMD USER-CGDNA USER-CGSDK USER-COLVARS USER-DIFFRACTION USER-DPD USER-DRUDE USER-EFF USER-FEP USER-H5MD USER-LB USER-MANIFOLD USER-MEAMC USER-MGPT USER-MISC USER-MOLFILE USER-NETCDF USER-PHONON USER-QTB USER-REAXC USER-SMD USER-SMTBQ USER-SPH USER-TALLY USER-VTK USER-QUIP USER-QMMM) set(ACCEL_PACKAGES USER-OMP KOKKOS OPT USER-INTEL GPU) -foreach(PKG ${PACKAGES}) +foreach(PKG ${DEFAULT_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" ${ENABLE_ALL}) endforeach() -foreach(PKG ${ACCEL_PACKAGES} ${USER-PACKAGES}) +foreach(PKG ${ACCEL_PACKAGES} ${OTHER_PACKAGES}) option(ENABLE_${PKG} "Build ${PKG} Package" OFF) endforeach() @@ -522,7 +523,7 @@ install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) ################################## # Print package summary ################################## -foreach(PKG ${PACKAGES} ${USER-PACKAGES} ${ACCEL_PACKAGES}) +foreach(PKG ${DEFAULT_PACKAGES} ${OTHER_PACKAGES} ${ACCEL_PACKAGES}) if(ENABLE_${PKG}) message(STATUS "Building package: ${PKG}") endif() From 3449d4226701ed7f11aa2908e9f29e240460904a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 17:58:49 -0400 Subject: [PATCH 193/293] include pair style kim doc changes that were accidentally included in PR #590 --- doc/src/pair_kim.txt | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/doc/src/pair_kim.txt b/doc/src/pair_kim.txt index 5a623e5ece..5ee607c2b0 100644 --- a/doc/src/pair_kim.txt +++ b/doc/src/pair_kim.txt @@ -27,13 +27,34 @@ pair_coeff * * Ar Ar :pre [Description:] This pair style is a wrapper on the "Knowledge Base for Interatomic -Models (KIM)"_https://openkim.org repository of interatomic potentials, -so that they can be used by LAMMPS scripts. +Models (OpenKIM)"_https://openkim.org repository of interatomic +potentials, so that they can be used by LAMMPS scripts. -In KIM lingo, a potential is a "model" and a model contains both the -analytic formulas that define the potential as well as the parameters -needed to run it for one or more materials, including coefficients and -cutoffs. +Note that in LAMMPS lingo, a KIM model driver is a pair style +(e.g. EAM or Tersoff). A KIM model is a pair style for a particular +element or alloy and set of parameters, e.g. EAM for Cu with a +specific EAM potential file. + +See the current list of "KIM model +drivers"_https://openkim.org/kim-items/model-drivers/alphabetical. + +See the current list of all "KIM +models"_https://openkim.org/kim-items/models/by-model-drivers + +See the list of "example KIM models"_https://openkim.org/kim-api which +are included in the KIM library by default, in the "What is in the KIM +API source package?" section. + +To use this pair style, you must first download and install the KIM +API library from the "OpenKIM website"_https://openkim.org. The "KIM +section of Section packages"_Section_packages.html#kim-package has +instructions on how to do this with a simple make command, when +building LAMMPS. + +See the examples/kim dir for an input script that uses a KIM model +(potential) for Lennard-Jones. + +:line The argument {virialmode} determines how the global virial is calculated. If {KIMvirial} is specified, the KIM model performs the From e8e9ea839207e9de447754c843db402b86969092 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Thu, 20 Jul 2017 16:14:02 -0600 Subject: [PATCH 194/293] added one trivial test --- cmake/CMakeLists.txt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c9e973e212..4a2a8773ec 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -71,6 +71,11 @@ add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) +option(ENABLE_TESTING "Enable testing" OFF) +if(ENABLE_TESTING) + enable_testing() +endif(ENABLE_TESTING) + option(ENABLE_ALL "Build all default packages" OFF) set(DEFAULT_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE GRANULAR KSPACE MANYBODY MC MEAM MISC MOLECULE PERI QEQ @@ -519,6 +524,9 @@ endif() add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) +if(ENABLE_TESTING) + add_test(ShowHelp lmp -help) +endif() ################################## # Print package summary From 61b1487cbd9364423129de4b506edd413c2524bd Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 18:17:19 -0400 Subject: [PATCH 195/293] avoid division by zero in reaxff bond interaction computations in very rare cases this addresses the issue reported by stan and ishan --- src/KOKKOS/pair_reaxc_kokkos.cpp | 3 ++- src/USER-REAXC/reaxc_bonds.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp index 6be09548da..841b7fbea9 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.cpp +++ b/src/KOKKOS/pair_reaxc_kokkos.cpp @@ -3335,7 +3335,8 @@ void PairReaxCKokkos::operator()(PairReaxComputeBond1select.bond_list[pj].bo_data ); /* calculate the constants */ - pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 ); + if (bo_ij->BO_s == 0.0) pow_BOs_be2 = 0.0; + else pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 ); exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) ); CEbo = -twbp->De_s * exp_be12 * ( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 ); From ec23aef20b2257d825d982bef677889e5218f254 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 20 Jul 2017 18:19:53 -0400 Subject: [PATCH 196/293] fix reaxc division by zero bug also for USER-OMP variant --- src/USER-OMP/reaxc_bonds_omp.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/USER-OMP/reaxc_bonds_omp.cpp b/src/USER-OMP/reaxc_bonds_omp.cpp index 2b7ab7e5e8..7522df2f60 100644 --- a/src/USER-OMP/reaxc_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_bonds_omp.cpp @@ -119,7 +119,8 @@ void BondsOMP( reax_system *system, control_params *control, bo_ij = &( bonds->select.bond_list[pj].bo_data ); /* calculate the constants */ - pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 ); + if (bo_ij->BO_s == 0.0) pow_BOs_be2 = 0.0; + else pow_BOs_be2 = pow( bo_ij->BO_s, twbp->p_be2 ); exp_be12 = exp( twbp->p_be1 * ( 1.0 - pow_BOs_be2 ) ); CEbo = -twbp->De_s * exp_be12 * ( 1.0 - twbp->p_be1 * twbp->p_be2 * pow_BOs_be2 ); From 733ea61bf1073ac4c24c9a563b2386bdcc6b49e4 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jul 2017 01:15:24 -0400 Subject: [PATCH 197/293] correct typo in USER-REAXC code --- src/USER-REAXC/reaxc_list.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/USER-REAXC/reaxc_list.cpp b/src/USER-REAXC/reaxc_list.cpp index e7fac4d418..c15ba7927c 100644 --- a/src/USER-REAXC/reaxc_list.cpp +++ b/src/USER-REAXC/reaxc_list.cpp @@ -37,7 +37,7 @@ int Make_List(int n, int num_intrs, int type, reax_list *l, MPI_Comm comm) l->num_intrs = num_intrs; if (l->index) sfree(l->index, "list:index"); - if (l->end_index) sfree(l->index, "list:end_index"); + if (l->end_index) sfree(l->end_index, "list:end_index"); l->index = (int*) smalloc( n * sizeof(int), "list:index", comm ); l->end_index = (int*) smalloc( n * sizeof(int), "list:end_index", comm ); From 00474ab09dcd9fbecc80287ae0ecd2e5da464a13 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jul 2017 10:30:11 -0400 Subject: [PATCH 198/293] handle one more case where allowing shifted potential with cutoff 0.0 would create NaNs --- src/USER-DRUDE/pair_lj_cut_thole_long.cpp | 2 +- src/USER-MISC/pair_morse_smooth_linear.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp index a74f51477c..ee9c0744d3 100644 --- a/src/USER-DRUDE/pair_lj_cut_thole_long.cpp +++ b/src/USER-DRUDE/pair_lj_cut_thole_long.cpp @@ -417,7 +417,7 @@ double PairLJCutTholeLong::init_one(int i, int j) lj3[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],12.0); lj4[i][j] = 4.0 * epsilon[i][j] * pow(sigma[i][j],6.0); - if (offset_flag) { + if (offset_flag && (cut_lj[i][j] > 0.0)) { double ratio = sigma[i][j] / cut_lj[i][j]; offset[i][j] = 4.0 * epsilon[i][j] * (pow(ratio,12.0) - pow(ratio,6.0)); } else offset[i][j] = 0.0; diff --git a/src/USER-MISC/pair_morse_smooth_linear.cpp b/src/USER-MISC/pair_morse_smooth_linear.cpp index 3e776e7e1c..0035338cd9 100644 --- a/src/USER-MISC/pair_morse_smooth_linear.cpp +++ b/src/USER-MISC/pair_morse_smooth_linear.cpp @@ -296,7 +296,6 @@ void PairMorseSmoothLinear::read_restart(FILE *fp) void PairMorseSmoothLinear::write_restart_settings(FILE *fp) { fwrite(&cut_global,sizeof(double),1,fp); - // fwrite(&offset_flag,sizeof(int),1,fp); fwrite(&mix_flag,sizeof(int),1,fp); } @@ -308,11 +307,9 @@ void PairMorseSmoothLinear::read_restart_settings(FILE *fp) { if (comm->me == 0) { fread(&cut_global,sizeof(double),1,fp); - // fread(&offset_flag,sizeof(int),1,fp); fread(&mix_flag,sizeof(int),1,fp); } MPI_Bcast(&cut_global,1,MPI_DOUBLE,0,world); - // MPI_Bcast(&offset_flag,1,MPI_INT,0,world); MPI_Bcast(&mix_flag,1,MPI_INT,0,world); } From 3d1d0c58c7322aca3ab8019dfc176875868a9743 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Fri, 21 Jul 2017 12:08:04 -0500 Subject: [PATCH 199/293] Cleaned up 3-body gpu styles, and fixed a bug for tersoff/zbl/gpu. There is a unresolved bug for neigh no with tpa > 1 with BaseThree, enforce tpa = 1 for neigh no in BaseThree for now. --- lib/gpu/lal_base_three.cpp | 41 ++++++++++++++----------------------- lib/gpu/lal_base_three.h | 2 +- lib/gpu/lal_tersoff_mod.cu | 2 +- lib/gpu/lal_tersoff_zbl.cpp | 2 +- lib/gpu/lal_tersoff_zbl.cu | 2 +- 5 files changed, 19 insertions(+), 30 deletions(-) diff --git a/lib/gpu/lal_base_three.cpp b/lib/gpu/lal_base_three.cpp index 4e8a95937c..5f3c57337e 100644 --- a/lib/gpu/lal_base_three.cpp +++ b/lib/gpu/lal_base_three.cpp @@ -20,7 +20,7 @@ using namespace LAMMPS_AL; extern Device global_device; template -BaseThreeT::BaseThree() : _compiled(false), _max_bytes(0), _short_nbor(false) { +BaseThreeT::BaseThree() : _compiled(false), _max_bytes(0) { device=&global_device; ans=new Answer(); nbor=new Neighbor(); @@ -73,6 +73,7 @@ int BaseThreeT::init_three(const int nlocal, const int nall, if (_threads_per_atom>1 && gpu_nbor==0) { // neigh no and tpa > 1 nbor->packing(true); _nbor_data=&(nbor->dev_packed); + _threads_per_atom = 1; // enforce tpa = 1 for now } else // neigh yes or tpa == 1 _nbor_data=&(nbor->dev_nbor); if (_threads_per_atom*_threads_per_atom>device->warp_size()) @@ -113,14 +114,10 @@ int BaseThreeT::init_three(const int nlocal, const int nall, _max_an_bytes+=ans2->gpu_bytes(); #endif - // if short neighbor list is supported - if (short_nbor) { - _short_nbor = true; - int ef_nall=nall; - if (ef_nall==0) - ef_nall=2000; - dev_short_nbor.alloc(ef_nall*(2+max_nbors),*(this->ucl_device),UCL_READ_WRITE); - } + int ef_nall=nall; + if (ef_nall==0) + ef_nall=2000; + dev_short_nbor.alloc(ef_nall*(2+max_nbors),*(this->ucl_device),UCL_READ_WRITE); return 0; } @@ -269,14 +266,10 @@ void BaseThreeT::compute(const int f_ago, const int inum_full, const int nall, hd_balancer.start_timer(); atom->add_x_data(host_x,host_type); - // if short neighbor list is supported - if (_short_nbor) { - - // re-allocate dev_short_nbor if necessary - if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - dev_short_nbor.resize((2+_max_nbors)*_nmax); - } + // re-allocate dev_short_nbor if necessary + if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + dev_short_nbor.resize((2+_max_nbors)*_nmax); } // _ainum to be used in loop() for short neighbor list build @@ -342,14 +335,10 @@ int ** BaseThreeT::compute(const int ago, const int inum_full, *ilist=nbor->host_ilist.begin(); *jnum=nbor->host_acc.begin(); - // if short neighbor list is supported - if (_short_nbor) { - - // re-allocate dev_short_nbor if necessary - if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { - int _nmax=static_cast(static_cast(nall)*1.10); - dev_short_nbor.resize((2+_max_nbors)*_nmax); - } + // re-allocate dev_short_nbor if necessary + if (nall*(2+_max_nbors) > dev_short_nbor.cols()) { + int _nmax=static_cast(static_cast(nall)*1.10); + dev_short_nbor.resize((2+_max_nbors)*_nmax); } // _ainum to be used in loop() for short neighbor list build @@ -394,7 +383,7 @@ void BaseThreeT::compile_kernels(UCL_Device &dev, const void *pair_str, k_three_end.set_function(*pair_program,three_end); k_three_end_vatom.set_function(*pair_program,vatom_name.c_str()); k_pair.set_function(*pair_program,two); - if (short_nbor) k_short_nbor.set_function(*pair_program,short_nbor); + k_short_nbor.set_function(*pair_program,short_nbor); pos_tex.get_texture(*pair_program,"pos_tex"); #ifdef THREE_CONCURRENT diff --git a/lib/gpu/lal_base_three.h b/lib/gpu/lal_base_three.h index fde1936b25..f5f36863c4 100644 --- a/lib/gpu/lal_base_three.h +++ b/lib/gpu/lal_base_three.h @@ -199,7 +199,7 @@ class BaseThree { UCL_Texture pos_tex; protected: - bool _compiled,_short_nbor; + bool _compiled; int _block_pair, _block_size, _threads_per_atom, _end_command_queue; int _gpu_nbor; double _max_bytes, _max_an_bytes; diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu index 555485a1b2..257d3972ed 100644 --- a/lib/gpu/lal_tersoff_mod.cu +++ b/lib/gpu/lal_tersoff_mod.cu @@ -690,7 +690,7 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_, const __global int * dev_nbor, const __global int * dev_packed, const __global int * dev_acc, - const __global int * dev_short_nbor, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, diff --git a/lib/gpu/lal_tersoff_zbl.cpp b/lib/gpu/lal_tersoff_zbl.cpp index 827613067c..341f663030 100644 --- a/lib/gpu/lal_tersoff_zbl.cpp +++ b/lib/gpu/lal_tersoff_zbl.cpp @@ -293,7 +293,7 @@ void TersoffZT::loop(const bool _eflag, const bool _vflag, const int evatom) { (BX/(JTHREADS*KTHREADS)))); this->k_zeta.set_size(GX,BX); - this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &cutsq, + this->k_zeta.run(&this->atom->x, &ts1, &ts2, &ts3, &ts4, &ts5, &ts6, &cutsq, &map, &elem2param, &_nelements, &_nparams, &_zetaij, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->dev_short_nbor, diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu index 89ae72df8a..89317b990c 100644 --- a/lib/gpu/lal_tersoff_zbl.cu +++ b/lib/gpu/lal_tersoff_zbl.cu @@ -702,7 +702,7 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_, const __global int * dev_nbor, const __global int * dev_packed, const __global int * dev_acc, - const __global int * dev_short_nbor, + const __global int * dev_short_nbor, __global acctyp4 *restrict ans, __global acctyp *restrict engv, const int eflag, const int vflag, From c010edc4fdc34ec1e4f527afbff1e6eb8d5f2293 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 21 Jul 2017 11:38:02 -0600 Subject: [PATCH 200/293] cmake: fixed two typos --- cmake/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4a2a8773ec..ebf452d183 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -142,7 +142,7 @@ if(ENABLE_KSPACE) list(APPEND LAMMPS_LINK_LIBS ${${FFT}_LIBRARIES}) endif() set(PACK_OPTIMIZATION "PACK_ARRAY" CACHE STRING "Optimization for FFT") - set_property(CACHE LAMMPS_SIZE_LIMIT PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) + set_property(CACHE PACK_OPTIMIZATION PROPERTY STRINGS PACK_ARRAY PACK_POINTER PACK_MEMCPY) if(NOT PACK_OPTIMIZATION STREQUAL "PACK_ARRAY") add_definitions(-D${PACK_OPTIMIZATION}) endif() @@ -320,7 +320,7 @@ RegisterStyles(${LAMMPS_SOURCE_DIR}) ############################################## # add sources of enabled packages ############################################ -foreach(PKG ${PACKAGES} ${USER-PACKAGES}) +foreach(PKG ${PACKAGES} ${OTHER-PACKAGES}) if(ENABLE_${PKG}) set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) From 74deeeca5855742fd2aa8274b4203c45be12086d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 21 Jul 2017 11:50:13 -0600 Subject: [PATCH 201/293] cmake: fixed another typo --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ebf452d183..228a9e36e3 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -320,7 +320,7 @@ RegisterStyles(${LAMMPS_SOURCE_DIR}) ############################################## # add sources of enabled packages ############################################ -foreach(PKG ${PACKAGES} ${OTHER-PACKAGES}) +foreach(PKG ${PACKAGES} ${OTHER_PACKAGES}) if(ENABLE_${PKG}) set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) From b1b399d5c3dda315bb1546b1a1c4c1595a7f5db8 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 5 Jul 2017 17:48:09 -0400 Subject: [PATCH 202/293] update readme for examples --- examples/README | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/README b/examples/README index 702ada790b..0b037f5c38 100644 --- a/examples/README +++ b/examples/README @@ -58,6 +58,7 @@ These are the sample problems and their output in the various sub-directories: accelerate: use of all the various accelerator packages +airebo: example for using AIREBO and AIREBO-M balance: dynamic load balancing, 2d system body: body particles, 2d system cmap: CMAP 5-body contributions to CHARMM force field From a477f26477fa2729ea92078eccefe13d5ddb5084 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jul 2017 15:37:40 -0400 Subject: [PATCH 203/293] add support for trapping floating point exception as an optional compile time feature we may make this a run time setting by connecting this code to a command. --- src/main.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main.cpp b/src/main.cpp index cc8f8be906..7401183fea 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,10 @@ #include #include +#if defined(LAMMPS_TRAP_FPE) && defined(_GNU_SOURCE) +#include +#endif + using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- @@ -28,6 +32,18 @@ int main(int argc, char **argv) { MPI_Init(&argc,&argv); +// enable trapping selected floating point exceptions. +// this uses GNU extensions and is only tested on Linux +// therefore we make it depend on -D_GNU_SOURCE, too. + +#if defined(LAMMPS_TRAP_FPE) && defined(_GNU_SOURCE) + fesetenv(FE_NOMASK_ENV); + fedisableexcept(FE_ALL_EXCEPT); + feenableexcept(FE_DIVBYZERO); + feenableexcept(FE_INVALID); + feenableexcept(FE_OVERFLOW); +#endif + #ifdef LAMMPS_EXCEPTIONS try { LAMMPS *lammps = new LAMMPS(argc,argv,MPI_COMM_WORLD); From edc756a65f76ca56d7dd9a3bf567d7b8cf4a1871 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Fri, 21 Jul 2017 17:09:28 -0600 Subject: [PATCH 204/293] LICENSE: update address of Free Software Foundation --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index a0c2723a0c..f9489c8cf8 100644 --- a/LICENSE +++ b/LICENSE @@ -3,7 +3,7 @@ GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. From 4e0a249e2779e20e10d6bf363db80ee1b8d363be Mon Sep 17 00:00:00 2001 From: Max Veit Date: Sat, 22 Jul 2017 01:33:15 +0100 Subject: [PATCH 205/293] Add a (contrived) molecular example for USER-QUIP This example showcases the use of different 'special_bonds' settings for different pair styles, so quip gets all the bonded neighbours but lj can exclude them if it needs to. The results have been checked against a pure quip implementation of the potential; the expected lammps output is included. DISCLAIMER: This example mixes parameters for methane and silane and is NOT intended to be a realistic representation of either system. --- examples/USER/quip/in.molecular | 38 ++++++ examples/USER/quip/methane-box-8.data | 162 ++++++++++++++++++++++++++ examples/USER/quip/out.molecular | 93 +++++++++++++++ 3 files changed, 293 insertions(+) create mode 100644 examples/USER/quip/in.molecular create mode 100644 examples/USER/quip/methane-box-8.data create mode 100644 examples/USER/quip/out.molecular diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular new file mode 100644 index 0000000000..ddec997955 --- /dev/null +++ b/examples/USER/quip/in.molecular @@ -0,0 +1,38 @@ +units metal +atom_style full +boundary p p p +processors 1 1 1 +timestep 0.0001 # 0.1 fs + +read_data methane-box-8.data + +pair_style hybrid/overlay lj/cut 8.0 quip +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # for quip + +# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT +pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC +pair_coeff 1 2 lj/cut 0.0019295487 2.95 +pair_modify shift no +pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 + +# Intramolecular +# Tell QUIP to pretend this is silane (which is covered by the parameter file) +pair_coeff * * quip ip.parms.SW.xml "IP SW" 14 1 +bond_style none +angle_style none + +fix 1 all nve + +# Include diagnostics that allow us to compare to a pure QUIP run +compute equip all pair quip +compute evdw all pair lj/cut +compute vir all pressure NULL virial + +thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip +thermo 1 + +dump 1 all custom 1 dump.molecular id type x y z fx fy fz +dump_modify 1 sort id + +run 10 diff --git a/examples/USER/quip/methane-box-8.data b/examples/USER/quip/methane-box-8.data new file mode 100644 index 0000000000..2a55fcf551 --- /dev/null +++ b/examples/USER/quip/methane-box-8.data @@ -0,0 +1,162 @@ +LAMMPS data file. CGCMM style. atom_style full generated by VMD/TopoTools v1.1 on Sat Oct 22 17:48:43 BST 2016. Original generated with Packmol + 40 atoms + 32 bonds + 48 angles + 0 dihedrals + 0 impropers + 2 atom types + 1 bond types + 1 angle types + 0 dihedral types + 0 improper types + -0.499095 8.410905 xlo xhi + -0.270629 8.639371 ylo yhi + 0.131683 9.041683 zlo zhi + +# Pair Coeffs +# +# 1 CT +# 2 HC + +# Bond Coeffs +# +# 1 CT-HC + +# Angle Coeffs +# +# 1 HC-CT-HC + + Masses + + 1 12.011000 # CT + 2 1.008000 # HC + + Atoms + +1 1 1 -0.240000 3.937038 0.677603 7.362249 # CT +2 1 2 0.060000 4.193022 1.709034 7.595834 # HC +3 1 2 0.060000 2.905136 0.486052 7.649386 # HC +4 1 2 0.060000 4.596317 0.007308 7.909996 # HC +5 1 2 0.060000 4.053670 0.507989 6.293814 # HC +6 2 1 -0.240000 6.131801 2.711096 0.901469 # CT +7 2 2 0.060000 6.787439 1.886720 0.628555 # HC +8 2 2 0.060000 5.728610 3.167652 -0.000171 # HC +9 2 2 0.060000 6.696346 3.453106 1.462433 # HC +10 2 2 0.060000 5.314820 2.336948 1.515051 # HC +11 3 1 -0.240000 5.723143 6.225007 1.430856 # CT +12 3 2 0.060000 5.585279 6.712817 2.393651 # HC +13 3 2 0.060000 5.584847 6.951755 0.632938 # HC +14 3 2 0.060000 4.994507 5.424203 1.322354 # HC +15 3 2 0.060000 6.727906 5.811248 1.374455 # HC +16 4 1 -0.240000 5.573754 5.038579 4.999124 # CT +17 4 2 0.060000 4.512787 5.184293 5.191620 # HC +18 4 2 0.060000 6.006150 5.966299 4.629893 # HC +19 4 2 0.060000 5.703088 4.256326 4.253924 # HC +20 4 2 0.060000 6.073008 4.747398 5.921016 # HC +21 5 1 -0.240000 2.108870 2.623461 3.348534 # CT +22 5 2 0.060000 2.886488 2.470897 2.602897 # HC +23 5 2 0.060000 1.382727 3.341833 2.973541 # HC +24 5 2 0.060000 2.554989 3.003606 4.265288 # HC +25 5 2 0.060000 1.611274 1.677549 3.552431 # HC +26 6 1 -0.240000 6.106165 2.015183 5.526875 # CT +27 6 2 0.060000 6.075817 2.038391 4.439456 # HC +28 6 2 0.060000 6.076127 0.982573 5.868599 # HC +29 6 2 0.060000 5.248943 2.554122 5.925227 # HC +30 6 2 0.060000 7.023739 2.485633 5.874240 # HC +31 7 1 -0.240000 0.644265 2.699668 7.212713 # CT +32 7 2 0.060000 0.403413 2.521819 6.166625 # HC +33 7 2 0.060000 0.098429 1.993976 7.835627 # HC +34 7 2 0.060000 0.361861 3.715309 7.482326 # HC +35 7 2 0.060000 1.713326 2.567585 7.366300 # HC +36 8 1 -0.240000 0.588072 6.428183 7.473536 # CT +37 8 2 0.060000 0.540903 6.363141 6.388417 # HC +38 8 2 0.060000 -0.008121 5.629967 7.910991 # HC +39 8 2 0.060000 0.197701 7.391140 7.796481 # HC +40 8 2 0.060000 1.621770 6.328495 7.798280 # HC + + Bonds + +1 1 1 3 +2 1 1 5 +3 1 1 2 +4 1 1 4 +5 1 6 7 +6 1 6 9 +7 1 6 8 +8 1 6 10 +9 1 11 14 +10 1 11 13 +11 1 11 12 +12 1 11 15 +13 1 16 17 +14 1 16 18 +15 1 16 19 +16 1 16 20 +17 1 21 22 +18 1 21 24 +19 1 21 25 +20 1 21 23 +21 1 26 27 +22 1 26 28 +23 1 26 29 +24 1 26 30 +25 1 31 33 +26 1 31 32 +27 1 31 34 +28 1 31 35 +29 1 36 38 +30 1 36 37 +31 1 36 39 +32 1 36 40 + + Angles + +1 1 3 1 5 +2 1 2 1 3 +3 1 3 1 4 +4 1 2 1 5 +5 1 4 1 5 +6 1 2 1 4 +7 1 7 6 9 +8 1 7 6 8 +9 1 7 6 10 +10 1 8 6 9 +11 1 9 6 10 +12 1 8 6 10 +13 1 13 11 14 +14 1 12 11 14 +15 1 14 11 15 +16 1 12 11 13 +17 1 13 11 15 +18 1 12 11 15 +19 1 17 16 18 +20 1 17 16 19 +21 1 17 16 20 +22 1 18 16 19 +23 1 18 16 20 +24 1 19 16 20 +25 1 22 21 24 +26 1 22 21 25 +27 1 22 21 23 +28 1 24 21 25 +29 1 23 21 24 +30 1 23 21 25 +31 1 27 26 28 +32 1 27 26 29 +33 1 27 26 30 +34 1 28 26 29 +35 1 28 26 30 +36 1 29 26 30 +37 1 32 31 33 +38 1 33 31 34 +39 1 33 31 35 +40 1 32 31 34 +41 1 32 31 35 +42 1 34 31 35 +43 1 37 36 38 +44 1 38 36 39 +45 1 38 36 40 +46 1 37 36 39 +47 1 37 36 40 +48 1 39 36 40 + diff --git a/examples/USER/quip/out.molecular b/examples/USER/quip/out.molecular new file mode 100644 index 0000000000..0e8d07d389 --- /dev/null +++ b/examples/USER/quip/out.molecular @@ -0,0 +1,93 @@ +LAMMPS (6 Jul 2017) +Reading data file ... + orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 40 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + reading bonds ... + 32 bonds + reading angles ... + 48 angles +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 0 0 0 + special bond factors coul: 0 0 0 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors +Finding 1-2 1-3 1-4 neighbors ... + special bond factors lj: 1 1 1 + special bond factors coul: 1 1 1 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 2 2 2 + 2 neighbor lists, perpetual/occasional/extra = 2 0 0 + (1) pair lj/cut, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) pair quip, perpetual + attributes: full, newton on + pair build: full/bin + stencil: full/bin/3d + bin: standard +Setting up Verlet run ... + Unit style : metal + Current step : 0 + Time step : 0.0001 +Per MPI rank memory allocation (min/avg/max) = 9.543 | 9.543 | 9.543 Mbytes +Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip + 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805 + 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093 + 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932 + 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264 + 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557 + 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546 + 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782 + 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787 + 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801 + 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653 + 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266 +Loop time of 0.131692 on 1 procs for 10 steps with 40 atoms + +Performance: 0.656 ns/day, 36.581 hours/ns, 75.935 timesteps/s +97.2% CPU use with 1 MPI tasks x no OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.12961 | 0.12961 | 0.12961 | 0.0 | 98.42 +Bond | 7.391e-06 | 7.391e-06 | 7.391e-06 | 0.0 | 0.01 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.00013185 | 0.00013185 | 0.00013185 | 0.0 | 0.10 +Output | 0.0018771 | 0.0018771 | 0.0018771 | 0.0 | 1.43 +Modify | 2.5988e-05 | 2.5988e-05 | 2.5988e-05 | 0.0 | 0.02 +Other | | 4.268e-05 | | | 0.03 + +Nlocal: 40 ave 40 max 40 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1175 ave 1175 max 1175 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 4768 ave 4768 max 4768 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 9536 ave 9536 max 9536 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 9536 +Ave neighs/atom = 238.4 +Ave special neighs/atom = 4 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 From 1af937e99d7124057b31decfb0142d7c195ac249 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 21 Jul 2017 22:00:29 -0400 Subject: [PATCH 206/293] Update in.molecular - expand comments to provide more details on the choice of exclusion settings - comment out dump file generation --- examples/USER/quip/in.molecular | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular index ddec997955..5af5647518 100644 --- a/examples/USER/quip/in.molecular +++ b/examples/USER/quip/in.molecular @@ -7,13 +7,17 @@ timestep 0.0001 # 0.1 fs read_data methane-box-8.data pair_style hybrid/overlay lj/cut 8.0 quip -special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # for quip + +# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, +# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 pair_modify shift no +# change exclusion settings for lj/cut only: exclude bonded pairs pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 # Intramolecular @@ -32,7 +36,7 @@ compute vir all pressure NULL virial thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip thermo 1 -dump 1 all custom 1 dump.molecular id type x y z fx fy fz -dump_modify 1 sort id +# dump 1 all custom 1 dump.molecular id type x y z fx fy fz +# dump_modify 1 sort id run 10 From 1afab981b0226e53f8959861eb4a03b913882231 Mon Sep 17 00:00:00 2001 From: Max Veit Date: Sat, 22 Jul 2017 14:40:33 +0100 Subject: [PATCH 207/293] Clarified some points in in.molecular example --- examples/USER/quip/in.molecular | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular index 5af5647518..24d21d6762 100644 --- a/examples/USER/quip/in.molecular +++ b/examples/USER/quip/in.molecular @@ -6,6 +6,11 @@ timestep 0.0001 # 0.1 fs read_data methane-box-8.data +# DISCLAIMER: This potential mixes parameters from methane and silane +# potentials and is NOT intended to be a realistic representation of either +# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, +# including the use of separate 'special_bonds' settings. + pair_style hybrid/overlay lj/cut 8.0 quip # exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, @@ -13,6 +18,7 @@ pair_style hybrid/overlay lj/cut 8.0 quip special_bonds lj/coul 0.999999999 0.999999999 0.999999999 # Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +# Coulomb interactions ommitted for simplicity pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC pair_coeff 1 2 lj/cut 0.0019295487 2.95 From 7b2182833fea75567add4342e3b7f2ab7a9a5095 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jul 2017 10:35:16 -0400 Subject: [PATCH 208/293] disallow binary output with dump style local. fixes #596 --- src/dump_local.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/dump_local.cpp b/src/dump_local.cpp index 4843352ea2..a3e62907a6 100644 --- a/src/dump_local.cpp +++ b/src/dump_local.cpp @@ -49,6 +49,9 @@ DumpLocal::DumpLocal(LAMMPS *lmp, int narg, char **arg) : nevery = force->inumeric(FLERR,arg[3]); if (nevery <= 0) error->all(FLERR,"Illegal dump local command"); + if (binary) + error->all(FLERR,"Binary files are not supported with dump local"); + nfield = narg - 5; // expand args if any have wildcard character "*" From 126d9cd3bc71cd354556999319e48a381d08d980 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sat, 22 Jul 2017 13:57:15 -0600 Subject: [PATCH 209/293] add GZIP and FFMPEG status --- cmake/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 228a9e36e3..959aea869a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -196,13 +196,15 @@ if(PNG_FOUND AND ZLIB_FOUND) add_definitions(-DLAMMPS_PNG) endif() -find_program(GZIP gzip) -if(GZIP) +find_program(GZIP_EXECUTABLE gzip) +find_package_handle_standard_args(GZIP REQUIRED_VARS GZIP_EXECUTABLE) +if(GZIP_FOUND) add_definitions(-DLAMMPS_GZIP) endif() -find_program(FFMPEG ffmpeg) -if(FFMPEG) +find_program(FFMPEG_EXECUTABLE ffmpeg) +find_package_handle_standard_args(FFMPEG REQUIRED_VARS FFMPEG_EXECUTABLE) +if(FFMPEG_FOUND) add_definitions(-DLAMMPS_FFMPEG) endif() From 2c6e177d5c55e640deef3bdf451b46380fdf0049 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jul 2017 23:14:17 -0400 Subject: [PATCH 210/293] avoid reporting negative memory allocation when memory_usage() is called before initialized --- src/USER-TALLY/compute_force_tally.cpp | 2 +- src/USER-TALLY/compute_heat_flux_tally.cpp | 2 +- src/USER-TALLY/compute_pe_tally.cpp | 2 +- src/USER-TALLY/compute_stress_tally.cpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/USER-TALLY/compute_force_tally.cpp b/src/USER-TALLY/compute_force_tally.cpp index cb7e3a4f23..5f29aea5b2 100644 --- a/src/USER-TALLY/compute_force_tally.cpp +++ b/src/USER-TALLY/compute_force_tally.cpp @@ -215,7 +215,7 @@ void ComputeForceTally::compute_peratom() double ComputeForceTally::memory_usage() { - double bytes = nmax*size_peratom_cols * sizeof(double); + double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double); return bytes; } diff --git a/src/USER-TALLY/compute_heat_flux_tally.cpp b/src/USER-TALLY/compute_heat_flux_tally.cpp index b366b92be3..c090050b15 100644 --- a/src/USER-TALLY/compute_heat_flux_tally.cpp +++ b/src/USER-TALLY/compute_heat_flux_tally.cpp @@ -275,7 +275,7 @@ void ComputeHeatFluxTally::compute_vector() double ComputeHeatFluxTally::memory_usage() { - double bytes = nmax*comm_reverse * sizeof(double); + double bytes = (nmax < 0) ? 0 : nmax*comm_reverse * sizeof(double); return bytes; } diff --git a/src/USER-TALLY/compute_pe_tally.cpp b/src/USER-TALLY/compute_pe_tally.cpp index e7c0bdd03c..5b4644d4e1 100644 --- a/src/USER-TALLY/compute_pe_tally.cpp +++ b/src/USER-TALLY/compute_pe_tally.cpp @@ -199,7 +199,7 @@ void ComputePETally::compute_peratom() double ComputePETally::memory_usage() { - double bytes = nmax*size_peratom_cols * sizeof(double); + double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double); return bytes; } diff --git a/src/USER-TALLY/compute_stress_tally.cpp b/src/USER-TALLY/compute_stress_tally.cpp index 28baafb9f8..32253d2cad 100644 --- a/src/USER-TALLY/compute_stress_tally.cpp +++ b/src/USER-TALLY/compute_stress_tally.cpp @@ -242,7 +242,7 @@ void ComputeStressTally::compute_peratom() double ComputeStressTally::memory_usage() { - double bytes = nmax*size_peratom_cols * sizeof(double); + double bytes = (nmax < 0) ? 0 : nmax*size_peratom_cols * sizeof(double); return bytes; } From c24e316baaa68e684d0bdd12c97f94301406bcd5 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 22 Jul 2017 23:15:01 -0400 Subject: [PATCH 211/293] avoid floating point overflows in iterative solvers of fix shake --- src/RIGID/fix_shake.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/RIGID/fix_shake.cpp b/src/RIGID/fix_shake.cpp index 36f56aa295..f08228f3d3 100644 --- a/src/RIGID/fix_shake.cpp +++ b/src/RIGID/fix_shake.cpp @@ -1617,6 +1617,12 @@ void FixShake::shake3(int m) lamda01 = lamda01_new; lamda02 = lamda02_new; + + // stop iterations before we have a floating point overflow + // max double is < 1.0e308, so 1e150 is a reasonable cutoff + + if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150) done = 1; + niter++; } @@ -1854,6 +1860,13 @@ void FixShake::shake4(int m) lamda01 = lamda01_new; lamda02 = lamda02_new; lamda03 = lamda03_new; + + // stop iterations before we have a floating point overflow + // max double is < 1.0e308, so 1e150 is a reasonable cutoff + + if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150 + || fabs(lamda03) > 1e150) done = 1; + niter++; } @@ -2097,6 +2110,13 @@ void FixShake::shake3angle(int m) lamda01 = lamda01_new; lamda02 = lamda02_new; lamda12 = lamda12_new; + + // stop iterations before we have a floating point overflow + // max double is < 1.0e308, so 1e150 is a reasonable cutoff + + if (fabs(lamda01) > 1e150 || fabs(lamda02) > 1e150 + || fabs(lamda12) > 1e150) done = 1; + niter++; } From a71f5a0c20f7e23c3d5cfe2e73eff38aa4dcb5c3 Mon Sep 17 00:00:00 2001 From: Trung Nguyen Date: Sat, 22 Jul 2017 22:57:37 -0500 Subject: [PATCH 212/293] Enabled again neigh no with tpa > 1 for 3-body gpu styles for backward compatibility, could be slower than neigh no tpa 1 in many cases --- lib/gpu/lal_base_three.cpp | 1 - lib/gpu/lal_sw.cu | 92 ++++++++++++++++---------- lib/gpu/lal_tersoff.cu | 131 ++++++++++++++++++++++--------------- lib/gpu/lal_tersoff_mod.cu | 130 ++++++++++++++++++++++-------------- lib/gpu/lal_tersoff_zbl.cu | 130 ++++++++++++++++++++++-------------- lib/gpu/lal_vashishta.cu | 82 ++++++++++++++--------- 6 files changed, 349 insertions(+), 217 deletions(-) diff --git a/lib/gpu/lal_base_three.cpp b/lib/gpu/lal_base_three.cpp index 5f3c57337e..aa77a48c66 100644 --- a/lib/gpu/lal_base_three.cpp +++ b/lib/gpu/lal_base_three.cpp @@ -73,7 +73,6 @@ int BaseThreeT::init_three(const int nlocal, const int nall, if (_threads_per_atom>1 && gpu_nbor==0) { // neigh no and tpa > 1 nbor->packing(true); _nbor_data=&(nbor->dev_packed); - _threads_per_atom = 1; // enforce tpa = 1 for now } else // neigh yes or tpa == 1 _nbor_data=&(nbor->dev_nbor); if (_threads_per_atom*_threads_per_atom>device->warp_size()) diff --git a/lib/gpu/lal_sw.cu b/lib/gpu/lal_sw.cu index 7dea52898e..a5c9f49d08 100644 --- a/lib/gpu/lal_sw.cu +++ b/lib/gpu/lal_sw.cu @@ -167,7 +167,6 @@ __kernel void k_sw_short_nbor(const __global numtyp4 *restrict x_, numtyp4 jx; fetch4(jx,j,pos_tex); //x_[j]; int jtype=jx.w; jtype=map[jtype]; - int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; // Compute r12 @@ -217,8 +216,8 @@ __kernel void k_sw(const __global numtyp4 *restrict x_, __syncthreads(); if (ii0) energy += (param3_bigh*reta+vc2-vc3-param3_bigw*r6inv-r*param3_dvrc+param3_c0); @@ -435,7 +436,7 @@ __kernel void k_vashishta_three_center(const __global numtyp4 *restrict x_, if (ii Date: Sun, 23 Jul 2017 00:08:55 -0500 Subject: [PATCH 213/293] Cleaned up 3-body kernels, reverted some mistaken changes to vashishta --- lib/gpu/lal_tersoff.cu | 5 ----- lib/gpu/lal_tersoff_mod.cu | 7 ------- lib/gpu/lal_tersoff_zbl.cu | 7 ------- lib/gpu/lal_vashishta.cu | 10 +++------- 4 files changed, 3 insertions(+), 26 deletions(-) diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu index 65c0fa49fc..cdeb5679d8 100644 --- a/lib/gpu/lal_tersoff.cu +++ b/lib/gpu/lal_tersoff.cu @@ -581,7 +581,6 @@ __kernel void k_tersoff_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -770,8 +769,6 @@ __kernel void k_tersoff_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; @@ -1017,8 +1014,6 @@ __kernel void k_tersoff_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu index 3297bc74fb..576359b514 100644 --- a/lib/gpu/lal_tersoff_mod.cu +++ b/lib/gpu/lal_tersoff_mod.cu @@ -308,8 +308,6 @@ __kernel void k_tersoff_mod_zeta(const __global numtyp4 *restrict x_, delr1.z = jx.z-ix.z; numtyp rsq1 = delr1.x*delr1.x+delr1.y*delr1.y+delr1.z*delr1.z; -// if (rsq1 > cutsq[ijparam]) continue; - // compute zeta_ij z = (acctyp)0; @@ -585,7 +583,6 @@ __kernel void k_tersoff_mod_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -780,8 +777,6 @@ __kernel void k_tersoff_mod_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; @@ -1036,8 +1031,6 @@ __kernel void k_tersoff_mod_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu index 8fd5489543..e8bb017f59 100644 --- a/lib/gpu/lal_tersoff_zbl.cu +++ b/lib/gpu/lal_tersoff_zbl.cu @@ -314,8 +314,6 @@ __kernel void k_tersoff_zbl_zeta(const __global numtyp4 *restrict x_, delr1.z = jx.z-ix.z; numtyp rsq1 = delr1.x*delr1.x+delr1.y*delr1.y+delr1.z*delr1.z; -// if (rsq1 > cutsq[ijparam]) continue; - // compute zeta_ij z = (acctyp)0; @@ -601,7 +599,6 @@ __kernel void k_tersoff_zbl_three_center(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; numtyp r1 = ucl_sqrt(rsq1); numtyp r1inv = ucl_rsqrt(rsq1); @@ -790,8 +787,6 @@ __kernel void k_tersoff_zbl_three_end(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; @@ -1037,8 +1032,6 @@ __kernel void k_tersoff_zbl_three_end_vatom(const __global numtyp4 *restrict x_, delr1[2] = jx.z-ix.z; numtyp rsq1 = delr1[0]*delr1[0] + delr1[1]*delr1[1] + delr1[2]*delr1[2]; -// if (rsq1 > cutsq[ijparam]) continue; - numtyp mdelr1[3]; mdelr1[0] = -delr1[0]; mdelr1[1] = -delr1[1]; diff --git a/lib/gpu/lal_vashishta.cu b/lib/gpu/lal_vashishta.cu index 26805588eb..fa7f413aa5 100644 --- a/lib/gpu/lal_vashishta.cu +++ b/lib/gpu/lal_vashishta.cu @@ -474,9 +474,7 @@ __kernel void k_vashishta_three_center(const __global numtyp4 *restrict x_, numtyp4 param4_ijparam; fetch4(param4_ijparam,ijparam,param4_tex); param_r0sq_ij=param4_ijparam.x; - -// if (rsq1 > param_r0sq_ij) continue; - + if (rsq1 > param_r0sq_ij) continue; // still keep this for neigh no and tpa > 1 param_gamma_ij=param4_ijparam.y; param_r0_ij=param4_ijparam.w; @@ -617,8 +615,7 @@ __kernel void k_vashishta_three_end(const __global numtyp4 *restrict x_, int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; numtyp4 param4_ijparam; fetch4(param4_ijparam,ijparam,param4_tex); param_r0sq_ij = param4_ijparam.x; - -// if (rsq1 > param_r0sq_ij) continue; + if (rsq1 > param_r0sq_ij) continue; // still keep this for neigh no and tpa > 1 param_gamma_ij=param4_ijparam.y; param_r0_ij = param4_ijparam.w; @@ -773,8 +770,7 @@ __kernel void k_vashishta_three_end_vatom(const __global numtyp4 *restrict x_, int ijparam=elem2param[itype*nelements*nelements+jtype*nelements+jtype]; numtyp4 param4_ijparam; fetch4(param4_ijparam,ijparam,param4_tex); param_r0sq_ij=param4_ijparam.x; - -// if (rsq1 > param_r0sq_ij) continue; + if (rsq1 > param_r0sq_ij) continue; // still keep this for neigh no and tpa > 1 param_gamma_ij=param4_ijparam.y; param_r0_ij=param4_ijparam.w; From a59b7e4d56473bd202957c1c673795871e0fa290 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 24 Jul 2017 09:09:22 -0600 Subject: [PATCH 214/293] patch 24Jul17 --- doc/src/Manual.txt | 4 ++-- src/version.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/src/Manual.txt b/doc/src/Manual.txt index 359aa19edb..07f0c8df41 100644 --- a/doc/src/Manual.txt +++ b/doc/src/Manual.txt @@ -1,7 +1,7 @@ LAMMPS Users Manual - + @@ -21,7 +21,7 @@

LAMMPS Documentation :c,h3 -6 Jul 2017 version :c,h4 +24 Jul 2017 version :c,h4 Version info: :h4 diff --git a/src/version.h b/src/version.h index 3fbe238325..c55566c88a 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "6 Jul 2017" +#define LAMMPS_VERSION "24 Jul 2017" From f2023431f69bd0449ef0bc622697d9bdca2b9b73 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 24 Jul 2017 12:54:26 -0600 Subject: [PATCH 215/293] cmake: fixed another typo --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 959aea869a..059a8733a3 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -322,7 +322,7 @@ RegisterStyles(${LAMMPS_SOURCE_DIR}) ############################################## # add sources of enabled packages ############################################ -foreach(PKG ${PACKAGES} ${OTHER_PACKAGES}) +foreach(PKG ${DEFAULT_PACKAGES} ${OTHER_PACKAGES}) if(ENABLE_${PKG}) set(${PKG}_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/${PKG}) From 6716de5320733f033ebbaba6fc6f2b28cf770c3a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 24 Jul 2017 20:17:17 -0600 Subject: [PATCH 216/293] allow user to override PYTHON_INSTDIR --- cmake/CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 059a8733a3..15a87b7f6e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -172,9 +172,11 @@ if(ENABLE_PYTHON) add_definitions(-DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) - execute_process(COMMAND ${PYTHON_EXECUTABLE} + if(NOT PYTHON_INSTDIR) + execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig as cg; print(cg.get_python_lib(1,0,prefix='${CMAKE_INSTALL_PREFIX}'))" - OUTPUT_VARIABLE PYTHON_INSTDIR OUTPUT_STRIP_TRAILING_WHITESPACE) + OUTPUT_VARIABLE PYTHON_INSTDIR OUTPUT_STRIP_TRAILING_WHITESPACE) + endif() install(FILES ${CMAKE_SOURCE_DIR}/../python/lammps.py DESTINATION ${PYTHON_INSTDIR}) if(NOT BUILD_SHARED_LIBS) message(FATAL_ERROR "Python package need lammps to be build shared, -DBUILD_SHARED_LIBS=ON") From 0231cc38a35e1d38a800305cd32cef12bae113b1 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 25 Jul 2017 19:09:20 -0600 Subject: [PATCH 217/293] cmake: some more typo fixes --- cmake/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 15a87b7f6e..d691386c05 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -18,10 +18,10 @@ list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) # Cmake modules/macros are in a subdirectory to keep this file cleaner set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/Modules) -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS) #release comes with -O3 by default set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel." FORCE) -endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_C_FLAGS) +endif(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CXX_FLAGS) foreach(STYLE_FILE style_angle.h style_atom.h style_body.h style_bond.h style_command.h style_compute.h style_dihedral.h style_dump.h style_fix.h style_improper.h style_integrate.h style_kspace.h style_minimize.h style_nbin.h style_npair.h style_nstencil.h @@ -498,7 +498,7 @@ if(ENABLE_GPU) endforeach() list(REMOVE_ITEM GPU_OBJS "${CU_FORBIDDEN_OBJ}") list(APPEND LIB_SOURCES ${GPU_SOURCES} ${GPU_LIB_SOURCES} ${GPU_LIB_CUDPP_SOURCES} ${GPU_OBJS}) - set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${AMMPS_LIB_BINARY_DIR}/gpu/*_cubin.h") + set_directory_properties(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${LAMMPS_LIB_BINARY_DIR}/gpu/*_cubin.h") endif() ###################################################### @@ -529,7 +529,7 @@ add_executable(lmp ${LMP_SOURCES}) target_link_libraries(lmp lammps) install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) if(ENABLE_TESTING) - add_test(ShowHelp lmp -help) + add_test(ShowHelp ${CMAKE_CURRENT_BINARY_DIR}/lmp -help) endif() ################################## From 60c67b07dc3785f3db79a417c1680796589abc0f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 10:45:11 -0400 Subject: [PATCH 218/293] import updated fix msst file with some additional cleanup and simplification --- src/SHOCK/fix_msst.cpp | 91 +++++++++++++++++++++++------------------- 1 file changed, 51 insertions(+), 40 deletions(-) diff --git a/src/SHOCK/fix_msst.cpp b/src/SHOCK/fix_msst.cpp index b66f0ed4d3..66a648cd17 100644 --- a/src/SHOCK/fix_msst.cpp +++ b/src/SHOCK/fix_msst.cpp @@ -446,7 +446,7 @@ void FixMSST::initial_integrate(int vflag) { int i,k; double p_msst; // MSST driving pressure - double vol,TS,TS_term,escale_term; + double vol; int nlocal = atom->nlocal; int *mask = atom->mask; @@ -469,12 +469,16 @@ void FixMSST::initial_integrate(int vflag) // must convert energy to mv^2 units if (dftb) { - double TS_dftb = fix_external->compute_vector(0); - TS = force->ftm2v*TS_dftb; + const double TS_dftb = fix_external->compute_vector(0); + const double TS = force->ftm2v*TS_dftb; + // update S_elec terms and compute TS_dot via finite differences + S_elec_2 = S_elec_1; + S_elec_1 = S_elec; + const double Temp = temperature->compute_scalar(); + S_elec = TS/Temp; + TS_dot = Temp*(3.0*S_elec-4.0*S_elec_1+S_elec_2)/(2.0*update->dt); + TS_int += (update->dt*TS_dot); if (update->ntimestep == 1) T0S0 = TS; - } else { - TS = 0.0; - T0S0 = 0.0; } // compute new pressure and volume @@ -484,16 +488,6 @@ void FixMSST::initial_integrate(int vflag) couple(); vol = compute_vol(); - // update S_elec terms and compute TS_dot via finite differences - - S_elec_2 = S_elec_1; - S_elec_1 = S_elec; - double Temp = temperature->compute_scalar(); - S_elec = TS/Temp; - TS_dot = Temp*(3.0*S_elec-4.0*S_elec_1+S_elec_2)/(2.0*update->dt); - TS_int += (update->dt*TS_dot); - //TS_int += (update->dt*TS_dot)/total_mass; - // compute etot + extra terms for conserved quantity double e_scale = compute_etotal() + compute_scalar(); @@ -530,9 +524,9 @@ void FixMSST::initial_integrate(int vflag) for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; - TS_term = TS_dot/(mass[type[i]]*velocity_sum); - escale_term = force->ftm2v*beta*(e0-e_scale) / + const double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); + const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); @@ -540,7 +534,7 @@ void FixMSST::initial_integrate(int vflag) old_velocity[i][k] = v[i][k]; if ( k == direction ) D -= 2.0 * omega[sd] / vol; if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -553,15 +547,15 @@ void FixMSST::initial_integrate(int vflag) for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); old_velocity[i][k] = v[i][k]; if ( k == direction ) { - D = D - 2.0 * omega[sd] / vol; + D -= 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -590,16 +584,16 @@ void FixMSST::initial_integrate(int vflag) for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; - TS_term = TS_dot/(mass[type[i]]*velocity_sum); - escale_term = force->ftm2v*beta*(e0-e_scale) / + const double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); + const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); D += escale_term - TS_term; if ( k == direction ) D -= 2.0 * omega[sd] / vol; if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -612,14 +606,14 @@ void FixMSST::initial_integrate(int vflag) for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if ( k == direction ) { - D = D - 2.0 * omega[sd] / vol; + D -= 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -669,7 +663,6 @@ void FixMSST::final_integrate() { int i; double p_msst; // MSST driving pressure - double TS_term,escale_term; // v update only for atoms in MSST group @@ -687,22 +680,38 @@ void FixMSST::final_integrate() double e_scale = compute_etotal() + compute_scalar(); + // for DFTB, extract TS_dftb from fix external + // must convert energy to mv^2 units + + if (dftb) { + const double TS_dftb = fix_external->compute_vector(0); + const double TS = force->ftm2v*TS_dftb; + S_elec_2 = S_elec_1; + S_elec_1 = S_elec; + const double Temp = temperature->compute_scalar(); + // update S_elec terms and compute TS_dot via finite differences + S_elec = TS/Temp; + TS_dot = Temp*(3.0*S_elec-4.0*S_elec_1+S_elec_2)/(2.0*update->dt); + TS_int += (update->dt*TS_dot); + if (update->ntimestep == 1) T0S0 = TS; + } + // propagate particle velocities 1/2 step if (dftb) { for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( int k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; - TS_term = TS_dot/(mass[type[i]]*velocity_sum); - escale_term = force->ftm2v*beta*(e0-e_scale) / + const double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double TS_term = TS_dot/(mass[type[i]]*velocity_sum); + const double escale_term = force->ftm2v*beta*(e0-e_scale) / (mass[type[i]]*velocity_sum); double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); D += escale_term - TS_term; if ( k == direction ) D -= 2.0 * omega[sd] / vol; if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -715,14 +724,14 @@ void FixMSST::final_integrate() for (i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { for ( int k = 0; k < 3; k++ ) { - double C = f[i][k] * force->ftm2v / mass[type[i]]; + const double C = f[i][k] * force->ftm2v / mass[type[i]]; double D = mu * omega[sd] * omega[sd] / (velocity_sum * mass[type[i]] * vol ); if ( k == direction ) { - D = D - 2.0 * omega[sd] / vol; + D -= 2.0 * omega[sd] / vol; } if ( fabs(dthalf * D) > 1.0e-06 ) { - double expd = exp(D * dthalf); + const double expd = exp(D * dthalf); v[i][k] = expd * ( C + D * v[i][k] - C / expd ) / D; } else { v[i][k] = v[i][k] + ( C + D * v[i][k] ) * dthalf + @@ -748,7 +757,7 @@ void FixMSST::final_integrate() ( v0 - vol )/( v0 * v0 ); double A = total_mass * ( p_current[sd] - p0 - p_msst ) / ( qmass * nktv2p * mvv2e ); - double B = total_mass * mu / ( qmass * vol ); + const double B = total_mass * mu / ( qmass * vol ); // prevent blow-up of the volume @@ -950,7 +959,9 @@ double FixMSST::compute_scalar() // subtract off precomputed TS_int integral value - energy -= TS_int; + if (dftb) { // TS_int == 0 for non DFTB calculations + energy -= TS_int; + } return energy; } From aa5ea95a0f34db29976151aad7fffc17c5257da1 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 11:55:50 -0400 Subject: [PATCH 219/293] avoid integer overflow and remove unused function argument causing it --- src/balance.cpp | 7 +++---- src/balance.h | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/balance.cpp b/src/balance.cpp index 47e7c0969b..c184a72d32 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -936,7 +936,7 @@ int Balance::shift() // stop at this point in bstr if imbalance factor < threshold // this is a true 3d test of particle count per processor - double imbfactor = imbalance_splits(max); + double imbfactor = imbalance_splits(); if (imbfactor <= stopthresh) break; } @@ -1047,11 +1047,10 @@ int Balance::adjust(int n, double *split) calculate imbalance based on processor splits in 3 dims atoms must be in lamda coords (0-1) before called map particles to 3d grid of procs - return maxcost = max load per proc return imbalance factor = max load per proc / ave load per proc ------------------------------------------------------------------------- */ -double Balance::imbalance_splits(int &maxcost) +double Balance::imbalance_splits() { double *xsplit = comm->xsplit; double *ysplit = comm->ysplit; @@ -1088,7 +1087,7 @@ double Balance::imbalance_splits(int &maxcost) MPI_Allreduce(proccost,allproccost,nprocs,MPI_DOUBLE,MPI_SUM,world); - maxcost = 0.0; + double maxcost = 0.0; double totalcost = 0.0; for (int i = 0; i < nprocs; i++) { maxcost = MAX(maxcost,allproccost[i]); diff --git a/src/balance.h b/src/balance.h index 0f2f79bb15..43e8851ad9 100644 --- a/src/balance.h +++ b/src/balance.h @@ -81,7 +81,7 @@ class Balance : protected Pointers { FILE *fp; // balance output file int firststep; - double imbalance_splits(int &); + double imbalance_splits(); void shift_setup_static(char *); void tally(int, int, double *); int adjust(int, double *); From 51a06334ad84203d321e239e962171f392b461a6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 12:08:42 -0400 Subject: [PATCH 220/293] avoid invalid calls to memcpy(): when ndot == 0, pointers may be NULL --- src/rcb.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/rcb.cpp b/src/rcb.cpp index 919df98a19..7ad1e84d4c 100644 --- a/src/rcb.cpp +++ b/src/rcb.cpp @@ -288,7 +288,7 @@ void RCB::compute(int dimension, int n, double **x, double *wt, // use old value on 1st iteration if old cut dimension is the same // on 2nd option: could push valuehalf towards geometric center // with "1.0-factor" to force overshoot - + if (first_iteration && reuse && dim == tree[procmid].dim) { counters[5]++; valuehalf = tree[procmid].cut; @@ -310,7 +310,7 @@ void RCB::compute(int dimension, int n, double **x, double *wt, medme.wtlo = medme.wthi = 0.0; medme.countlo = medme.counthi = 0; medme.proclo = medme.prochi = me; - + // mark all active dots on one side or other of bisector // also set all fields in median data struct // save indices of closest dots on either side @@ -391,11 +391,11 @@ void RCB::compute(int dimension, int n, double **x, double *wt, wtlo += med.wthi; if (targetlo-wtlo <= tolerance) break; // close enough - + valuemin = med.valuehi; // iterate again markactive = 1; } - + else if (wthi + med.totalhi < targethi) { // upper half TOO SMALL wthi += med.totalhi; @@ -431,7 +431,7 @@ void RCB::compute(int dimension, int n, double **x, double *wt, } if (breakflag) break; // done if moved enough } - + wthi += med.wtlo; if (targethi-wthi <= tolerance) break; // close enough @@ -455,13 +455,13 @@ void RCB::compute(int dimension, int n, double **x, double *wt, // cut produces 2 sub-boxes with reduced size in dim // compare smaller of the 2 sizes to previous dims // keep dim that has the largest smaller - + smaller = MIN(valuehalf-lo[dim],hi[dim]-valuehalf); if (smaller > largest) { largest = smaller; dim_select = dim; valuehalf_select = valuehalf; - memcpy(dotmark_select,dotmark,ndot*sizeof(int)); + if (ndot > 0) memcpy(dotmark_select,dotmark,ndot*sizeof(int)); } } @@ -469,11 +469,11 @@ void RCB::compute(int dimension, int n, double **x, double *wt, dim = dim_select; valuehalf = valuehalf_select; - memcpy(dotmark,dotmark_select,ndot*sizeof(int)); + if (ndot > 0) memcpy(dotmark,dotmark_select,ndot*sizeof(int)); // found median // store cut info only if I am procmid - + if (me == procmid) { cut = valuehalf; cutdim = dim; From f0d286358ea096fcad656303a12addc777041d8b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 14:02:02 -0400 Subject: [PATCH 221/293] must not include system headers within 'extern "C"' blocks. breaks with MPICH --- lib/h5md/include/ch5md.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/h5md/include/ch5md.h b/lib/h5md/include/ch5md.h index 351e337ed4..8fefc9565d 100644 --- a/lib/h5md/include/ch5md.h +++ b/lib/h5md/include/ch5md.h @@ -9,13 +9,13 @@ #ifndef CH5MD_H #define CH5MD_H +#include "hdf5.h" +#include + #ifdef __cplusplus extern "C" { #endif -#include "hdf5.h" -#include - #define CH5MD_RANK_ERROR -10 typedef struct h5md_element_struct { From f7a243a4d9eeca7bc9fdb3346b9d8157ab81126f Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 14:20:03 -0400 Subject: [PATCH 222/293] convert explicit copies back into symbolic links --- lib/atc/Install.py | 83 +------------------------------------------- lib/awpmd/Install.py | 83 +------------------------------------------- lib/h5md/Install.py | 83 +------------------------------------------- lib/meam/Install.py | 83 +------------------------------------------- lib/poems/Install.py | 83 +------------------------------------------- lib/qmmm/Install.py | 83 +------------------------------------------- lib/reax/Install.py | 83 +------------------------------------------- 7 files changed, 7 insertions(+), 574 deletions(-) mode change 100644 => 120000 lib/atc/Install.py mode change 100644 => 120000 lib/awpmd/Install.py mode change 100644 => 120000 lib/h5md/Install.py mode change 100644 => 120000 lib/meam/Install.py mode change 100644 => 120000 lib/poems/Install.py mode change 100644 => 120000 lib/qmmm/Install.py mode change 100644 => 120000 lib/reax/Install.py diff --git a/lib/atc/Install.py b/lib/atc/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/atc/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/atc/Install.py b/lib/atc/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/atc/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/awpmd/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/awpmd/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/h5md/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/h5md/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/meam/Install.py b/lib/meam/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/meam/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/meam/Install.py b/lib/meam/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/meam/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/poems/Install.py b/lib/poems/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/poems/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/poems/Install.py b/lib/poems/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/poems/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/qmmm/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/qmmm/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file diff --git a/lib/reax/Install.py b/lib/reax/Install.py deleted file mode 100644 index 18b426f928..0000000000 --- a/lib/reax/Install.py +++ /dev/null @@ -1,82 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax: python Install.py -m machine -e suffix - specify -m and optionally -e, order does not matter - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/reax/Install.py b/lib/reax/Install.py new file mode 120000 index 0000000000..37041d2ea1 --- /dev/null +++ b/lib/reax/Install.py @@ -0,0 +1 @@ +Install.py \ No newline at end of file From fd6e11f8217a0a58002b3eef6a80cceee27e905c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 14:29:17 -0400 Subject: [PATCH 223/293] convert copies of Install.py files to symlinks --- lib/atc/Install.py | 92 +------------------------------------------- lib/awpmd/Install.py | 92 +------------------------------------------- lib/h5md/Install.py | 92 +------------------------------------------- lib/meam/Install.py | 92 +------------------------------------------- lib/poems/Install.py | 92 +------------------------------------------- lib/qmmm/Install.py | 92 +------------------------------------------- lib/reax/Install.py | 92 +------------------------------------------- 7 files changed, 7 insertions(+), 637 deletions(-) mode change 100644 => 120000 lib/atc/Install.py mode change 100644 => 120000 lib/awpmd/Install.py mode change 100644 => 120000 lib/h5md/Install.py mode change 100644 => 120000 lib/meam/Install.py mode change 100644 => 120000 lib/poems/Install.py mode change 100644 => 120000 lib/qmmm/Install.py mode change 100644 => 120000 lib/reax/Install.py diff --git a/lib/atc/Install.py b/lib/atc/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/atc/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/atc/Install.py b/lib/atc/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/atc/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/awpmd/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/awpmd/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/h5md/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/h5md/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/meam/Install.py b/lib/meam/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/meam/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/meam/Install.py b/lib/meam/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/meam/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/poems/Install.py b/lib/poems/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/poems/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/poems/Install.py b/lib/poems/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/poems/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/qmmm/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/qmmm/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file diff --git a/lib/reax/Install.py b/lib/reax/Install.py deleted file mode 100644 index 29270560a6..0000000000 --- a/lib/reax/Install.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -# install.py tool to do a generic build of a library -# soft linked to by many of the lib/Install.py files -# used to automate the steps described in the corresponding lib/README - -import sys,commands,os - -# help message - -help = """ -Syntax from src dir: make lib-libname args="-m machine -e suffix" -Syntax from lib dir: python Install.py -m machine -e suffix - -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) -specify -m and optionally -e, order does not matter - - -m = peform a clean followed by "make -f Makefile.machine" - machine = suffix of a lib/Makefile.* file - -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix - does not alter existing Makefile.machine - -Examplesx: - -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler -""" - -# print error message or help - -def error(str=None): - if not str: print help - else: print "ERROR",str - sys.exit() - -# parse args - -args = sys.argv[1:] -nargs = len(args) -if nargs == 0: error() - -machine = None -extraflag = 0 - -iarg = 0 -while iarg < nargs: - if args[iarg] == "-m": - if iarg+2 > nargs: error() - machine = args[iarg+1] - iarg += 2 - elif args[iarg] == "-e": - if iarg+2 > nargs: error() - extraflag = 1 - suffix = args[iarg+1] - iarg += 2 - else: error() - -# set lib from working dir - -cwd = os.getcwd() -lib = os.path.basename(cwd) - -# create Makefile.auto as copy of Makefile.machine -# reset EXTRAMAKE if requested - -if not os.path.exists("Makefile.%s" % machine): - error("lib/%s/Makefile.%s does not exist" % (lib,machine)) - -lines = open("Makefile.%s" % machine,'r').readlines() -fp = open("Makefile.auto",'w') - -for line in lines: - words = line.split() - if len(words) == 3 and extraflag and \ - words[0] == "EXTRAMAKE" and words[1] == '=': - line = line.replace(words[2],"Makefile.lammps.%s" % suffix) - print >>fp,line, - -fp.close() - -# make the library via Makefile.auto - -print "Building lib%s.a ..." % lib -cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt - -if os.path.exists("lib%s.a" % lib): print "Build was successful" -else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) -if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib diff --git a/lib/reax/Install.py b/lib/reax/Install.py new file mode 120000 index 0000000000..ffe709d44c --- /dev/null +++ b/lib/reax/Install.py @@ -0,0 +1 @@ +../Install.py \ No newline at end of file From 715c797df051ef711310785c8c556eab4876927b Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 26 Jul 2017 15:14:12 -0400 Subject: [PATCH 224/293] simplify Install.py for voronoi --- lib/voronoi/.gitignore | 4 +++ lib/voronoi/Install.py | 76 ++++++++++++++++++++---------------------- lib/voronoi/README | 2 +- 3 files changed, 42 insertions(+), 40 deletions(-) create mode 100644 lib/voronoi/.gitignore diff --git a/lib/voronoi/.gitignore b/lib/voronoi/.gitignore new file mode 100644 index 0000000000..6ca01c094f --- /dev/null +++ b/lib/voronoi/.gitignore @@ -0,0 +1,4 @@ +# files to ignore +/liblink +/includelink +/voro++-* diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 1c4bc5cb6d..285e11fb9a 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -10,27 +10,23 @@ except: from urllib import urlretrieve as geturl # help message help = """ -Syntax from src dir: make lib-voronoi args="-v version -h hpath hdir -g -b -l" -Syntax from lib dir: python Install.py -v version -h hpath hdir -g -b -l +Syntax from src dir: make lib-voronoi + or: make lib-voronoi args="-p /usr/local/voro++-0.4.6" + or: make lib-voronoi args="-v voro++-0.4.6 -b" +Syntax from lib dir: python Install.py -v voro++-0.4.6 -b + or: python Install.py + or: python Install.py -p /usr/local/voro++-0.4.6 specify one or more options, order does not matter + -b = download and build the Voro++ library (default) + -p = specify folder of existing Voro++ installation -v = version of Voro++ to download and build default version = voro++-0.4.6 (current as of Jan 2015) - -h = set home dir of Voro++ to be hpath/hdir - hpath can be full path, contain '~' or '.' chars - default hpath = . = lib/voronoi - default hdir = voro++-0.4.6 = what tarball unpacks to - -g = grab (download) tarball from math.lbl.gov/voro++ website - unpack it to hpath/hdir - hpath must already exist - if hdir already exists, it will be deleted before unpack - -b = build Voro++ library in its src dir - -l = create 2 softlinks (includelink,liblink) in lib/voronoi to Voro++ src dir Example: -make lib-voronoi args="-g -b -l" # download/build in lib/voronoi/voro++-0.4.6 +make lib-voronoi args="-b" # download/build in lib/voronoi/voro++-0.4.6 """ # settings @@ -47,10 +43,10 @@ def error(str=None): # expand to full path name # process leading '~' or relative path - + def fullpath(path): return os.path.abspath(os.path.expanduser(path)) - + # parse args args = sys.argv[1:] @@ -60,9 +56,10 @@ if nargs == 0: error() homepath = "." homedir = version -grabflag = False -buildflag = False -linkflag = False +grabflag = True +buildflag = True +pathflag = False +linkflag = True iarg = 0 while iarg < nargs: @@ -70,42 +67,43 @@ while iarg < nargs: if iarg+2 > nargs: error() version = args[iarg+1] iarg += 2 - elif args[iarg] == "-h": - if iarg+3 > nargs: error() - homepath = args[iarg+1] - homedir = args[iarg+2] - iarg += 3 - elif args[iarg] == "-g": - grabflag = True - iarg += 1 + elif args[iarg] == "-p": + if iarg+2 > nargs: error() + voropath = fullpath(args[iarg+1]) + pathflag = True + buildflag = False + iarg += 2 elif args[iarg] == "-b": buildflag = True iarg += 1 - elif args[iarg] == "-l": - linkflag = True - iarg += 1 else: error() homepath = fullpath(homepath) -if not os.path.isdir(homepath): error("Voro++ path does not exist") -homedir = "%s/%s" % (homepath,homedir) +homedir = "%s/%s" % (homepath,version) + +if (pathflag): + if not os.path.isdir(voropath): error("Voro++ path does not exist") + homedir = voropath + +if (buildflag and pathflag): + error("Cannot use -b and -p flag at the same time") # download and unpack Voro++ tarball if grabflag: print("Downloading Voro++ ...") geturl(url,"%s/%s.tar.gz" % (homepath,version)) - + print("Unpacking Voro++ tarball ...") if os.path.exists("%s/%s" % (homepath,version)): cmd = 'rm -rf "%s/%s"' % (homepath,version) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) cmd = 'cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version) - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) if os.path.basename(homedir) != version: if os.path.exists(homedir): cmd = 'rm -rf "%s"' % homedir - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) os.rename("%s/%s" % (homepath,version),homedir) # build Voro++ @@ -113,8 +111,8 @@ if grabflag: if buildflag: print("Building Voro++ ...") cmd = 'cd "%s"; make' % homedir - txt = subprocess.check_output(cmd,shell=True) - print(txt) + txt = subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + print(txt.decode('UTF-8')) # create 2 links in lib/voronoi to Voro++ src dir @@ -125,6 +123,6 @@ if linkflag: if os.path.isfile("liblink") or os.path.islink("liblink"): os.remove("liblink") cmd = ['ln -s "%s/src" includelink' % homedir, 'includelink'] - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) cmd = ['ln -s "%s/src" liblink' % homedir] - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) diff --git a/lib/voronoi/README b/lib/voronoi/README index 9863632be0..2ca11c9221 100644 --- a/lib/voronoi/README +++ b/lib/voronoi/README @@ -22,7 +22,7 @@ Instructions: or somewhere else on your system. 2. compile Voro++ from within its home directory - % make + % make 3. There is no need to install Voro++ if you only wish to use it from LAMMPS. You can install it if you From 934cbbbecaffafb7050474bf24ac7537c4fcfe83 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 26 Jul 2017 16:07:08 -0600 Subject: [PATCH 225/293] restore lost KIM doc section in Section packages --- doc/src/Section_commands.txt | 4 ++-- doc/src/Section_packages.txt | 38 +++++++++++++++++++++++------ src/SHOCK/fix_msst.cpp | 12 ++++------ src/SHOCK/fix_msst.h | 46 ++++++++++++++++++------------------ 4 files changed, 61 insertions(+), 39 deletions(-) diff --git a/doc/src/Section_commands.txt b/doc/src/Section_commands.txt index 7dc3d27b6a..f1eb225fe5 100644 --- a/doc/src/Section_commands.txt +++ b/doc/src/Section_commands.txt @@ -734,8 +734,8 @@ package"_Section_start.html#start_3. "smd/wall/surface"_fix_smd_wall_surface.html, "temp/rescale/eff"_fix_temp_rescale_eff.html, "ti/spring"_fix_ti_spring.html, -"ttm/mod"_fix_ttm.html -"wall/ees"_fix_wall_ees.html +"ttm/mod"_fix_ttm.html, +"wall/ees"_fix_wall_ees.html, "wall/region/ees"_fix_wall_ees.html :tb(c=6,ea=c) :line diff --git a/doc/src/Section_packages.txt b/doc/src/Section_packages.txt index 54a2685b86..6afcb2758d 100644 --- a/doc/src/Section_packages.txt +++ b/doc/src/Section_packages.txt @@ -492,14 +492,38 @@ Minnesota). [Install or un-install:] -Using this package requires the KIM library and its models -(interatomic potentials) to be downloaded and installed on your -system. The library can be downloaded and built in lib/kim or -elsewhere on your system. Details of the download, build, and install -process for KIM are given in the lib/kim/README file. +Before building LAMMPS with this package, you must first download and +build the KIM library and include the KIM models that you want to +use. You can do this manually if you prefer; follow the instructions +in lib/kim/README. You can also do it in one step from the lammps/src +dir, using a command like these, which simply invoke the +lib/kim/Install.py script with the specified args. -Once that process is complete, you can then install/un-install the -package and build LAMMPS in the usual manner: +make lib-kim # print help message +make lib-kim args="-b . none" # install KIM API lib with only example models +make lib-kim args="-b . Glue_Ercolessi_Adams_Al__MO_324507536345_001" # ditto plus one model +make lib-kim args="-b . OpenKIM" # install KIM API lib with all models +make lib-kim args="-a EAM_Dynamo_Ackland_W__MO_141627196590_002" # add one model or model driver :pre + +Note that in LAMMPS lingo, a KIM model driver is a pair style +(e.g. EAM or Tersoff). A KIM model is a pair style for a particular +element or alloy and set of parameters, e.g. EAM for Cu with a +specific EAM potential file. Also note that installing the KIM API +library with all its models, may take around 30 min to build. Of +course you only need to do that once. + +See the list of KIM model drivers here: +https://openkim.org/kim-items/model-drivers/alphabetical + +See the list of all KIM models here: +https://openkim.org/kim-items/models/by-model-drivers + +See the list of example KIM models included by default here: +https://openkim.org/kim-api in the "What is in the KIM API source +package?" section + +You can then install/un-install the package and build LAMMPS in the +usual manner: make yes-kim make machine :pre diff --git a/src/SHOCK/fix_msst.cpp b/src/SHOCK/fix_msst.cpp index 66a648cd17..d7e5723980 100644 --- a/src/SHOCK/fix_msst.cpp +++ b/src/SHOCK/fix_msst.cpp @@ -939,7 +939,7 @@ int FixMSST::modify_param(int narg, char **arg) double FixMSST::compute_scalar() { - // compute new pressure and volume. + // compute new pressure and volume temperature->compute_vector(); pressure->compute_vector(); @@ -958,10 +958,9 @@ double FixMSST::compute_scalar() energy -= p0 * ( v0 - volume ) / nktv2p; // subtract off precomputed TS_int integral value + // TS_int = 0 for non DFTB calculations - if (dftb) { // TS_int == 0 for non DFTB calculations - energy -= TS_int; - } + if (dftb) energy -= TS_int; return energy; } @@ -987,7 +986,7 @@ double FixMSST::compute_vector(int n) /* ---------------------------------------------------------------------- Computes the deviation of the current point - from the Hugoniot in Kelvin for the MSST. + from the Hugoniot in Kelvin for the MSST ------------------------------------------------------------------------- */ double FixMSST::compute_hugoniot() @@ -1012,7 +1011,7 @@ double FixMSST::compute_hugoniot() /* ---------------------------------------------------------------------- Computes the deviation of the current point from the Rayleigh - in pressure units for the MSST. + in pressure units for the MSST ------------------------------------------------------------------------- */ double FixMSST::compute_rayleigh() @@ -1108,4 +1107,3 @@ double FixMSST::memory_usage() double bytes = 3*atom->nmax * sizeof(double); return bytes; } - diff --git a/src/SHOCK/fix_msst.h b/src/SHOCK/fix_msst.h index 092017bfbb..b6229e7527 100644 --- a/src/SHOCK/fix_msst.h +++ b/src/SHOCK/fix_msst.h @@ -41,56 +41,56 @@ class FixMSST : public Fix { double memory_usage(); private: - double dtv,dtf,dthalf; // Full and half step sizes + double dtv,dtf,dthalf; // full and half step sizes double boltz,nktv2p, mvv2e; // Boltzmann factor and unit conversions - double total_mass; // Mass of the computational cell + double total_mass; // mass of the computational cell - double omega[3]; // Time derivative of the volume + double omega[3]; // time derivative of the volume double p_current[3],dilation[3]; - double qmass; // Effective cell mass - double mu; // Effective cell viscosity - double tscale; // Converts thermal energy to compressive + double qmass; // effective cell mass + double mu; // effective cell viscosity + double tscale; // converts thermal energy to compressive // strain ke at simulation start int dftb; // flag for use with DFTB+ - double velocity_sum; // Sum of the velocities squared - double damping; // Damping function for TS force term at + double velocity_sum; // sum of the velocities squared + double damping; // damping function for TS force term at // small volume difference (v0 - vol) - double T0S0; // Initial TS term for DFTB+ simulations + double T0S0; // initial TS term for DFTB+ simulations double S_elec,S_elec_1,S_elec_2; // time history of electron entropy // for DFTB+ simulaitons double TS_dot; // time derivative of TS term for // DFTB+ simulations - double **old_velocity; // Saved velocities + double **old_velocity; // saved velocities int kspace_flag; // 1 if KSpace invoked, 0 if not int nrigid; // number of rigid fixes int *rfix; // indices of rigid fixes - char *id_temp,*id_press; // Strings with identifiers of + char *id_temp,*id_press; // strings with identifiers of char *id_pe; // created computes - class Compute *temperature; // Computes created to evaluate + class Compute *temperature; // computes created to evaluate class Compute *pressure; // thermodynamic quantities class Compute *pe; - int tflag,pflag,vsflag,peflag; // Flags to keep track of computes that + int tflag,pflag,vsflag,peflag; // flags to keep track of computes that // were created // shock initial conditions - double e0; // Initial energy - double v0; // Initial volume - double p0; // Initial pressure - double velocity; // Velocity of the shock + double e0; // initial energy + double v0; // initial volume + double p0; // initial pressure + double velocity; // velocity of the shock double lagrangian_position; // Lagrangian location of computational cell - int direction; // Direction of shock - int p0_set; // Is pressure set - int v0_set; // Is volume set - int e0_set; // Is energy set - double TS_int; // Needed for conserved quantity + int direction; // direction of shock + int p0_set; // is pressure set + int v0_set; // is volume set + int e0_set; // is energy set + double TS_int; // needed for conserved quantity // with thermal electronic excitations - double beta; // Energy conservation scaling factor + double beta; // energy conservation scaling factor int maxold; // allocated size of old_velocity class FixExternal *fix_external; // ptr to fix external From 0427f6205ec51133bafcc528ede07fcc1e435739 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 27 Jul 2017 09:25:02 -0400 Subject: [PATCH 226/293] fix typo --- lib/colvars/Install.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/colvars/Install.py b/lib/colvars/Install.py index af658fa26c..2fc207710c 100644 --- a/lib/colvars/Install.py +++ b/lib/colvars/Install.py @@ -28,7 +28,7 @@ make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler def error(str=None): if not str: print(help) - else: print("ERROR"),str + else: print("ERROR",str) sys.exit() # parse args From acf6d54ec1703d92e070b4c6ab47fb2b79334850 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 27 Jul 2017 09:25:39 -0400 Subject: [PATCH 227/293] python3 port, yet untested --- lib/Install.py | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/lib/Install.py b/lib/Install.py index 29270560a6..6b90254336 100644 --- a/lib/Install.py +++ b/lib/Install.py @@ -4,7 +4,8 @@ # soft linked to by many of the lib/Install.py files # used to automate the steps described in the corresponding lib/README -import sys,commands,os +from __future__ import print_function +import sys,os,subprocess # help message @@ -12,7 +13,7 @@ help = """ Syntax from src dir: make lib-libname args="-m machine -e suffix" Syntax from lib dir: python Install.py -m machine -e suffix -libname = name of lib dir (e.g. atc, colvars, h5md, meam, poems, etc) +libname = name of lib dir (e.g. atc, h5md, meam, poems, etc) specify -m and optionally -e, order does not matter -m = peform a clean followed by "make -f Makefile.machine" @@ -20,17 +21,17 @@ specify -m and optionally -e, order does not matter -e = set EXTRAMAKE variable in Makefile.machine to Makefile.lammps.suffix does not alter existing Makefile.machine -Examplesx: +Examples: -make lib-colvars args="-m g++" # build COLVARS lib with GNU g++ compiler -make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler +make lib-poems args="-m g++" # build COLVARS lib with GNU g++ compiler +make lib-meam args="-m ifort" # build MEAM lib with Intel ifort compiler """ # print error message or help def error(str=None): - if not str: print help - else: print "ERROR",str + if not str: print(help) + else: print("ERROR",str) sys.exit() # parse args @@ -47,12 +48,12 @@ while iarg < nargs: if args[iarg] == "-m": if iarg+2 > nargs: error() machine = args[iarg+1] - iarg += 2 + iarg += 2 elif args[iarg] == "-e": if iarg+2 > nargs: error() extraflag = 1 suffix = args[iarg+1] - iarg += 2 + iarg += 2 else: error() # set lib from working dir @@ -62,7 +63,7 @@ lib = os.path.basename(cwd) # create Makefile.auto as copy of Makefile.machine # reset EXTRAMAKE if requested - + if not os.path.exists("Makefile.%s" % machine): error("lib/%s/Makefile.%s does not exist" % (lib,machine)) @@ -80,12 +81,12 @@ fp.close() # make the library via Makefile.auto -print "Building lib%s.a ..." % lib +print("Building lib%s.a ..." % lib) cmd = "make -f Makefile.auto clean; make -f Makefile.auto" -txt = commands.getoutput(cmd) -print txt +txt = subprocess.check_output(cmd,shell=True,stderr=subprocess.STDOUT) +print(txt) -if os.path.exists("lib%s.a" % lib): print "Build was successful" +if os.path.exists("lib%s.a" % lib): print("Build was successful") else: error("Build of lib/%s/lib%s.a was NOT successful" % (lib,lib)) if not os.path.exists("Makefile.lammps"): - print "lib/%s/Makefile.lammps was NOT created" % lib + print("lib/%s/Makefile.lammps was NOT created" % lib) From c494ec35e2428caf964abb37fb424b543b8fe83c Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 27 Jul 2017 12:48:32 -0400 Subject: [PATCH 228/293] correct symbolic links to shared Install.py file --- lib/atc/Install.py | 2 +- lib/awpmd/Install.py | 2 +- lib/h5md/Install.py | 2 +- lib/meam/Install.py | 2 +- lib/poems/Install.py | 2 +- lib/qmmm/Install.py | 2 +- lib/reax/Install.py | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/atc/Install.py b/lib/atc/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/atc/Install.py +++ b/lib/atc/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/awpmd/Install.py b/lib/awpmd/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/awpmd/Install.py +++ b/lib/awpmd/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/h5md/Install.py b/lib/h5md/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/h5md/Install.py +++ b/lib/h5md/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/meam/Install.py b/lib/meam/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/meam/Install.py +++ b/lib/meam/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/poems/Install.py b/lib/poems/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/poems/Install.py +++ b/lib/poems/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/qmmm/Install.py b/lib/qmmm/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/qmmm/Install.py +++ b/lib/qmmm/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file diff --git a/lib/reax/Install.py b/lib/reax/Install.py index 37041d2ea1..ffe709d44c 120000 --- a/lib/reax/Install.py +++ b/lib/reax/Install.py @@ -1 +1 @@ -Install.py \ No newline at end of file +../Install.py \ No newline at end of file From e3973796bacc608e97968060ef5fc67c51ff3419 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 27 Jul 2017 15:51:45 -0400 Subject: [PATCH 229/293] fix bug in power operator in LAMMPS variable expressions --- src/variable.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/variable.cpp b/src/variable.cpp index 6e16597c63..a8f195dbc8 100644 --- a/src/variable.cpp +++ b/src/variable.cpp @@ -2148,8 +2148,10 @@ double Variable::evaluate(char *str, Tree **tree) argstack[nargstack++] = fmod(value1,value2); } else if (opprevious == CARAT) { if (value2 == 0.0) - error->all(FLERR,"Power by 0 in variable formula"); - argstack[nargstack++] = pow(value1,value2); + argstack[nargstack++] = 1.0; + else if ((value1 == 0.0) && (value2 < 0.0)) + error->all(FLERR,"Invalid power expression in variable formula"); + else argstack[nargstack++] = pow(value1,value2); } else if (opprevious == UNARY) { argstack[nargstack++] = -value2; } else if (opprevious == NOT) { From f3850da9fe9dd08924ef61ba319e560a922bdaa6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 13:36:06 -0400 Subject: [PATCH 230/293] clean up makefiles provide "serial" and "mpi" targets for atc and awpmd --- lib/atc/Makefile.g++ | 6 ++ lib/atc/Makefile.lammps | 5 -- lib/atc/Makefile.mingw32-cross | 67 ------------------- lib/atc/Makefile.mingw32-cross-mpi | 68 ------------------- lib/atc/Makefile.mingw64-cross | 67 ------------------- lib/atc/Makefile.mingw64-cross-mpi | 68 ------------------- lib/atc/{Makefile.mpic++ => Makefile.mpi} | 38 +++++++---- lib/atc/Makefile.serial | 24 ++++--- lib/awpmd/Makefile.mingw32-cross | 80 ----------------------- lib/awpmd/Makefile.mingw32-cross-mpi | 13 ---- lib/awpmd/Makefile.mingw64-cross | 79 ---------------------- lib/awpmd/Makefile.mingw64-cross-mpi | 13 ---- lib/h5md/Makefile.mpi | 1 + lib/h5md/Makefile.serial | 1 + 14 files changed, 49 insertions(+), 481 deletions(-) delete mode 100644 lib/atc/Makefile.lammps delete mode 100644 lib/atc/Makefile.mingw32-cross delete mode 100644 lib/atc/Makefile.mingw32-cross-mpi delete mode 100644 lib/atc/Makefile.mingw64-cross delete mode 100644 lib/atc/Makefile.mingw64-cross-mpi rename lib/atc/{Makefile.mpic++ => Makefile.mpi} (59%) delete mode 100644 lib/awpmd/Makefile.mingw32-cross delete mode 100644 lib/awpmd/Makefile.mingw32-cross-mpi delete mode 100644 lib/awpmd/Makefile.mingw64-cross delete mode 100644 lib/awpmd/Makefile.mingw64-cross-mpi create mode 120000 lib/h5md/Makefile.mpi create mode 120000 lib/h5md/Makefile.serial diff --git a/lib/atc/Makefile.g++ b/lib/atc/Makefile.g++ index d15e6cb3b8..bb3028392a 100644 --- a/lib/atc/Makefile.g++ +++ b/lib/atc/Makefile.g++ @@ -1,3 +1,4 @@ +# library build -*- makefile -*- SHELL = /bin/sh # which file will be copied to Makefile.lammps @@ -5,6 +6,7 @@ SHELL = /bin/sh EXTRAMAKE = Makefile.lammps.installed # ------ FILES ------ + SRC = $(wildcard *.cpp) INC = $(wildcard *.h) @@ -47,5 +49,9 @@ DEPENDS = $(OBJ:.o=.d) # ------ CLEAN ------ +.PHONY: clean lib + clean: -rm *.o *.d *~ $(LIB) + +sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.lammps b/lib/atc/Makefile.lammps deleted file mode 100644 index c8cd66af26..0000000000 --- a/lib/atc/Makefile.lammps +++ /dev/null @@ -1,5 +0,0 @@ -# Settings that the LAMMPS build will import when this package library is used - -user-atc_SYSINC = -user-atc_SYSLIB = -lblas -llapack -user-atc_SYSPATH = diff --git a/lib/atc/Makefile.mingw32-cross b/lib/atc/Makefile.mingw32-cross deleted file mode 100644 index 8b33540981..0000000000 --- a/lib/atc/Makefile.mingw32-cross +++ /dev/null @@ -1,67 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw32/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -I../../src -I../../src/STUBS -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLSMALL -Wno-uninitialized -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw32-cross-mpi b/lib/atc/Makefile.mingw32-cross-mpi deleted file mode 100644 index c5feeca81a..0000000000 --- a/lib/atc/Makefile.mingw32-cross-mpi +++ /dev/null @@ -1,68 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw32-mpi/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -I../../tools/mingw-cross/mpich2-win32/include/ \ - -I../../src -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLSMALL -Wno-uninitialized -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw64-cross b/lib/atc/Makefile.mingw64-cross deleted file mode 100644 index fbd3a02610..0000000000 --- a/lib/atc/Makefile.mingw64-cross +++ /dev/null @@ -1,67 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw64/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -I../../src -I../../src/STUBS -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLBIG -Wno-uninitialized -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mingw64-cross-mpi b/lib/atc/Makefile.mingw64-cross-mpi deleted file mode 100644 index f8dd64eae3..0000000000 --- a/lib/atc/Makefile.mingw64-cross-mpi +++ /dev/null @@ -1,68 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = $(wildcard *.cpp) -INC = $(wildcard *.h) - -# ------ DEFINITIONS ------ - -DIR = Obj_mingw64-mpi/ -LIB = $(DIR)libatc.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -I../../tools/mingw-cross/mpich2-win64/include/ \ - -I../../src -DMPICH_IGNORE_CXX_SEEK \ - -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -DLAMMPS_SMALLBIG -Wno-uninitialized -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rcs -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm $(DIR)*.o $(DIR)*.d *~ $(LIB) - -$(DEPENDS) : $(DIR) -sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.mpic++ b/lib/atc/Makefile.mpi similarity index 59% rename from lib/atc/Makefile.mpic++ rename to lib/atc/Makefile.mpi index c9dfdb79c9..ec941efdcb 100644 --- a/lib/atc/Makefile.mpic++ +++ b/lib/atc/Makefile.mpi @@ -2,38 +2,54 @@ SHELL = /bin/sh # which file will be copied to Makefile.lammps -EXTRAMAKE = Makefile.lammps.installed +EXTRAMAKE = Makefile.lammps.linalg + # ------ FILES ------ + SRC = $(wildcard *.cpp) INC = $(wildcard *.h) + # ------ DEFINITIONS ------ + LIB = libatc.a OBJ = $(SRC:.cpp=.o) + +default: lib + # ------ SETTINGS ------ +.PHONY: clean lib depend + # include any MPI settings needed for the ATC library to build with # must be the same MPI library that LAMMPS is built with -CC = mpic++ -CCFLAGS = -O3 -Wall -g -I../../src -fPIC -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 +CC = mpicxx +CCFLAGS = -O3 -Wall -g -fPIC +CPPFLAGS = -I../../src -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 ARCHIVE = ar ARCHFLAG = -rc -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O # ------ MAKE PROCEDURE ------ + lib: $(OBJ) $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) @cp $(EXTRAMAKE) Makefile.lammps + # ------ COMPILE RULES ------ + %.o:%.cpp - $(CC) $(CCFLAGS) -c $< -%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ + $(CC) $(CPPFLAGS) $(CCFLAGS) -c $< + # ------ DEPENDENCIES ------ -DEPENDS = $(OBJ:.o=.d) + +depend .depend : fastdep.exe $(SRC) + @./fastdep.exe $(INCFLAGS) -- $^ > .depend || exit 1 + +fastdep.exe: ../../src/DEPEND/fastdep.c + @cc -O -o $@ $< + # ------ CLEAN ------ + clean: - -rm *.o *.d *~ $(LIB) + -rm -f *.o *~ .depend $(LIB) fastdep.exe sinclude $(DEPENDS) diff --git a/lib/atc/Makefile.serial b/lib/atc/Makefile.serial index 44ce5fd341..70b786a6b8 100644 --- a/lib/atc/Makefile.serial +++ b/lib/atc/Makefile.serial @@ -14,18 +14,20 @@ INC = $(wildcard *.h) LIB = libatc.a OBJ = $(SRC:.cpp=.o) +default: lib + # ------ SETTINGS ------ +.PHONY: clean lib depend + # include any MPI settings needed for the ATC library to build with # must be the same MPI library that LAMMPS is built with CC = g++ -CCFLAGS = -O -g -fPIC -I../../src -I../../src/STUBS +CCFLAGS = -O3 -g -fPIC +CPPFLAGS = -I../../src -I../../src/STUBS ARCHIVE = ar ARCHFLAG = -rc -DEPFLAGS = -M -LINK = $(CC) -LINKFLAGS = -O # ------ MAKE PROCEDURE ------ lib: $(OBJ) @@ -35,17 +37,19 @@ lib: $(OBJ) # ------ COMPILE RULES ------ %.o:%.cpp - $(CC) $(CCFLAGS) -c $< -%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ + $(CC) $(CPPFLAGS) $(CCFLAGS) -c $< # ------ DEPENDENCIES ------ -DEPENDS = $(OBJ:.o=.d) +depend .depend : fastdep.exe $(SRC) + @./fastdep.exe $(INCFLAGS) -- $^ > .depend || exit 1 + +fastdep.exe: ../../src/DEPEND/fastdep.c + @cc -O -o $@ $< # ------ CLEAN ------ clean: - -rm *.o *.d *~ $(LIB) + -rm -f *.o *~ .depend $(LIB) fastdep.exe -sinclude $(DEPENDS) +sinclude .depend diff --git a/lib/awpmd/Makefile.mingw32-cross b/lib/awpmd/Makefile.mingw32-cross deleted file mode 100644 index 6a93987173..0000000000 --- a/lib/awpmd/Makefile.mingw32-cross +++ /dev/null @@ -1,80 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = logexc.cpp wpmd.cpp wpmd_split.cpp -vpath %.cpp ivutils/src -vpath %.cpp systems/interact/TCP - -INC = \ - cerf.h \ - cerf2.h \ - cerf_octave.h \ - cvector_3.h \ - lapack_inter.h \ - logexc.h \ - pairhash.h \ - refobj.h \ - tcpdefs.h \ - vector_3.h \ - wavepacket.h \ - wpmd.h \ - wpmd_split.h - -# ------ DEFINITIONS ------ -DIR = Obj_mingw32/ -LIB = $(DIR)libawpmd.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = i686-w64-mingw32-g++ -CCFLAGS = -O2 -march=i686 -mtune=generic -mfpmath=387 -mpc64 \ - -finline-functions \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -Wall -W -Wno-uninitialized -Isystems/interact/TCP/ -Isystems/interact -Iivutils/include -ARCHIVE = i686-w64-mingw32-ar -ARCHFLAG = -rscv -DEPFLAGS = -M -#LINK = -#LINKFLAGS = -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm *.d *~ $(OBJ) $(LIB) diff --git a/lib/awpmd/Makefile.mingw32-cross-mpi b/lib/awpmd/Makefile.mingw32-cross-mpi deleted file mode 100644 index cc2a76111a..0000000000 --- a/lib/awpmd/Makefile.mingw32-cross-mpi +++ /dev/null @@ -1,13 +0,0 @@ -# -*- makefile -*- wrapper for non-MPI libraries - -SHELL=/bin/sh - -all: - $(MAKE) $(MFLAGS) mingw32-cross - rm -f Obj_mingw32-mpi - ln -s Obj_mingw32 Obj_mingw32-mpi - -clean: - $(MAKE) $(MFLAGS) clean-mingw32-cross - rm -f Obj_mingw32-mpi - diff --git a/lib/awpmd/Makefile.mingw64-cross b/lib/awpmd/Makefile.mingw64-cross deleted file mode 100644 index 1f3e608129..0000000000 --- a/lib/awpmd/Makefile.mingw64-cross +++ /dev/null @@ -1,79 +0,0 @@ -# library build -*- makefile -*- -SHELL = /bin/sh - -# which file will be copied to Makefile.lammps - -EXTRAMAKE = Makefile.lammps.linalg - -# ------ FILES ------ - -SRC = logexc.cpp wpmd.cpp wpmd_split.cpp -vpath %.cpp ivutils/src -vpath %.cpp systems/interact/TCP - -INC = \ - cerf.h \ - cerf2.h \ - cerf_octave.h \ - cvector_3.h \ - lapack_inter.h \ - logexc.h \ - pairhash.h \ - refobj.h \ - tcpdefs.h \ - vector_3.h \ - wavepacket.h \ - wpmd.h \ - wpmd_split.h - -# ------ DEFINITIONS ------ -DIR = Obj_mingw64/ -LIB = $(DIR)libawpmd.a -OBJ = $(SRC:%.cpp=$(DIR)%.o) - -# ------ SETTINGS ------ - -# include any MPI settings needed for the ATC library to build with -# the same MPI library that LAMMPS is built with - -CC = x86_64-w64-mingw32-g++ -CCFLAGS = -O3 -march=core2 -mtune=core2 -mpc64 -msse2 \ - -ffast-math -funroll-loops -fstrict-aliasing \ - -Wall -W -Wno-uninitialized -Isystems/interact/TCP/ -Isystems/interact -Iivutils/include -ARCHIVE = x86_64-w64-mingw32-ar -ARCHFLAG = -rscv -DEPFLAGS = -M -#LINK = -#LINKFLAGS = -USRLIB = -SYSLIB = - -# ------ MAKE PROCEDURE ------ - -default: $(DIR) $(LIB) Makefile.lammps - -$(DIR): - mkdir $(DIR) - -Makefile.lammps: - @cp $(EXTRAMAKE) Makefile.lammps - -$(LIB): $(OBJ) - $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) - @cp $(EXTRAMAKE) Makefile.lammps - -# ------ COMPILE RULES ------ - -$(DIR)%.o:%.cpp - $(CC) $(CCFLAGS) -c $< -o $@ -$(DIR)%.d:%.cpp - $(CC) $(CCFLAGS) $(DEPFLAGS) $< > $@ - -# ------ DEPENDENCIES ------ - -DEPENDS = $(OBJ:.o=.d) - -# ------ CLEAN ------ - -clean: - -rm *.d *~ $(OBJ) $(LIB) diff --git a/lib/awpmd/Makefile.mingw64-cross-mpi b/lib/awpmd/Makefile.mingw64-cross-mpi deleted file mode 100644 index 1ec1a0995b..0000000000 --- a/lib/awpmd/Makefile.mingw64-cross-mpi +++ /dev/null @@ -1,13 +0,0 @@ -# -*- makefile -*- wrapper for non-MPI libraries - -SHELL=/bin/sh - -all: - $(MAKE) $(MFLAGS) mingw64-cross - rm -f Obj_mingw64-mpi - ln -s Obj_mingw64 Obj_mingw64-mpi - -clean: - $(MAKE) $(MFLAGS) clean-mingw64-cross - rm -f Obj_mingw64-mpi - diff --git a/lib/h5md/Makefile.mpi b/lib/h5md/Makefile.mpi new file mode 120000 index 0000000000..df682a9547 --- /dev/null +++ b/lib/h5md/Makefile.mpi @@ -0,0 +1 @@ +Makefile.h5cc \ No newline at end of file diff --git a/lib/h5md/Makefile.serial b/lib/h5md/Makefile.serial new file mode 120000 index 0000000000..df682a9547 --- /dev/null +++ b/lib/h5md/Makefile.serial @@ -0,0 +1 @@ +Makefile.h5cc \ No newline at end of file From ffb778cf9b252cf42dc4c7522d88e6ff6f9892f6 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 14:03:29 -0400 Subject: [PATCH 231/293] make Install.py for lib/smd and lib/voronoi consistent --- lib/smd/.gitignore | 5 +++ lib/smd/Install.py | 88 +++++++++++++++++++++--------------------- lib/voronoi/Install.py | 5 +-- 3 files changed, 52 insertions(+), 46 deletions(-) create mode 100644 lib/smd/.gitignore diff --git a/lib/smd/.gitignore b/lib/smd/.gitignore new file mode 100644 index 0000000000..4ab7a789ec --- /dev/null +++ b/lib/smd/.gitignore @@ -0,0 +1,5 @@ +# ignore these entries with git +/eigen.tar.gz +/eigen-eigen-* +/includelink +/eigen3 diff --git a/lib/smd/Install.py b/lib/smd/Install.py index 0fa05375db..18986b4477 100644 --- a/lib/smd/Install.py +++ b/lib/smd/Install.py @@ -11,30 +11,28 @@ except: from urllib import urlretrieve as geturl # help message help = """ -Syntax from src dir: make lib-smd args="-h hpath hdir -g -l" -Syntax from lib dir: python Install.py -h hpath hdir -g -l +Syntax from src dir: make lib-smd + or: make lib-smd args="-p /usr/include/eigen3" + +Syntax from lib dir: python Install.py + or: python Install.py -p /usr/include/eigen3" + or: python Install.py -v 3.3.4 -b specify one or more options, order does not matter - -h = set home dir of Eigen to be hpath/hdir - hpath can be full path, contain '~' or '.' chars - default hpath = . = lib/smd - default hdir = "ee" = what tarball unpacks to (eigen-eigen-*) - -g = grab (download) tarball from http://eigen.tuxfamily.org website - unpack it to hpath/hdir - hpath must already exist - if hdir already exists, it will be deleted before unpack - -l = create softlink (includelink) in lib/smd to Eigen src dir + -b = download and unpack/configure the Eigen library (default) + -p = specify folder holding an existing installation of Eigen + -v = set version of Eigen library to download and set up (default = 3.3.4) + Example: -make lib-smd args="-g -l" # download/build in default lib/smd/eigen-eigen-* +make lib-smd args="-b" # download/build in default lib/smd/eigen-eigen-* """ # settings version = '3.3.4' -url = "http://bitbucket.org/eigen/eigen/get/%s.tar.gz" % version tarball = "eigen.tar.gz" # print error message or help @@ -46,59 +44,65 @@ def error(str=None): # expand to full path name # process leading '~' or relative path - + def fullpath(path): return os.path.abspath(os.path.expanduser(path)) - + # parse args args = sys.argv[1:] nargs = len(args) -if nargs == 0: error() homepath = "." -homedir = "ee" +homedir = "eigen3" -grabflag = 0 -linkflag = 0 +grabflag = True +buildflag = True +pathflag = False +linkflag = True iarg = 0 while iarg < nargs: - if args[iarg] == "-h": - if iarg+3 > nargs: error() - homepath = args[iarg+1] - homedir = args[iarg+2] - iarg += 3 - elif args[iarg] == "-g": - grabflag = 1 - iarg += 1 - elif args[iarg] == "-l": - linkflag = 1 + if args[iarg] == "-v": + if iarg+2 > nargs: error() + version = args[iarg+1] + iarg += 2 + elif args[iarg] == "-p": + if iarg+2 > nargs: error() + eigenpath = fullpath(args[iarg+1]) + pathflag = True + buildflag = False + iarg += 2 + elif args[iarg] == "-b": + buildflag = True iarg += 1 else: error() homepath = fullpath(homepath) -if not os.path.isdir(homepath): error("Eigen path does not exist") + +if (pathflag): + if not os.path.isdir(eigenpath): error("Eigen path does not exist") + +if (buildflag and pathflag): + error("Cannot use -b and -p flag at the same time") # download and unpack Eigen tarball -# glob to find name of dir it unpacks to +# use glob to find name of dir it unpacks to -if grabflag: +if buildflag: print("Downloading Eigen ...") + url = "http://bitbucket.org/eigen/eigen/get/%s.tar.gz" % version geturl(url,"%s/%s" % (homepath,tarball)) print("Unpacking Eigen tarball ...") edir = glob.glob("%s/eigen-eigen-*" % homepath) for one in edir: if os.path.isdir(one): - subprocess.check_output("rm -rf %s" % one,shell=True) + subprocess.check_output("rm -rf %s" % one,stderr=subprocess.STDOUT,shell=True) cmd = 'cd "%s"; tar -xzvf %s' % (homepath,tarball) - subprocess.check_output(cmd,shell=True) - if homedir != "ee": - if os.path.exists(homedir): - subprocess.check_output("rm -rf %s" % homedir,shell=True) - edir = glob.glob("%s/eigen-eigen-*" % homepath) - os.rename(edir[0],"%s/%s" % (homepath,homedir)) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + edir = glob.glob("%s/eigen-eigen-*" % homepath) + os.rename(edir[0],"%s/%s" % (homepath,homedir)) # create link in lib/smd to Eigen src dir @@ -106,9 +110,7 @@ if linkflag: print("Creating link to Eigen files") if os.path.isfile("includelink") or os.path.islink("includelink"): os.remove("includelink") - if homedir == "ee": - edir = glob.glob("%s/eigen-eigen-*" % homepath) - linkdir = edir[0] + if pathflag: linkdir = eigenpath else: linkdir = "%s/%s" % (homepath,homedir) cmd = "ln -s %s includelink" % linkdir - subprocess.check_output(cmd,shell=True) + subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 285e11fb9a..9d6c58d273 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -2,6 +2,7 @@ # Install.py tool to download, unpack, build, and link to the Voro++ library # used to automate the steps described in the README file in this dir + from __future__ import print_function import sys,os,re,subprocess try: from urllib.request import urlretrieve as geturl @@ -21,8 +22,7 @@ specify one or more options, order does not matter -b = download and build the Voro++ library (default) -p = specify folder of existing Voro++ installation - -v = version of Voro++ to download and build - default version = voro++-0.4.6 (current as of Jan 2015) + -v = set version of Voro++ to download and build (default voro++-0.4.6) Example: @@ -51,7 +51,6 @@ def fullpath(path): args = sys.argv[1:] nargs = len(args) -if nargs == 0: error() homepath = "." homedir = version From 3ebf561e0dea0da33383f13a898b325a5dbaf0e2 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 14:25:47 -0400 Subject: [PATCH 232/293] remove tarball after unpacking --- lib/smd/Install.py | 1 + lib/voronoi/Install.py | 1 + 2 files changed, 2 insertions(+) diff --git a/lib/smd/Install.py b/lib/smd/Install.py index 18986b4477..337f993be5 100644 --- a/lib/smd/Install.py +++ b/lib/smd/Install.py @@ -103,6 +103,7 @@ if buildflag: subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) edir = glob.glob("%s/eigen-eigen-*" % homepath) os.rename(edir[0],"%s/%s" % (homepath,homedir)) + os.remove(tarball) # create link in lib/smd to Eigen src dir diff --git a/lib/voronoi/Install.py b/lib/voronoi/Install.py index 9d6c58d273..17bba5e8eb 100644 --- a/lib/voronoi/Install.py +++ b/lib/voronoi/Install.py @@ -99,6 +99,7 @@ if grabflag: subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) cmd = 'cd "%s"; tar -xzvf %s.tar.gz' % (homepath,version) subprocess.check_output(cmd,stderr=subprocess.STDOUT,shell=True) + os.remove("%s/%s.tar.gz" % (homepath,version)) if os.path.basename(homedir) != version: if os.path.exists(homedir): cmd = 'rm -rf "%s"' % homedir From 85120842dd8405d591c8780d012739fe4a37babe Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 15:20:33 -0400 Subject: [PATCH 233/293] update QUIP examples to closer match typical LAMMPS examples --- examples/USER/quip/in.gap | 2 +- examples/USER/quip/in.molecular | 3 +- examples/USER/quip/in.sw | 5 +- .../USER/quip/log.24Jul17.molecular.g++.1 | 130 ++++++++++++++++++ .../USER/quip/log.24Jul17.molecular.g++.4 | 130 ++++++++++++++++++ examples/USER/quip/log.24Jul17.sw.g++.1 | 83 +++++++++++ examples/USER/quip/log.24Jul17.sw.g++.4 | 83 +++++++++++ 7 files changed, 431 insertions(+), 5 deletions(-) create mode 100644 examples/USER/quip/log.24Jul17.molecular.g++.1 create mode 100644 examples/USER/quip/log.24Jul17.molecular.g++.4 create mode 100644 examples/USER/quip/log.24Jul17.sw.g++.1 create mode 100644 examples/USER/quip/log.24Jul17.sw.g++.4 diff --git a/examples/USER/quip/in.gap b/examples/USER/quip/in.gap index 37667e39b9..dd049a4737 100644 --- a/examples/USER/quip/in.gap +++ b/examples/USER/quip/in.gap @@ -17,6 +17,6 @@ fix 1 all nve thermo 10 timestep 0.001 -dump 1 all custom 10 dump.gap id fx fy fz +#dump 1 all custom 10 dump.gap id fx fy fz run 40 diff --git a/examples/USER/quip/in.molecular b/examples/USER/quip/in.molecular index 24d21d6762..4253399d7c 100644 --- a/examples/USER/quip/in.molecular +++ b/examples/USER/quip/in.molecular @@ -1,7 +1,6 @@ units metal atom_style full boundary p p p -processors 1 1 1 timestep 0.0001 # 0.1 fs read_data methane-box-8.data @@ -28,7 +27,7 @@ pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 # Intramolecular # Tell QUIP to pretend this is silane (which is covered by the parameter file) -pair_coeff * * quip ip.parms.SW.xml "IP SW" 14 1 +pair_coeff * * quip sw_example.xml "IP SW" 14 1 bond_style none angle_style none diff --git a/examples/USER/quip/in.sw b/examples/USER/quip/in.sw index c1367ac805..aaa4217b2f 100644 --- a/examples/USER/quip/in.sw +++ b/examples/USER/quip/in.sw @@ -10,6 +10,7 @@ read_data data_sw pair_style quip pair_coeff * * sw_example.xml "IP SW" 14 +velocity all create 10.0 355311 neighbor 0.3 bin neigh_modify delay 10 @@ -17,6 +18,6 @@ fix 1 all nve thermo 10 timestep 0.001 -dump 1 all custom 10 dump.sw id fx fy fz +#dump 1 all custom 10 dump.sw id fx fy fz -run 1 +run 100 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.1 b/examples/USER/quip/log.24Jul17.molecular.g++.1 new file mode 100644 index 0000000000..28fc63579b --- /dev/null +++ b/examples/USER/quip/log.24Jul17.molecular.g++.1 @@ -0,0 +1,130 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +units metal +atom_style full +boundary p p p +timestep 0.0001 # 0.1 fs + +read_data methane-box-8.data + orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 40 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + reading bonds ... + 32 bonds + reading angles ... + 48 angles + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# DISCLAIMER: This potential mixes parameters from methane and silane +# potentials and is NOT intended to be a realistic representation of either +# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, +# including the use of separate 'special_bonds' settings. + +pair_style hybrid/overlay lj/cut 8.0 quip + +# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, +# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +# Coulomb interactions ommitted for simplicity +pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT +pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC +pair_coeff 1 2 lj/cut 0.0019295487 2.95 +pair_modify shift no +# change exclusion settings for lj/cut only: exclude bonded pairs +pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 + +# Intramolecular +# Tell QUIP to pretend this is silane (which is covered by the parameter file) +pair_coeff * * quip sw_example.xml "IP SW" 14 1 +bond_style none +angle_style none + +fix 1 all nve + +# Include diagnostics that allow us to compare to a pure QUIP run +compute equip all pair quip +compute evdw all pair lj/cut +compute vir all pressure NULL virial + +thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip +thermo 1 + +# dump 1 all custom 1 dump.molecular id type x y z fx fy fz +# dump_modify 1 sort id + +run 10 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 2 2 2 + 2 neighbor lists, perpetual/occasional/extra = 2 0 0 + (1) pair lj/cut, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) pair quip, perpetual + attributes: full, newton on + pair build: full/bin + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 8.288 | 8.288 | 8.288 Mbytes +Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip + 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805 + 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093 + 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932 + 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264 + 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557 + 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546 + 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782 + 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787 + 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801 + 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653 + 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266 +Loop time of 0.0537777 on 1 procs for 10 steps with 40 atoms + +Performance: 1.607 ns/day, 14.938 hours/ns, 185.951 timesteps/s +90.3% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.053478 | 0.053478 | 0.053478 | 0.0 | 99.44 +Bond | 1.9073e-06 | 1.9073e-06 | 1.9073e-06 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 7.7724e-05 | 7.7724e-05 | 7.7724e-05 | 0.0 | 0.14 +Output | 0.00018263 | 0.00018263 | 0.00018263 | 0.0 | 0.34 +Modify | 1.5974e-05 | 1.5974e-05 | 1.5974e-05 | 0.0 | 0.03 +Other | | 2.122e-05 | | | 0.04 + +Nlocal: 40 ave 40 max 40 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 1175 ave 1175 max 1175 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 4768 ave 4768 max 4768 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 9536 ave 9536 max 9536 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 9536 +Ave neighs/atom = 238.4 +Ave special neighs/atom = 4 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.molecular.g++.4 b/examples/USER/quip/log.24Jul17.molecular.g++.4 new file mode 100644 index 0000000000..a8be8e77bb --- /dev/null +++ b/examples/USER/quip/log.24Jul17.molecular.g++.4 @@ -0,0 +1,130 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +units metal +atom_style full +boundary p p p +timestep 0.0001 # 0.1 fs + +read_data methane-box-8.data + orthogonal box = (-0.499095 -0.270629 0.131683) to (8.4109 8.63937 9.04168) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 40 atoms + scanning bonds ... + 4 = max bonds/atom + scanning angles ... + 6 = max angles/atom + reading bonds ... + 32 bonds + reading angles ... + 48 angles + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# DISCLAIMER: This potential mixes parameters from methane and silane +# potentials and is NOT intended to be a realistic representation of either +# system. It is meant to demonstrate the use of hybrid QUIP/LAMMPS potentials, +# including the use of separate 'special_bonds' settings. + +pair_style hybrid/overlay lj/cut 8.0 quip + +# exclusion setting for quip; cannot be exactly 1.0 1.0 1.0, +# since that would not flag 1-2, 1-3, and 1-4 pairs in lj/cut +special_bonds lj/coul 0.999999999 0.999999999 0.999999999 + 4 = max # of 1-2 neighbors + 3 = max # of 1-3 neighbors + 3 = max # of 1-4 neighbors + 4 = max # of special neighbors + +# Intermolecular: OPLS (JACS 118 (45), p. 11225 (1996)) +# Coulomb interactions ommitted for simplicity +pair_coeff 1 1 lj/cut 0.0028619844 3.5 # CT +pair_coeff 2 2 lj/cut 0.0013009018 2.5 # HC +pair_coeff 1 2 lj/cut 0.0019295487 2.95 +pair_modify shift no +# change exclusion settings for lj/cut only: exclude bonded pairs +pair_modify pair lj/cut special lj/coul 0.0 0.0 0.0 + +# Intramolecular +# Tell QUIP to pretend this is silane (which is covered by the parameter file) +pair_coeff * * quip sw_example.xml "IP SW" 14 1 +bond_style none +angle_style none + +fix 1 all nve + +# Include diagnostics that allow us to compare to a pure QUIP run +compute equip all pair quip +compute evdw all pair lj/cut +compute vir all pressure NULL virial + +thermo_style custom step epair ke etotal temp press c_vir c_evdw c_equip +thermo 1 + +# dump 1 all custom 1 dump.molecular id type x y z fx fy fz +# dump_modify 1 sort id + +run 10 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 10 + ghost atom cutoff = 10 + binsize = 5, bins = 2 2 2 + 2 neighbor lists, perpetual/occasional/extra = 2 0 0 + (1) pair lj/cut, perpetual, half/full from (2) + attributes: half, newton on + pair build: halffull/newton + stencil: none + bin: none + (2) pair quip, perpetual + attributes: full, newton on + pair build: full/bin + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 8.26 | 8.386 | 8.762 Mbytes +Step E_pair KinEng TotEng Temp Press c_vir c_evdw c_equip + 0 -5.3530213 0 -5.3530213 0 518847.56 518847.56 -0.10904079 -5.2439805 + 1 -5.9384459 0.58384822 -5.3545977 115.81657 517370.5 516488.87 -0.10783656 -5.8306093 + 2 -7.669616 2.3104051 -5.3592109 458.30954 512986.36 509497.58 -0.10422283 -7.5653932 + 3 -10.473314 5.1069211 -5.3663924 1013.0477 505833.04 498121.43 -0.098049469 -10.375264 + 4 -14.234705 8.859182 -5.3755227 1757.3747 496127.44 482749.79 -0.089147485 -14.145557 + 5 -18.806851 13.420941 -5.3859098 2662.28 484148.76 463882.72 -0.077305196 -18.729546 + 6 -24.021727 18.625147 -5.3965797 3694.6259 470219.95 442095.39 -0.06194509 -23.959782 + 7 -29.702647 24.295529 -5.4071176 4819.446 454683.57 417996.56 -0.042859727 -29.659787 + 8 -35.67405 30.257258 -5.4167913 6002.0599 437887.03 392197.62 -0.019248651 -35.654801 + 9 -41.771047 36.345757 -5.4252893 7209.8209 420163.51 365280.27 0.0096063065 -41.780653 + 10 -47.845522 42.413161 -5.4323614 8413.3973 401821.91 337776.7 0.044743702 -47.890266 +Loop time of 0.0506847 on 4 procs for 10 steps with 40 atoms + +Performance: 1.705 ns/day, 14.079 hours/ns, 197.298 timesteps/s +94.4% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.04216 | 0.045656 | 0.049349 | 1.2 | 90.08 +Bond | 1.9073e-06 | 2.4438e-06 | 2.861e-06 | 0.0 | 0.00 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.00068545 | 0.004438 | 0.0079191 | 3.9 | 8.76 +Output | 0.00048304 | 0.00053334 | 0.00060964 | 0.0 | 1.05 +Modify | 1.1444e-05 | 1.4424e-05 | 1.9312e-05 | 0.0 | 0.03 +Other | | 4.047e-05 | | | 0.08 + +Nlocal: 10 ave 15 max 6 min +Histogram: 1 0 0 1 1 0 0 0 0 1 +Nghost: 878 ave 948 max 812 min +Histogram: 1 0 1 0 0 0 1 0 0 1 +Neighs: 1192 ave 1764 max 731 min +Histogram: 1 0 0 1 1 0 0 0 0 1 +FullNghs: 2384 ave 3527 max 1439 min +Histogram: 1 0 0 1 1 0 0 0 0 1 + +Total # of neighbors = 9536 +Ave neighs/atom = 238.4 +Ave special neighs/atom = 4 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.sw.g++.1 b/examples/USER/quip/log.24Jul17.sw.g++.1 new file mode 100644 index 0000000000..c8115f4cfc --- /dev/null +++ b/examples/USER/quip/log.24Jul17.sw.g++.1 @@ -0,0 +1,83 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of SW potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_sw + orthogonal box = (0 0 0) to (5.431 5.431 5.431) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 8 atoms + +pair_style quip +pair_coeff * * sw_example.xml "IP SW" 14 + +velocity all create 10.0 355311 +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.sw id fx fy fz + +run 100 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.2258 + ghost atom cutoff = 4.2258 + binsize = 2.1129, bins = 3 3 3 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.684 | 2.684 | 2.684 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 10 -34.68 0 -34.670952 32.206289 + 10 4.5659178 -34.675073 0 -34.670942 46.253731 + 20 1.606683 -34.672391 0 -34.670937 44.736892 + 30 6.7007748 -34.677011 0 -34.670948 16.403049 + 40 5.682757 -34.676087 0 -34.670945 18.696408 + 50 2.2140716 -34.672942 0 -34.670939 37.592282 + 60 5.0475382 -34.675512 0 -34.670944 37.331666 + 70 7.0990979 -34.677369 0 -34.670946 40.533757 + 80 5.7306189 -34.676128 0 -34.670943 47.748813 + 90 5.0895648 -34.675549 0 -34.670944 38.092721 + 100 4.1070919 -34.674659 0 -34.670943 28.737864 +Loop time of 0.384233 on 1 procs for 100 steps with 8 atoms + +Performance: 22.486 ns/day, 1.067 hours/ns, 260.259 timesteps/s +94.6% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.38365 | 0.38365 | 0.38365 | 0.0 | 99.85 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.00017333 | 0.00017333 | 0.00017333 | 0.0 | 0.05 +Output | 0.00014162 | 0.00014162 | 0.00014162 | 0.0 | 0.04 +Modify | 7.081e-05 | 7.081e-05 | 7.081e-05 | 0.0 | 0.02 +Other | | 0.0001957 | | | 0.05 + +Nlocal: 8 ave 8 max 8 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 162 ave 162 max 162 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 128 ave 128 max 128 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 128 +Ave neighs/atom = 16 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 diff --git a/examples/USER/quip/log.24Jul17.sw.g++.4 b/examples/USER/quip/log.24Jul17.sw.g++.4 new file mode 100644 index 0000000000..d7306c7055 --- /dev/null +++ b/examples/USER/quip/log.24Jul17.sw.g++.4 @@ -0,0 +1,83 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of SW potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_sw + orthogonal box = (0 0 0) to (5.431 5.431 5.431) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 8 atoms + +pair_style quip +pair_coeff * * sw_example.xml "IP SW" 14 + +velocity all create 10.0 355311 +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.sw id fx fy fz + +run 100 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.2258 + ghost atom cutoff = 4.2258 + binsize = 2.1129, bins = 3 3 3 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.698 | 2.698 | 2.698 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 10 -34.68 0 -34.670952 32.206289 + 10 4.5659178 -34.675073 0 -34.670942 46.253731 + 20 1.606683 -34.672391 0 -34.670937 44.736892 + 30 6.7007748 -34.677011 0 -34.670948 16.403049 + 40 5.682757 -34.676087 0 -34.670945 18.696408 + 50 2.2140716 -34.672942 0 -34.670939 37.592282 + 60 5.0475382 -34.675512 0 -34.670944 37.331666 + 70 7.0990979 -34.677369 0 -34.670946 40.533757 + 80 5.7306189 -34.676128 0 -34.670943 47.748813 + 90 5.0895648 -34.675549 0 -34.670944 38.092721 + 100 4.1070919 -34.674659 0 -34.670943 28.737864 +Loop time of 0.423803 on 4 procs for 100 steps with 8 atoms + +Performance: 20.387 ns/day, 1.177 hours/ns, 235.959 timesteps/s +90.6% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.39332 | 0.40011 | 0.40704 | 0.8 | 94.41 +Neigh | 0 | 0 | 0 | 0.0 | 0.00 +Comm | 0.015632 | 0.022605 | 0.029425 | 3.3 | 5.33 +Output | 0.00025702 | 0.00028491 | 0.00035429 | 0.0 | 0.07 +Modify | 7.3671e-05 | 8.1897e-05 | 8.9884e-05 | 0.0 | 0.02 +Other | | 0.0007259 | | | 0.17 + +Nlocal: 2 ave 2 max 2 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +Nghost: 113 ave 113 max 113 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 32 ave 32 max 32 min +Histogram: 4 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 128 +Ave neighs/atom = 16 +Neighbor list builds = 0 +Dangerous builds = 0 +Total wall time: 0:00:00 From 841a92c7fadadc62d340e02916a1ad65450a2c0e Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 16:03:24 -0400 Subject: [PATCH 234/293] remove unused variable --- src/balance.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/balance.cpp b/src/balance.cpp index c184a72d32..8f994466ad 100644 --- a/src/balance.cpp +++ b/src/balance.cpp @@ -782,7 +782,7 @@ void Balance::shift_setup(char *str, int nitermax_in, double thresh_in) int Balance::shift() { - int i,j,k,m,np,max; + int i,j,k,m,np; double mycost,totalcost; double *split; From 7d0d701eaf0999c874fc820112923f29aed47f1d Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 16:05:16 -0400 Subject: [PATCH 235/293] add reference outputs for QUIP/GAP example --- examples/USER/quip/log.24Jul17.gap.g++.1 | 76 ++++++++++++++++++++++++ examples/USER/quip/log.24Jul17.gap.g++.4 | 76 ++++++++++++++++++++++++ 2 files changed, 152 insertions(+) create mode 100644 examples/USER/quip/log.24Jul17.gap.g++.1 create mode 100644 examples/USER/quip/log.24Jul17.gap.g++.4 diff --git a/examples/USER/quip/log.24Jul17.gap.g++.1 b/examples/USER/quip/log.24Jul17.gap.g++.1 new file mode 100644 index 0000000000..348f2ae0cc --- /dev/null +++ b/examples/USER/quip/log.24Jul17.gap.g++.1 @@ -0,0 +1,76 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of GAP potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_gap + orthogonal box = (0 0 0) to (10.9685 10.9685 10.9685) + 1 by 1 by 1 MPI processor grid + reading atoms ... + 64 atoms + +pair_style quip +pair_coeff * * gap_example.xml "Potential xml_label=GAP_2015_2_20_0_10_54_35_765" 14 + +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.gap id fx fy fz + +run 40 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.3 + ghost atom cutoff = 4.3 + binsize = 2.15, bins = 6 6 6 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.689 | 2.689 | 2.689 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 0 -10412.677 0 -10412.677 -107490.01 + 10 173.98393 -10414.096 0 -10412.679 -91270.969 + 20 417.38493 -10416.08 0 -10412.681 -42816.133 + 30 434.34789 -10416.217 0 -10412.68 2459.83 + 40 423.05899 -10416.124 0 -10412.679 22936.209 +Loop time of 1.83555 on 1 procs for 40 steps with 64 atoms + +Performance: 1.883 ns/day, 12.747 hours/ns, 21.792 timesteps/s +98.1% CPU use with 1 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 1.8349 | 1.8349 | 1.8349 | 0.0 | 99.96 +Neigh | 0.00022817 | 0.00022817 | 0.00022817 | 0.0 | 0.01 +Comm | 0.00013709 | 0.00013709 | 0.00013709 | 0.0 | 0.01 +Output | 9.8228e-05 | 9.8228e-05 | 9.8228e-05 | 0.0 | 0.01 +Modify | 8.6308e-05 | 8.6308e-05 | 8.6308e-05 | 0.0 | 0.00 +Other | | 0.0001223 | | | 0.01 + +Nlocal: 64 ave 64 max 64 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Nghost: 303 ave 303 max 303 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +Neighs: 0 ave 0 max 0 min +Histogram: 1 0 0 0 0 0 0 0 0 0 +FullNghs: 1080 ave 1080 max 1080 min +Histogram: 1 0 0 0 0 0 0 0 0 0 + +Total # of neighbors = 1080 +Ave neighs/atom = 16.875 +Neighbor list builds = 2 +Dangerous builds = 0 +Total wall time: 0:00:01 diff --git a/examples/USER/quip/log.24Jul17.gap.g++.4 b/examples/USER/quip/log.24Jul17.gap.g++.4 new file mode 100644 index 0000000000..a8127148b5 --- /dev/null +++ b/examples/USER/quip/log.24Jul17.gap.g++.4 @@ -0,0 +1,76 @@ +LAMMPS (24 Jul 2017) + using 1 OpenMP thread(s) per MPI task +# Test of GAP potential for Si system + +units metal +boundary p p p + +atom_style atomic + +read_data data_gap + orthogonal box = (0 0 0) to (10.9685 10.9685 10.9685) + 1 by 2 by 2 MPI processor grid + reading atoms ... + 64 atoms + +pair_style quip +pair_coeff * * gap_example.xml "Potential xml_label=GAP_2015_2_20_0_10_54_35_765" 14 + +neighbor 0.3 bin +neigh_modify delay 10 + +fix 1 all nve +thermo 10 +timestep 0.001 + +#dump 1 all custom 10 dump.gap id fx fy fz + +run 40 +Neighbor list info ... + update every 1 steps, delay 10 steps, check yes + max neighbors/atom: 2000, page size: 100000 + master list distance cutoff = 4.3 + ghost atom cutoff = 4.3 + binsize = 2.15, bins = 6 6 6 + 1 neighbor lists, perpetual/occasional/extra = 1 0 0 + (1) pair quip, perpetual + attributes: full, newton on + pair build: full/bin/atomonly + stencil: full/bin/3d + bin: standard +Per MPI rank memory allocation (min/avg/max) = 2.685 | 2.779 | 3.06 Mbytes +Step Temp E_pair E_mol TotEng Press + 0 0 -10412.677 0 -10412.677 -107490.01 + 10 173.98393 -10414.096 0 -10412.679 -91270.969 + 20 417.38493 -10416.08 0 -10412.681 -42816.133 + 30 434.34789 -10416.217 0 -10412.68 2459.83 + 40 423.05899 -10416.124 0 -10412.679 22936.209 +Loop time of 0.837345 on 4 procs for 40 steps with 64 atoms + +Performance: 4.127 ns/day, 5.815 hours/ns, 47.770 timesteps/s +96.0% CPU use with 4 MPI tasks x 1 OpenMP threads + +MPI task timing breakdown: +Section | min time | avg time | max time |%varavg| %total +--------------------------------------------------------------- +Pair | 0.73144 | 0.79214 | 0.83586 | 4.3 | 94.60 +Neigh | 5.7936e-05 | 6.5327e-05 | 7.1049e-05 | 0.0 | 0.01 +Comm | 0.00085807 | 0.044631 | 0.10532 | 18.0 | 5.33 +Output | 0.00013208 | 0.00013494 | 0.00013733 | 0.0 | 0.02 +Modify | 6.0558e-05 | 7.8678e-05 | 9.5129e-05 | 0.0 | 0.01 +Other | | 0.0002971 | | | 0.04 + +Nlocal: 16 ave 18 max 14 min +Histogram: 1 0 1 0 0 0 0 1 0 1 +Nghost: 174 ave 182 max 167 min +Histogram: 1 0 0 0 2 0 0 0 0 1 +Neighs: 0 ave 0 max 0 min +Histogram: 4 0 0 0 0 0 0 0 0 0 +FullNghs: 270 ave 294 max 237 min +Histogram: 1 0 0 0 1 0 0 0 1 1 + +Total # of neighbors = 1080 +Ave neighs/atom = 16.875 +Neighbor list builds = 2 +Dangerous builds = 0 +Total wall time: 0:00:00 From 9bfd9267fabb51d565a7689951d2424d8957ab18 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Fri, 28 Jul 2017 16:11:13 -0400 Subject: [PATCH 236/293] update and automate the QUIP configuration so that no environment variables are needed --- lib/quip/.gitignore | 1 + lib/quip/Makefile.lammps | 22 ++++++++++++++++------ lib/quip/README | 25 ++++++++++++++++++------- 3 files changed, 35 insertions(+), 13 deletions(-) create mode 100644 lib/quip/.gitignore diff --git a/lib/quip/.gitignore b/lib/quip/.gitignore new file mode 100644 index 0000000000..d6797a67fe --- /dev/null +++ b/lib/quip/.gitignore @@ -0,0 +1 @@ +/QUIP diff --git a/lib/quip/Makefile.lammps b/lib/quip/Makefile.lammps index 19ff20b073..e471d3f6f4 100644 --- a/lib/quip/Makefile.lammps +++ b/lib/quip/Makefile.lammps @@ -1,17 +1,26 @@ # Settings that the LAMMPS build will import when this package library is used -# include ${QUIP_ROOT}/Makefiles/Makefile.${QUIP_ARCH} - -F95=$(shell egrep 'F95[ ]*=' ${QUIP_ROOT}/arch/Makefile.${QUIP_ARCH} | sed 's/.*F95[ ]*=[ ]*//') +# try to guess settings assuming there is a configured QUIP git checkout inside the lib/quip directory +QUIPDIR=$(abspath ../../lib/quip/QUIP) +ifeq (${QUIP_ROOT},) + QUIP_ROOT=$(shell test -d $(QUIPDIR) && echo $(QUIPDIR)) + ifeq (${QUIP_ARCH},) + QUIP_ARCH=$(notdir $(wildcard $(QUIP_ROOT)/build/*)) + endif +else +# uncomment and set manually or set the corresponding environment variables +# QUIP_ROOT= +# QUIP_ARCH= +endif ifeq (${QUIP_ROOT},) -$(error Environment variable QUIP_ROOT must be set.) +$(error Environment or make variable QUIP_ROOT must be set.) endif - ifeq (${QUIP_ARCH},) -$(error Environment variable QUIP_ARCH must be set.) +$(error Environment or make variable QUIP_ARCH must be set.) endif +F95=$(shell egrep 'F95[ ]*=' ${QUIP_ROOT}/arch/Makefile.${QUIP_ARCH} | sed 's/.*F95[ ]*=[ ]*//') include ${QUIP_ROOT}/build/${QUIP_ARCH}/Makefile.inc include ${QUIP_ROOT}/Makefile.rules @@ -28,3 +37,4 @@ $(error fortran compiler >>${F95}<< not recognised. Edit lib/quip/Makefile.lammp endif quip_SYSPATH = -L${QUIP_ROOT}/build/${QUIP_ARCH} + diff --git a/lib/quip/README b/lib/quip/README index 94039cfa17..e6cc3903bd 100644 --- a/lib/quip/README +++ b/lib/quip/README @@ -17,7 +17,7 @@ Building LAMMPS with QUIP support: 1) Building QUIP 1.1) Obtaining QUIP -The most current release of QUIP can be obtained from github: +The most current release of QUIP can be obtained from github: $ git clone https://github.com/libAtoms/QUIP.git QUIP @@ -59,7 +59,7 @@ necessary libraries will be built. for example: $ cd QUIP -$ export QUIP_ROOT=/path/to/QUIP +$ export QUIP_ROOT=${PWD} $ export QUIP_ARCH=linux_x86_64_gfortran $ make config $ make libquip @@ -70,21 +70,32 @@ to run a test suite. 2) Building LAMMPS -LAMMPS is now shipped with the interface necessary to use QUIP potentials, but -it should be enabled first. Enter the LAMMPS directory: +Edit Makefile.lammps in the lib/quip folder, if necessary. If you +have cloned, configured, and built QUIP inside this folder, QUIP_ROOT +and QUIP_ARCH should be autodetected, even without having to set +the environment variables. Otherwise export the environment variables +as shown above or edit Makefile.lammps + +LAMMPS ships with a user package containing the interface necessary +to use QUIP potentials, but it needs to be added to the compilation +first. To do that, enter the LAMMPS source directory and type: -$ cd LAMMPS -$ cd src $ make yes-user-quip 2.2) Build LAMMPS according to the instructions on the LAMMPS website. -3) There are two example sets in examples/USER/quip: +3) There are three example sets in examples/USER/quip: - a set of input files to compute the energy of an 8-atom cubic diamond cell of silicon with the Stillinger-Weber potential. Use this to benchmark that the interface is working correctly. +- a set of input files demonstrating the use of the QUIP pair style + for a molecular system with pair style hybrid/overlay and different + exclusion settings for different pair styles. This input is + for DEMONSTRATION purposes only, and does not simulate a physically + meaningful system. + - a set of input files to demonstrate how GAP potentials are specified in a LAMMPS input file to run a short MD. The GAP parameter file gap_example.xml is intended for TESTING purposes only. Potentials can be From 13f2d39f55b17515b9637eaf4a24536d1c203f62 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 31 Jul 2017 10:34:21 -0600 Subject: [PATCH 237/293] Update Kokkos library to v2.03.13 --- lib/kokkos/CHANGELOG.md | 41 + lib/kokkos/Makefile.kokkos | 75 +- lib/kokkos/Makefile.targets | 8 +- .../algorithms/unit_tests/TestOpenMP.cpp | 13 +- .../algorithms/unit_tests/TestRandom.hpp | 38 +- .../algorithms/unit_tests/UnitTestMain.cpp | 8 +- .../benchmarks/bytes_and_flops/main.cpp | 9 +- lib/kokkos/benchmarks/gather/main.cpp | 2 +- .../benchmarks/policy_performance/Makefile | 44 + .../benchmarks/policy_performance/main.cpp | 170 + .../policy_performance/policy_perf_test.hpp | 354 + .../script_basic_testing.sh | 53 + .../policy_performance/script_sample_usage.sh | 126 + lib/kokkos/bin/hpcbind | 454 + lib/kokkos/bin/kokkos-bind | 221 + lib/kokkos/bin/runtest | 165 + lib/kokkos/cmake/kokkos.cmake | 4 + lib/kokkos/config/master_history.txt | 1 + lib/kokkos/config/query_cuda_arch.cpp | 24 + lib/kokkos/config/test_all_sandia | 11 +- .../shepard_jenkins_run_script_pthread_intel | 6 +- .../shepard_jenkins_run_script_serial_intel | 6 +- .../containers/performance_tests/Makefile | 1 - .../containers/performance_tests/TestMain.cpp | 11 +- .../performance_tests/TestOpenMP.cpp | 21 +- lib/kokkos/containers/src/Kokkos_DualView.hpp | 2 +- .../containers/src/Kokkos_DynRankView.hpp | 98 +- .../containers/src/Kokkos_DynamicView.hpp | 30 +- lib/kokkos/containers/unit_tests/TestCuda.cpp | 6 + .../containers/unit_tests/TestOpenMP.cpp | 15 +- .../containers/unit_tests/TestSerial.cpp | 6 + .../containers/unit_tests/TestThreads.cpp | 6 + .../TestViewCtorPropEmbeddedDim.hpp | 213 + .../containers/unit_tests/UnitTestMain.cpp | 10 +- lib/kokkos/core/perf_test/Makefile | 1 - lib/kokkos/core/perf_test/PerfTestMain.cpp | 10 +- .../KokkosExp_Cuda_IterateTile_Refactor.hpp | 2715 +++ lib/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp | 108 +- lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp | 96 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Impl.cpp | 85 +- .../core/src/Cuda/Kokkos_Cuda_Locks.cpp | 119 + .../core/src/Cuda/Kokkos_Cuda_Locks.hpp | 166 + .../core/src/Cuda/Kokkos_Cuda_Parallel.hpp | 404 +- .../core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp | 19 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp | 128 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp | 23 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp | 26 +- .../core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp | 133 + lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp | 6 +- .../src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp | 119 + .../core/src/KokkosExp_MDRangePolicy.hpp | 175 +- lib/kokkos/core/src/Kokkos_Atomic.hpp | 33 +- lib/kokkos/core/src/Kokkos_Concepts.hpp | 16 + lib/kokkos/core/src/Kokkos_Core.hpp | 15 +- lib/kokkos/core/src/Kokkos_Core_fwd.hpp | 3 + lib/kokkos/core/src/Kokkos_Crs.hpp | 333 + lib/kokkos/core/src/Kokkos_Cuda.hpp | 3 +- lib/kokkos/core/src/Kokkos_CudaSpace.hpp | 6 +- lib/kokkos/core/src/Kokkos_ExecPolicy.hpp | 40 + lib/kokkos/core/src/Kokkos_HBWSpace.hpp | 8 - lib/kokkos/core/src/Kokkos_HostSpace.hpp | 10 +- lib/kokkos/core/src/Kokkos_Layout.hpp | 2 + lib/kokkos/core/src/Kokkos_Macros.hpp | 11 +- lib/kokkos/core/src/Kokkos_MasterLock.hpp | 73 + lib/kokkos/core/src/Kokkos_MemoryPool.hpp | 182 +- lib/kokkos/core/src/Kokkos_MemoryTraits.hpp | 16 +- lib/kokkos/core/src/Kokkos_OpenMP.hpp | 172 +- lib/kokkos/core/src/Kokkos_Parallel.hpp | 64 +- .../core/src/Kokkos_Parallel_Reduce.hpp | 19 +- lib/kokkos/core/src/Kokkos_Serial.hpp | 228 + lib/kokkos/core/src/Kokkos_TaskScheduler.hpp | 108 +- lib/kokkos/core/src/Kokkos_UniqueToken.hpp | 88 + lib/kokkos/core/src/Kokkos_View.hpp | 233 +- .../core/src/Kokkos_WorkGraphPolicy.hpp | 265 + .../core/src/OpenMP/Kokkos_OpenMP_Exec.cpp | 431 +- .../core/src/OpenMP/Kokkos_OpenMP_Exec.hpp | 490 +- .../src/OpenMP/Kokkos_OpenMP_Parallel.hpp | 419 +- .../core/src/OpenMP/Kokkos_OpenMP_Task.cpp | 94 +- .../core/src/OpenMP/Kokkos_OpenMP_Task.hpp | 4 +- .../core/src/OpenMP/Kokkos_OpenMP_Team.hpp | 245 + .../OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp | 107 + .../OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp | 28 +- .../core/src/Qthreads/Kokkos_QthreadsExec.hpp | 2 +- .../core/src/Threads/Kokkos_ThreadsExec.cpp | 12 +- .../core/src/Threads/Kokkos_ThreadsExec.hpp | 70 +- .../core/src/Threads/Kokkos_ThreadsTeam.hpp | 6 +- .../src/Threads/Kokkos_Threads_Parallel.hpp | 267 + .../Kokkos_Threads_WorkGraphPolicy.hpp | 115 + .../src/impl/KokkosExp_Host_IterateTile.hpp | 566 +- .../core/src/impl/Kokkos_AnalyzePolicy.hpp | 35 +- .../Kokkos_Atomic_Compare_Exchange_Strong.hpp | 34 +- .../core/src/impl/Kokkos_Atomic_Decrement.hpp | 19 + .../core/src/impl/Kokkos_Atomic_Exchange.hpp | 32 + .../core/src/impl/Kokkos_Atomic_Fetch_Add.hpp | 62 +- .../core/src/impl/Kokkos_Atomic_Fetch_And.hpp | 32 +- .../core/src/impl/Kokkos_Atomic_Fetch_Or.hpp | 32 +- .../core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp | 44 +- .../core/src/impl/Kokkos_Atomic_Increment.hpp | 16 + lib/kokkos/core/src/impl/Kokkos_Core.cpp | 20 +- .../core/src/impl/Kokkos_FunctorAdapter.hpp | 13 +- lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp | 56 - lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp | 59 - .../core/src/impl/Kokkos_HostThreadTeam.cpp | 30 +- .../core/src/impl/Kokkos_HostThreadTeam.hpp | 33 +- .../src/impl/Kokkos_Profiling_Interface.cpp | 102 +- .../src/impl/Kokkos_Profiling_Interface.hpp | 53 +- .../core/src/impl/Kokkos_Rendezvous.cpp | 208 + .../core/src/impl/Kokkos_Rendezvous.hpp | 87 + lib/kokkos/core/src/impl/Kokkos_Serial.cpp | 4 +- .../core/src/impl/Kokkos_Serial_Task.cpp | 4 +- .../core/src/impl/Kokkos_Serial_Task.hpp | 2 +- .../impl/Kokkos_Serial_WorkGraphPolicy.hpp | 102 + .../core/src/impl/Kokkos_SharedAlloc.cpp | 24 +- .../core/src/impl/Kokkos_SharedAlloc.hpp | 16 +- lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp | 210 + ...okkos_spinwait.hpp => Kokkos_Spinwait.hpp} | 17 + lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp | 606 +- .../core/src/impl/Kokkos_TaskQueue_impl.hpp | 86 +- lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp | 14 +- lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp | 21 + .../core/src/impl/Kokkos_ViewMapping.hpp | 137 +- lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp | 12 +- lib/kokkos/core/src/impl/Kokkos_spinwait.cpp | 183 - lib/kokkos/core/unit_test/CMakeLists.txt | 6 + lib/kokkos/core/unit_test/Makefile | 8 +- lib/kokkos/core/unit_test/TestAggregate.hpp | 2 +- .../unit_test/TestDefaultDeviceTypeInit.hpp | 21 +- lib/kokkos/core/unit_test/TestMDRange.hpp | 882 +- lib/kokkos/core/unit_test/TestMemoryPool.hpp | 228 +- lib/kokkos/core/unit_test/TestRange.hpp | 25 + lib/kokkos/core/unit_test/TestResize.hpp | 140 + .../core/unit_test/TestTaskScheduler.hpp | 32 +- lib/kokkos/core/unit_test/TestTeamVector.hpp | 12 + lib/kokkos/core/unit_test/TestTile.hpp | 2 +- lib/kokkos/core/unit_test/TestUniqueToken.hpp | 138 + .../unit_test/TestViewCtorPropEmbeddedDim.hpp | 160 + .../core/unit_test/TestViewMapping_a.hpp | 114 +- lib/kokkos/core/unit_test/TestViewSubview.hpp | 224 +- lib/kokkos/core/unit_test/TestWorkGraph.hpp | 172 + lib/kokkos/core/unit_test/UnitTestMain.cpp | 1 + .../core/unit_test/UnitTestMainInit.cpp | 2 + .../core/unit_test/cuda/TestCuda_Other.cpp | 2 + .../unit_test/cuda/TestCuda_UniqueToken.cpp | 46 + .../unit_test/cuda/TestCuda_WorkGraph.cpp | 45 + .../default/TestDefaultDeviceTypeResize.cpp | 57 + .../core/unit_test/openmp/TestOpenMP.hpp | 19 +- .../unit_test/openmp/TestOpenMP_Other.cpp | 90 + .../openmp/TestOpenMP_UniqueToken.cpp | 46 + .../unit_test/openmp/TestOpenMP_WorkGraph.cpp | 45 + .../unit_test/serial/TestSerial_Other.cpp | 2 + .../unit_test/serial/TestSerial_WorkGraph.cpp | 45 + .../unit_test/threads/TestThreads_Other.cpp | 2 + .../threads/TestThreads_WorkGraph.cpp | 45 + lib/kokkos/example/cmake_build/CMakeLists.txt | 2 + lib/kokkos/example/feint/main.cpp | 22 +- .../example/global_2_local_ids/G2L_Main.cpp | 11 +- lib/kokkos/example/grow_array/main.cpp | 2 +- .../example/tutorial/03_simple_view/Makefile | 1 + .../example/tutorial/Advanced_Views/Makefile | 86 +- .../example/tutorial/Algorithms/Makefile | 12 +- .../Hierarchical_Parallelism/Makefile | 60 +- lib/kokkos/example/tutorial/Makefile | 132 +- .../tutorial/launch_bounds/CMakeLists.txt | 10 + .../example/tutorial/launch_bounds/Makefile | 56 + .../launch_bounds/launch_bounds_reduce.cpp | 173 + lib/kokkos/generate_makefile.bash | 191 +- lib/kokkos/tpls/gtest/gtest/LICENSE | 28 + lib/kokkos/tpls/gtest/gtest/README | 13 + lib/kokkos/tpls/gtest/gtest/gtest-all.cc | 9594 ++++++++ lib/kokkos/tpls/gtest/gtest/gtest-test-part.h | 1 + lib/kokkos/tpls/gtest/gtest/gtest.h | 20065 ++++++++++++++++ 171 files changed, 44039 insertions(+), 2807 deletions(-) create mode 100644 lib/kokkos/benchmarks/policy_performance/Makefile create mode 100644 lib/kokkos/benchmarks/policy_performance/main.cpp create mode 100644 lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp create mode 100755 lib/kokkos/benchmarks/policy_performance/script_basic_testing.sh create mode 100755 lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh create mode 100755 lib/kokkos/bin/hpcbind create mode 100755 lib/kokkos/bin/kokkos-bind create mode 100755 lib/kokkos/bin/runtest create mode 100644 lib/kokkos/config/query_cuda_arch.cpp create mode 100644 lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp create mode 100644 lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp create mode 100644 lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp create mode 100644 lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp create mode 100644 lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp create mode 100644 lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp create mode 100644 lib/kokkos/core/src/Kokkos_Crs.hpp create mode 100644 lib/kokkos/core/src/Kokkos_MasterLock.hpp create mode 100644 lib/kokkos/core/src/Kokkos_UniqueToken.hpp create mode 100644 lib/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp create mode 100644 lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Team.hpp create mode 100644 lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp create mode 100644 lib/kokkos/core/src/Threads/Kokkos_Threads_WorkGraphPolicy.hpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Rendezvous.cpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Rendezvous.hpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Serial_WorkGraphPolicy.hpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp rename lib/kokkos/core/src/impl/{Kokkos_spinwait.hpp => Kokkos_Spinwait.hpp} (82%) delete mode 100644 lib/kokkos/core/src/impl/Kokkos_spinwait.cpp create mode 100644 lib/kokkos/core/unit_test/TestResize.hpp create mode 100644 lib/kokkos/core/unit_test/TestUniqueToken.hpp create mode 100644 lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp create mode 100644 lib/kokkos/core/unit_test/TestWorkGraph.hpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_WorkGraph.cpp create mode 100644 lib/kokkos/core/unit_test/default/TestDefaultDeviceTypeResize.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_WorkGraph.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_WorkGraph.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_WorkGraph.cpp create mode 100644 lib/kokkos/example/tutorial/launch_bounds/CMakeLists.txt create mode 100644 lib/kokkos/example/tutorial/launch_bounds/Makefile create mode 100644 lib/kokkos/example/tutorial/launch_bounds/launch_bounds_reduce.cpp create mode 100644 lib/kokkos/tpls/gtest/gtest/LICENSE create mode 100644 lib/kokkos/tpls/gtest/gtest/README create mode 100644 lib/kokkos/tpls/gtest/gtest/gtest-all.cc create mode 120000 lib/kokkos/tpls/gtest/gtest/gtest-test-part.h create mode 100644 lib/kokkos/tpls/gtest/gtest/gtest.h diff --git a/lib/kokkos/CHANGELOG.md b/lib/kokkos/CHANGELOG.md index acb54ff22f..3fe9e46111 100644 --- a/lib/kokkos/CHANGELOG.md +++ b/lib/kokkos/CHANGELOG.md @@ -1,5 +1,46 @@ # Change Log +## [2.03.13](https://github.com/kokkos/kokkos/tree/2.03.13) (2017-07-27) +[Full Changelog](https://github.com/kokkos/kokkos/compare/2.03.05...2.03.13) + +**Implemented enhancements:** + +- Disallow enabling both OpenMP and Threads in the same executable [\#406](https://github.com/kokkos/kokkos/issues/406) +- Make Kokkos::OpenMP respect OMP environment even if hwloc is available [\#630](https://github.com/kokkos/kokkos/issues/630) +- Improve Atomics Performance on KNL/Broadwell where PREFETCHW/RFO is Available [\#898](https://github.com/kokkos/kokkos/issues/898) +- Kokkos::resize should test whether dimensions have changed before resizing [\#904](https://github.com/kokkos/kokkos/issues/904) +- Develop performance-regression/acceptance tests [\#737](https://github.com/kokkos/kokkos/issues/737) +- Make the deep\_copy Profiling hook a start/end system [\#890](https://github.com/kokkos/kokkos/issues/890) +- Add deep\_copy Profiling hook [\#843](https://github.com/kokkos/kokkos/issues/843) +- Append tag name to parallel construct name for Profiling [\#842](https://github.com/kokkos/kokkos/issues/842) +- Add view label to `View bounds error` message for CUDA backend [\#870](https://github.com/kokkos/kokkos/issues/870) +- Disable printing the loaded profiling library [\#824](https://github.com/kokkos/kokkos/issues/824) +- "Declared but never referenced" warnings [\#853](https://github.com/kokkos/kokkos/issues/853) +- Warnings about lock\_address\_cuda\_space [\#852](https://github.com/kokkos/kokkos/issues/852) +- WorkGraph execution policy [\#771](https://github.com/kokkos/kokkos/issues/771) +- Simplify makefiles by guarding compilation with appropriate KOKKOS\_ENABLE\_\#\#\# macros [\#716](https://github.com/kokkos/kokkos/issues/716) +- Cmake build: wrong include install directory [\#668](https://github.com/kokkos/kokkos/issues/668) +- Derived View type and allocation [\#566](https://github.com/kokkos/kokkos/issues/566) +- Fix Compiler warnings when compiling core unit tests for Cuda [\#214](https://github.com/kokkos/kokkos/issues/214) + +**Fixed bugs:** + +- Out-of-bounds read in Kokkos\_Layout.hpp [\#975](https://github.com/kokkos/kokkos/issues/975) +- CudaClang: Fix failing test with Clang 4.0 [\#941](https://github.com/kokkos/kokkos/issues/941) +- Respawn when memory pool allocation fails \(not available memory\) [\#940](https://github.com/kokkos/kokkos/issues/940) +- Memory pool aborts on zero allocation request, returns NULL for \< minimum [\#939](https://github.com/kokkos/kokkos/issues/939) +- Error with TaskScheduler query of underlying memory pool [\#917](https://github.com/kokkos/kokkos/issues/917) +- Profiling::\*Callee static variables declared in header [\#863](https://github.com/kokkos/kokkos/issues/863) +- calling \*Space::name\(\) causes compile error [\#862](https://github.com/kokkos/kokkos/issues/862) +- bug in Profiling::deallocateData [\#860](https://github.com/kokkos/kokkos/issues/860) +- task\_depend test failing, CUDA 8.0 + Pascal + RDC [\#829](https://github.com/kokkos/kokkos/issues/829) +- \[develop branch\] Standalone cmake issues [\#826](https://github.com/kokkos/kokkos/issues/826) +- Kokkos CUDA failes to compile with OMPI\_CXX and MPICH\_CXX wrappers [\#776](https://github.com/kokkos/kokkos/issues/776) +- Task Team reduction on Pascal [\#767](https://github.com/kokkos/kokkos/issues/767) +- CUDA stack overflow with TaskDAG test [\#758](https://github.com/kokkos/kokkos/issues/758) +- TeamVector test on Cuda [\#670](https://github.com/kokkos/kokkos/issues/670) +- Clang 4.0 Cuda Build broken again [\#560](https://github.com/kokkos/kokkos/issues/560) + ## [2.03.05](https://github.com/kokkos/kokkos/tree/2.03.05) (2017-05-27) [Full Changelog](https://github.com/kokkos/kokkos/compare/2.03.00...2.03.05) diff --git a/lib/kokkos/Makefile.kokkos b/lib/kokkos/Makefile.kokkos index 24cd772e00..acb6c36134 100644 --- a/lib/kokkos/Makefile.kokkos +++ b/lib/kokkos/Makefile.kokkos @@ -33,6 +33,7 @@ KOKKOS_INTERNAL_USE_LIBRT := $(strip $(shell echo $(KOKKOS_USE_TPLS) | grep "lib KOKKOS_INTERNAL_USE_MEMKIND := $(strip $(shell echo $(KOKKOS_USE_TPLS) | grep "experimental_memkind" | wc -l)) # Check for advanced settings. +KOKKOS_INTERNAL_ENABLE_COMPILER_WARNINGS := $(strip $(shell echo $(KOKKOS_OPTIONS) | grep "compiler_warnings" | wc -l)) KOKKOS_INTERNAL_OPT_RANGE_AGGRESSIVE_VECTORIZATION := $(strip $(shell echo $(KOKKOS_OPTIONS) | grep "aggressive_vectorization" | wc -l)) KOKKOS_INTERNAL_DISABLE_PROFILING := $(strip $(shell echo $(KOKKOS_OPTIONS) | grep "disable_profiling" | wc -l)) KOKKOS_INTERNAL_DISABLE_DUALVIEW_MODIFY_CHECK := $(strip $(shell echo $(KOKKOS_OPTIONS) | grep "disable_dualview_modify_check" | wc -l)) @@ -78,6 +79,12 @@ KOKKOS_INTERNAL_COMPILER_PGI := $(strip $(shell $(CXX) --version 2 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 $(CXX) --version 2>&1 | grep nvcc | wc -l)) +ifneq ($(OMPI_CXX),) + KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell $(OMPI_CXX) --version 2>&1 | grep nvcc | wc -l)) +endif +ifneq ($(MPICH_CXX),) + KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell $(MPICH_CXX) --version 2>&1 | grep nvcc | wc -l)) +endif KOKKOS_INTERNAL_COMPILER_CLANG := $(strip $(shell $(CXX) --version 2>&1 | grep clang | wc -l)) KOKKOS_INTERNAL_COMPILER_APPLE_CLANG := $(strip $(shell $(CXX) --version 2>&1 | grep "apple-darwin" | wc -l)) ifneq ($(OMPI_CXX),) @@ -111,6 +118,36 @@ ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) endif endif +# Set compiler warnings flags. +ifeq ($(KOKKOS_INTERNAL_ENABLE_COMPILER_WARNINGS), 1) + ifeq ($(KOKKOS_INTERNAL_COMPILER_PGI), 1) + # TODO check if PGI accepts GNU style warnings + KOKKOS_INTERNAL_COMPILER_WARNINGS = + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) + KOKKOS_INTERNAL_COMPILER_WARNINGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wuninitialized + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_APPLE_CLANG), 1) + KOKKOS_INTERNAL_COMPILER_WARNINGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wuninitialized + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_XL), 1) + KOKKOS_INTERNAL_COMPILER_WARNINGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wuninitialized + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_CRAY), 1) + # TODO check if cray accepts GNU style warnings + KOKKOS_INTERNAL_COMPILER_WARNINGS = + else + #gcc + KOKKOS_INTERNAL_COMPILER_WARNINGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wignored-qualifiers -Wempty-body -Wclobbered -Wuninitialized + endif + endif + endif + endif + endif +else + KOKKOS_INTERNAL_COMPILER_WARNINGS = +endif + # Set OpenMP flags. ifeq ($(KOKKOS_INTERNAL_COMPILER_PGI), 1) KOKKOS_INTERNAL_OPENMP_FLAG := -mp @@ -162,6 +199,7 @@ endif # Intel based. KOKKOS_INTERNAL_USE_ARCH_KNC := $(strip $(shell echo $(KOKKOS_ARCH) | grep KNC | wc -l)) +KOKKOS_INTERNAL_USE_ARCH_WSM := $(strip $(shell echo $(KOKKOS_ARCH) | grep WSM | wc -l)) KOKKOS_INTERNAL_USE_ARCH_SNB := $(strip $(shell echo $(KOKKOS_ARCH) | grep SNB | wc -l)) KOKKOS_INTERNAL_USE_ARCH_HSW := $(strip $(shell echo $(KOKKOS_ARCH) | grep HSW | wc -l)) KOKKOS_INTERNAL_USE_ARCH_BDW := $(strip $(shell echo $(KOKKOS_ARCH) | grep BDW | wc -l)) @@ -229,13 +267,14 @@ KOKKOS_INTERNAL_USE_ARCH_IBM := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_ KOKKOS_INTERNAL_USE_ARCH_AMDAVX := $(strip $(shell echo $(KOKKOS_ARCH) | grep AMDAVX | wc -l)) # Any AVX? +KOKKOS_INTERNAL_USE_ARCH_SSE42 := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_WSM) | bc )) KOKKOS_INTERNAL_USE_ARCH_AVX := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_SNB)+$(KOKKOS_INTERNAL_USE_ARCH_AMDAVX) | bc )) KOKKOS_INTERNAL_USE_ARCH_AVX2 := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_HSW)+$(KOKKOS_INTERNAL_USE_ARCH_BDW) | bc )) KOKKOS_INTERNAL_USE_ARCH_AVX512MIC := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_KNL) | bc )) KOKKOS_INTERNAL_USE_ARCH_AVX512XEON := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_SKX) | bc )) # Decide what ISA level we are able to support. -KOKKOS_INTERNAL_USE_ISA_X86_64 := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_SNB)+$(KOKKOS_INTERNAL_USE_ARCH_HSW)+$(KOKKOS_INTERNAL_USE_ARCH_BDW)+$(KOKKOS_INTERNAL_USE_ARCH_KNL)+$(KOKKOS_INTERNAL_USE_ARCH_SKX) | bc )) +KOKKOS_INTERNAL_USE_ISA_X86_64 := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_WSM)+$(KOKKOS_INTERNAL_USE_ARCH_SNB)+$(KOKKOS_INTERNAL_USE_ARCH_HSW)+$(KOKKOS_INTERNAL_USE_ARCH_BDW)+$(KOKKOS_INTERNAL_USE_ARCH_KNL)+$(KOKKOS_INTERNAL_USE_ARCH_SKX) | bc )) KOKKOS_INTERNAL_USE_ISA_KNC := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_KNC) | bc )) KOKKOS_INTERNAL_USE_ISA_POWERPCLE := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_POWER8)+$(KOKKOS_INTERNAL_USE_ARCH_POWER9) | bc )) @@ -243,7 +282,7 @@ KOKKOS_INTERNAL_USE_ISA_POWERPCLE := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ KOKKOS_INTERNAL_USE_TM := $(strip $(shell echo $(KOKKOS_INTERNAL_USE_ARCH_BDW)+$(KOKKOS_INTERNAL_USE_ARCH_SKX) | bc )) # Incompatible flags? -KOKKOS_INTERNAL_USE_ARCH_MULTIHOST := $(strip $(shell echo "$(KOKKOS_INTERNAL_USE_ARCH_AVX)+$(KOKKOS_INTERNAL_USE_ARCH_AVX2)+$(KOKKOS_INTERNAL_USE_ARCH_AVX512MIC)+$(KOKKOS_INTERNAL_USE_ARCH_AVX512XEON)+$(KOKKOS_INTERNAL_USE_ARCH_KNC)+$(KOKKOS_INTERNAL_USE_ARCH_IBM)+$(KOKKOS_INTERNAL_USE_ARCH_ARM)>1" | bc )) +KOKKOS_INTERNAL_USE_ARCH_MULTIHOST := $(strip $(shell echo "$(KOKKOS_INTERNAL_USE_ARCH_SSE42)+$(KOKKOS_INTERNAL_USE_ARCH_AVX)+$(KOKKOS_INTERNAL_USE_ARCH_AVX2)+$(KOKKOS_INTERNAL_USE_ARCH_AVX512MIC)+$(KOKKOS_INTERNAL_USE_ARCH_AVX512XEON)+$(KOKKOS_INTERNAL_USE_ARCH_KNC)+$(KOKKOS_INTERNAL_USE_ARCH_IBM)+$(KOKKOS_INTERNAL_USE_ARCH_ARM)>1" | bc )) KOKKOS_INTERNAL_USE_ARCH_MULTIGPU := $(strip $(shell echo "$(KOKKOS_INTERNAL_USE_ARCH_NVIDIA)>1" | bc)) ifeq ($(KOKKOS_INTERNAL_USE_ARCH_MULTIHOST), 1) @@ -257,12 +296,10 @@ endif KOKKOS_CPPFLAGS = -I./ -I$(KOKKOS_PATH)/core/src -I$(KOKKOS_PATH)/containers/src -I$(KOKKOS_PATH)/algorithms/src -# No warnings: KOKKOS_CXXFLAGS = -# INTEL and CLANG warnings: -#KOKKOS_CXXFLAGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wuninitialized -# GCC warnings: -#KOKKOS_CXXFLAGS = -Wall -Wshadow -pedantic -Wsign-compare -Wtype-limits -Wuninitialized -Wignored-qualifiers -Wempty-body -Wclobbered +ifeq ($(KOKKOS_INTERNAL_ENABLE_COMPILER_WARNINGS), 1) + KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_COMPILER_WARNINGS) +endif KOKKOS_LIBS = -lkokkos -ldl KOKKOS_LDFLAGS = -L$(shell pwd) @@ -486,6 +523,28 @@ ifeq ($(KOKKOS_INTERNAL_USE_ARCH_ARMV8_THUNDERX), 1) endif endif +ifeq ($(KOKKOS_INTERNAL_USE_ARCH_SSE42), 1) + tmp := $(shell echo "\#define KOKKOS_ARCH_SSE42 1" >> KokkosCore_config.tmp ) + + ifeq ($(KOKKOS_INTERNAL_COMPILER_INTEL), 1) + KOKKOS_CXXFLAGS += -xSSE4.2 + KOKKOS_LDFLAGS += -xSSE4.2 + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_CRAY), 1) + + else + ifeq ($(KOKKOS_INTERNAL_COMPILER_PGI), 1) + KOKKOS_CXXFLAGS += -tp=nehalem + KOKKOS_LDFLAGS += -tp=nehalem + else + # Assume that this is a really a GNU compiler. + KOKKOS_CXXFLAGS += -msse4.2 + KOKKOS_LDFLAGS += -msse4.2 + endif + endif + endif +endif + ifeq ($(KOKKOS_INTERNAL_USE_ARCH_AVX), 1) tmp := $(shell echo "\#define KOKKOS_ARCH_AVX 1" >> KokkosCore_config.tmp ) @@ -689,7 +748,7 @@ ifeq ($(KOKKOS_INTERNAL_USE_CUDA), 1) endif endif -KOKKOS_INTERNAL_LS_CONFIG := $(shell ls KokkosCore_config.h) +KOKKOS_INTERNAL_LS_CONFIG := $(shell ls KokkosCore_config.h 2>&1) ifeq ($(KOKKOS_INTERNAL_LS_CONFIG), KokkosCore_config.h) KOKKOS_INTERNAL_NEW_CONFIG := $(strip $(shell diff KokkosCore_config.h KokkosCore_config.tmp | grep define | wc -l)) else diff --git a/lib/kokkos/Makefile.targets b/lib/kokkos/Makefile.targets index 3cb52a04cd..a9341a907c 100644 --- a/lib/kokkos/Makefile.targets +++ b/lib/kokkos/Makefile.targets @@ -20,8 +20,10 @@ Kokkos_TaskQueue.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Ta $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_TaskQueue.cpp Kokkos_HostThreadTeam.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_HostThreadTeam.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_HostThreadTeam.cpp -Kokkos_spinwait.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_spinwait.cpp - $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_spinwait.cpp +Kokkos_Spinwait.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Spinwait.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Spinwait.cpp +Kokkos_Rendezvous.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Rendezvous.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Rendezvous.cpp Kokkos_Profiling_Interface.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Profiling_Interface.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Profiling_Interface.cpp Kokkos_SharedAlloc.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_SharedAlloc.cpp @@ -36,6 +38,8 @@ Kokkos_CudaSpace.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/Cuda/Kokkos_Cu $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/Cuda/Kokkos_CudaSpace.cpp Kokkos_Cuda_Task.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/Cuda/Kokkos_Cuda_Task.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/Cuda/Kokkos_Cuda_Task.cpp +Kokkos_Cuda_Locks.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/Cuda/Kokkos_Cuda_Locks.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/Cuda/Kokkos_Cuda_Locks.cpp endif ifeq ($(KOKKOS_INTERNAL_USE_PTHREADS), 1) diff --git a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp index 1e7ee68549..c2c118ce1a 100644 --- a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp @@ -61,14 +61,19 @@ protected: { std::cout << std::setprecision(5) << std::scientific; - unsigned threads_count = omp_get_max_threads(); + int threads_count = 0; + #pragma omp parallel + { + #pragma omp atomic + ++threads_count; + } - if ( Kokkos::hwloc::available() ) { - threads_count = Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa(); + if (threads_count > 3) { + threads_count /= 2; } Kokkos::OpenMP::initialize( threads_count ); + Kokkos::OpenMP::print_configuration( std::cout ); } static void TearDownTestCase() diff --git a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp index 9cf02f74b4..2771f1793d 100644 --- a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp +++ b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp @@ -1,12 +1,12 @@ //@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: @@ -35,7 +35,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER @@ -283,12 +283,12 @@ struct test_random_scalar { RandomGenerator& pool, unsigned int num_draws) { - using std::cerr; + using std::cout; using std::endl; using Kokkos::parallel_reduce; { - cerr << " -- Testing randomness properties" << endl; + cout << " -- Testing randomness properties" << endl; RandomProperties result; typedef test_random_functor functor_type; @@ -307,7 +307,7 @@ struct test_random_scalar { ( 1.5*tolerance > variance_eps)) ? 1:0; pass_covar = ((-2.0*tolerance < covariance_eps) && ( 2.0*tolerance > covariance_eps)) ? 1:0; - cerr << "Pass: " << pass_mean + cout << "Pass: " << pass_mean << " " << pass_var << " " << mean_eps << " " << variance_eps @@ -315,7 +315,7 @@ struct test_random_scalar { << " || " << tolerance << endl; } { - cerr << " -- Testing 1-D histogram" << endl; + cout << " -- Testing 1-D histogram" << endl; RandomProperties result; typedef test_histogram1d_functor functor_type; @@ -335,7 +335,7 @@ struct test_random_scalar { pass_hist1d_covar = ((-0.06 < covariance_eps) && ( 0.06 > covariance_eps)) ? 1:0; - cerr << "Density 1D: " << mean_eps + cout << "Density 1D: " << mean_eps << " " << variance_eps << " " << (result.covariance/HIST_DIM1D/HIST_DIM1D) << " || " << tolerance @@ -348,7 +348,7 @@ struct test_random_scalar { << endl; } { - cerr << " -- Testing 3-D histogram" << endl; + cout << " -- Testing 3-D histogram" << endl; RandomProperties result; typedef test_histogram3d_functor functor_type; @@ -368,7 +368,7 @@ struct test_random_scalar { pass_hist3d_covar = ((-tolerance < covariance_eps) && ( tolerance > covariance_eps)) ? 1:0; - cerr << "Density 3D: " << mean_eps + cout << "Density 3D: " << mean_eps << " " << variance_eps << " " << result.covariance/HIST_DIM1D/HIST_DIM1D << " || " << tolerance @@ -381,18 +381,18 @@ struct test_random_scalar { template void test_random(unsigned int num_draws) { - using std::cerr; + using std::cout; using std::endl; 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(); - cerr << "Test Seed:" << ticks << endl; + cout << "Test Seed:" << ticks << endl; RandomGenerator pool(ticks); - cerr << "Test Scalar=int" << endl; + 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); @@ -406,7 +406,7 @@ void test_random(unsigned int num_draws) deep_copy(density_1d,0); deep_copy(density_3d,0); - cerr << "Test Scalar=unsigned int" << endl; + 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); @@ -420,7 +420,7 @@ void test_random(unsigned int num_draws) deep_copy(density_1d,0); deep_copy(density_3d,0); - cerr << "Test Scalar=int64_t" << endl; + 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); @@ -434,7 +434,7 @@ void test_random(unsigned int num_draws) deep_copy(density_1d,0); deep_copy(density_3d,0); - cerr << "Test Scalar=uint64_t" << endl; + 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); @@ -448,7 +448,7 @@ void test_random(unsigned int num_draws) deep_copy(density_1d,0); deep_copy(density_3d,0); - cerr << "Test Scalar=float" << endl; + 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); @@ -462,7 +462,7 @@ void test_random(unsigned int num_draws) deep_copy(density_1d,0); deep_copy(density_3d,0); - cerr << "Test Scalar=double" << endl; + 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); diff --git a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp index f952ab3db5..9e75b580bc 100644 --- a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp +++ b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp @@ -1,13 +1,13 @@ /* //@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: @@ -36,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER */ diff --git a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp index f545247212..8db5ce0eb5 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp @@ -44,12 +44,13 @@ #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"); @@ -68,7 +69,7 @@ int main(int argc, char* argv[]) { Kokkos::finalize(); return 0; } - + int P = atoi(argv[1]); int N = atoi(argv[2]); @@ -80,7 +81,7 @@ 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(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;} diff --git a/lib/kokkos/benchmarks/gather/main.cpp b/lib/kokkos/benchmarks/gather/main.cpp index 161c6f2091..88eb0493c1 100644 --- a/lib/kokkos/benchmarks/gather/main.cpp +++ b/lib/kokkos/benchmarks/gather/main.cpp @@ -44,11 +44,11 @@ #include #include #include +#include int main(int argc, char* argv[]) { Kokkos::initialize(argc,argv); - if(argc<8) { printf("Arguments: S N K D\n"); printf(" S: Scalar Type Size (1==float, 2==double, 4=complex)\n"); diff --git a/lib/kokkos/benchmarks/policy_performance/Makefile b/lib/kokkos/benchmarks/policy_performance/Makefile new file mode 100644 index 0000000000..13aef3209c --- /dev/null +++ b/lib/kokkos/benchmarks/policy_performance/Makefile @@ -0,0 +1,44 @@ +KOKKOS_PATH = ../.. +SRC = $(wildcard *.cpp) + +default: build + echo "Start Build" + +ifneq (,$(findstring Cuda,$(KOKKOS_DEVICES))) +CXX = ${KOKKOS_PATH}/bin/nvcc_wrapper +CXXFLAGS = -O3 -g +LINK = ${CXX} +LINKFLAGS = +EXE = policy_performance.cuda +KOKKOS_DEVICES = "Cuda,OpenMP" +KOKKOS_ARCH = "SNB,Kepler35" +KOKKOS_CUDA_OPTIONS+=enable_lambda +else +CXX = g++ +CXXFLAGS = -O3 -g -Wall -Werror +LINK = ${CXX} +LINKFLAGS = +EXE = policy_performance.host +KOKKOS_DEVICES = "OpenMP" +KOKKOS_ARCH = "SNB" +endif + +DEPFLAGS = -M + +OBJ = $(SRC:.cpp=.o) +LIB = + +include $(KOKKOS_PATH)/Makefile.kokkos + +build: $(EXE) + +$(EXE): $(OBJ) $(KOKKOS_LINK_DEPENDS) + $(LINK) $(KOKKOS_LDFLAGS) $(LINKFLAGS) $(EXTRA_PATH) $(OBJ) $(KOKKOS_LIBS) $(LIB) -o $(EXE) + +clean: kokkos-clean + rm -f *.o *.cuda *.host + +# Compilation rules + +%.o:%.cpp $(KOKKOS_CPP_DEPENDS) main.cpp policy_perf_test.hpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) $(EXTRA_INC) -c $< diff --git a/lib/kokkos/benchmarks/policy_performance/main.cpp b/lib/kokkos/benchmarks/policy_performance/main.cpp new file mode 100644 index 0000000000..b0ed9bb512 --- /dev/null +++ b/lib/kokkos/benchmarks/policy_performance/main.cpp @@ -0,0 +1,170 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include "policy_perf_test.hpp" + +int main(int argc, char* argv[] ) { + Kokkos::initialize(argc,argv); + + 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(" 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(" 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(" 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(" RangePolicy:\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"); + Kokkos::finalize(); + return 0; + } + + 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 thread_repeat = atoi(argv[5]); + int vector_repeat = atoi(argv[6]); + + int team_size = atoi(argv[7]); + int vector_size = atoi(argv[8]); + int schedule = atoi(argv[9]); + int test_type = atoi(argv[10]); + + int disable_verbose_output = 0; + if ( argc > 11 ) { + disable_verbose_output = atoi(argv[11]); + } + + 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 + ) + { + printf("Incorrect test_type option\n"); + Kokkos::finalize(); + return -2; + } + + 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); + + 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); + + double result_computed = 0.0; + double result_expect = 0.0; + double time = 0.0; + + 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 { + // 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); + } + } + 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 { + // 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); + } + } + + 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(); + + return 0; +} diff --git a/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp new file mode 100644 index 0000000000..8c79f3b88d --- /dev/null +++ b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp @@ -0,0 +1,354 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include + +template < class ViewType > +struct ParallelScanFunctor { + using value_type = double; + ViewType 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; + } + } +}; + +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; + typedef typename t_policy::member_type t_team; + Kokkos::Timer timer; + + for(int orep = 0; orep(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) { + // inclusive scan + val += v1(idx); + if ( final ) { + v1(idx) = val; + } + } +#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); + } + + } // end outer for loop + + time = timer.seconds(); +} //end test_policy diff --git a/lib/kokkos/benchmarks/policy_performance/script_basic_testing.sh b/lib/kokkos/benchmarks/policy_performance/script_basic_testing.sh new file mode 100755 index 0000000000..e621fffbd4 --- /dev/null +++ b/lib/kokkos/benchmarks/policy_performance/script_basic_testing.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Script to check policy_perf_test code works with each possible combo of options + +echo "Performance test results for parallel_reduce code computing sum of sequence [0,N) with various (nested) policies" + +EXECUTABLE=policy_performance + +TEAMRANGE=1000 +THREADRANGE=4 +VECTORRANGE=32 +TEAMSIZE=4 +VECTORSIZE=1 +OREPEAT=1 +MREPEAT=1 +IREPEAT=1 +SCHEDULE=1 + +SUFFIX=host +if [ -e $EXECUTABLE.$SUFFIX ] +then +SCHEDULE=1 +echo "Host tests Static schedule" +for CODE in {100,110,111,112,120,121,122,200,210,211,212,220,221,222,300,400,500} +do + OMP_PROC_BIND=true ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE +done + +SCHEDULE=2 +echo "Host tests Dynamic schedule" +for CODE in {100,110,111,112,120,121,122,200,210,211,212,220,221,222,300,400,500} +do + OMP_PROC_BIND=true ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE +done +fi + +SUFFIX=cuda +if [ -e $EXECUTABLE.$SUFFIX ] +then +SCHEDULE=1 +echo "Cuda tests Static schedule" +for CODE in {100,110,111,112,120,121,122,200,210,211,212,220,221,222,300,400,500} +do + ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE +done + +SCHEDULE=2 +echo "Cuda tests Dynamic schedule" +for CODE in {100,110,111,112,120,121,122,200,210,211,212,220,221,222,300,400,500} +do + ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE +done +fi diff --git a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh new file mode 100755 index 0000000000..f4bfb87f8f --- /dev/null +++ b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh @@ -0,0 +1,126 @@ +#!/bin/bash + +# Sample script for benchmarking policy performance + +# Suggested enviroment variables to export prior to executing script: +# KNL: +# OMP_NUM_THREADS=256 KMP_AFFINITY=compact +# Power: +# OMP_NUM_THREADS=64 OMP_PROC_BIND=true + +# Constants and Variables: +# Vary: TEAMSIZE, and THREADRANGE +# for TEAMSIZE in {1,2,4,5,8}; do +# for THREADRANGE in {32,41,1000}; do +# Fixed: TEAMRANGE, VECTORRANGE, VECTORSIZE +# System specific: Adjust REPEAT values to architecture tests are run on + +# Tests +# Static SCHEDULE = 1 +# Tier 1: parallel_for + RangePolicy 300 +# Tier 2: parallel_reduce, parallel_scan + RangePolicy 400 500 +# Tier 3: 'outer' parallel_for with TeamPolicy (nested parallelism) 1XY +# Tier 4: 'outer' parallel_reduce with TeamPolicy (nested parallelism) 2XY +# Dynamic SCHEDULE = 2 +# Tier 5: parallel_for + RangePolicy 300 +# Tier 6: parallel_reduce, parallel_scan + RangePolicy 400 500 +# Tier 7: 'outer' parallel_for with TeamPolicy (nested parallelism) 1XY +# Tier 8: 'outer' parallel_reduce with TeamPolicy (nested parallelism) 2XY + +# Results grouped by: +# 0) SCHEDULE 1) CODE (test) 2) TEAMRANGE 3) TEAMSIZE 4) THREADRANGE + +EXECUTABLE=policy_performance + +# Default defined values +TEAMRANGE=1000 +THREADRANGE=1 +VECTORRANGE=32 +TEAMSIZE=1 +VECTORSIZE=1 +OREPEAT=1 +MREPEAT=1 +IREPEAT=1 +SCHEDULE=1 + +# Host tests +SUFFIX=host +if [ -e $EXECUTABLE.$SUFFIX ]; then +echo "Host" + +for SCHEDULE in {1,2}; do + +# Tier 1 and 2, 5 and 6 +for CODE in {300,400,500}; do + for TEAMSIZE in {1,2,4,5,8}; do + OMP_PROC_BIND=true ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done +done + +# Tier 3, 7 +for CODE in {100,110,111,112,120,121,122}; do + for TEAMSIZE in {1,2,4,5,8}; do + for THREADRANGE in {32,41,1000}; do + OMP_PROC_BIND=true ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done + done +done + +# Tier 4, 8 +for CODE in {200,210,211,212,220,221,222}; do + for TEAMSIZE in {1,2,4,5,8}; do + for THREADRANGE in {32,41,1000}; do + OMP_PROC_BIND=true ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done + done +done + +done # end SCHEDULE + +fi # end host + + +# Cuda tests +SUFFIX=cuda +# TEAMRANGE=10000, TEAMSIZE=8 too large +# TEAMRANGE=10000, TEAMSIZE=8, THREADRANGE=1000 too large +if [ -e $EXECUTABLE.$SUFFIX ]; then +echo "Cuda" + +for SCHEDULE in {1,2}; do + +# Reset defaults +TEAMRANGE=1000 +THREADRANGE=1 +VECTORRANGE=32 +TEAMSIZE=1 +VECTORSIZE=1 + +# Tier 1 and 2, 5 and 6 +for CODE in {300,400,500}; do + for TEAMSIZE in {1,2,4,5,8}; do + ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done +done + +# Tier 3, 7 +for CODE in {100,110,111,112,120,121,122}; do + for TEAMSIZE in {1,2,4,5,8}; do + for THREADRANGE in {32,41,1000}; do + ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done + done +done + +# Tier 4, 8 +for CODE in {200,210,211,212,220,221,222}; do + for TEAMSIZE in {1,2,4,5,8}; do + for THREADRANGE in {32,41,1000}; do + ./$EXECUTABLE.$SUFFIX $TEAMRANGE $THREADRANGE $VECTORRANGE $OREPEAT $MREPEAT $IREPEAT $TEAMSIZE $VECTORSIZE $SCHEDULE $CODE + done + done +done + +done # end SCHEDULE + +fi #end cuda diff --git a/lib/kokkos/bin/hpcbind b/lib/kokkos/bin/hpcbind new file mode 100755 index 0000000000..ca34648780 --- /dev/null +++ b/lib/kokkos/bin/hpcbind @@ -0,0 +1,454 @@ +#!/usr/bin/env bash + +################################################################################ +# Check if hwloc commands exist +################################################################################ +declare -i HPCBIND_HAS_HWLOC=1 +type hwloc-bind >/dev/null 2>&1 +HPCBIND_HAS_HWLOC=$((HPCBIND_HAS_HWLOC & ! $?)) + +type hwloc-distrib >/dev/null 2>&1 +HPCBIND_HAS_HWLOC=$((HPCBIND_HAS_HWLOC & ! $?)) + +type hwloc-ls >/dev/null 2>&1 +HPCBIND_HAS_HWLOC=$((HPCBIND_HAS_HWLOC & ! $?)) + +type hwloc-calc >/dev/null 2>&1 +HPCBIND_HAS_HWLOC=$((HPCBIND_HAS_HWLOC & ! $?)) + +type hwloc-ps >/dev/null 2>&1 +HPCBIND_HAS_HWLOC=$((HPCBIND_HAS_HWLOC & ! $?)) + +if [[ ${HPCBIND_HAS_HWLOC} -eq 0 ]]; then + echo "hwloc not found, no process binding will occur" +fi + +# Get parent cpuset +HPCBIND_HWLOC_PARENT_CPUSET="" +if [[ ${HPCBIND_HAS_HWLOC} -eq 1 ]]; then + MY_PID="$BASHPID" + HPCBIND_HWLOC_PARENT_CPUSET=$(hwloc-ps --cpuset | grep "${MY_PID}" | cut -f 2) +fi + +################################################################################ +# Check if nvidia-smi exist +################################################################################ +declare -i HPCBIND_HAS_NVIDIA=0 +type nvidia-smi >/dev/null 2>&1 +HPCBIND_HAS_NVIDIA=$((!$?)) + + +################################################################################ +# Get visible gpu +################################################################################ +declare -i NUM_GPUS=0 +HPCBIND_VISIBLE_GPUS="" +if [[ ${HPCBIND_HAS_NVIDIA} -eq 1 ]]; then + NUM_GPUS=$(nvidia-smi -L | wc -l); + GPU_LIST="$( seq 0 $((NUM_GPUS-1)) )" + HPCBIND_VISIBLE_GPUS=${CUDA_VISIBLE_DEVICES:-${GPU_LIST}} +fi + +declare -i HPCBIND_ENABLE_GPU_MAPPING=$((NUM_GPUS > 0)) + + +################################################################################ +# Get queue id +# supports sbatch, bsub, aprun +################################################################################ +HPCBIND_QUEUE_NAME="" +declare -i HPCBIND_QUEUE_INDEX=0 +declare -i HPCBIND_QUEUE_GPU_MAPPING=0 + +if [[ ! -z "${SLURM_LOCAL_ID}" ]]; then + HPCBIND_QUEUE_GPU_MAPPING=1 + HPCBIND_QUEUE_NAME="sbatch" + HPCBIND_QUEUE_INDEX=${SLURM_LOCAL_ID} +elif [[ ! -z "${LBS_JOBINDEX}" ]]; then + HPCBIND_QUEUE_GPU_MAPPING=1 + HPCBIND_QUEUE_NAME="bsub" + HPCBIND_QUEUE_INDEX=${LBS_JOBINDEX} +elif [[ ! -z "${ALPS_APP_PE}" ]]; then + HPCBIND_QUEUE_GPU_MAPPING=1 + HPCBIND_QUEUE_NAME="aprun" + HPCBIND_QUEUE_INDEX=${ALPS_APP_PE} +fi + + +################################################################################ +# Show help +################################################################################ +function show_help { + local cmd=$(basename "$0") + echo "Usage: ${cmd} -- command ..." + echo " Set the process mask, OMP environment variables and CUDA environment" + echo " variables to sane values if possible. Uses hwloc and nvidia-smi if" + echo " available. Will preserve the current process binding, so it is safe" + echo " to use with a queuing system or mpiexec." + echo "" + echo "Options:" + echo " --no-hwloc-bind Disable binding" + echo " --proc-bind= Set the initial process mask for the script" + echo " LOC can be any valid location argument for" + echo " hwloc-calc Default: all" + echo " --distribute=N Distribute the current cpuset into N partitions" + echo " --distribute-partition=I" + echo " Use the i'th partition (zero based)" + echo " --visible-gpus= Comma separated list of gpu ids" + echo " Default: CUDA_VISIBLE_DEVICES or all gpus in" + echo " sequential order" + echo " --gpu-ignore-queue Ignore queue job id when choosing visible GPU" + echo " --no-gpu-mapping Do not set CUDA_VISIBLE_DEVICES" + echo " --openmp=M.m Set env variables for the given OpenMP version" + echo " Default: 4.0" + echo " --openmp-percent=N Integer percentage of cpuset to use for OpenMP" + echo " threads Default: 100" + echo " --openmp-places= Op=threads|cores|sockets. Default: threads" + echo " --no-openmp-proc-bind Set OMP_PROC_BIND to false and unset OMP_PLACES" + echo " --force-openmp-num-threads=N" + echo " Override logic for selecting OMP_NUM_THREADS" + echo " --force-openmp-proc-bind=" + echo " Override logic for selecting OMP_PROC_BIND" + echo " --no-openmp-nested Set OMP_NESTED to false" + echo " --show-bindings Show the bindings" + echo " --lstopo Show bindings in lstopo without executing a command" + echo " -v|--verbose Show options and relevant environment variables" + echo " -h|--help Show this message" + echo "" + echo "Sample Usage:" + echo " Split the current process cpuset into 4 and use the 3rd partition" + echo " ${cmd} --distribute=4 --distribute-partition=2 -v -- command ..." + echo " Bing the process to all even cores" + echo " ${cmd} --proc-bind=core:even -v -- command ..." + echo " Bind to the first 64 cores and split the current process cpuset into 4" + echo " ${cmd} --proc-bind=core:0-63 --distribute=4 --distribute-partition=0 -- command ..." + echo " skip GPU 0 when mapping visible devices" + echo " ${cmd} --distribute=4 --distribute-partition=0 --visible-gpus=1,2 -v -- command ..." + echo " Display the current bindings" + echo " ${cmd} --proc-bind=numa:0 --show-bindings -- command" + echo " Display the current bindings using lstopo" + echo " ${cmd} --proc-bind=numa:0.core:odd --lstopo" + echo "" +} + + +################################################################################ +# Parse command line arguments +################################################################################ +# Show help if no command line arguments given +if [[ "$#" -eq 0 ]]; then + show_help + exit 0 +fi + +declare -a UNKNOWN_ARGS=() +declare -i HPCBIND_ENABLE_HWLOC_BIND=${HPCBIND_HAS_HWLOC} +declare -i HPCBIND_DISTRIBUTE=1 +declare -i HPCBIND_PARTITION=0 +HPCBIND_PROC_BIND="all" +HPCBIND_OPENMP_VERSION=4.0 +declare -i HPCBIND_OPENMP_PERCENT=100 +HPCBIND_OPENMP_PLACES=${OMP_PLACES:-threads} +declare -i HPCBIND_OPENMP_PROC_BIND=1 +declare -i HPCBIND_OPENMP_FORCE_NUM_THREADS=-1 +HPCBIND_OPENMP_FORCE_PROC_BIND="" +HPCBIND_OPENMP_NESTED=${OMP_NESTED:-true} +declare -i HPCBIND_VERBOSE=0 + +declare -i HPCBIND_SHOW_BINDINGS=0 +declare -i HPCBIND_LSTOPO=0 + +for i in $@; do + case $i in + # number of partitions to create + --no-hwloc-bind) + HPCBIND_ENABLE_HWLOC_BIND=0 + shift + ;; + --proc-bind=*) + HPCBIND_PROC_BIND="${i#*=}" + shift + ;; + --distribute=*) + HPCBIND_DISTRIBUTE="${i#*=}" + shift + ;; + # which partition to use + --distribute-partition=*) + HPCBIND_PARTITION="${i#*=}" + shift + ;; + --visible-gpus=*) + HPCBIND_VISIBLE_GPUS=$(echo "${i#*=}" | tr ',' ' ') + shift + ;; + --gpu-ignore-queue) + HPCBIND_QUEUE_GPU_MAPPING=0 + shift + ;; + --no-gpu-mapping) + HPCBIND_ENABLE_GPU_MAPPING=0 + shift + ;; + --openmp=*) + HPCBIND_OPENMP_VERSION="${i#*=}" + shift + ;; + --openmp-percent=*) + HPCBIND_OPENMP_PERCENT="${i#*=}" + shift + ;; + --openmp-places=*) + HPCBIND_OPENMP_PLACES="${i#*=}" + shift + ;; + --no-openmp-proc-bind) + HPCBIND_OPENMP_PROC_BIND=0 + shift + ;; + --force-openmp-proc-bind=*) + HPCBIND_OPENMP_FORCE_PROC_BIND="${i#*=}" + shift + ;; + --force-openmp-num-threads=*) + HPCBIND_OPENMP_FORCE_NUM_THREADS="${i#*=}" + shift + ;; + --no-openmp-nested) + HPCBIND_OPENMP_NESTED="false" + shift + ;; + --show-bindings) + HPCBIND_VERBOSE=1 + HPCBIND_SHOW_BINDINGS=1 + shift + ;; + --lstopo) + HPCBIND_VERBOSE=1 + HPCBIND_SHOW_BINDINGS=0 + HPCBIND_LSTOPO=1 + shift + ;; + -v|--verbose) + HPCBIND_VERBOSE=1 + shift + ;; + -h|--help) + show_help + exit 0 + ;; + # ignore remaining arguments + --) + shift + break + ;; + # unknown option + *) + UNKNOWN_ARGS+=("$i") + shift + ;; + esac +done + + +################################################################################ +# Check unknown arguments +################################################################################ +if [[ ${#UNKNOWN_ARGS[*]} > 0 ]]; then + echo "Uknown options: ${UNKNOWN_ARGS[*]}" + exit 1 +fi + + +################################################################################ +# Check that visible gpus are valid +################################################################################ +HPCBIND_VISIBLE_GPUS=(${HPCBIND_VISIBLE_GPUS}) +if [[ ${HPCBIND_ENABLE_GPU_MAPPING} -eq 1 ]]; then + for ((i=0; i < ${#HPCBIND_VISIBLE_GPUS[*]}; i++)); do + if [[ ${HPCBIND_VISIBLE_GPUS[$i]} -ge ${NUM_GPUS} || + ${HPCBIND_VISIBLE_GPUS[$i]} -lt 0 ]]; then + echo "Invaild GPU ID ${HPCBIND_VISIBLE_GPUS[$i]}, setting to 0" + HPCBIND_VISIBLE_GPUS[$i]=0; + fi + done + NUM_GPUS=${#HPCBIND_VISIBLE_GPUS[@]} +fi + + +################################################################################ +# Check OpenMP percent +################################################################################ +if [[ ${HPCBIND_OPENMP_PERCENT} -lt 1 ]]; then + echo "OpenMP percent < 1, setting to 1" + HPCBIND_OPENMP_PERCENT=1 +elif [[ ${HPCBIND_OPENMP_PERCENT} -gt 100 ]]; then + echo "OpenMP percent > 100, setting to 100" + HPCBIND_OPENMP_PERCENT=100 +fi + +################################################################################ +# Check distribute +################################################################################ +if [[ ${HPCBIND_DISTRIBUTE} -le 0 ]]; then + echo "Invalid input for distribute, changing distribute to 1" + HPCBIND_DISTRIBUTE=1 +fi + +if [[ ${HPCBIND_PARTITION} -ge ${HPCBIND_DISTRIBUTE} ]]; then + echo "Invalid input for distribute-partition, changing to 0" + HPCBIND_PARTITION=0 +fi + + +################################################################################ +# Find cpuset and num threads +################################################################################ +HPCBIND_HWLOC_CPUSET="" +declare -i HPCBIND_NUM_PUS=0 + +if [[ ${HPCBIND_ENABLE_HWLOC_BIND} -eq 1 ]]; then + if [[ "${HPCBIND_HWLOC_PARENT_CPUSET}" == "" ]]; then + BINDING=$(hwloc-calc ${HPCBIND_PROC_BIND}) + else + BINDING=$(hwloc-calc --restrict ${HPCBIND_HWLOC_PARENT_CPUSET} ${HPCBIND_PROC_BIND}) + fi + + CPUSETS=($(hwloc-distrib --restrict ${BINDING} --at core ${HPCBIND_DISTRIBUTE})) + HPCBIND_HWLOC_CPUSET=${CPUSETS[${HPCBIND_PARTITION}]} + HPCBIND_NUM_PUS=$(hwloc-ls --restrict ${HPCBIND_HWLOC_CPUSET} --only pu | wc -l) +else + HPCBIND_NUM_PUS=$(cat /proc/cpuinfo | grep -c processor) +fi + +declare -i HPCBIND_OPENMP_NUM_THREADS=$((HPCBIND_NUM_PUS * HPCBIND_OPENMP_PERCENT)) +HPCBIND_OPENMP_NUM_THREADS=$((HPCBIND_OPENMP_NUM_THREADS / 100)) + + +if [[ ${HPCBIND_OPENMP_NUM_THREADS} -lt 1 ]]; then + HPCBIND_OPENMP_NUM_THREADS=1 +elif [[ ${HPCBIND_OPENMP_NUM_THREADS} -gt ${HPCBIND_NUM_PUS} ]]; then + HPCBIND_OPENMP_NUM_THREADS=${HPCBIND_NUM_PUS} +fi + +if [[ ${HPCBIND_OPENMP_FORCE_NUM_THREADS} -gt 0 ]]; then + HPCBIND_OPENMP_NUM_THREADS=${HPCBIND_OPENMP_FORCE_NUM_THREADS} +fi + +################################################################################ +# Set OpenMP environment variables +################################################################################ + +# set OMP_NUM_THREADS +export OMP_NUM_THREADS=${HPCBIND_OPENMP_NUM_THREADS} + +# set OMP_PROC_BIND and OMP_PLACES +if [[ ${HPCBIND_OPENMP_PROC_BIND} -eq 1 ]]; then + if [[ "${HPCBIND_OPENMP_FORCE_PROC_BIND}" == "" ]]; then + #default proc bind logic + if [[ "${HPCBIND_OPENMP_VERSION}" == "4.0" || "${HPCBIND_OPENMP_VERSION}" > "4.0" ]]; then + export OMP_PLACES="${HPCBIND_OPENMP_PLACES}" + export OMP_PROC_BIND="spread" + else + export OMP_PROC_BIND="true" + unset OMP_PLACES + fi + else + #force proc bind + export OMP_PLACES="${HPCBIND_OPENMP_PLACES}" + export OMP_PROC_BIND="${HPCBIND_OPENMP_FORCE_PROC_BIND}" + fi +else + # no openmp proc bind + unset OMP_PLACES + unset OMP_PROC_BIND +fi + +# set OMP_NESTED +export OMP_NESTED=${HPCBIND_OPENMP_NESTED} + + +################################################################################ +# Set CUDA environment variables +################################################################################ + +if [[ ${HPCBIND_ENABLE_GPU_MAPPING} -eq 1 ]]; then + if [[ ${HPCBIND_QUEUE_GPU_MAPPING} -eq 0 ]]; then + declare -i GPU_ID=$((HPCBIND_PARTITION % NUM_GPUS)) + export CUDA_VISIBLE_DEVICES=${HPCBIND_VISIBLE_GPUS[${GPU_ID}]} + else + declare -i MY_TASK_ID=$((HPCBIND_QUEUE_INDEX * HPCBIND_DISTRIBUTE + HPCBIND_PARTITION)) + declare -i GPU_ID=$((MY_TASK_ID % NUM_GPUS)) + export CUDA_VISIBLE_DEVICES=${HPCBIND_VISIBLE_GPUS[${GPU_ID}]} + fi +fi + +################################################################################ +# Set hpcbind environment variables +################################################################################ +export HPCBIND_HAS_HWLOC=${HPCBIND_HAS_HWLOC} +export HPCBIND_HAS_NVIDIA=${HPCBIND_HAS_NVIDIA} +export HPCBIND_NUM_PUS=${HPCBIND_NUM_PUS} +export HPCBIND_HWLOC_CPUSET=${HPCBIND_HWLOC_CPUSET} +export HPCBIND_HWLOC_DISTRIBUTE=${HPCBIND_DISTRIBUTE} +export HPCBIND_HWLOC_DISTRIBUTE_PARTITION=${HPCBIND_PARTITION} +if [[ "${HPCBIND_HWLOC_PARENT_CPUSET}" == "" ]]; then + export HPCBIND_HWLOC_PARENT_CPUSET="all" +else + export HPCBIND_HWLOC_PARENT_CPUSET=${HPCBIND_HWLOC_PARENT_CPUSET} +fi +export HPCBIND_HWLOC_PROC_BIND=${HPCBIND_PROC_BIND} +export HPCBIND_NVIDIA_ENABLE_GPU_MAPPING=${HPCBIND_ENABLE_GPU_MAPPING} +export HPCBIND_NVIDIA_VISIBLE_GPUS=$(echo "${HPCBIND_VISIBLE_GPUS[*]}" | tr ' ' ',') +export HPCBIND_OPENMP_VERSION=${HPCBIND_OPENMP_VERSION} +if [[ "${HPCBIND_QUEUE_NAME}" != "" ]]; then + export HPCBIND_QUEUE_INDEX=${HPCBIND_QUEUE_INDEX} + export HPCBIND_QUEUE_NAME=${HPCBIND_QUEUE_NAME} + export HPCBIND_QUEUE_GPU_MAPPING=${HPCBIND_QUEUE_GPU_MAPPING} +fi + + +################################################################################ +# Print verbose +################################################################################ + +if [[ ${HPCBIND_VERBOSE} -eq 1 ]]; then + MY_ENV=$(env | sort) + echo "[HPCBIND]" + echo "${MY_ENV}" | grep -E "^HPCBIND_" + echo "[CUDA]" + echo "${MY_ENV}" | grep -E "^CUDA_" + echo "[OPENMP]" + echo "${MY_ENV}" | grep -E "^OMP_" +fi + +if [[ ${HPCBIND_HAS_HWLOC} -eq 1 && ${HPCBIND_SHOW_BINDINGS} -eq 1 ]]; then + echo "[BINDINGS]" + hwloc-ls --restrict ${HPCBIND_HWLOC_CPUSET} --only pu +elif [[ ${HPCBIND_SHOW_BINDINGS} -eq 1 ]]; then + echo "Unable to show bindings, hwloc not available." +fi + +################################################################################ +# Run command +################################################################################ + +if [[ ${HPCBIND_LSTOPO} -eq 0 ]]; then + if [[ ${HPCBIND_ENABLE_HWLOC_BIND} -eq 1 ]]; then + hwloc-bind ${HPCBIND_HWLOC_CPUSET} -- $@ + else + eval $@ + fi +else + if [[ ${HPCBIND_HAS_HWLOC} -eq 1 ]]; then + if [[ ${HPCBIND_ENABLE_HWLOC_BIND} -eq 1 && ! -z ${DISPLAY} ]]; then + echo "[BINDINGS]" + hwloc-ls --restrict ${HPCBIND_HWLOC_CPUSET} --only pu + hwloc-bind ${HPCBIND_HWLOC_CPUSET} -- lstopo --pid 0 + else + hwloc-ls --restrict ${HPCBIND_HWLOC_CPUSET} + fi + else + echo "Unable to show bindings, hwloc not available." + fi +fi diff --git a/lib/kokkos/bin/kokkos-bind b/lib/kokkos/bin/kokkos-bind new file mode 100755 index 0000000000..b6fe07a1bd --- /dev/null +++ b/lib/kokkos/bin/kokkos-bind @@ -0,0 +1,221 @@ +#!/usr/bin/env bash + +# check if hwloc commands exist +declare -i HAS_HWLOC=0 +type hwloc-bind >/dev/null 2>&1 +HAS_HWLOC="${HAS_HWLOC} + $?" + +type hwloc-distrib >/dev/null 2>&1 +HAS_HWLOC="${HAS_HWLOC} + $?" + +type hwloc-ls >/dev/null 2>&1 +HAS_HWLOC="${HAS_HWLOC} + $?" + +type hwloc-calc >/dev/null 2>&1 +HAS_HWLOC="${HAS_HWLOC} + $?" + +type hwloc-ps >/dev/null 2>&1 +HAS_HWLOC="${HAS_HWLOC} + $?" + + +#parse args +declare -a UNKNOWN_ARGS=() +declare -i DISTRIBUTE=1 +declare -i INDEX=0 +PROC_BIND="all" +CURRENT_CPUSET="" +OPENMP_VERSION=4.0 +OPENMP_PROC_BIND=True +OPENMP_NESTED=True +VERBOSE=False + +#get the current process cpuset +if [[ ${HAS_HWLOC} -eq 0 ]]; then + MY_PID="$BASHPID" + CURRENT_CPUSET=$(hwloc-ps --cpuset | grep "${MY_PID}" | cut -f 2) + echo "$CURRENT_CPUSET" +fi + +function show_help { + local cmd=$(basename "$0") + echo "Usage: ${cmd} -- command ..." + echo " Uses hwloc to divide the node into the given number of groups," + echo " set the appropriate OMP_NUM_THREADS and execute the command on the" + echo " selected group." + echo "" + echo " NOTE: This command assumes it has exclusive use of the node" + echo "" + echo "Options:" + echo " --proc-bind= Set the initial process mask for the script. " + echo " LOC can be any valid location argumnet for" + echo " hwloc-calc. Defaults to the entire machine" + echo " --distribute=N Distribute the current proc-bind into N groups" + echo " --index=I Use the i'th group (zero based)" + echo " --openmp=M.m Set env variables for the given OpenMP version" + echo " (default 4.0)" + echo " --no-openmp-proc-bind Set OMP_PROC_BIND to false and unset OMP_PLACES" + echo " --no-openmp-nested Set OMP_NESTED to false" + echo " -v|--verbose" + echo " -h|--help" + echo "" + echo "Sample Usage:" + echo " ${cmd} --distribute=4 --index=2 -v -- command ..." + echo "" +} + +if [[ "$#" -eq 0 ]]; then + show_help + exit 0 +fi + + +for i in $@; do + case $i in + # number of partitions to create + --proc-bind=*) + PROC_BIND="${i#*=}" + shift + ;; + --distribute=*) + DISTRIBUTE="${i#*=}" + shift + ;; + # which group to use + --index=*) + INDEX="${i#*=}" + shift + ;; + --openmp=*) + OPENMP_VERSION="${i#*=}" + shift + ;; + --no-openmp-proc-bind) + OPENMP_PROC_BIND=False + shift + ;; + --no-openmp-nested) + OPENMP_NESTED=False + shift + ;; + -v|--verbose) + VERBOSE=True + shift + ;; + -h|--help) + show_help + exit 0 + ;; + # ignore remaining arguments + --) + shift + break + ;; + # unknown option + *) + UNKNOWN_ARGS+=("$i") + shift + ;; + esac +done + +if [[ ${#UNKNOWN_ARGS[*]} > 0 ]]; then + echo "Uknown options: ${UNKNOWN_ARGS[*]}" + exit 1 +fi + +if [[ ${DISTRIBUTE} -le 0 ]]; then + echo "Invalid input for distribute, changing distribute to 1" + DISTRIBUTE=1 +fi + +if [[ ${INDEX} -ge ${DISTRIBUTE} ]]; then + echo "Invalid input for index, changing index to 0" + INDEX=0 +fi + +if [[ ${HAS_HWLOC} -ne 0 ]]; then + echo "hwloc not found, no process binding will occur" + DISTRIBUTE=1 + INDEX=0 +fi + +if [[ ${HAS_HWLOC} -eq 0 ]]; then + + if [[ "${CURRENT_CPUSET}" == "" ]]; then + BINDING=$(hwloc-calc ${PROC_BIND}) + else + BINDING=$(hwloc-calc --restrict ${CURRENT_CPUSET} ${PROC_BIND}) + fi + + CPUSETS=($(hwloc-distrib --restrict ${BINDING} --at core ${DISTRIBUTE})) + CPUSET=${CPUSETS[${INDEX}]} + NUM_THREADS=$(hwloc-ls --restrict ${CPUSET} --only pu | wc -l) + + if [[ "${VERBOSE}" == "True" ]]; then + echo "hwloc: true" + echo " proc_bind: ${PROC_BIND}" + echo " distribute: ${DISTRIBUTE}" + echo " index: ${INDEX}" + echo " parent_cpuset: ${CURRENT_CPUSET}" + echo " cpuset: ${CPUSET}" + echo "omp_num_threads: ${NUM_THREADS}" + echo "omp_proc_bind: ${OPENMP_PROC_BIND}" + echo "omp_nested: ${OPENMP_NESTED}" + echo "OpenMP: ${OPENMP_VERSION}" + fi + + # set OMP env + if [[ "${OPENMP_PROC_BIND}" == "True" ]]; then + if [[ "${OPENMP_VERSION}" == "4.0" || "${OPENMP_VERSION}" > "4.0" ]]; then + export OMP_PLACES="threads" + export OMP_PROC_BIND="spread" + else + export OMP_PROC_BIND="true" + unset OMP_PLACES + fi + else + unset OMP_PLACES + unset OMP_PROC_BIND + fi + if [[ "${OPENMP_NESTED}" == "True" ]]; then + export OMP_NESTED="true" + else + export OMP_NESTED="false" + fi + export OMP_NUM_THREADS="${NUM_THREADS}" + + hwloc-bind ${CPUSET} -- $@ +else + NUM_THREADS=$(cat /proc/cpuinfo | grep -c processor) + + if [[ "${VERBOSE}" == "True" ]]; then + echo "hwloc: false" + echo "omp_num_threads: ${NUM_THREADS}" + echo "omp_proc_bind: ${OPENMP_PROC_BIND}" + echo "omp_nested: ${OPENMP_NESTED}" + echo "OpenMP: ${OPENMP_VERSION}" + fi + + # set OMP env + if [[ "${OPENMP_PROC_BIND}" == "True" ]]; then + if [[ "${OPENMP_VERSION}" == "4.0" || "${OPENMP_VERSION}" > "4.0" ]]; then + export OMP_PLACES="threads" + export OMP_PROC_BIND="spread" + else + export OMP_PROC_BIND="true" + unset OMP_PLACES + fi + else + unset OMP_PLACES + unset OMP_PROC_BIND + fi + if [[ "${OPENMP_NESTED}" == "True" ]]; then + export OMP_NESTED="true" + else + export OMP_NESTED="false" + fi + export OMP_NUM_THREADS="${NUM_THREADS}" + + eval $@ +fi + diff --git a/lib/kokkos/bin/runtest b/lib/kokkos/bin/runtest new file mode 100755 index 0000000000..92411fe5ba --- /dev/null +++ b/lib/kokkos/bin/runtest @@ -0,0 +1,165 @@ +#!/usr/bin/env bash + +function get_path() { + cd "$(dirname "$0")" + cd .. + echo "$(pwd -P)" +} + +KOKKOS_PATH="$(get_path "$0")" + +function show_help() { + local cmd=$(basename "$0") + echo "Usage: ${cmd} " + echo " Build and run the tests" + echo "" + echo "Options:" + echo " -j=N|--make-j=N Build the tests in parallel" + echo " -c|--clean Clean build and regenerate make files" + echo " --clean-on-pass Clean build when runtest passes" + echo " --output-prefix=
  Prefix of log files  Default: runtest"
+  echo "  --build-only           Only build the tests"
+  echo "  -v|--verbose           Tee STDOUT and STDERR to screen and files"
+  echo "  -h|--help              Show this message"
+  echo ""
+  ${KOKKOS_PATH}/generate_makefile.bash --help
+  return 0
+}
+
+
+declare -a GENERATE_ARGS=()
+declare -i VERBOSE=0
+declare -i CLEAN=0
+declare -i CLEAN_ON_PASS=0
+declare -i BUILD_ONLY=0
+OUTPUT="runtest"
+
+declare -i MAKE_J=${HPCBIND_NUM_PUS:-1}
+
+for i in $@; do
+  case $i in
+    -j=*|--make-j=*)
+      MAKE_J=${i#*=}
+      shift
+      ;;
+    -c|--clean)
+      CLEAN=1
+      shift
+      ;;
+    --clean-on-pass)
+      CLEAN_ON_PASS=1
+      shift
+      ;;
+    --output-prefix=*)
+      OUTPUT=${i#*=}
+      shift
+      ;;
+    --build-only)
+      BUILD_ONLY=1
+      shift
+      ;;
+    -v|--verbose)
+      VERBOSE=1
+      shift
+      ;;
+    -h|--help)
+      show_help
+      exit 0
+      ;;
+    *)
+      GENERATE_ARGS+=("$i")
+      shift
+      ;;
+  esac
+done
+
+if [[ "$(pwd -P)" == ${KOKKOS_PATH} ]]; then
+  echo "Cannot call $0 from root repository path ${KOKKOS_PATH}"
+  exit 1
+fi
+
+# Some makefile dependencies are incorrect, so clean needs to force
+# a new call to generate_makefiles.bash
+if [[ ${CLEAN} -eq 1 ]]; then
+  START=${SECONDS}
+  echo "Cleaning"
+  /bin/rm -rf algorithms containers core example install Makefile >/dev/null 2>&1
+  END=${SECONDS}
+  echo "    $((END-START)) seconds"
+  if [[ ${VERBOSE} -eq 1 ]]; then
+    echo ""
+    echo ""
+  fi
+fi
+
+declare -i START=${SECONDS}
+echo "Generating Makefile"
+echo "    ${KOKKOS_PATH}/generate_makefile.bash --kokkos-path=${KOKKOS_PATH} ${GENERATE_ARGS[@]}"
+
+if [[ ${VERBOSE} -eq 0 ]]; then
+  "${KOKKOS_PATH}"/generate_makefile.bash --kokkos-path="${KOKKOS_PATH}" "${GENERATE_ARGS[@]}" > ${OUTPUT}.out 2> >(tee ${OUTPUT}.err >&2)
+else
+  "${KOKKOS_PATH}"/generate_makefile.bash --kokkos-path="${KOKKOS_PATH}" "${GENERATE_ARGS[@]}" > >(tee ${OUTPUT}.out) 2> >(tee ${OUTPUT}.err >&2)
+fi
+declare -i RESULT=$?
+declare -i END=${SECONDS}
+if [[ ${RESULT} -eq 0 ]]; then
+  echo "    PASS:  $((END-START)) seconds"
+  if [[ ${VERBOSE} -eq 1 ]]; then
+    echo ""
+    echo ""
+  fi
+else
+  cat ${OUTPUT}.out | grep "FAIL"
+  cat ${OUTPUT}.err | grep "FAIL"
+  echo "    FAIL:  $((END-START)) seconds"
+  exit 1
+fi
+
+START=${SECONDS}
+echo "Building"
+if [[ ${VERBOSE} -eq 0 ]]; then
+  make --keep-going -j ${MAKE_J} build-test >> ${OUTPUT}.out 2> >(tee -a ${OUTPUT}.err >&2)
+else
+  make --keep-going -j ${MAKE_J} build-test > >(tee -a ${OUTPUT}.out) 2> >(tee -a ${OUTPUT}.err >&2)
+fi
+RESULT=$?
+END=${SECONDS}
+if [[ ${RESULT} -eq 0 ]]; then
+  echo "    PASS:  $((END-START)) seconds"
+  if [[ ${VERBOSE} -eq 1 ]]; then
+    echo ""
+    echo ""
+  fi
+else
+  cat ${OUTPUT}.out | grep -E "[[:space:]]error:[[:space:]]"
+  cat ${OUTPUT}.err | grep -E "[[:space:]]error:[[:space:]]"
+  echo "    FAIL:  $((END-START)) seconds"
+  exit 1
+fi
+
+if [[ ${BUILD_ONLY} -eq 0 ]]; then
+  START=${SECONDS}
+  echo "Testing"
+  if [[ ${VERBOSE} -eq 0 ]]; then
+    make --keep-going test >> ${OUTPUT}.out 2> >(tee -a ${OUTPUT}.err >&2)
+  else
+    make --keep-going test > >(tee -a ${OUTPUT}.out) 2> >(tee -a ${OUTPUT}.err >&2)
+  fi
+  RESULT=$?
+  END=${SECONDS}
+  if [[ ${RESULT} -eq 0 ]]; then
+    echo "    PASS:  $((END-START)) seconds"
+    if [[ ${CLEAN_ON_PASS} -eq 1 ]]; then
+      make clean
+    fi
+  else
+    cat ${OUTPUT}.out | grep "FAIL"
+    cat ${OUTPUT}.err | grep "FAIL"
+    echo "    FAIL:  $((END-START)) seconds"
+    exit 1
+  fi
+fi
+
+exit ${RESULT}
+
diff --git a/lib/kokkos/cmake/kokkos.cmake b/lib/kokkos/cmake/kokkos.cmake
index 235b7eaba4..396822c7fa 100644
--- a/lib/kokkos/cmake/kokkos.cmake
+++ b/lib/kokkos/cmake/kokkos.cmake
@@ -999,8 +999,12 @@ SET (Kokkos_INCLUDE_DIRS
     ${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
+SET(Kokkos_INCLUDE_DIRS_RET ${Kokkos_INCLUDE_DIRS} PARENT_SCOPE)
+
 INCLUDE_DIRECTORIES(${Kokkos_INCLUDE_DIRS})
 
 IF(KOKKOS_SEPARATE_LIBS)
diff --git a/lib/kokkos/config/master_history.txt b/lib/kokkos/config/master_history.txt
index cc6f4c97d7..0447db4b2b 100644
--- a/lib/kokkos/config/master_history.txt
+++ b/lib/kokkos/config/master_history.txt
@@ -7,3 +7,4 @@ tag:  2.02.07    date: 12:16:2016    master: 4b4cc4ba    develop: 382c0966
 tag:  2.02.15    date: 02:10:2017    master: 8c64cd93    develop: 28dea8b6
 tag:  2.03.00    date: 04:25:2017    master: 120d9ce7    develop: 015ba641
 tag:  2.03.05    date: 05:27:2017    master: 36b92f43    develop: 79073186
+tag:  2.03.13    date: 07:27:2017    master: da314444    develop: 29ccb58a
diff --git a/lib/kokkos/config/query_cuda_arch.cpp b/lib/kokkos/config/query_cuda_arch.cpp
new file mode 100644
index 0000000000..383f04e34e
--- /dev/null
+++ b/lib/kokkos/config/query_cuda_arch.cpp
@@ -0,0 +1,24 @@
+#include 
+#include 
+int main()
+{
+	cudaDeviceProp prop;
+  const cudaError_t err_code = cudaGetDeviceProperties(&prop, 0);
+  if (cudaSuccess != err_code) {
+		fprintf(stderr,"cudaGetDeviceProperties failed: %s\n", cudaGetErrorString(err_code));
+		return -1;
+	}
+  switch (prop.major) {
+    case 3:
+      printf("Kepler"); break;
+    case 5:
+      printf("Maxwell"); break;
+    case 6:
+      printf("Pascal"); break;
+    default:
+      fprintf(stderr, "Unspported Device %d%d\n", (int)prop.major, (int)prop.minor);
+      return -1;
+  }
+  printf("%d%d\n", (int)prop.major, (int)prop.minor);
+  return 0;
+}
diff --git a/lib/kokkos/config/test_all_sandia b/lib/kokkos/config/test_all_sandia
index 8e1246bf8b..005cd20721 100755
--- a/lib/kokkos/config/test_all_sandia
+++ b/lib/kokkos/config/test_all_sandia
@@ -160,9 +160,14 @@ if [ "$MACHINE" = "sems" ]; then
     # Format: (compiler module-list build-list exe-name warning-flag)
     COMPILERS=("gcc/4.7.2 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
                "gcc/4.8.4 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
+               "gcc/4.9.3 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
+               "gcc/5.3.0 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
+               "gcc/6.1.0 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
                "intel/14.0.4 $BASE_MODULE_LIST $INTEL_BUILD_LIST icpc $INTEL_WARNING_FLAGS"
                "intel/15.0.2 $BASE_MODULE_LIST $INTEL_BUILD_LIST icpc $INTEL_WARNING_FLAGS"
                "intel/16.0.1 $BASE_MODULE_LIST $INTEL_BUILD_LIST icpc $INTEL_WARNING_FLAGS"
+               "intel/16.0.3 $BASE_MODULE_LIST $INTEL_BUILD_LIST icpc $INTEL_WARNING_FLAGS"
+               "intel/17.0.1 $BASE_MODULE_LIST $INTEL_BUILD_LIST icpc $INTEL_WARNING_FLAGS"
                "clang/3.6.1 $BASE_MODULE_LIST $CLANG_BUILD_LIST clang++ $CLANG_WARNING_FLAGS"
                "clang/3.7.1 $BASE_MODULE_LIST $CLANG_BUILD_LIST clang++ $CLANG_WARNING_FLAGS"
                "clang/3.8.1 $BASE_MODULE_LIST $CLANG_BUILD_LIST clang++ $CLANG_WARNING_FLAGS"
@@ -280,13 +285,13 @@ elif [ "$MACHINE" = "apollo" ]; then
                "gcc/5.1.0 $BASE_MODULE_LIST "Serial" g++ $GCC_WARNING_FLAGS"
                "intel/16.0.1 $BASE_MODULE_LIST "OpenMP" icpc $INTEL_WARNING_FLAGS"
                "clang/3.9.0 $BASE_MODULE_LIST "Pthread_Serial" clang++ $CLANG_WARNING_FLAGS"
-               "clang/head $CLANG_MODULE_LIST "Cuda_Pthread" clang++ $CUDA_WARNING_FLAGS"
+               "clang/4.0.0 $CLANG_MODULE_LIST "Cuda_Pthread" clang++ $CUDA_WARNING_FLAGS"
                "cuda/8.0.44 $CUDA_MODULE_LIST "Cuda_OpenMP" $KOKKOS_PATH/bin/nvcc_wrapper $CUDA_WARNING_FLAGS"
     )
   else
     # Format: (compiler module-list build-list exe-name warning-flag)
     COMPILERS=("cuda/8.0.44 $CUDA8_MODULE_LIST $BUILD_LIST_CUDA_NVCC $KOKKOS_PATH/bin/nvcc_wrapper $CUDA_WARNING_FLAGS"
-               "clang/head $CLANG_MODULE_LIST $BUILD_LIST_CUDA_CLANG clang++ $CUDA_WARNING_FLAGS"
+               "clang/4.0.0 $CLANG_MODULE_LIST $BUILD_LIST_CUDA_CLANG clang++ $CUDA_WARNING_FLAGS"
                "clang/3.9.0 $CLANG_MODULE_LIST $BUILD_LIST_CLANG clang++ $CLANG_WARNING_FLAGS"
                "gcc/4.7.2 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
                "gcc/4.8.4 $BASE_MODULE_LIST $GCC_BUILD_LIST g++ $GCC_WARNING_FLAGS"
@@ -584,7 +589,7 @@ single_build_and_test() {
   else
     run_cmd ${KOKKOS_PATH}/generate_makefile.bash --with-devices=$build $ARCH_FLAG --compiler=$(which $compiler_exe) --cxxflags=\"$cxxflags\" $extra_args &>> ${desc}.configure.log || { report_and_log_test_result 1 ${desc} configure && return 0; }
     local -i build_start_time=$(date +%s)
-    run_cmd make build-test >& ${desc}.build.log || { report_and_log_test_result 1 ${desc} build && return 0; }
+    run_cmd make -j 32 build-test >& ${desc}.build.log || { report_and_log_test_result 1 ${desc} build && return 0; }
     local -i build_end_time=$(date +%s)
     comment="build_time=$(($build_end_time-$build_start_time))"
 
diff --git a/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_pthread_intel b/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_pthread_intel
index 23968e8c0f..6527df2eb9 100755
--- a/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_pthread_intel
+++ b/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_pthread_intel
@@ -28,14 +28,14 @@ export JENKINS_DO_PTHREAD=ON
 export JENKINS_DO_SERIAL=OFF
 export JENKINS_DO_COMPLEX=OFF
 
-export ARCH_CXX_FLAG="-xCORE-AVX2 -mkl"
-export ARCH_C_FLAG="-xCORE-AVX2 -mkl"
+export JENKINS_ARCH_CXX_FLAG="-xCORE-AVX2 -mkl"
+export JENKINS_ARCH_C_FLAG="-xCORE-AVX2 -mkl"
 export BLAS_LIBRARIES="-mkl;${MKLROOT}/lib/intel64/libmkl_intel_lp64.a;${MKLROOT}/lib/intel64/libmkl_intel_thread.a;${MKLROOT}/lib/intel64/libmkl_core.a"
 export LAPACK_LIBRARIES=${BLAS_LIBRARIES}
 
 export JENKINS_DO_TESTS=ON
 export JENKINS_DO_EXAMPLES=ON
-export JENKINS_DO_SHARED=OFF
+export JENKINS_DO_SHARED=ON
 
 export QUEUE=haswell
 
diff --git a/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_serial_intel b/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_serial_intel
index 964de3a002..1a306bc2b2 100755
--- a/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_serial_intel
+++ b/lib/kokkos/config/trilinos-integration/shepard_jenkins_run_script_serial_intel
@@ -28,14 +28,14 @@ export JENKINS_DO_PTHREAD=OFF
 export JENKINS_DO_SERIAL=ON
 export JENKINS_DO_COMPLEX=ON
 
-export ARCH_CXX_FLAG="-xCORE-AVX2 -mkl"
-export ARCH_C_FLAG="-xCORE-AVX2 -mkl"
+export JENKINS_ARCH_CXX_FLAG="-xCORE-AVX2 -mkl"
+export JENKINS_ARCH_C_FLAG="-xCORE-AVX2 -mkl"
 export BLAS_LIBRARIES="-mkl;${MKLROOT}/lib/intel64/libmkl_intel_lp64.a;${MKLROOT}/lib/intel64/libmkl_intel_thread.a;${MKLROOT}/lib/intel64/libmkl_core.a"
 export LAPACK_LIBRARIES=${BLAS_LIBRARIES}
 
 export JENKINS_DO_TESTS=ON
 export JENKINS_DO_EXAMPLES=ON
-export JENKINS_DO_SHARED=OFF
+export JENKINS_DO_SHARED=ON
 
 export QUEUE=haswell
 
diff --git a/lib/kokkos/containers/performance_tests/Makefile b/lib/kokkos/containers/performance_tests/Makefile
index edaaf1ee51..ec69363a17 100644
--- a/lib/kokkos/containers/performance_tests/Makefile
+++ b/lib/kokkos/containers/performance_tests/Makefile
@@ -60,7 +60,6 @@ test-threads: KokkosContainers_PerformanceTest_Threads
 test-openmp: KokkosContainers_PerformanceTest_OpenMP
 	./KokkosContainers_PerformanceTest_OpenMP
 
-
 build_all: $(TARGETS)
 
 test: $(TEST_TARGETS)
diff --git a/lib/kokkos/containers/performance_tests/TestMain.cpp b/lib/kokkos/containers/performance_tests/TestMain.cpp
index f952ab3db5..1224af7cdb 100644
--- a/lib/kokkos/containers/performance_tests/TestMain.cpp
+++ b/lib/kokkos/containers/performance_tests/TestMain.cpp
@@ -1,13 +1,13 @@
 /*
 //@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:
@@ -36,12 +36,15 @@
 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 // Questions? Contact  H. Carter Edwards (hcedwar@sandia.gov)
-// 
+//
 // ************************************************************************
 //@HEADER
 */
 
 #include 
+#include 
+
+#include 
 
 int main(int argc, char *argv[]) {
   ::testing::InitGoogleTest(&argc,argv);
diff --git a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp
index b674ec4a74..6631184624 100644
--- a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp
+++ b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp
@@ -69,30 +69,13 @@ protected:
   {
     std::cout << std::setprecision(5) << std::scientific;
 
-    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::cout << "OpenMP: " << num_threads << std::endl;
-
-    Kokkos::OpenMP::initialize( num_threads );
-
-    std::cout << "available threads: " << omp_get_max_threads() << std::endl;
+    Kokkos::OpenMP::initialize();
+    Kokkos::OpenMP::print_configuration( std::cout );
   }
 
   static void TearDownTestCase()
   {
     Kokkos::OpenMP::finalize();
-
-    omp_set_num_threads(1);
-
-    ASSERT_EQ( 1 , omp_get_max_threads() );
   }
 };
 
diff --git a/lib/kokkos/containers/src/Kokkos_DualView.hpp b/lib/kokkos/containers/src/Kokkos_DualView.hpp
index 937eab0d88..35cc8ec753 100644
--- a/lib/kokkos/containers/src/Kokkos_DualView.hpp
+++ b/lib/kokkos/containers/src/Kokkos_DualView.hpp
@@ -564,7 +564,7 @@ namespace Impl {
 template< class D, class A1, class A2, class A3, class ... Args >
 struct DualViewSubview {
 
-  typedef typename Kokkos::Experimental::Impl::ViewMapping
+  typedef typename Kokkos::Impl::ViewMapping
     < void
     , Kokkos::ViewTraits< D, A1, A2, A3 >
     , Args ...
diff --git a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp
index 8e464506f9..d22d6b865d 100644
--- a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp
+++ b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp
@@ -46,19 +46,6 @@
 ///
 /// This header file declares and defines Kokkos::Experimental::DynRankView and its
 /// related nonmember functions.
-/*
- *   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 name is subdynrankview
- *   4. Every subdynrankview is returned with LayoutStride
- *
- *   NEW: Redesigned DynRankView
- *   5. subview function name now available
- *   6. Copy and Copy-Assign View to DynRankView
- *   7. deep_copy between Views and DynRankViews
- *   8. rank( view ); returns the rank of View or DynRankView
- */
 
 #ifndef KOKKOS_DYNRANKVIEW_HPP
 #define KOKKOS_DYNRANKVIEW_HPP
@@ -117,6 +104,14 @@ struct DynRankDimTraits {
                       , 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 )
+  {
+    return computeRank(layout);
+  }
+
   // Create the layout for the rank-7 view.
   // Non-strided Layout
   template 
@@ -158,8 +153,17 @@ struct DynRankDimTraits {
                  );
   }
 
+  // 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 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
   template 
   static ViewType createView( const ViewArg& arg
                             , const size_t N0
@@ -186,7 +190,8 @@ struct DynRankDimTraits {
   // 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 )
+  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] : ~size_t(0)
                  , dynrank > 1 ? layout.dimension[1] : ~size_t(0)
@@ -202,7 +207,8 @@ struct DynRankDimTraits {
   // 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 )
+  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] : ~size_t(0)
                  , dynrank > 0 ? layout.stride[0] : (0)
@@ -311,6 +317,11 @@ void dyn_rank_view_verify_operator_bounds
 /** \brief  Assign compatible default mappings */
 struct ViewToDynRankViewTag {};
 
+} // namespace Impl
+} // namespace Experimental
+
+namespace Impl {
+
 template< class DstTraits , class SrcTraits >
 class ViewMapping< DstTraits , SrcTraits ,
   typename std::enable_if<(
@@ -337,7 +348,7 @@ class ViewMapping< DstTraits , SrcTraits ,
         )
       )
     )
-  ) , ViewToDynRankViewTag >::type >
+  ) , Kokkos::Experimental::Impl::ViewToDynRankViewTag >::type >
 {
 private:
 
@@ -376,7 +387,7 @@ public:
 
       typedef typename DstType::offset_type  dst_offset_type ;
       dst.m_map.m_offset = dst_offset_type(std::integral_constant() , src.layout() ); //Check this for integer input1 for padding, etc
-      dst.m_map.m_handle = Kokkos::Experimental::Impl::ViewDataHandle< DstTraits >::assign( src.m_map.m_handle , src.m_track );
+      dst.m_map.m_handle = Kokkos::Impl::ViewDataHandle< DstTraits >::assign( src.m_map.m_handle , src.m_track );
       dst.m_track.assign( src.m_track , DstTraits::is_managed );
       dst.m_rank = src.Rank ;
     }
@@ -384,22 +395,20 @@ public:
 
 } //end Impl
 
+namespace Experimental {
+
 /* \class DynRankView
  * \brief Container that creates a Kokkos view with rank determined at runtime.
- *   Essentially this is a rank 7 view that wraps the access operators
- *   to yield the functionality of a view
+ *   Essentially this is a rank 7 view
  *
  *   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 name is subdynrankview
- *   4. Every subdynrankview is returned with LayoutStride
- *
- *   NEW: Redesigned DynRankView
- *   5. subview function name now available
- *   6. Copy and Copy-Assign View to DynRankView
- *   7. deep_copy between Views and DynRankViews
- *   8. rank( view ); returns the rank of View or DynRankView
+ *   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
+ *   7. rank( view ); returns the rank of View or DynRankView
  *
  */
 
@@ -427,7 +436,7 @@ public:
 
 
 private:
-  typedef Kokkos::Experimental::Impl::ViewMapping< traits , void > map_type ;
+  typedef Kokkos::Impl::ViewMapping< traits , void > map_type ;
   typedef Kokkos::Experimental::Impl::SharedAllocationTracker      track_type ;
 
   track_type  m_track ;
@@ -556,7 +565,7 @@ public:
   // Allow specializations to query their specialized map
 
   KOKKOS_INLINE_FUNCTION
-  const Kokkos::Experimental::Impl::ViewMapping< traits , void > &
+  const Kokkos::Impl::ViewMapping< traits , void > &
   implementation_map() const { return m_map ; }
 
   //----------------------------------------
@@ -803,7 +812,7 @@ public:
     , m_rank(rhs.m_rank)
     {
       typedef typename DynRankView ::traits SrcTraits ;
-      typedef Kokkos::Experimental::Impl::ViewMapping< traits , SrcTraits , void > Mapping ;
+      typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , void > Mapping ;
       static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" );
       Mapping::assign( m_map , rhs.m_map , rhs.m_track );
     }
@@ -813,7 +822,7 @@ public:
   DynRankView & operator = (const DynRankView & rhs )
     {
       typedef typename DynRankView ::traits SrcTraits ;
-      typedef Kokkos::Experimental::Impl::ViewMapping< traits , SrcTraits , void > Mapping ;
+      typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , void > 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 );
@@ -831,7 +840,7 @@ public:
     , m_rank( rhs.Rank )
     {
       typedef typename View::traits  SrcTraits ;
-      typedef Kokkos::Experimental::Impl::ViewMapping< traits , SrcTraits , Kokkos::Experimental::Impl::ViewToDynRankViewTag >  Mapping ;
+      typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Experimental::Impl::ViewToDynRankViewTag >  Mapping ;
       static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" );
       Mapping::assign( *this , rhs );
     }
@@ -841,7 +850,7 @@ public:
   DynRankView & operator = ( const View & rhs )
     {
       typedef typename View::traits  SrcTraits ;
-      typedef Kokkos::Experimental::Impl::ViewMapping< traits , SrcTraits , Kokkos::Experimental::Impl::ViewToDynRankViewTag >  Mapping ;
+      typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Experimental::Impl::ViewToDynRankViewTag >  Mapping ;
       static_assert( Mapping::is_assignable , "Incompatible View to DynRankView copy assignment" );
       Mapping::assign( *this , rhs );
       return *this ;
@@ -870,7 +879,7 @@ public:
       )
       : m_track()
       , m_map()
-      , m_rank( Impl::DynRankDimTraits::computeRank(arg_layout) )
+      , m_rank( Impl::DynRankDimTraits::template computeRank< typename traits::array_layout, P...>(arg_prop, arg_layout) )
     {
       // Append layout and spaces if not input
       typedef Impl::ViewCtorProp< P ... > alloc_prop_input ;
@@ -923,7 +932,7 @@ public:
 //------------------------------------------------------------
 
       Kokkos::Experimental::Impl::SharedAllocationRecord<> *
-        record = m_map.allocate_shared( prop , Impl::DynRankDimTraits::createLayout(arg_layout) );
+        record = m_map.allocate_shared( prop , Impl::DynRankDimTraits::template createLayout(arg_prop, arg_layout) );
 
 //------------------------------------------------------------
 #if defined( KOKKOS_ENABLE_CUDA )
@@ -947,8 +956,8 @@ public:
                                >::type const & arg_layout
       )
       : m_track() // No memory tracking
-      , m_map( arg_prop , Impl::DynRankDimTraits::createLayout(arg_layout) )
-      , m_rank( Impl::DynRankDimTraits::computeRank(arg_layout) )
+      , 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
@@ -1034,6 +1043,7 @@ public:
     {}
 
   // For backward compatibility
+  // NDE This ctor does not take ViewCtorProp argument - should not use alternative createLayout call
   explicit inline
   DynRankView( const ViewAllocateWithoutInitializing & arg_prop
       , const typename traits::array_layout & arg_layout
@@ -1179,6 +1189,11 @@ namespace Impl {
 
 struct DynRankSubviewTag {};
 
+} // namespace Impl
+} // namespace Experimental
+
+namespace Impl {
+
 template< class SrcTraits , class ... Args >
 struct ViewMapping
   < typename std::enable_if<(
@@ -1192,7 +1207,7 @@ struct ViewMapping
         std::is_same< typename SrcTraits::array_layout
                     , Kokkos::LayoutStride >::value
       )
-    ), DynRankSubviewTag >::type
+    ), Kokkos::Experimental::Impl::DynRankSubviewTag >::type
   , SrcTraits
   , Args ... >
 {
@@ -1264,7 +1279,7 @@ public:
   };
 
 
-  typedef DynRankView< value_type , array_layout , typename SrcTraits::device_type , typename SrcTraits::memory_traits >  ret_type;
+  typedef Kokkos::Experimental::DynRankView< value_type , array_layout , typename SrcTraits::device_type , typename SrcTraits::memory_traits >  ret_type;
 
   template < typename T , class ... P >
   KOKKOS_INLINE_FUNCTION
@@ -1336,9 +1351,10 @@ public:
 
 } // end Impl
 
+namespace Experimental {
 
 template< class V , class ... Args >
-using Subdynrankview = typename Kokkos::Experimental::Impl::ViewMapping< Kokkos::Experimental::Impl::DynRankSubviewTag , V , Args... >::ret_type ;
+using Subdynrankview = typename Kokkos::Impl::ViewMapping< Kokkos::Experimental::Impl::DynRankSubviewTag , V , Args... >::ret_type ;
 
 template< class D , class ... P , class ...Args >
 KOKKOS_INLINE_FUNCTION
@@ -1348,7 +1364,7 @@ subdynrankview( const Kokkos::Experimental::DynRankView< D , P... > &src , Args.
     if ( src.rank() > sizeof...(Args) ) //allow sizeof...(Args) >= src.rank(), ignore the remaining args
       { Kokkos::abort("subdynrankview: num of args must be >= rank of the source DynRankView"); }
 
-    typedef Kokkos::Experimental::Impl::ViewMapping< Kokkos::Experimental::Impl::DynRankSubviewTag , Kokkos::ViewTraits< D*******, P... > , Args... > metafcn ;
+    typedef Kokkos::Impl::ViewMapping< Kokkos::Experimental::Impl::DynRankSubviewTag , Kokkos::ViewTraits< D*******, P... > , Args... > metafcn ;
 
     return metafcn::subview( src.rank() , src , args... );
   }
diff --git a/lib/kokkos/containers/src/Kokkos_DynamicView.hpp b/lib/kokkos/containers/src/Kokkos_DynamicView.hpp
index da96db2d6b..e9059d64c4 100644
--- a/lib/kokkos/containers/src/Kokkos_DynamicView.hpp
+++ b/lib/kokkos/containers/src/Kokkos_DynamicView.hpp
@@ -1,13 +1,13 @@
 /*
 //@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:
@@ -36,7 +36,7 @@
 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 // Questions? Contact  H. Carter Edwards (hcedwar@sandia.gov)
-// 
+//
 // ************************************************************************
 //@HEADER
 */
@@ -57,7 +57,7 @@ namespace Experimental {
  */
 template< typename DataType , typename ... P >
 class DynamicView : public Kokkos::ViewTraits< DataType , P ... >
-{ 
+{
 public:
 
   typedef Kokkos::ViewTraits< DataType , P ... >  traits ;
@@ -68,7 +68,7 @@ private:
 
   typedef Kokkos::Experimental::Impl::SharedAllocationTracker   track_type ;
 
-  static_assert( traits::rank == 1 && traits::rank_dynamic == 1 
+  static_assert( traits::rank == 1 && traits::rank_dynamic == 1
                , "DynamicView must be rank-one" );
 
   static_assert( std::is_trivial< typename traits::value_type >::value &&
@@ -216,14 +216,14 @@ public:
         // Verify that allocation of the requested chunk in in progress.
 
         // The allocated chunk counter is m_chunks[ m_chunk_max ]
-        const uintptr_t n = 
+        const uintptr_t n =
           *reinterpret_cast( m_chunks + m_chunk_max );
 
         if ( n <= ic ) {
           Kokkos::abort("Kokkos::DynamicView array bounds error");
         }
 
-        // Allocation of this chunk is in progress 
+        // Allocation of this chunk is in progress
         // so wait for allocation to complete.
         while ( 0 == *ch );
       }
@@ -267,7 +267,7 @@ public:
         const uintptr_t jc_try = jc ;
 
         // Jump iteration to the chunk counter.
-        
+
         jc = atomic_compare_exchange( pc , jc_try , jc_try + 1 );
 
         if ( jc_try == jc ) {
@@ -316,7 +316,7 @@ public:
       }
       else {
         while ( NC + 1 <= *pc ) {
-          --*pc ;        
+          --*pc ;
           m_pool.deallocate( m_chunks[*pc]
                            , sizeof(value_type) << m_chunk_shift );
           m_chunks[*pc] = 0 ;
@@ -331,7 +331,7 @@ public:
     typename traits::value_type ** m_chunks ;
     uintptr_t                    * m_pc ;
     uintptr_t                      m_nc ;
-    unsigned                       m_chunk_shift ;  
+    unsigned                       m_chunk_shift ;
 
     KOKKOS_INLINE_FUNCTION
     void operator()( int ) const
@@ -348,7 +348,7 @@ public:
         }
         else {
           while ( m_nc + 1 <= *m_pc ) {
-            --*m_pc ;        
+            --*m_pc ;
             m_pool.deallocate( m_chunks[*m_pc]
                              , sizeof(value_type) << m_chunk_shift );
             m_chunks[*m_pc] = 0 ;
@@ -482,7 +482,7 @@ public:
   };
 
 
-  /**\brief  Allocation constructor 
+  /**\brief  Allocation constructor
    *
    *  Memory is allocated in chunks from the memory pool.
    *  The chunk size conforms to the memory pool's chunk size.
@@ -557,7 +557,7 @@ void deep_copy( const View & dst
 
   if ( DstExecCanAccessSrc ) {
     // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape.
-    Kokkos::Experimental::Impl::ViewRemap< dst_type , src_type >( dst , src );
+    Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src );
   }
   else {
     Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation");
@@ -581,7 +581,7 @@ void deep_copy( const DynamicView & dst
 
   if ( DstExecCanAccessSrc ) {
     // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape.
-    Kokkos::Experimental::Impl::ViewRemap< dst_type , src_type >( dst , src );
+    Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src );
   }
   else {
     Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation");
diff --git a/lib/kokkos/containers/unit_tests/TestCuda.cpp b/lib/kokkos/containers/unit_tests/TestCuda.cpp
index 5a78a5de9e..651a4e7eb8 100644
--- a/lib/kokkos/containers/unit_tests/TestCuda.cpp
+++ b/lib/kokkos/containers/unit_tests/TestCuda.cpp
@@ -69,6 +69,8 @@
 #include 
 #include 
 
+#include 
+
 //----------------------------------------------------------------------------
 
 
@@ -94,6 +96,10 @@ TEST_F( cuda , dyn_view_api) {
   TestDynViewAPI< double , Kokkos::Cuda >();
 }
 
+TEST_F( cuda, viewctorprop_embedded_dim ) {
+  TestViewCtorProp_EmbeddedDim< Kokkos::Cuda >::test_vcpt( 2, 3 );
+}
+
 TEST_F( cuda , staticcrsgraph )
 {
   TestStaticCrsGraph::run_test_graph< Kokkos::Cuda >();
diff --git a/lib/kokkos/containers/unit_tests/TestOpenMP.cpp b/lib/kokkos/containers/unit_tests/TestOpenMP.cpp
index 2448bd077b..5365d91361 100644
--- a/lib/kokkos/containers/unit_tests/TestOpenMP.cpp
+++ b/lib/kokkos/containers/unit_tests/TestOpenMP.cpp
@@ -66,6 +66,8 @@
 #include 
 #include 
 
+#include 
+
 #include 
 
 namespace Test {
@@ -76,14 +78,7 @@ protected:
   {
     std::cout << std::setprecision(5) << std::scientific;
 
-    unsigned threads_count = 4 ;
-
-    if ( Kokkos::hwloc::available() ) {
-      threads_count = Kokkos::hwloc::get_available_numa_count() *
-                      Kokkos::hwloc::get_available_cores_per_numa();
-    }
-
-    Kokkos::OpenMP::initialize( threads_count );
+    Kokkos::OpenMP::initialize();
   }
 
   static void TearDownTestCase()
@@ -96,6 +91,10 @@ TEST_F( openmp, dyn_view_api) {
   TestDynViewAPI< double , Kokkos::OpenMP >();
 }
 
+TEST_F( openmp, viewctorprop_embedded_dim ) {
+  TestViewCtorProp_EmbeddedDim< Kokkos::OpenMP >::test_vcpt( 2, 3 );
+}
+
 TEST_F( openmp, bitset )
 {
   test_bitset();
diff --git a/lib/kokkos/containers/unit_tests/TestSerial.cpp b/lib/kokkos/containers/unit_tests/TestSerial.cpp
index 06c4d9f6ed..1b9b5a2da3 100644
--- a/lib/kokkos/containers/unit_tests/TestSerial.cpp
+++ b/lib/kokkos/containers/unit_tests/TestSerial.cpp
@@ -67,6 +67,8 @@
 #include 
 #include 
 
+#include 
+
 namespace Test {
 
 class serial : public ::testing::Test {
@@ -85,6 +87,10 @@ TEST_F( serial, dyn_view_api) {
   TestDynViewAPI< double , Kokkos::Serial >();
 }
 
+TEST_F( serial, viewctorprop_embedded_dim ) {
+  TestViewCtorProp_EmbeddedDim< Kokkos::Serial >::test_vcpt( 2, 3 );
+}
+
 TEST_F( serial , staticcrsgraph )
 {
   TestStaticCrsGraph::run_test_graph< Kokkos::Serial >();
diff --git a/lib/kokkos/containers/unit_tests/TestThreads.cpp b/lib/kokkos/containers/unit_tests/TestThreads.cpp
index 938ec88e90..aca0b57d65 100644
--- a/lib/kokkos/containers/unit_tests/TestThreads.cpp
+++ b/lib/kokkos/containers/unit_tests/TestThreads.cpp
@@ -70,6 +70,8 @@
 #include 
 #include 
 
+#include 
+
 namespace Test {
 
 class threads : public ::testing::Test {
@@ -103,6 +105,10 @@ TEST_F( threads , dyn_view_api) {
   TestDynViewAPI< double , Kokkos::Threads >();
 }
 
+TEST_F( threads, viewctorprop_embedded_dim ) {
+  TestViewCtorProp_EmbeddedDim< Kokkos::Threads >::test_vcpt( 2, 3 );
+}
+
 TEST_F( threads , staticcrsgraph )
 {
   TestStaticCrsGraph::run_test_graph< Kokkos::Threads >();
diff --git a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp
new file mode 100644
index 0000000000..1efd1ddc51
--- /dev/null
+++ b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp
@@ -0,0 +1,213 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+
+namespace Test {
+
+namespace {
+
+template 
+struct TestViewCtorProp_EmbeddedDim {
+
+  using ViewIntType     = typename Kokkos::View< int**, ExecSpace >;
+  using ViewDoubleType     = typename Kokkos::View< double*, ExecSpace >;
+
+  using DynRankViewIntType     = typename Kokkos::DynRankView< int, ExecSpace >;
+  using DynRankViewDoubleType     = typename Kokkos::DynRankView< double, ExecSpace >;
+
+  // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the view - replace with this functor
+  template < class ViewType >
+  struct Functor {
+
+    ViewType v;
+
+    Functor( const ViewType & v_ ) : v(v_) {}
+
+    KOKKOS_INLINE_FUNCTION
+    void operator()( const int i ) const {
+      v(i) = i;
+    }
+
+  };
+
+
+  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 ;
+
+      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
+      {
+        // 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 );
+
+        Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), 
+          Functor(cv1)
+        );
+
+        HostCVT hcv1 = Kokkos::create_mirror_view( cv1 );
+        Kokkos::deep_copy( hcv1, cv1 );
+
+        ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ;
+      #if 0
+      // debug output
+      for ( int i = 0; i < N0*N1; ++i ) {
+        printf(" Output check: hcv1(%d) = %lf\n ", i, hcv1(i) );
+      }
+
+      printf( " Common value type view: %s \n", typeid( CVT() ).name() );
+      printf( " Common value type: %s \n", typeid( CommonViewValueType() ).name() );
+      if ( std::is_same< CommonViewValueType, double >::value == true ) {
+        printf("Proper common value_type\n");
+      }
+      else {
+        printf("WRONG common value_type\n");
+      }
+      // end debug output
+      #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;
+
+        // 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)
+        );
+
+        HostCVT hcv1 = Kokkos::create_mirror_view( cv1 );
+        Kokkos::deep_copy( hcv1, cv1 );
+
+        ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ;
+      }
+
+    }
+
+    // Create two dynamic rank views to test
+    {
+      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
+      {
+        // 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 );
+
+
+        Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), 
+          Functor(cv1)
+        );
+
+        HostCVT hcv1 = Kokkos::create_mirror_view( cv1 );
+        Kokkos::deep_copy( hcv1, cv1 );
+
+        ASSERT_EQ( (std::is_same< CommonViewValueType, double >::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;
+
+        // 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)
+        );
+
+        HostCVT hcv1 = Kokkos::create_mirror_view( cv1 );
+        Kokkos::deep_copy( hcv1, cv1 );
+
+        ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ;
+      }
+    }
+
+
+  } // end test_vcpt
+
+}; // end struct
+
+} // namespace
+
+} // namespace Test
diff --git a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp
index f952ab3db5..2b73535c83 100644
--- a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp
+++ b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp
@@ -1,13 +1,13 @@
 /*
 //@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:
@@ -36,12 +36,14 @@
 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 // Questions? Contact  H. Carter Edwards (hcedwar@sandia.gov)
-// 
+//
 // ************************************************************************
 //@HEADER
 */
 
 #include 
+#include 
+#include 
 
 int main(int argc, char *argv[]) {
   ::testing::InitGoogleTest(&argc,argv);
diff --git a/lib/kokkos/core/perf_test/Makefile b/lib/kokkos/core/perf_test/Makefile
index f59e7bbe1c..bb9353f583 100644
--- a/lib/kokkos/core/perf_test/Makefile
+++ b/lib/kokkos/core/perf_test/Makefile
@@ -79,7 +79,6 @@ test-mempool: KokkosCore_PerformanceTest_Mempool
 test-taskdag: KokkosCore_PerformanceTest_TaskDAG
 	./KokkosCore_PerformanceTest_TaskDAG
 
-
 build_all: $(TARGETS)
 
 test: $(TEST_TARGETS)
diff --git a/lib/kokkos/core/perf_test/PerfTestMain.cpp b/lib/kokkos/core/perf_test/PerfTestMain.cpp
index d80cfab8b5..832f650b9a 100644
--- a/lib/kokkos/core/perf_test/PerfTestMain.cpp
+++ b/lib/kokkos/core/perf_test/PerfTestMain.cpp
@@ -1,13 +1,13 @@
 /*
 //@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:
@@ -36,12 +36,14 @@
 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 //
 // Questions? Contact  H. Carter Edwards (hcedwar@sandia.gov)
-// 
+//
 // ************************************************************************
 //@HEADER
 */
 
 #include 
+#include 
+
 #include 
 
 namespace Test {
diff --git a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp
new file mode 100644
index 0000000000..46321378d9
--- /dev/null
+++ b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp
@@ -0,0 +1,2715 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#ifndef KOKKOS_CUDA_EXP_ITERATE_TILE_REFACTOR_HPP
+#define KOKKOS_CUDA_EXP_ITERATE_TILE_REFACTOR_HPP
+
+#include 
+#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA )
+
+#include 
+#include 
+#include 
+
+#include 
+
+// #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
+
+#if defined(KOKKOS_ENABLE_PROFILING)
+#include 
+#include 
+#endif
+
+namespace Kokkos { namespace Experimental { namespace Impl {
+
+namespace Refactor {
+
+// ------------------------------------------------------------------ //
+// ParallelFor iteration pattern
+template< int N , typename RP , typename Functor , typename Tag >
+struct DeviceIterateTile;
+
+//Rank 2
+// Specializations for void tag type
+template< typename RP , typename Functor >
+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_)
+  {}
+
+  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;
+        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;
+            if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) {
+              m_func(offset_0 , offset_1);
+            }
+          }
+        }
+      }
+    }
+    // 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;
+        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;
+            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
+
+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>
+{
+  using index_type = typename RP::index_type;
+
+  inline __device__
+  DeviceIterateTile( 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 = (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;
+        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;
+            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;
+        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;
+            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
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+};
+
+
+//Rank 3
+// Specializations for void tag type
+template< typename RP , typename Functor >
+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_)
+  {}
+
+  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;
+        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;
+            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;
+                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);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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;
+        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;
+            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;
+                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);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+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>
+{
+  using index_type = typename RP::index_type;
+
+  inline __device__
+  DeviceIterateTile( const RP & rp_ , const Functor & f_ )
+  : m_rp(rp_)
+  , m_func(f_)
+  {}
+
+  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;
+        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;
+            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;
+                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;
+        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;
+            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;
+                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);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+};
+
+
+//Rank 4
+// Specializations for void tag type
+template< typename RP , typename Functor >
+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_)
+  {}
+
+  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() );
+    // 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 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;
+        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;
+            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;
+                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;
+                    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);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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 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;
+        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;
+            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;
+                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;
+                    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);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+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>
+{
+  using index_type = typename RP::index_type;
+
+  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() );
+    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 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;
+        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;
+            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;
+                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;
+                    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);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    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;
+        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;
+            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;
+                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;
+                    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);
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+};
+
+
+//Rank 5
+// Specializations for void tag type
+template< typename RP , typename Functor >
+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_)
+  {}
+
+  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() );
+    // 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 ) );
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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);
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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 ) );
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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);
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+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>
+{
+  using index_type = typename RP::index_type;
+
+  __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() );
+    // 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 ) );
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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);
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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 ) );
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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);
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+};
+
+
+//Rank 6
+// Specializations for void tag type
+template< typename RP , typename Functor >
+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_)
+  {}
+
+  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() );
+    // 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 ) );
+
+      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];
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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;
+                            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);
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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 ) );
+
+      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];
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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;
+                            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);
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+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>
+{
+  using index_type = typename RP::index_type;
+
+  __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() );
+    // 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 ) );
+
+      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];
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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;
+                            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);
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // 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 ) );
+
+      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];
+
+      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];
+
+      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;
+        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;
+            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;
+                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;
+                    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;
+                        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;
+                            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);
+                            }
+                          }
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+};
+
+} // Refactor
+
+// ----------------------------------------------------------------------------------
+
+namespace Reduce {
+
+template < typename T >
+using is_void = std::is_same< T, void >;
+
+template < typename T >
+struct is_array_type : std::false_type
+{
+  using value_type = T;
+};
+
+template < typename T >
+struct is_array_type< T* > : std::true_type
+{
+  using value_type = T;
+};
+
+template < typename T >
+struct is_array_type< T[] > : std::true_type
+{
+  using value_type = T;
+};
+
+// ------------------------------------------------------------------ //
+template< int N , typename RP , typename Functor , typename Tag , typename ValueType , typename Enable = void >
+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
+
+// Pattern:
+// 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)
+// 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
+
+// ValueType = T
+//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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_v ); }
+        }
+      }
+    }
+
+  } //end exec_range
+
+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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( Tag(), m_offset[0], m_offset[1], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  ValueType & m_v;
+};
+
+
+//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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  ValueType & m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  ValueType & m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  ValueType & m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  ValueType & m_v;
+};
+
+
+// ValueType = T[], T*
+//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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          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 exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  value_type* m_v;
+};
+
+
+//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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  value_type* m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              in_bounds &= false;
+            }
+          }
+          if ( in_bounds )
+          { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  value_type* m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  value_type* m_v;
+};
+
+
+//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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+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 >
+{
+  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_)
+  {}
+
+  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
+        index_type thrd_idx = (index_type)threadIdx.y;
+        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] ;
+            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]);
+            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]) ) {
+              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 ); }
+        }
+      }
+    }
+  } //end exec_range
+
+private:
+  const RP & m_rp;
+  const Functor & m_func;
+  value_type* m_v;
+};
+
+} // Reduce
+
+// ----------------------------------------------------------------------------------
+
+} } } //end namespace Kokkos::Experimental::Impl
+
+#endif
+#endif
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp b/lib/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp
index 13abcfd93c..cae8ecd489 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp
@@ -53,6 +53,7 @@
 #include 
 #include 
 #include 
+#include 
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
@@ -125,53 +126,12 @@ unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits:
 
 #endif
 
-
-namespace Kokkos {
-namespace Impl {
-  struct CudaLockArraysStruct {
-    int* atomic;
-    int* scratch;
-    int* threadid;
-    int n;
-  };
-}
-}
-__device__ __constant__
-#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-extern
-#endif
-Kokkos::Impl::CudaLockArraysStruct kokkos_impl_cuda_lock_arrays ;
-
-#define CUDA_SPACE_ATOMIC_MASK 0x1FFFF
-#define CUDA_SPACE_ATOMIC_XOR_MASK 0x15A39
-
 namespace Kokkos {
 namespace Impl {
   void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink = false);
 }
 }
 
-namespace Kokkos {
-namespace Impl {
-__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_cuda_lock_arrays.atomic[offset],0,1));
-}
-
-__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_cuda_lock_arrays.atomic[ offset ], 0);
-}
-
-}
-}
-
 template< typename T >
 inline
 __device__
@@ -192,7 +152,7 @@ namespace Impl {
 // For 2.0 capability: 48 KB L1 and 16 KB shared
 //----------------------------------------------------------------------------
 
-template< class DriverType >
+template< class DriverType>
 __global__
 static void cuda_parallel_launch_constant_memory()
 {
@@ -202,19 +162,39 @@ static void cuda_parallel_launch_constant_memory()
   driver();
 }
 
-template< class DriverType >
+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 );
+
+  driver();
+}
+
+template< class DriverType>
 __global__
 static void cuda_parallel_launch_local_memory( const DriverType driver )
 {
   driver();
 }
 
-template < class DriverType ,
-           bool Large = ( CudaTraits::ConstantMemoryUseThreshold < sizeof(DriverType) ) >
+template< class DriverType, unsigned int maxTperB, unsigned int minBperSM >
+__global__
+__launch_bounds__(maxTperB, minBperSM)
+static void cuda_parallel_launch_local_memory( const DriverType driver )
+{
+  driver();
+}
+
+template < class DriverType
+         , class LaunchBounds = Kokkos::LaunchBounds<>
+         , bool Large = ( CudaTraits::ConstantMemoryUseThreshold < sizeof(DriverType) ) >
 struct CudaParallelLaunch ;
 
-template < class DriverType >
-struct CudaParallelLaunch< DriverType , true > {
+template < class DriverType, class LaunchBounds >
+struct CudaParallelLaunch< DriverType, LaunchBounds, true > {
 
   inline
   CudaParallelLaunch( const DriverType & driver
@@ -238,26 +218,19 @@ struct CudaParallelLaunch< DriverType , true > {
       }
       #ifndef KOKKOS_ARCH_KEPLER //On Kepler the L1 has no benefit since it doesn't cache reads
       else if ( shmem ) {
-        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_constant_memory< DriverType > , cudaFuncCachePreferShared ) );
+        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_constant_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM > , cudaFuncCachePreferShared ) );
       } else {
-        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_constant_memory< DriverType > , cudaFuncCachePreferL1 ) );
+        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_constant_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM > , cudaFuncCachePreferL1 ) );
       }
       #endif
 
       // Copy functor to constant memory on the device
       cudaMemcpyToSymbol( kokkos_impl_cuda_constant_memory_buffer , & driver , sizeof(DriverType) );
 
-      #ifndef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-      Kokkos::Impl::CudaLockArraysStruct locks;
-      locks.atomic = atomic_lock_array_cuda_space_ptr(false);
-      locks.scratch = scratch_lock_array_cuda_space_ptr(false);
-      locks.threadid = threadid_lock_array_cuda_space_ptr(false);
-      locks.n = Kokkos::Cuda::concurrency();
-      cudaMemcpyToSymbol( kokkos_impl_cuda_lock_arrays , & locks , sizeof(CudaLockArraysStruct) );
-      #endif
+      KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE();
 
       // Invoke the driver function on the device
-      cuda_parallel_launch_constant_memory< DriverType ><<< grid , block , shmem , stream >>>();
+      cuda_parallel_launch_constant_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM ><<< grid , block , shmem , stream >>>();
 
 #if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
       CUDA_SAFE_CALL( cudaGetLastError() );
@@ -267,8 +240,8 @@ struct CudaParallelLaunch< DriverType , true > {
   }
 };
 
-template < class DriverType >
-struct CudaParallelLaunch< DriverType , false > {
+template < class DriverType, class LaunchBounds >
+struct CudaParallelLaunch< DriverType, LaunchBounds, false > {
 
   inline
   CudaParallelLaunch( const DriverType & driver
@@ -284,22 +257,15 @@ struct CudaParallelLaunch< DriverType , false > {
       }
       #ifndef KOKKOS_ARCH_KEPLER //On Kepler the L1 has no benefit since it doesn't cache reads
       else if ( shmem ) {
-        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_local_memory< DriverType > , cudaFuncCachePreferShared ) );
+        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_local_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM > , cudaFuncCachePreferShared ) );
       } else {
-        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_local_memory< DriverType > , cudaFuncCachePreferL1 ) );
+        CUDA_SAFE_CALL( cudaFuncSetCacheConfig( cuda_parallel_launch_local_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM > , cudaFuncCachePreferL1 ) );
       }
       #endif
 
-      #ifndef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-      Kokkos::Impl::CudaLockArraysStruct locks;
-      locks.atomic = atomic_lock_array_cuda_space_ptr(false);
-      locks.scratch = scratch_lock_array_cuda_space_ptr(false);
-      locks.threadid = threadid_lock_array_cuda_space_ptr(false);
-      locks.n = Kokkos::Cuda::concurrency();
-      cudaMemcpyToSymbol( kokkos_impl_cuda_lock_arrays , & locks , sizeof(CudaLockArraysStruct) );
-      #endif
+      KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE();
 
-      cuda_parallel_launch_local_memory< DriverType ><<< grid , block , shmem , stream >>>( driver );
+      cuda_parallel_launch_local_memory< DriverType, LaunchBounds::maxTperB, LaunchBounds::minBperSM ><<< grid , block , shmem , stream >>>( driver );
 
 #if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK )
       CUDA_SAFE_CALL( cudaGetLastError() );
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp
index 406b4f1e22..b699f0d6ba 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp
@@ -230,18 +230,6 @@ void CudaHostPinnedSpace::deallocate( void * const arg_alloc_ptr , const size_t
   } catch(...) {}
 }
 
-constexpr const char* CudaSpace::name() {
-  return m_name;
-}
-
-constexpr const char* CudaUVMSpace::name() {
-  return m_name;
-}
-
-constexpr const char* CudaHostPinnedSpace::name() {
-  return m_name;
-}
-
 } // namespace Kokkos
 
 //----------------------------------------------------------------------------
@@ -655,11 +643,12 @@ reallocate_tracked( void * const arg_alloc_ptr
 SharedAllocationRecord< Kokkos::CudaSpace , void > *
 SharedAllocationRecord< Kokkos::CudaSpace , void >::get_record( void * alloc_ptr )
 {
-  using Header     = SharedAllocationHeader ;
   using RecordBase = SharedAllocationRecord< void , void > ;
   using RecordCuda = SharedAllocationRecord< Kokkos::CudaSpace , void > ;
 
 #if 0
+  using Header     = SharedAllocationHeader ;
+
   // Copy the header from the allocation
   Header head ;
 
@@ -812,83 +801,6 @@ print_records( std::ostream & s , const Kokkos::CudaHostPinnedSpace & space , bo
   SharedAllocationRecord< void , void >::print_host_accessible_records( s , "CudaHostPinned" , & s_root_record , detail );
 }
 
-} // namespace Impl
-} // namespace Kokkos
-
-/*--------------------------------------------------------------------------*/
-/*--------------------------------------------------------------------------*/
-
-namespace Kokkos {
-namespace {
-  __global__ void init_lock_array_kernel_atomic() {
-    unsigned i = blockIdx.x*blockDim.x + threadIdx.x;
-
-    if(i>>();
-    init_lock_array_kernel_scratch_threadid<<<(Kokkos::Cuda::concurrency()+255)/256,256>>>(Kokkos::Cuda::concurrency());
-  }
-}
-
 void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) {
   static void* ptr = NULL;
   static std::int64_t current_size = 0;
@@ -908,8 +820,8 @@ void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) {
   return ptr;
 }
 
-}
-}
+} // namespace Impl
+} // namespace Kokkos
 #else
 void KOKKOS_CORE_SRC_CUDA_CUDASPACE_PREVENT_LINK_ERROR() {}
 #endif // KOKKOS_ENABLE_CUDA
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Impl.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Impl.cpp
index daf55cbd97..80e8f9bd8a 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Impl.cpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Impl.cpp
@@ -51,6 +51,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -69,9 +70,6 @@
 __device__ __constant__
 unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long) ] ;
 
-__device__ __constant__
-Kokkos::Impl::CudaLockArraysStruct kokkos_impl_cuda_lock_arrays ;
-
 #endif
 
 /*--------------------------------------------------------------------------*/
@@ -103,6 +101,7 @@ int cuda_kernel_arch()
   return arch ;
 }
 
+#ifdef KOKKOS_ENABLE_CUDA_UVM
 bool cuda_launch_blocking()
 {
   const char * env = getenv("CUDA_LAUNCH_BLOCKING");
@@ -111,16 +110,13 @@ bool cuda_launch_blocking()
 
   return atoi(env);
 }
+#endif
 
 }
 
 void cuda_device_synchronize()
 {
-//  static const bool launch_blocking = cuda_launch_blocking();
-
-//  if (!launch_blocking) {
-    CUDA_SAFE_CALL( cudaDeviceSynchronize() );
-//  }
+  CUDA_SAFE_CALL( cudaDeviceSynchronize() );
 }
 
 void cuda_internal_error_throw( cudaError e , const char * name, const char * file, const int line )
@@ -240,6 +236,7 @@ public:
   unsigned    m_maxWarpCount ;
   unsigned    m_maxBlock ;
   unsigned    m_maxSharedWords ;
+  uint32_t    m_maxConcurrency ;
   size_type   m_scratchSpaceCount ;
   size_type   m_scratchFlagsCount ;
   size_type   m_scratchUnifiedCount ;
@@ -248,6 +245,7 @@ public:
   size_type * m_scratchSpace ;
   size_type * m_scratchFlags ;
   size_type * m_scratchUnified ;
+  uint32_t  * m_scratchConcurrentBitset ;
   cudaStream_t * m_stream ;
 
   static int was_initialized;
@@ -274,6 +272,7 @@ public:
     , m_maxWarpCount( 0 )
     , m_maxBlock( 0 )
     , m_maxSharedWords( 0 )
+    , m_maxConcurrency( 0 )
     , m_scratchSpaceCount( 0 )
     , m_scratchFlagsCount( 0 )
     , m_scratchUnifiedCount( 0 )
@@ -282,6 +281,7 @@ public:
     , m_scratchSpace( 0 )
     , m_scratchFlags( 0 )
     , m_scratchUnified( 0 )
+    , m_scratchConcurrentBitset( 0 )
     , m_stream( 0 )
     {}
 
@@ -327,7 +327,8 @@ CudaInternal::~CudaInternal()
   if ( m_stream ||
        m_scratchSpace ||
        m_scratchFlags ||
-       m_scratchUnified ) {
+       m_scratchUnified ||
+       m_scratchConcurrentBitset ) {
     std::cerr << "Kokkos::Cuda ERROR: Failed to call Kokkos::Cuda::finalize()"
               << std::endl ;
     std::cerr.flush();
@@ -339,6 +340,7 @@ CudaInternal::~CudaInternal()
   m_maxWarpCount            = 0 ;
   m_maxBlock                = 0 ;
   m_maxSharedWords          = 0 ;
+  m_maxConcurrency          = 0 ;
   m_scratchSpaceCount       = 0 ;
   m_scratchFlagsCount       = 0 ;
   m_scratchUnifiedCount     = 0 ;
@@ -347,6 +349,7 @@ CudaInternal::~CudaInternal()
   m_scratchSpace            = 0 ;
   m_scratchFlags            = 0 ;
   m_scratchUnified          = 0 ;
+  m_scratchConcurrentBitset = 0 ;
   m_stream                  = 0 ;
 }
 
@@ -485,6 +488,33 @@ void CudaInternal::initialize( int cuda_device_id , int stream_count )
       (void) scratch_space( reduce_block_count * 16 * sizeof(size_type) );
     }
     //----------------------------------
+    // Concurrent bitset for obtaining unique tokens from within
+    // an executing kernel.
+    {
+      const unsigned max_threads_per_sm = 2048 ; // up to capability 7.0
+
+      m_maxConcurrency =
+        max_threads_per_sm * cudaProp.multiProcessorCount ;
+
+      const int32_t buffer_bound =
+         Kokkos::Impl::concurrent_bitset::buffer_bound( m_maxConcurrency );
+
+      // Allocate and initialize uint32_t[ buffer_bound ]
+
+      typedef Kokkos::Experimental::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ;
+
+      Record * const r = Record::allocate( Kokkos::CudaSpace()
+                                         , "InternalScratchBitset"
+                                         , sizeof(uint32_t) * buffer_bound );
+
+      Record::increment( r );
+
+      m_scratchConcurrentBitset = reinterpret_cast( r->data() );
+
+      CUDA_SAFE_CALL( cudaMemset( m_scratchConcurrentBitset , 0 , sizeof(uint32_t) * buffer_bound ) );
+
+    }
+    //----------------------------------
 
     if ( stream_count ) {
       m_stream = (cudaStream_t*) ::malloc( stream_count * sizeof(cudaStream_t) );
@@ -543,16 +573,7 @@ void CudaInternal::initialize( int cuda_device_id , int stream_count )
   cudaThreadSetCacheConfig(cudaFuncCachePreferShared);
 
   // Init the array for used for arbitrarily sized atomics
-  Impl::init_lock_arrays_cuda_space();
-
-  #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-  Kokkos::Impl::CudaLockArraysStruct locks;
-  locks.atomic = atomic_lock_array_cuda_space_ptr(false);
-  locks.scratch = scratch_lock_array_cuda_space_ptr(false);
-  locks.threadid = threadid_lock_array_cuda_space_ptr(false);
-  locks.n = Kokkos::Cuda::concurrency();
-  cudaMemcpyToSymbol( kokkos_impl_cuda_lock_arrays , & locks , sizeof(CudaLockArraysStruct) );
-  #endif
+  Impl::initialize_host_cuda_lock_arrays();
 }
 
 //----------------------------------------------------------------------------
@@ -635,9 +656,7 @@ void CudaInternal::finalize()
   was_finalized = 1;
   if ( 0 != m_scratchSpace || 0 != m_scratchFlags ) {
 
-    atomic_lock_array_cuda_space_ptr(true);
-    scratch_lock_array_cuda_space_ptr(true);
-    threadid_lock_array_cuda_space_ptr(true);
+    Impl::finalize_host_cuda_lock_arrays();
 
     if ( m_stream ) {
       for ( size_type i = 1 ; i < m_streamCount ; ++i ) {
@@ -653,6 +672,7 @@ void CudaInternal::finalize()
     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 ) );
 
     m_cudaDev             = -1 ;
     m_multiProcCount      = 0 ;
@@ -666,6 +686,7 @@ void CudaInternal::finalize()
     m_scratchSpace        = 0 ;
     m_scratchFlags        = 0 ;
     m_scratchUnified      = 0 ;
+    m_scratchConcurrentBitset = 0 ;
     m_stream              = 0 ;
   }
 }
@@ -713,9 +734,8 @@ namespace Kokkos {
 Cuda::size_type Cuda::detect_device_count()
 { return Impl::CudaInternalDevices::singleton().m_cudaDevCount ; }
 
-int Cuda::concurrency() {
-  return 131072;
-}
+int Cuda::concurrency()
+{ return Impl::CudaInternal::singleton().m_maxConcurrency ; }
 
 int Cuda::is_initialized()
 { return Impl::CudaInternal::singleton().is_initialized(); }
@@ -798,7 +818,22 @@ void Cuda::fence()
 const char* Cuda::name() { return "Cuda"; }
 
 } // 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 )
+  {}
+
+} // namespace Experimental
+} // namespace Kokkos
+
 #else
+
 void KOKKOS_CORE_SRC_CUDA_IMPL_PREVENT_LINK_ERROR() {}
+
 #endif // KOKKOS_ENABLE_CUDA
 
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp
new file mode 100644
index 0000000000..237022ad23
--- /dev/null
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp
@@ -0,0 +1,119 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#include 
+
+#ifdef KOKKOS_ENABLE_CUDA
+
+#include 
+#include 
+#include 
+
+#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
+namespace Kokkos {
+namespace Impl {
+__device__ __constant__
+CudaLockArrays g_device_cuda_lock_arrays = { nullptr, nullptr, 0 };
+}
+}
+#endif
+
+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());
+  CUDA_SAFE_CALL(cudaDeviceSynchronize());
+}
+
+void finalize_host_cuda_lock_arrays() {
+  if (g_host_cuda_lock_arrays.atomic == nullptr) return;
+  cudaFree(g_host_cuda_lock_arrays.atomic);
+  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;
+#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
+  KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE();
+#endif
+}
+
+} // namespace Impl
+
+} // namespace Kokkos
+
+#else
+
+void KOKKOS_CORE_SRC_CUDA_CUDA_LOCKS_PREVENT_LINK_ERROR() {}
+
+#endif
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp
new file mode 100644
index 0000000000..d01f06fb4f
--- /dev/null
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp
@@ -0,0 +1,166 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#ifndef KOKKOS_CUDA_LOCKS_HPP
+#define KOKKOS_CUDA_LOCKS_HPP
+
+#include 
+
+#ifdef KOKKOS_ENABLE_CUDA
+
+#include 
+
+#include 
+
+namespace Kokkos {
+namespace Impl {
+
+struct CudaLockArrays {
+  std::int32_t* atomic;
+  std::int32_t* scratch;
+  std::int32_t n;
+};
+
+/// \brief This global variable in Host space is the central definition
+///        of these 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.
+///
+/// This call is idempotent.
+void initialize_host_cuda_lock_arrays();
+
+/// \brief After this call, the g_host_cuda_lock_arrays variable has
+///        all null pointers, and all array memory has been freed.
+///
+/// This call is idempotent.
+void finalize_host_cuda_lock_arrays();
+
+} // namespace Impl
+} // namespace Kokkos
+
+#if defined( __CUDACC__ )
+
+namespace Kokkos {
+namespace Impl {
+
+/// \brief This global variable in CUDA space is what kernels use
+///        to get access to the lock arrays.
+///
+/// When relocatable device code is enabled, there can be one single
+/// instance of this global variable for the entire executable,
+/// whose definition will be in Kokkos_Cuda_Locks.cpp (and whose declaration
+/// here must then be extern.
+/// This one instance will be initialized by initialize_host_cuda_lock_arrays
+/// and need not be modified afterwards.
+///
+/// When relocatable device code is disabled, an instance of this variable
+/// will be created in every translation unit that sees this header file
+/// (we make this clear by marking it static, meaning no other translation
+///  unit can link to it).
+/// Since the Kokkos_Cuda_Locks.cpp translation unit cannot initialize the
+/// instances in other translation units, we must update this CUDA global
+/// variable based on the Host global variable prior to running any kernels
+/// that will use it.
+/// That is the purpose of the KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE macro.
+__device__ __constant__
+#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
+extern
+#endif
+Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays ;
+
+#define CUDA_SPACE_ATOMIC_MASK 0x1FFFF
+
+/// \brief Aquire a lock for the address
+///
+/// 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) {
+  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));
+}
+
+/// \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 aquiring a lock with
+/// lock_address.
+__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);
+}
+
+} // 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() \
+{ \
+  CUDA_SAFE_CALL(cudaMemcpyToSymbol( \
+        Kokkos::Impl::g_device_cuda_lock_arrays , \
+        & Kokkos::Impl::g_host_cuda_lock_arrays , \
+        sizeof(Kokkos::Impl::CudaLockArrays) ) ); \
+}
+
+#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()
+#endif
+
+#endif /* defined( __CUDACC__ ) */
+
+#endif /* defined( KOKKOS_ENABLE_CUDA ) */
+
+#endif /* #ifndef KOKKOS_CUDA_LOCKS_HPP */
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp
index 0c8c700e8f..e2eab19e45 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp
@@ -58,6 +58,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #if defined(KOKKOS_ENABLE_PROFILING)
@@ -65,6 +66,8 @@
 #include 
 #endif
 
+#include 
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 
@@ -318,6 +321,7 @@ private:
   typedef Kokkos::RangePolicy< Traits ... > Policy;
   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 ;
@@ -363,7 +367,7 @@ public:
       const dim3 block(  1 , CudaTraits::WarpSize * cuda_internal_maximum_warp_count(), 1);
       const dim3 grid( std::min( ( nwork + block.y - 1 ) / block.y , cuda_internal_maximum_grid_count() ) , 1 , 1);
 
-      CudaParallelLaunch< ParallelFor >( *this , grid , block , 0 );
+      CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 );
     }
 
   ParallelFor( const FunctorType  & arg_functor ,
@@ -373,6 +377,115 @@ public:
     { }
 };
 
+
+// MDRangePolicy impl
+template< class FunctorType , class ... Traits >
+class ParallelFor< FunctorType
+                 , Kokkos::Experimental::MDRangePolicy< Traits ... >
+                 , Kokkos::Cuda
+                 >
+{
+private:
+  typedef Kokkos::Experimental::MDRangePolicy< Traits ...  > Policy ;
+  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 ;
+
+public:
+
+  inline
+  __device__
+  void operator()(void) const
+    {
+      Kokkos::Experimental::Impl::Refactor::DeviceIterateTile(m_rp,m_functor).exec_range();
+    }
+
+
+  inline
+  void execute() const
+  {
+    const array_index_type maxblocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount);
+    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 );
+    }
+    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 );
+    }
+    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 );
+    }
+    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 );
+    }
+    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 );
+    }
+    else
+    {
+      printf("Kokkos::MDRange Error: Exceeded rank bounds with Cuda\n");
+      Kokkos::abort("Aborting");
+    }
+
+  } //end execute
+
+//  inline
+  ParallelFor( const FunctorType & arg_functor
+             , Policy arg_policy )
+    : m_functor( arg_functor )
+    , m_rp(  arg_policy )
+    {}
+};
+
+
 template< class FunctorType , class ... Properties >
 class ParallelFor< FunctorType
                  , Kokkos::TeamPolicy< Properties ... >
@@ -384,6 +497,7 @@ private:
   typedef TeamPolicyInternal< Kokkos::Cuda , Properties ... >   Policy ;
   typedef typename Policy::member_type  Member ;
   typedef typename Policy::work_tag     WorkTag ;
+  typedef typename Policy::launch_bounds  LaunchBounds ;
 
 public:
 
@@ -430,15 +544,15 @@ public:
     if ( m_scratch_size[1]>0 ) {
       __shared__ int base_thread_id;
       if (threadIdx.x==0 && threadIdx.y==0 ) {
-        threadid = ((blockIdx.x*blockDim.z + threadIdx.z) * blockDim.x * blockDim.y) % kokkos_impl_cuda_lock_arrays.n;
+        threadid = ((blockIdx.x*blockDim.z + threadIdx.z) * blockDim.x * blockDim.y) % Kokkos::Impl::g_device_cuda_lock_arrays.n;
         threadid = ((threadid + blockDim.x * blockDim.y-1)/(blockDim.x * blockDim.y)) * blockDim.x * blockDim.y;
-        if(threadid > kokkos_impl_cuda_lock_arrays.n) threadid-=blockDim.x * blockDim.y;
+        if(threadid > Kokkos::Impl::g_device_cuda_lock_arrays.n) threadid-=blockDim.x * blockDim.y;
         int done = 0;
         while (!done) {
-          done = (0 == atomicCAS(&kokkos_impl_cuda_lock_arrays.atomic[threadid],0,1));
+          done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1));
           if(!done) {
             threadid += blockDim.x * blockDim.y;
-            if(threadid > kokkos_impl_cuda_lock_arrays.n) threadid = 0;
+            if(threadid > Kokkos::Impl::g_device_cuda_lock_arrays.n) threadid = 0;
           }
         }
         base_thread_id = threadid;
@@ -448,7 +562,8 @@ public:
     }
 
 
-    for ( int league_rank = blockIdx.x ; league_rank < m_league_size ; league_rank += gridDim.x ) {
+    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()
@@ -462,7 +577,7 @@ public:
     if ( m_scratch_size[1]>0 ) {
       __syncthreads();
       if (threadIdx.x==0 && threadIdx.y==0 )
-        kokkos_impl_cuda_lock_arrays.atomic[threadid]=0;
+        Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0;
     }
   }
 
@@ -473,7 +588,7 @@ public:
       const dim3 grid( int(m_league_size) , 1 , 1 );
       const dim3 block( int(m_vector_size) , int(m_team_size) , 1 );
 
-      CudaParallelLaunch< ParallelFor >( *this, grid, block, shmem_size_total ); // copy to device and execute
+      CudaParallelLaunch< ParallelFor, LaunchBounds >( *this, grid, block, shmem_size_total ); // copy to device and execute
 
     }
 
@@ -529,6 +644,7 @@ 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 Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional;
   typedef typename ReducerConditional::type ReducerTypeFwd;
@@ -563,6 +679,7 @@ private:
   typedef int DummySHMEMReductionType;
 
 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
@@ -686,7 +803,7 @@ public:
 
       const int shmem = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( m_functor , block.y );
 
-      CudaParallelLaunch< ParallelReduce >( *this, grid, block, shmem ); // copy to device and execute
+      CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem ); // copy to device and execute
 
       Cuda::fence();
 
@@ -737,6 +854,232 @@ public:
   { }
 };
 
+
+// MDRangePolicy impl
+template< class FunctorType , class ReducerType, class ... Traits >
+class ParallelReduce< FunctorType
+                    , Kokkos::Experimental::MDRangePolicy< Traits ... >
+                    , ReducerType
+                    , Kokkos::Cuda
+                    >
+{
+private:
+
+  typedef Kokkos::Experimental::MDRangePolicy< Traits ... > Policy ;
+  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 Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTag > ValueTraits ;
+  typedef Kokkos::Impl::FunctorValueInit<   ReducerTypeFwd, WorkTag > ValueInit ;
+  typedef Kokkos::Impl::FunctorValueJoin<   ReducerTypeFwd, WorkTag > 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 ;
+  size_type *         m_scratch_space ;
+  size_type *         m_scratch_flags ;
+  size_type *         m_unified_space ;
+
+  typedef typename Kokkos::Experimental::Impl::Reduce::DeviceIterateTile 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) };
+  // Some crutch to do function overloading
+private:
+  typedef double DummyShflReductionType;
+  typedef int DummySHMEMReductionType;
+
+public:
+  inline
+  __device__
+  void
+  exec_range( reference_type update ) const
+  {
+    Kokkos::Experimental::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) );
+  }
+
+  __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) );
+
+    {
+      reference_type 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.
+
+      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_unified_space ? m_unified_space : m_scratch_space ;
+
+      if ( threadIdx.y == 0 ) {
+        Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTag >::final( ReducerConditional::select(m_functor , m_reducer) , shared );
+      }
+
+      if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); }
+
+      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 , WorkTag >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value );
+         *result = value;
+       }
+     }
+   }
+
+  // Determine block size constrained by shared memory:
+  static inline
+  unsigned local_block_size( const FunctorType & f )
+    {
+      unsigned n = CudaTraits::WarpSize * 8 ;
+      while ( n && CudaTraits::SharedMemoryCapacity < cuda_single_inter_block_reduce_scan_shmem( f , n ) ) { n >>= 1 ; }
+      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( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_size /* block_size == max block_count */ );
+        m_scratch_flags = cuda_internal_scratch_flags( sizeof(size_type) );
+        m_unified_space = cuda_internal_scratch_unified( 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< ParallelReduce, LaunchBounds >( *this, grid, block, shmem ); // copy to device and execute
+
+      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 );
+        }
+      }
+    }
+    else {
+      if (m_result_ptr) {
+        ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr );
+      }
+    }
+  }
+
+  template< class HostViewType >
+  ParallelReduce( const FunctorType  & arg_functor
+                , const Policy       & arg_policy
+                , const HostViewType & arg_result
+                , typename std::enable_if<
+                   Kokkos::is_view< HostViewType >::value
+                ,void*>::type = NULL)
+  : m_functor( arg_functor )
+  , m_policy(  arg_policy )
+  , m_reducer( InvalidType() )
+  , m_result_ptr( arg_result.ptr_on_device() )
+  , 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().ptr_on_device() )
+  , m_scratch_space( 0 )
+  , m_scratch_flags( 0 )
+  , m_unified_space( 0 )
+  {}
+};
+
+
 //----------------------------------------------------------------------------
 
 #if 1
@@ -753,6 +1096,7 @@ private:
   typedef TeamPolicyInternal< Kokkos::Cuda, Properties ... >  Policy ;
   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;
@@ -819,15 +1163,15 @@ public:
     if ( m_scratch_size[1]>0 ) {
       __shared__ int base_thread_id;
       if (threadIdx.x==0 && threadIdx.y==0 ) {
-        threadid = ((blockIdx.x*blockDim.z + threadIdx.z) * blockDim.x * blockDim.y) % kokkos_impl_cuda_lock_arrays.n;
+        threadid = ((blockIdx.x*blockDim.z + threadIdx.z) * blockDim.x * blockDim.y) % Kokkos::Impl::g_device_cuda_lock_arrays.n;
         threadid = ((threadid + blockDim.x * blockDim.y-1)/(blockDim.x * blockDim.y)) * blockDim.x * blockDim.y;
-        if(threadid > kokkos_impl_cuda_lock_arrays.n) threadid-=blockDim.x * blockDim.y;
+        if(threadid > Kokkos::Impl::g_device_cuda_lock_arrays.n) threadid-=blockDim.x * blockDim.y;
         int done = 0;
         while (!done) {
-          done = (0 == atomicCAS(&kokkos_impl_cuda_lock_arrays.atomic[threadid],0,1));
+          done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1));
           if(!done) {
             threadid += blockDim.x * blockDim.y;
-            if(threadid > kokkos_impl_cuda_lock_arrays.n) threadid = 0;
+            if(threadid > Kokkos::Impl::g_device_cuda_lock_arrays.n) threadid = 0;
           }
         }
         base_thread_id = threadid;
@@ -840,7 +1184,7 @@ public:
     if ( m_scratch_size[1]>0 ) {
       __syncthreads();
       if (threadIdx.x==0 && threadIdx.y==0 )
-        kokkos_impl_cuda_lock_arrays.atomic[threadid]=0;
+        Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0;
     }
   }
 
@@ -854,7 +1198,8 @@ public:
       ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value );
 
     // Iterate this block through the league
-    for ( int league_rank = blockIdx.x ; league_rank < m_league_size ; league_rank += gridDim.x ) {
+    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
@@ -894,7 +1239,8 @@ public:
     ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value);
 
     // Iterate this block through the league
-    for ( int league_rank = blockIdx.x ; league_rank < m_league_size ; league_rank += gridDim.x ) {
+    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
@@ -936,7 +1282,7 @@ public:
         const dim3 grid( block_count , 1 , 1 );
         const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ;
 
-        CudaParallelLaunch< ParallelReduce >( *this, grid, block, shmem_size_total ); // copy to device and execute
+        CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem_size_total ); // copy to device and execute
 
         Cuda::fence();
 
@@ -975,12 +1321,6 @@ public:
   , m_shmem_begin( 0 )
   , m_shmem_size( 0 )
   , m_scratch_ptr{NULL,NULL}
-  , m_league_size( arg_policy.league_size() )
-  , m_team_size( 0 <= arg_policy.team_size() ? arg_policy.team_size() :
-      Kokkos::Impl::cuda_get_opt_block_size< ParallelReduce >( arg_functor , arg_policy.vector_length(),
-                                                               arg_policy.team_scratch_size(0),arg_policy.thread_scratch_size(0) ) /
-                                                               arg_policy.vector_length() )
-  , m_vector_size( arg_policy.vector_length() )
   , m_scratch_size{
     arg_policy.scratch_size(0,( 0 <= arg_policy.team_size() ? arg_policy.team_size() :
         Kokkos::Impl::cuda_get_opt_block_size< ParallelReduce >( arg_functor , arg_policy.vector_length(),
@@ -991,6 +1331,12 @@ public:
                                                                  arg_policy.team_scratch_size(0),arg_policy.thread_scratch_size(0) ) /
                                                                  arg_policy.vector_length() )
         )}
+  , m_league_size( arg_policy.league_size() )
+  , m_team_size( 0 <= arg_policy.team_size() ? arg_policy.team_size() :
+      Kokkos::Impl::cuda_get_opt_block_size< ParallelReduce >( arg_functor , arg_policy.vector_length(),
+                                                               arg_policy.team_scratch_size(0),arg_policy.thread_scratch_size(0) ) /
+                                                               arg_policy.vector_length() )
+  , m_vector_size( arg_policy.vector_length() )
   {
     // Return Init value if the number of worksets is zero
     if( arg_policy.league_size() == 0) {
@@ -1150,6 +1496,7 @@ private:
   typedef typename reducer_type<>::pointer_type    pointer_type ;
   typedef typename reducer_type<>::reference_type  reference_type ;
   typedef typename reducer_type<>::value_type      value_type ;
+  typedef typename Policy::launch_bounds           LaunchBounds ;
 
   typedef Kokkos::Impl::FunctorAnalysis
     < Kokkos::Impl::FunctorPatternInterface::REDUCE
@@ -1273,7 +1620,7 @@ public:
         const int  shmem = m_shmem_team_begin + m_shmem_team_size ;
 
         // copy to device and execute
-        CudaParallelLaunch( *this, grid, block, shmem );
+        CudaParallelLaunch( *this, grid, block, shmem );
 
         Cuda::fence();
 
@@ -1373,7 +1720,7 @@ public:
 
     if ( CudaTraits::WarpSize < team_threads ) {
       // Need inter-warp team reduction (collectives) shared memory
-      // Speculate an upper bound for the value size 
+      // Speculate an upper bound for the value size
 
       m_shmem_team_begin =
         align_scratch( CudaTraits::warp_count(team_threads) * sizeof(double) );
@@ -1426,7 +1773,7 @@ public:
 
     // Reduce space has claim flag followed by vaue buffer
     const int global_reduce_value_size =
-      max_concurrent_block * 
+      max_concurrent_block *
       ( aligned_flag_size + align_scratch( value_size ) );
 
     // Scratch space has claim flag followed by scratch buffer
@@ -1469,6 +1816,7 @@ 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 ;
@@ -1655,10 +2003,10 @@ public:
         const int shmem = ValueTraits::value_size( m_functor ) * ( block_size + 2 );
 
         m_final = false ;
-        CudaParallelLaunch< ParallelScan >( *this, grid, block, shmem ); // copy to device and execute
+        CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem ); // copy to device and execute
 
         m_final = true ;
-        CudaParallelLaunch< ParallelScan >( *this, grid, block, shmem ); // copy to device and execute
+        CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem ); // copy to device and execute
       }
     }
 
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp
index 432c7895cc..709cbbd534 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp
@@ -151,7 +151,7 @@ template< class ValueType , class JoinOp>
 __device__
 inline void cuda_intra_warp_reduction( ValueType& result,
                                        const JoinOp& join,
-                                       const int max_active_thread = blockDim.y) {
+                                       const uint32_t max_active_thread = blockDim.y) {
 
   unsigned int shift = 1;
 
@@ -268,29 +268,33 @@ bool cuda_inter_block_reduction( typename FunctorValueTraits< FunctorType , ArgT
         if( id + 1 < int(gridDim.x) )
           join(value, tmp);
       }
+      int active = __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
     }
   }
-
   //The last block has in its thread=0 the global reduction value through "value"
   return last_block;
 #else
@@ -302,7 +306,7 @@ template< class ReducerType >
 __device__ inline
 typename std::enable_if< Kokkos::is_reducer::value >::type
 cuda_intra_warp_reduction( const ReducerType& reducer,
-                           const int max_active_thread = blockDim.y) {
+                           const uint32_t max_active_thread = blockDim.y) {
 
   typedef typename ReducerType::value_type ValueType;
 
@@ -428,26 +432,31 @@ cuda_inter_block_reduction( const ReducerType& reducer,
         if( id + 1 < int(gridDim.x) )
           reducer.join(value, tmp);
       }
+      int active = __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
       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);
       }
+      active += __ballot(1);
     }
   }
 
@@ -594,7 +603,7 @@ bool cuda_single_inter_block_reduce_scan( const FunctorType     & functor ,
   typedef FunctorValueOps<    FunctorType , ArgTag >  ValueOps ;
 
   typedef typename ValueTraits::pointer_type    pointer_type ;
-  typedef typename ValueTraits::reference_type  reference_type ;
+  //typedef typename ValueTraits::reference_type  reference_type ;
 
   // '__ffs' = position of the least significant bit set to 1.
   // 'blockDim.y' is guaranteed to be a power of two so this
@@ -637,7 +646,7 @@ bool cuda_single_inter_block_reduce_scan( const FunctorType     & functor ,
 
     {
       void * const shared_ptr = shared_data + word_count.value * threadIdx.y ;
-      reference_type shared_value = ValueInit::init( functor , shared_ptr );
+      /* 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 );
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp
index 3c6f0a5dda..5f08800c40 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp
@@ -58,25 +58,56 @@ template class TaskQueue< Kokkos::Cuda > ;
 
 //----------------------------------------------------------------------------
 
+#if defined( KOKKOS_DEBUG )
+
+__device__
+void verify_warp_convergence( const char * const where )
+{
+  const unsigned b = __ballot(1);
+
+  if ( b != ~0u ) {
+
+printf(" verify_warp_convergence( %s ) (%d,%d,%d) (%d,%d,%d) failed %x\n"
+      , where
+      , blockIdx.x
+      , blockIdx.y
+      , blockIdx.z
+      , threadIdx.x
+      , threadIdx.y
+      , threadIdx.z
+      , b );
+
+  }
+}
+
+#endif // #if defined( KOKKOS_DEBUG )
+
+//----------------------------------------------------------------------------
+
 __device__
 void TaskQueueSpecialization< Kokkos::Cuda >::driver
-  ( TaskQueueSpecialization< Kokkos::Cuda >::queue_type * const queue )
+  ( TaskQueueSpecialization< Kokkos::Cuda >::queue_type * const queue 
+  , int32_t shmem_per_warp )
 {
   using Member = TaskExec< Kokkos::Cuda > ;
   using Queue  = TaskQueue< Kokkos::Cuda > ;
-  using task_root_type = TaskBase< Kokkos::Cuda , void , void > ;
+  using task_root_type = TaskBase< void , void , void > ;
+
+  extern __shared__ int32_t shmem_all[];
 
   task_root_type * const end = (task_root_type *) task_root_type::EndTag ;
 
-  Member single_exec( 1 );
-  Member team_exec( blockDim.y );
+  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 ;
 
   const int warp_lane = threadIdx.x + threadIdx.y * blockDim.x ;
 
-  union {
-    task_root_type * ptr ;
-    int              raw[2] ;
-  } task ;
+  Member single_exec( warp_shmem , 1 );
+  Member team_exec( warp_shmem , blockDim.y );
+
+  task_root_type * task_ptr ;
 
   // Loop until all queues are empty and no tasks in flight
 
@@ -87,41 +118,86 @@ void TaskQueueSpecialization< Kokkos::Cuda >::driver
 
     if ( 0 == warp_lane ) {
 
-      task.ptr = 0 < *((volatile int *) & queue->m_ready_count) ? end : 0 ;
+      task_ptr = 0 < *((volatile int *) & queue->m_ready_count) ? end : 0 ;
 
       // Loop by priority and then type
-      for ( int i = 0 ; i < Queue::NumQueue && end == task.ptr ; ++i ) {
-        for ( int j = 0 ; j < 2 && end == task.ptr ; ++j ) {
-          task.ptr = Queue::pop_ready_task( & queue->m_ready[i][j] );
+      for ( int i = 0 ; i < Queue::NumQueue && end == task_ptr ; ++i ) {
+        for ( int j = 0 ; j < 2 && end == task_ptr ; ++j ) {
+          task_ptr = Queue::pop_ready_task( & queue->m_ready[i][j] );
         }
       }
 
 #if 0
 printf("TaskQueue::driver(%d,%d) task(%lx)\n",threadIdx.z,blockIdx.x
-      , uintptr_t(task.ptr));
+      , uintptr_t(task_ptr));
 #endif
 
     }
 
     // shuffle broadcast
 
-    task.raw[0] = __shfl( task.raw[0] , 0 );
-    task.raw[1] = __shfl( task.raw[1] , 0 );
+    ((int*) & task_ptr )[0] = __shfl( ((int*) & task_ptr )[0] , 0 );
+    ((int*) & task_ptr )[1] = __shfl( ((int*) & task_ptr )[1] , 0 );
 
-    if ( 0 == task.ptr ) break ; // 0 == queue->m_ready_count
+#if defined( KOKKOS_DEBUG )
+    verify_warp_convergence("task_ptr");
+#endif
 
-    if ( end != task.ptr ) {
-      if ( task_root_type::TaskTeam == task.ptr->m_task_type ) {
+    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 volatile * const task_mem = (int32_t volatile *) task_ptr ;
+
+      // copy global to shared memory:
+
+      for ( int32_t i = warp_lane ; i < e ; i += CudaTraits::WarpSize ) {
+        warp_shmem[i] = task_mem[i] ;
+      }
+
+      Kokkos::memory_fence();
+
+      // Copy done - use memory fence so that memory writes are visible.
+      // For reliable warp convergence on Pascal and Volta an explicit
+      // warp level synchronization will also be required.
+
+      if ( task_root_type::TaskTeam == task_shmem->m_task_type ) {
         // Thread Team Task
-        (*task.ptr->m_apply)( task.ptr , & team_exec );
+        (*task_shmem->m_apply)( task_shmem , & team_exec );
       }
       else if ( 0 == threadIdx.y ) {
         // Single Thread Task
-        (*task.ptr->m_apply)( task.ptr , & single_exec );
+        (*task_shmem->m_apply)( task_shmem , & single_exec );
       }
 
+      // copy shared to global memory:
+
+      for ( int32_t i = b + warp_lane ; i < e ; i += CudaTraits::WarpSize ) {
+        task_mem[i] = warp_shmem[i] ;
+      }
+
+      Kokkos::memory_fence();
+
+#if defined( KOKKOS_DEBUG )
+    verify_warp_convergence("apply");
+#endif
+
+      // If respawn requested copy respawn data back to main memory
+
       if ( 0 == warp_lane ) {
-        queue->complete( task.ptr );
+
+        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 ;
+        }
+
+        queue->complete( task_ptr );
       }
     }
   } while(1);
@@ -130,18 +206,20 @@ printf("TaskQueue::driver(%d,%d) task(%lx)\n",threadIdx.z,blockIdx.x
 namespace {
 
 __global__
-void cuda_task_queue_execute( TaskQueue< Kokkos::Cuda > * queue )
-{ TaskQueueSpecialization< Kokkos::Cuda >::driver( queue ); }
+void cuda_task_queue_execute( TaskQueue< Kokkos::Cuda > * queue 
+                            , int32_t shmem_size )
+{ TaskQueueSpecialization< Kokkos::Cuda >::driver( queue , shmem_size ); }
 
 }
 
 void TaskQueueSpecialization< Kokkos::Cuda >::execute
   ( TaskQueue< Kokkos::Cuda > * const queue )
 {
+  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 block( 1 , Kokkos::Impl::CudaTraits::WarpSize , warps_per_block );
-  const int shared = 0 ;
+  const int shared_total = shared_per_warp * warps_per_block ;
   const cudaStream_t stream = 0 ;
 
   CUDA_SAFE_CALL( cudaDeviceSynchronize() );
@@ -159,7 +237,7 @@ printf("cuda_task_queue_execute before\n");
   //
   // CUDA_SAFE_CALL( cudaDeviceSetLimit( cudaLimitStackSize , stack_size ) );
 
-  cuda_task_queue_execute<<< grid , block , shared , stream >>>( queue );
+  cuda_task_queue_execute<<< grid , block , shared_total , stream >>>( queue , shared_per_warp );
 
   CUDA_SAFE_CALL( cudaGetLastError() );
 
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp
index 5d08219ea5..4a52985d29 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp
@@ -57,7 +57,7 @@ namespace {
 template< typename TaskType >
 __global__
 void set_cuda_task_base_apply_function_pointer
-  ( TaskBase::function_type * ptr )
+  ( TaskBase::function_type * ptr )
 { *ptr = TaskType::apply ; }
 
 }
@@ -78,7 +78,7 @@ public:
   void iff_single_thread_recursive_execute( queue_type * const ) {}
 
   __device__
-  static void driver( queue_type * const );
+  static void driver( queue_type * const , int32_t );
 
   static
   void execute( queue_type * const );
@@ -106,7 +106,14 @@ public:
 
 extern template class TaskQueue< Kokkos::Cuda > ;
 
+}} /* namespace Kokkos::Impl */
+
 //----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+
+namespace Kokkos {
+namespace Impl {
+
 /**\brief  Impl::TaskExec is the TaskScheduler::member_type
  *         passed to tasks running in a Cuda space.
  *
@@ -134,11 +141,13 @@ private:
   friend class Kokkos::Impl::TaskQueue< Kokkos::Cuda > ;
   friend class Kokkos::Impl::TaskQueueSpecialization< Kokkos::Cuda > ;
 
+  int32_t * m_team_shmem ;
   const int m_team_size ;
 
   __device__
-  TaskExec( int arg_team_size = blockDim.y )
-    : m_team_size( arg_team_size ) {}
+  TaskExec( int32_t * arg_team_shmem , int arg_team_size = blockDim.y )
+    : m_team_shmem( arg_team_shmem )
+    , m_team_size( arg_team_size ) {}
 
 public:
 
@@ -154,7 +163,13 @@ public:
 
 };
 
+}} /* namespace Kokkos::Impl */
+
 //----------------------------------------------------------------------------
+//----------------------------------------------------------------------------
+
+namespace Kokkos {
+namespace Impl {
 
 template
 struct TeamThreadRangeBoundariesStruct >
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp
index 084daa098b..3f3d85ecd1 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp
@@ -106,7 +106,7 @@ private:
   typedef Kokkos::Cuda                           execution_space ;
   typedef execution_space::scratch_memory_space  scratch_memory_space ;
 
-  void                * m_team_reduce ;
+  mutable void        * m_team_reduce ;
   scratch_memory_space  m_team_shared ;
   int                   m_team_reduce_size ;
   int                   m_league_rank ;
@@ -166,7 +166,7 @@ public:
       if ( 1 == blockDim.z ) { // team == block
         __syncthreads();
         // Wait for shared data write until all threads arrive here
-        if ( threadIdx.x == 0 && threadIdx.y == thread_id ) {
+        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
@@ -210,7 +210,7 @@ public:
       const int wx =
         ( threadIdx.x + blockDim.x * threadIdx.y ) & CudaTraits::WarpIndexMask ;
 
-      for ( int i = CudaTraits::WarpSize ; blockDim.x <= ( i >>= 1 ) ; ) {
+      for ( int i = CudaTraits::WarpSize ; (int)blockDim.x <= ( i >>= 1 ) ; ) {
 
         cuda_shfl_down( reducer.reference() , tmp , i , CudaTraits::WarpSize );
 
@@ -354,7 +354,7 @@ public:
 
       for ( int i = blockDim.x ; ( i >>= 1 ) ; ) {
         cuda_shfl_down( reducer.reference() , tmp , i , blockDim.x );
-        if ( threadIdx.x < i ) { reducer.join( tmp , reducer.reference() ); }
+        if ( (int)threadIdx.x < i ) { reducer.join( tmp , reducer.reference() ); }
       }
 
       // Broadcast from root lane to all other lanes.
@@ -410,7 +410,7 @@ public:
 
         value_type tmp( reducer.reference() );
 
-        for ( int i = CudaTraits::WarpSize ; blockDim.x <= ( i >>= 1 ) ; ) {
+        for ( int i = CudaTraits::WarpSize ; (int)blockDim.x <= ( i >>= 1 ) ; ) {
 
           cuda_shfl_down( reducer.reference(), tmp, i, CudaTraits::WarpSize );
 
@@ -479,7 +479,7 @@ public:
 
           __threadfence(); // Wait until global write is visible.
 
-          last_block = gridDim.x ==
+          last_block = (int)gridDim.x ==
                        1 + Kokkos::atomic_fetch_add(global_scratch_flags,1);
 
           // If last block then reset count
@@ -509,7 +509,7 @@ public:
         reducer.copy( ((pointer_type)shmem) + offset
                     , ((pointer_type)global_scratch_space) + offset );
 
-        for ( int i = nentry + tid ; i < gridDim.x ; i += nentry ) {
+        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() );
@@ -576,6 +576,14 @@ public:
     , 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
+  {
+    return m_team_reduce_size > 0 && m_team_reduce != nullptr;
+  }
 };
 
 } // namspace Impl
@@ -913,10 +921,10 @@ void parallel_scan
     //  [t] += [t-4] if t >= 4
     //  ...
 
-    for ( int j = 1 ; j < blockDim.x ; j <<= 1 ) {
+    for ( int j = 1 ; j < (int)blockDim.x ; j <<= 1 ) {
       value_type tmp = 0 ;
       Impl::cuda_shfl_up( tmp , sval , j , blockDim.x );
-      if ( j <= threadIdx.x ) { sval += tmp ; }
+      if ( j <= (int)threadIdx.x ) { sval += tmp ; }
     }
 
     // Include accumulation and remove value for exclusive scan:
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp
new file mode 100644
index 0000000000..e11ae4798f
--- /dev/null
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp
@@ -0,0 +1,133 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#ifndef KOKKOS_CUDA_UNIQUE_TOKEN_HPP
+#define KOKKOS_CUDA_UNIQUE_TOKEN_HPP
+
+#include 
+#ifdef KOKKOS_ENABLE_CUDA
+
+#include 
+#include 
+#include 
+#include 
+
+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:
+
+  using execution_space = Cuda;
+
+  explicit
+  UniqueToken( execution_space const& );
+
+  KOKKOS_INLINE_FUNCTION
+  UniqueToken() : m_buffer(0), m_count(0) {}
+
+  KOKKOS_INLINE_FUNCTION
+  UniqueToken( const UniqueToken & ) = default;
+
+  KOKKOS_INLINE_FUNCTION
+  UniqueToken( UniqueToken && )      = default;
+
+  KOKKOS_INLINE_FUNCTION
+  UniqueToken & operator=( const UniqueToken & ) = default ;
+
+  KOKKOS_INLINE_FUNCTION
+  UniqueToken & operator=( UniqueToken && ) = default ;
+
+  /// \brief upper bound for acquired values, i.e. 0 <= value < size()
+  KOKKOS_INLINE_FUNCTION
+  int32_t size() const noexcept { return m_count ; }
+
+  /// \brief acquire value such that 0 <= value < size()
+  KOKKOS_INLINE_FUNCTION
+  int32_t 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;
+  }
+
+  /// \brief release an acquired value
+  KOKKOS_INLINE_FUNCTION
+  void release( int32_t i ) const noexcept
+  {
+    Kokkos::Impl::concurrent_bitset::release( m_buffer, i );
+  }
+};
+
+template<>
+class UniqueToken< Cuda, UniqueTokenScope::Instance >
+  : public UniqueToken< Cuda, UniqueTokenScope::Global >
+{
+public:
+
+  explicit
+  UniqueToken( execution_space const& arg )
+    : UniqueToken< Cuda, UniqueTokenScope::Global >( arg ) {}
+};
+
+}} // namespace Kokkos::Experimental
+
+#endif // KOKKOS_ENABLE_CUDA
+#endif // KOKKOS_CUDA_UNIQUE_TOKEN_HPP
+
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp
index f5e2d87fb6..d641622bb6 100644
--- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp
@@ -221,7 +221,6 @@ struct CudaLDGFetch {
 //----------------------------------------------------------------------------
 
 namespace Kokkos {
-namespace Experimental {
 namespace Impl {
 
 /** \brief  Replace Default ViewDataHandle with Cuda texture fetch specialization
@@ -294,9 +293,8 @@ public:
     }
 };
 
-}
-}
-}
+} // namespace Impl
+} // namespace Kokkos
 
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp
new file mode 100644
index 0000000000..99778c64b1
--- /dev/null
+++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp
@@ -0,0 +1,119 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#ifndef KOKKOS_CUDA_WORKGRAPHPOLICY_HPP
+#define KOKKOS_CUDA_WORKGRAPHPOLICY_HPP
+
+namespace Kokkos {
+namespace Impl {
+
+template< class FunctorType , class ... Traits >
+class ParallelFor< FunctorType ,
+                   Kokkos::Experimental::WorkGraphPolicy< Traits ... > ,
+                   Kokkos::Cuda
+                 >
+  : public Kokkos::Impl::Experimental::
+           WorkGraphExec< FunctorType,
+                          Kokkos::Cuda,
+                          Traits ...
+                        >
+{
+public:
+
+  typedef Kokkos::Experimental::WorkGraphPolicy< Traits ... >   Policy ;
+  typedef Kokkos::Impl::Experimental::
+          WorkGraphExec Base ;
+  typedef ParallelFor        Self ;
+
+private:
+
+  template< class TagType >
+  __device__
+  typename std::enable_if< std::is_same< TagType , void >::value >::type
+  exec_one(const typename Policy::member_type& i) const {
+    Base::m_functor( i );
+  }
+
+  template< class TagType >
+  __device__
+  typename std::enable_if< ! std::is_same< TagType , void >::value >::type
+  exec_one(const typename Policy::member_type& i) const {
+    const TagType t{} ;
+    Base::m_functor( t , i );
+  }
+
+public:
+
+  __device__
+  inline
+  void operator()() const {
+    for (std::int32_t i; (-1 != (i = Base::before_work())); ) {
+      exec_one< typename Policy::work_tag >( i );
+      Base::after_work(i);
+    }
+  }
+
+  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 ;
+    const cudaStream_t stream = 0 ;
+
+    Kokkos::Impl::CudaParallelLaunch(*this, grid, block, shared, stream);
+  }
+
+  inline
+  ParallelFor( const FunctorType & arg_functor
+             , const Policy      & arg_policy )
+    : Base( arg_functor, arg_policy )
+  {
+  }
+};
+
+} // namespace Impl
+} // namespace Kokkos
+
+#endif /* #define KOKKOS_CUDA_WORKGRAPHPOLICY_HPP */
diff --git a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp
index 4f68d9c2c0..6ef7443a14 100644
--- a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp
+++ b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp
@@ -52,6 +52,7 @@
 
 #if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA )
 #include
+#include 
 #endif
 
 namespace Kokkos { namespace Experimental {
@@ -120,28 +121,17 @@ struct MDRangePolicy
                                        , typename traits::index_type
                                        > ;
 
+  typedef MDRangePolicy execution_policy; // needed for is_execution_space interrogation
+
   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;
 
-  static constexpr int rank = iteration_pattern::rank;
-
-  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 );
-
-  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 ) ;
-
-
-  // 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 );
+  enum { rank = static_cast(iteration_pattern::rank) };
 
   using index_type  = typename traits::index_type;
   using array_index_type = long;
@@ -155,11 +145,50 @@ struct MDRangePolicy
   // 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
 
+  point_type m_lower;
+  point_type m_upper;
+  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 ) };
+
+  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;
+
+  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 );
+
+  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 ) ;
+
+  // 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 );
+
   MDRangePolicy( point_type const& lower, point_type const& upper, tile_type const& tile = tile_type{} )
     : m_lower(lower)
     , m_upper(upper)
     , m_tile(tile)
     , m_num_tiles(1)
+    , m_prod_tile_dims(1)
   {
     // Host
     if ( true
@@ -172,8 +201,8 @@ struct MDRangePolicy
       for (int i=0; i 0)) )
+          if (  ((int)inner_direction == (int)Right && (i < rank-1))
+              || ((int)inner_direction == (int)Left && (i > 0)) )
           {
             m_tile[i] = 2;
           }
@@ -183,6 +212,7 @@ struct MDRangePolicy
         }
         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)
@@ -190,14 +220,18 @@ struct MDRangePolicy
     {
       index_type span;
       for (int i=0; i 0)) )
+          if (  ((int)inner_direction == (int)Right && (i < rank-1))
+              || ((int)inner_direction == (int)Left && (i > 0)) )
           {
-            m_tile[i] = 2;
+            if ( m_prod_tile_dims < 512 ) {
+              m_tile[i] = 2;
+            } else {
+              m_tile[i] = 1;
+            }
           }
           else {
             m_tile[i] = 16;
@@ -205,12 +239,9 @@ struct MDRangePolicy
         }
         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];
       }
-      index_type total_tile_size_check = 1;
-      for (int i=0; i= 1024 ) { // improve this check - 1024,1024,64 max per dim (Kepler), but product num_threads < 1024; more restrictions pending register limit
+      if ( m_prod_tile_dims > 512 ) { // 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");
@@ -223,19 +254,7 @@ struct MDRangePolicy
   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 = {} )
   {
-#if 0
-    // This should work, less duplicated code but not yet extensively tested
-    point_type lower_tmp, upper_tmp;
-    tile_type tile_tmp;
-    for ( auto i = 0; i < rank; ++i ) {
-      lower_tmp[i] = static_cast(lower.begin()[i]);
-      upper_tmp[i] = static_cast(upper.begin()[i]);
-      tile_tmp[i]  = static_cast(tile.begin()[i]);
-    }
 
-    MDRangePolicy( lower_tmp, upper_tmp, tile_tmp );
-
-#else
     if(static_cast(m_lower.size()) != rank || static_cast(m_upper.size()) != rank)
       Kokkos::abort("MDRangePolicy: Constructor initializer lists have wrong size");
 
@@ -249,7 +268,7 @@ struct MDRangePolicy
     }
 
     m_num_tiles = 1;
-
+    m_prod_tile_dims = 1;
 
     // Host
     if ( true
@@ -262,8 +281,8 @@ struct MDRangePolicy
       for (int i=0; i 0)) )
+          if (  ((int)inner_direction == (int)Right && (i < rank-1))
+              || ((int)inner_direction == (int)Left && (i > 0)) )
           {
             m_tile[i] = 2;
           }
@@ -273,6 +292,7 @@ struct MDRangePolicy
         }
         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)
@@ -284,10 +304,14 @@ struct MDRangePolicy
         if ( m_tile[i] <= 0 ) {
           // TODO: determine what is a good default tile size for cuda
           // may be rank dependent
-          if (  (inner_direction == Right && (i < rank-1))
-              || (inner_direction == Left && (i > 0)) )
+          if (  ((int)inner_direction == (int)Right && (i < rank-1))
+              || ((int)inner_direction == (int)Left && (i > 0)) )
           {
-            m_tile[i] = 2;
+            if ( m_prod_tile_dims < 512 ) {
+              m_tile[i] = 2;
+            } else {
+              m_tile[i] = 1;
+            }
           }
           else {
             m_tile[i] = 16;
@@ -295,32 +319,22 @@ struct MDRangePolicy
         }
         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];
       }
-      index_type total_tile_size_check = 1;
-      for (int i=0; i= 1024 ) { // improve this check - 1024,1024,64 max per dim (Kepler), but product num_threads < 1024; more restrictions pending register limit
+      if ( m_prod_tile_dims > 512 ) { // 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");
       }
     }
     #endif
-#endif
   }
 
-
-  point_type m_lower;
-  point_type m_upper;
-  tile_type  m_tile;
-  point_type m_tile_end;
-  index_type m_num_tiles;
 };
 // ------------------------------------------------------------------ //
 
 // ------------------------------------------------------------------ //
-//md_parallel_for
+//md_parallel_for - deprecated use parallel_for
 // ------------------------------------------------------------------ //
 template 
 void md_parallel_for( MDRange const& range
@@ -335,7 +349,6 @@ void md_parallel_for( MDRange const& range
 {
   Impl::MDFunctor g(range, f);
 
-  //using range_policy = typename MDRange::range_policy;
   using range_policy = typename MDRange::impl_range_policy;
 
   Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str );
@@ -354,7 +367,6 @@ void md_parallel_for( const std::string& str
 {
   Impl::MDFunctor g(range, f);
 
-  //using range_policy = typename MDRange::range_policy;
   using range_policy = typename MDRange::impl_range_policy;
 
   Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str );
@@ -395,7 +407,7 @@ void md_parallel_for( MDRange const& range
 // ------------------------------------------------------------------ //
 
 // ------------------------------------------------------------------ //
-//md_parallel_reduce
+//md_parallel_reduce - deprecated use parallel_reduce
 // ------------------------------------------------------------------ //
 template 
 void md_parallel_reduce( MDRange const& range
@@ -409,9 +421,8 @@ void md_parallel_reduce( MDRange const& range
                       ) >::type* = 0
                     )
 {
-  Impl::MDFunctor g(range, f, v);
+  Impl::MDFunctor g(range, f);
 
-  //using range_policy = typename MDRange::range_policy;
   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 );
 }
@@ -428,48 +439,14 @@ void md_parallel_reduce( const std::string& str
                       ) >::type* = 0
                     )
 {
-  Impl::MDFunctor g(range, f, v);
+  Impl::MDFunctor g(range, f);
 
-  //using range_policy = typename MDRange::range_policy;
   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 );
 }
 
-// Cuda - parallel_reduce not implemented yet
-/*
-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
-                      ) >::type* = 0
-                    )
-{
-  Impl::DeviceIterateTile closure(range, f, v);
-  closure.execute();
-}
-
-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
-                      ) >::type* = 0
-                    )
-{
-  Impl::DeviceIterateTile closure(range, f, v);
-  closure.execute();
-}
-*/
+// Cuda - md_parallel_reduce not implemented - use parallel_reduce
 
 }} // namespace Kokkos::Experimental
 
diff --git a/lib/kokkos/core/src/Kokkos_Atomic.hpp b/lib/kokkos/core/src/Kokkos_Atomic.hpp
index 3ecae24da4..3c8673c66a 100644
--- a/lib/kokkos/core/src/Kokkos_Atomic.hpp
+++ b/lib/kokkos/core/src/Kokkos_Atomic.hpp
@@ -114,40 +114,9 @@
 #endif /* Not pre-selected atomic implementation */
 #endif
 
-//----------------------------------------------------------------------------
-
-// Forward decalaration of functions supporting arbitrary sized atomics
-// This is necessary since Kokkos_Atomic.hpp is internally included very early
-// through Kokkos_HostSpace.hpp as well as the allocation tracker.
 #ifdef KOKKOS_ENABLE_CUDA
-namespace Kokkos {
-namespace Impl {
-/// \brief Aquire a lock for the address
-///
-/// 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.
-#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-extern
+#include 
 #endif
-__device__ inline
-bool lock_address_cuda_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 aquiring a lock with
-/// lock_address.
-#ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE
-extern
-#endif
-__device__ inline
-void unlock_address_cuda_space(void* ptr);
-}
-}
-#endif
-
 
 namespace Kokkos {
 template 
diff --git a/lib/kokkos/core/src/Kokkos_Concepts.hpp b/lib/kokkos/core/src/Kokkos_Concepts.hpp
index 9a2b53e157..5480dbf40c 100644
--- a/lib/kokkos/core/src/Kokkos_Concepts.hpp
+++ b/lib/kokkos/core/src/Kokkos_Concepts.hpp
@@ -79,6 +79,21 @@ struct IndexType
   using type = T;
 };
 
+/**\brief Specify Launch Bounds for CUDA execution.
+ *
+ *  The "best" defaults may be architecture specific.
+ */
+template< unsigned int maxT = 1024 /* Max threads per block */
+        , unsigned int minB = 1    /* Min blocks per SM */
+        >
+struct LaunchBounds
+{
+  using launch_bounds = LaunchBounds;
+  using type = LaunchBounds;
+  static unsigned int constexpr maxTperB {maxT};
+  static unsigned int constexpr minBperSM {minB};
+};
+
 } // namespace Kokkos
 
 //----------------------------------------------------------------------------
@@ -119,6 +134,7 @@ using Kokkos::is_array_layout ;
 KOKKOS_IMPL_IS_CONCEPT( iteration_pattern )
 KOKKOS_IMPL_IS_CONCEPT( schedule_type )
 KOKKOS_IMPL_IS_CONCEPT( index_type )
+KOKKOS_IMPL_IS_CONCEPT( launch_bounds )
 
 }
 
diff --git a/lib/kokkos/core/src/Kokkos_Core.hpp b/lib/kokkos/core/src/Kokkos_Core.hpp
index 19de791c0f..ddb11d2894 100644
--- a/lib/kokkos/core/src/Kokkos_Core.hpp
+++ b/lib/kokkos/core/src/Kokkos_Core.hpp
@@ -96,11 +96,13 @@ struct InitArguments {
   int num_numa;
   int device_id;
 
-  InitArguments() {
-    num_threads = -1;
-    num_numa = -1;
-    device_id = -1;
-  }
+  InitArguments( int nt = -1
+               , int nn = -1
+               , int dv = -1)
+    : num_threads( nt )
+    , num_numa( nn )
+    , device_id( dv )
+  {}
 };
 
 void initialize(int& narg, char* arg[]);
@@ -168,6 +170,9 @@ void * kokkos_realloc( void * arg_alloc , const size_t arg_alloc_size )
 
 } // namespace Kokkos
 
+#include 
+#include 
+
 //----------------------------------------------------------------------------
 //----------------------------------------------------------------------------
 
diff --git a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp
index 09081d2387..8c080f7a8f 100644
--- a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp
+++ b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp
@@ -51,6 +51,9 @@
 #include 
 #include 
 
+#include 
+#include 
+
 //----------------------------------------------------------------------------
 // Have assumed a 64bit build (8byte pointers) throughout the code base.
 
diff --git a/lib/kokkos/core/src/Kokkos_Crs.hpp b/lib/kokkos/core/src/Kokkos_Crs.hpp
new file mode 100644
index 0000000000..93b3fa5ca9
--- /dev/null
+++ b/lib/kokkos/core/src/Kokkos_Crs.hpp
@@ -0,0 +1,333 @@
+/*
+//@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  H. Carter Edwards (hcedwar@sandia.gov)
+//
+// ************************************************************************
+//@HEADER
+*/
+
+#ifndef KOKKOS_CRS_HPP
+#define KOKKOS_CRS_HPP
+
+namespace Kokkos {
+namespace Experimental {
+
+/// \class Crs
+/// \brief Compressed row storage array.
+///
+/// \tparam DataType The type of stored entries.  If a Crs is
+///   used as the graph of a sparse matrix, then this is usually an
+///   integer type, the type of the column indices in the sparse
+///   matrix.
+///
+/// \tparam Arg1Type The second template parameter, corresponding
+///   either to the Device type (if there are no more template
+///   parameters) or to the Layout type (if there is at least one more
+///   template parameter).
+///
+/// \tparam Arg2Type The third template parameter, which if provided
+///   corresponds to the Device type.
+///
+/// \tparam SizeType The type of row offsets.  Usually the default
+///   parameter suffices.  However, setting a nondefault value is
+///   necessary in some cases, for example, if you want to have a
+///   sparse matrices with dimensions (and therefore column indices)
+///   that fit in \c int, but want to store more than INT_MAX
+///   entries in the sparse matrix.
+///
+/// A row has a range of entries:
+/// 
    +///
  • row_map[i0] <= entry < row_map[i0+1]
  • +///
  • 0 <= i1 < row_map[i0+1] - row_map[i0]
  • +///
  • 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> +class Crs { +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; + + entries_type entries; + row_map_type row_map; + + //! Construct an empty view. + Crs () : entries(), row_map() {} + + //! Copy constructor (shallow copy). + Crs (const Crs& rhs) : entries (rhs.entries), row_map (rhs.row_map) + {} + + template + Crs (const EntriesType& entries_,const RowMapType& row_map_) : entries (entries_), row_map (row_map_) + {} + + /** \brief Assign to a view of the rhs array. + * If the old view is the last view + * then allocated memory is deallocated. + */ + Crs& operator= (const Crs& rhs) { + entries = rhs.entries; + row_map = rhs.row_map; + return *this; + } + + /** \brief Destroy this view of the array. + * If the last view then allocated memory is deallocated. + */ + ~Crs() {} + + /** \brief Return number of rows in the graph + */ + KOKKOS_INLINE_FUNCTION + size_type numRows() const { + return (row_map.dimension_0 () != 0) ? + row_map.dimension_0 () - static_cast (1) : + static_cast (0); + } +}; + +/*--------------------------------------------------------------------------*/ + +template< class OutCounts, + class DataType, + class Arg1Type, + class Arg2Type, + class SizeType> +void get_crs_transpose_counts( + OutCounts& out, + Crs const& in, + std::string const& name = "transpose_counts"); + +template< class OutCounts, + class InCrs> +void get_crs_row_map_from_counts( + 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); + +}} // namespace Kokkos::Experimental + +/*--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------*/ + +namespace Kokkos { +namespace Impl { +namespace Experimental { + +template +class GetCrsTransposeCounts { + public: + using execution_space = typename InCrs::execution_space; + 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; + using closure_type = Kokkos::Impl::ParallelFor; + const closure_type closure(*this, policy_type(0, index_type(in.entries.size()))); + closure.execute(); + execution_space::fence(); + } +}; + +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; + private: + InCounts in; + OutRowMap out; + public: + KOKKOS_INLINE_FUNCTION + void operator()(index_type i, value_type& update, bool final_pass) const { + update += in(i); + if (final_pass) { + out(i + 1) = update; + if (i == 0) { + out(0) = 0; + } + } + } + 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 { + update += input; + } + using self_type = CrsRowMapFromCounts; + CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out): + in(arg_in),out(arg_out) { + using policy_type = RangePolicy; + using closure_type = Kokkos::Impl::ParallelScan; + closure_type closure(*this, policy_type(0, in.size())); + closure.execute(); + execution_space::fence(); + } +}; + +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; + 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); + 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; + } + } + 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; + using closure_type = Kokkos::Impl::ParallelFor; + const closure_type closure(*this, policy_type(0, index_type(in.numRows()))); + closure.execute(); + execution_space::fence(); + } +}; + +}}} // namespace Kokkos::Impl::Experimental + +/*--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------*/ + +namespace Kokkos { +namespace Experimental { + +template< class OutCounts, + class DataType, + class Arg1Type, + class Arg2Type, + class SizeType> +void get_crs_transpose_counts( + OutCounts& out, + Crs const& in, + std::string const& name) { + using InCrs = Crs; + out = OutCounts(name, in.numRows()); + Kokkos::Impl::Experimental:: + GetCrsTransposeCounts functor(in, out); +} + +template< class OutRowMap, + class InCounts> +void get_crs_row_map_from_counts( + OutRowMap& out, + InCounts const& in, + std::string const& name) { + out = OutRowMap(ViewAllocateWithoutInitializing(name), in.size() + 1); + Kokkos::Impl::Experimental:: + CrsRowMapFromCounts functor(in, out); +} + +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 ; + { + counts_type counts; + Kokkos::Experimental::get_crs_transpose_counts(counts, in); + Kokkos::Experimental::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::Experimental:: + FillCrsTransposeEntries entries_functor(in, out); +} + +}} // namespace Kokkos::Experimental + +#endif /* #define KOKKOS_CRS_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_Cuda.hpp b/lib/kokkos/core/src/Kokkos_Cuda.hpp index f0f0f87458..197831dee5 100644 --- a/lib/kokkos/core/src/Kokkos_Cuda.hpp +++ b/lib/kokkos/core/src/Kokkos_Cuda.hpp @@ -217,8 +217,8 @@ public: private: - cudaStream_t m_stream ; int m_device ; + cudaStream_t m_stream ; }; } // namespace Kokkos @@ -295,6 +295,7 @@ struct VerifyExecutionCanAccessMemorySpace #include #include #include +#include #include //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp index 307ab193b1..fb5985e164 100644 --- a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp @@ -90,7 +90,7 @@ public: , const size_t arg_alloc_size ) const ; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name(); + static constexpr const char* name() { return m_name; } /*--------------------------------*/ /** \brief Error reporting for HostSpace attempt to access CudaSpace */ @@ -186,7 +186,7 @@ public: , const size_t arg_alloc_size ) const ; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name(); + static constexpr const char* name() { return m_name; } /*--------------------------------*/ @@ -234,7 +234,7 @@ public: , const size_t arg_alloc_size ) const ; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name(); + static constexpr const char* name() { return m_name; } private: diff --git a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp index 375a2d3744..a8c4d77c62 100644 --- a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp +++ b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp @@ -384,6 +384,7 @@ Impl::PerThreadValue PerThread(const int& arg); * 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 (LaunchBounds<1024,1>: Launch Bounds for CUDA compilation. */ template< class ... Properties> class TeamPolicy: public @@ -561,6 +562,45 @@ KOKKOS_INLINE_FUNCTION Impl::ThreadVectorRangeBoundariesStruct ThreadVectorRange( const TeamMemberType&, const iType& count ); +#if defined(KOKKOS_ENABLE_PROFILING) +namespace Impl { + +template::value > +struct ParallelConstructName; + +template +struct ParallelConstructName { + ParallelConstructName(std::string const& label):label_ref(label) { + if (label.empty()) { + default_name = std::string(typeid(FunctorType).name()) + "/" + + typeid(TagType).name(); + } + } + std::string const& get() { + return (label_ref.empty()) ? default_name : label_ref; + } + std::string const& label_ref; + std::string default_name; +}; + +template +struct ParallelConstructName { + ParallelConstructName(std::string const& label):label_ref(label) { + if (label.empty()) { + default_name = std::string(typeid(FunctorType).name()); + } + } + std::string const& get() { + return (label_ref.empty()) ? default_name : label_ref; + } + std::string const& label_ref; + std::string default_name; +}; + +} // namespace Impl +#endif /* defined KOKKOS_ENABLE_PROFILING */ + } // namespace Kokkos #endif /* #define KOKKOS_EXECPOLICY_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp index e224cd4e84..9c9af0dd8b 100644 --- a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp @@ -126,14 +126,6 @@ public: //! This memory space preferred device_type typedef Kokkos::Device< execution_space, memory_space > device_type; - /*--------------------------------*/ - /* Functions unique to the HBWSpace */ - static int in_parallel(); - - static void register_in_parallel( int (*)() ); - - /*--------------------------------*/ - /**\brief Default memory space instance */ HBWSpace(); HBWSpace( const HBWSpace & rhs ) = default; diff --git a/lib/kokkos/core/src/Kokkos_HostSpace.hpp b/lib/kokkos/core/src/Kokkos_HostSpace.hpp index d00cce8f60..431635047a 100644 --- a/lib/kokkos/core/src/Kokkos_HostSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HostSpace.hpp @@ -130,14 +130,6 @@ public: //! This memory space preferred device_type typedef Kokkos::Device< execution_space, memory_space > device_type; - /*--------------------------------*/ - /* Functions unique to the HostSpace */ - static int in_parallel(); - - static void register_in_parallel( int (*)() ); - - /*--------------------------------*/ - /**\brief Default memory space instance */ HostSpace(); HostSpace( HostSpace && rhs ) = default; @@ -161,7 +153,7 @@ public: , const size_t arg_alloc_size ) const; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name(); + static constexpr const char* name() { return m_name; } private: AllocationMechanism m_alloc_mech; diff --git a/lib/kokkos/core/src/Kokkos_Layout.hpp b/lib/kokkos/core/src/Kokkos_Layout.hpp index f300a6d9f6..87c705153e 100644 --- a/lib/kokkos/core/src/Kokkos_Layout.hpp +++ b/lib/kokkos/core/src/Kokkos_Layout.hpp @@ -156,6 +156,8 @@ struct LayoutStride { 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 ) { diff --git a/lib/kokkos/core/src/Kokkos_Macros.hpp b/lib/kokkos/core/src/Kokkos_Macros.hpp index 1439dbd3f8..250ef6630a 100644 --- a/lib/kokkos/core/src/Kokkos_Macros.hpp +++ b/lib/kokkos/core/src/Kokkos_Macros.hpp @@ -297,6 +297,10 @@ #endif #endif + #if defined( KOKKOS_ARCH_AVX512MIC ) + #define KOKKOS_ENABLE_RFO_PREFETCH 1 + #endif + #if defined( __MIC__ ) // Compiling for Xeon Phi #endif @@ -344,13 +348,18 @@ //#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_FORCEINLINE_FUNCTION ) #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) #endif #if !defined( KOKKOS_ENABLE_ASM ) && !defined( __PGIC__ ) && \ ( defined( __amd64 ) || defined( __amd64__ ) || \ - defined( __x86_64 ) || defined( __x86_64__ ) ) + defined( __x86_64 ) || defined( __x86_64__ ) || \ + defined(__PPC64__) ) #define KOKKOS_ENABLE_ASM 1 #endif #endif diff --git a/lib/kokkos/core/src/Kokkos_MasterLock.hpp b/lib/kokkos/core/src/Kokkos_MasterLock.hpp new file mode 100644 index 0000000000..81564b8eac --- /dev/null +++ b/lib/kokkos/core/src/Kokkos_MasterLock.hpp @@ -0,0 +1,73 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_MASTER_LOCK_HPP +#define KOKKOS_MASTER_LOCK_HPP + +#include + +namespace Kokkos { namespace Experimental { + +// my be used to coordinate work between master instances +// SHOULD NOT be used within a parallel algorithm +// +// This lock should be used with with a scoped lock guard +// i.e. std::unique_lock, std::lock_guard +// +// cannot be copied or moved +// has the following functions available +// +// Lock() +// ~Lock() +// +// void lock() +// void unlock() +// bool try_lock() +// +template +class MasterLock; + +}} // namespace Kokkos::Experimental + +#endif //KOKKOS_MASTER_LOCK_HPP + diff --git a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp index dbf1ad8057..1da936067d 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp @@ -66,11 +66,6 @@ private: enum : uint32_t { max_bit_count_lg2 = CB::max_bit_count_lg2 }; enum : uint32_t { max_bit_count = CB::max_bit_count }; - /* Defaults for min block, max block, and superblock sizes */ - enum : uint32_t { MIN_BLOCK_SIZE_LG2 = 6 /* 64 bytes */ }; - enum : uint32_t { MAX_BLOCK_SIZE_LG2 = 12 /* 4k bytes */ }; - enum : uint32_t { SUPERBLOCK_SIZE_LG2 = 16 /* 64k bytes */ }; - enum : uint32_t { HINT_PER_BLOCK_SIZE = 2 }; /* Each superblock has a concurrent bitset state @@ -85,6 +80,14 @@ private: * is concurrently updated. */ + /* Mapping between block_size <-> block_state + * + * block_state = ( m_sb_size_lg2 - block_size_lg2 ) << state_shift + * block_size = m_sb_size_lg2 - ( block_state >> state_shift ) + * + * Thus A_block_size < B_block_size <=> A_block_state > B_block_state + */ + typedef typename DeviceType::memory_space base_memory_space ; enum { accessible = @@ -251,10 +254,10 @@ public: * significant runtime performance improvements. */ MemoryPool( const base_memory_space & memspace - , const size_t min_total_alloc_size - , const uint32_t min_block_alloc_size // = 1 << MIN_BLOCK_SIZE_LG2 - , const uint32_t max_block_alloc_size // = 1 << MAX_BLOCK_SIZE_LG2 - , const uint32_t min_superblock_size // = 1 << SUPERBLOCK_SIZE_LG2 + , 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) @@ -267,8 +270,43 @@ public: , 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 int_align_lg2 = 3 ; /* align as int[8] */ + const uint32_t int_align_mask = ( 1u << int_align_lg2 ) - 1 ; + + // Constraints and defaults: + // min_block_alloc_size <= max_block_alloc_size + // max_block_alloc_size <= min_superblock_size + // min_superblock_size <= min_total_alloc_size + + const uint32_t MIN_BLOCK_SIZE = 1u << 6 /* 64 bytes */ ; + const uint32_t MAX_BLOCK_SIZE = 1u << 12 /* 4k bytes */ ; + + if ( 0 == min_block_alloc_size ) min_block_alloc_size = MIN_BLOCK_SIZE ; + + if ( 0 == max_block_alloc_size ) { + + max_block_alloc_size = MAX_BLOCK_SIZE ; + + // Upper bound of total allocation size + max_block_alloc_size = std::min( size_t(max_block_alloc_size) + , min_total_alloc_size ); + + // Lower bound of minimum block size + max_block_alloc_size = std::max( max_block_alloc_size + , min_block_alloc_size ); + } + + if ( 0 == min_superblock_size ) { + min_superblock_size = max_block_alloc_size ; + + // Upper bound of total allocation size + min_superblock_size = std::min( size_t(min_superblock_size) + , min_total_alloc_size ); + + // Lower bound of maximum block size + min_superblock_size = std::max( min_superblock_size + , max_block_alloc_size ); + } // Block and superblock size is power of two: @@ -435,6 +473,8 @@ public: void * allocate( size_t alloc_size , int32_t attempt_limit = 1 ) const noexcept { + if ( 0 == alloc_size ) return (void*) 0 ; + void * p = 0 ; const uint32_t block_size_lg2 = get_block_size_lg2( alloc_size ); @@ -444,10 +484,9 @@ public: // 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_mask = block_count - 1 ; + 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 @@ -465,7 +504,7 @@ public: // the guess for which block within a superblock should // be claimed. If not available then a search occurs. - const uint32_t block_id_hint = block_count_mask & + 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 @@ -474,6 +513,9 @@ public: #endif ); + // expected state of superblock for allocation + uint32_t sb_state = block_state ; + int32_t sb_id = -1 ; volatile uint32_t * sb_state_array = 0 ; @@ -484,6 +526,8 @@ public: if ( sb_id < 0 ) { + // No superblock specified, try the hint for this block size + sb_id = hint_sb_id = int32_t( *hint_sb_id_ptr ); sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); @@ -493,16 +537,20 @@ public: // 0 <= sb_id // sb_state_array == m_sb_state_array + m_sb_state_size * sb_id - if ( block_state == ( state_header_mask & *sb_state_array ) ) { + if ( sb_state == ( state_header_mask & *sb_state_array ) ) { - // This superblock state is assigned to this block size. - // Try to claim a bit. + // 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 Kokkos::pair result = CB::acquire_bounded_lg2( sb_state_array - , block_count_lg2 - , block_id_hint - , block_state + , count_lg2 + , block_id_hint & mask + , sb_state ); // If result.first < 0 then failed to acquire @@ -512,16 +560,18 @@ public: if ( 0 <= result.first ) { // acquired a bit + const uint32_t size_lg2 = m_sb_size_lg2 - count_lg2 ; + // Set the allocated block pointer p = ((char*)( m_sb_state_array + m_data_offset )) + ( uint32_t(sb_id) << m_sb_size_lg2 ) // superblock memory - + ( result.first << block_size_lg2 ); // block memory + + ( result.first << size_lg2 ); // block memory break ; // Success } -// printf(" acquire block_count_lg2(%d) block_state(0x%x) sb_id(%d) result(%d,%d)\n" , block_count_lg2 , block_state , sb_id , result.first , result.second ); +// printf(" acquire count_lg2(%d) sb_state(0x%x) sb_id(%d) result(%d,%d)\n" , count_lg2 , sb_state , sb_id , result.first , result.second ); } //------------------------------------------------------------------ @@ -529,12 +579,18 @@ public: // Must find a new superblock. // Start searching at designated index for this block size. - // Look for a partially full superblock of this block size. - // Look for an empty superblock just in case cannot find partfull. + // 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 ; @@ -544,38 +600,54 @@ public: // Note that the state may change at any moment // as concurrent allocations and deallocations occur. - const uint32_t state = *sb_state_array ; - const uint32_t used = state & state_used_mask ; + 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 ; - if ( block_state == ( state & state_header_mask ) ) { + if ( state == block_state ) { // Superblock is assigned to this block size - if ( used < block_count ) { + if ( used < block_count ) { // There is room to allocate one block sb_id = id ; - if ( used + 1 < block_count ) { + // Is there room to allocate more than one block? - // There is room to allocate more than one block - - Kokkos::atomic_compare_exchange - ( hint_sb_id_ptr , uint32_t(hint_sb_id) , uint32_t(sb_id) ); - } + update_hint = used + 1 < block_count ; break ; } } - else if ( ( used == 0 ) && ( sb_id_empty == -1 ) ) { + else if ( 0 == used ) { - // 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. + // Superblock is empty - sb_id_empty = id ; + 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. + + 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 ; + } + + // Iterate around the superblock array: if ( ++id < m_sb_count ) { sb_state_array += m_sb_state_size ; @@ -586,7 +658,7 @@ public: } } -// printf(" search m_sb_count(%d) sb_id(%d) sb_id_empty(%d)\n" , m_sb_count , sb_id , sb_id_empty ); +// 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 ( sb_id < 0 ) { @@ -609,21 +681,31 @@ public: const uint32_t state_empty = state_header_mask & *sb_state_array ; - if ( state_empty == - Kokkos::atomic_compare_exchange - (sb_state_array,state_empty,block_state) ) { + // 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 claimed the block then update the hint + // Found a larger superblock with space available - Kokkos::atomic_compare_exchange - ( hint_sb_id_ptr , uint32_t(hint_sb_id) , uint32_t(sb_id) ); - } + 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 ; } } + + if ( update_hint ) { + Kokkos::atomic_compare_exchange + ( hint_sb_id_ptr , uint32_t(hint_sb_id) , uint32_t(sb_id) ); + } } // end allocation attempt loop //-------------------------------------------------------------------- @@ -646,6 +728,8 @@ public: 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 )); diff --git a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp index 94b58b8aff..af9c8ea782 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp @@ -72,11 +72,11 @@ struct MemoryTraits { //! Tag this class as a kokkos memory traits: typedef MemoryTraits memory_traits ; - enum { Unmanaged = T & unsigned(Kokkos::Unmanaged) }; - enum { RandomAccess = T & unsigned(Kokkos::RandomAccess) }; - enum { Atomic = T & unsigned(Kokkos::Atomic) }; - enum { Restrict = T & unsigned(Kokkos::Restrict) }; - enum { Aligned = 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))) }; }; @@ -109,7 +109,11 @@ enum { MEMORY_ALIGNMENT = #else ( 1 << Kokkos::Impl::integral_power_of_two( 128 ) ) #endif - , MEMORY_ALIGNMENT_THRESHOLD = 4 +#if defined( KOKKOS_MEMORY_ALIGNMENT_THRESHOLD ) + , MEMORY_ALIGNMENT_THRESHOLD = KOKKOS_MEMORY_ALIGNMENT_THRESHOLD +#else + , MEMORY_ALIGNMENT_THRESHOLD = 4 +#endif }; diff --git a/lib/kokkos/core/src/Kokkos_OpenMP.hpp b/lib/kokkos/core/src/Kokkos_OpenMP.hpp index 3e11621ce6..d5de01cf2f 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMP.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMP.hpp @@ -47,10 +47,6 @@ #include #if defined( KOKKOS_ENABLE_OPENMP) -#if !defined(_OPENMP) -#error "You enabled Kokkos OpenMP support without enabling OpenMP in the compiler!" -#endif - #include #include @@ -67,95 +63,144 @@ #include #include +#include + /*--------------------------------------------------------------------------*/ namespace Kokkos { +namespace Impl { +class OpenMPExec; +} + /// \class OpenMP /// \brief Kokkos device for multicore processors in the host memory space. class OpenMP { public: - //------------------------------------ - //! \name Type declarations that all Kokkos devices must provide. - //@{ - //! Tag this class as a kokkos execution space using execution_space = OpenMP; + + using memory_space = #ifdef KOKKOS_ENABLE_HBWSPACE - using memory_space = Experimental::HBWSpace; + Experimental::HBWSpace; #else - using memory_space = HostSpace; + HostSpace; #endif + //! This execution space preferred device_type - using device_type = Kokkos::Device; - - using array_layout = LayoutRight; - using size_type = memory_space::size_type; - + using device_type = Kokkos::Device< execution_space, memory_space >; + using array_layout = LayoutRight; + using size_type = memory_space::size_type; using scratch_memory_space = ScratchMemorySpace< OpenMP >; - //@} - //------------------------------------ - //! \name Functions that all Kokkos execution spaces must implement. - //@{ + /// \brief Get a handle to the default execution space instance + inline + OpenMP() noexcept; - inline static bool in_parallel(); + // 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(); + static int get_current_max_threads() noexcept; - /** \brief Set the device in a "sleep" state. A noop for OpenMP. */ - static bool sleep(); + /// \brief Initialize the default execution space + /// + /// if ( thread_count == -1 ) + /// then use the number of threads that openmp defaults to + /// if ( thread_count == 0 && Kokkos::hwlow_available() ) + /// then use hwloc to choose the number of threads and change + /// the default number of threads + /// 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 ); - /** \brief Wake the device from the 'sleep' state. A noop for OpenMP. */ - static bool wake(); - - /** \brief Wait until all dispatched functors complete. A noop for OpenMP. */ - static void fence() {} - - /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); - - /// \brief Free any resources being consumed by the device. + /// \brief Free any resources being consumed by the default execution space static void finalize(); - /** \brief Initialize the device. - * - * 1) If the hardware locality library is enabled and OpenMP has not - * already bound threads then bind OpenMP threads to maximize - * core utilization and group for memory hierarchy locality. - * - * 2) Allocate a HostThread for each OpenMP 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 ); + /// \brief is the default execution space initialized for current 'master' thread + static bool is_initialized() noexcept; - static int is_initialized(); + /// \brief Print configuration information to the given output stream. + static void print_configuration( std::ostream & , const bool verbose = false ); - /** \brief Return the maximum amount of concurrency. */ - static int concurrency(); + /// \brief is the instance running a parallel algorithm + inline + static bool in_parallel( OpenMP const& = OpenMP() ) noexcept; - //@} - //------------------------------------ - /** \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. - */ - inline static int thread_pool_size( int depth = 0 ); + /// \brief Wait until all dispatched functors complete on the given instance + /// + /// This is a no-op on OpenMP + inline + static void fence( OpenMP const& = OpenMP() ) noexcept; + + /// \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; + + + /// \brief Partition the default instance into new instances without creating + /// new masters + /// + /// This is a no-op on OpenMP since the default instance cannot be partitioned + /// without promoting other threads to 'master' + static std::vector partition(...); + + /// Non-default instances should be ref-counted so that when the last + /// is destroyed the instance resources are released + /// + /// 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 + /// + /// 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 + ); + + 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(); + KOKKOS_INLINE_FUNCTION + static int thread_pool_rank() noexcept; - //------------------------------------ +#if !defined( KOKKOS_DISABLE_DEPRECATED ) + /// \brief Initialize the default execution space + static void initialize( int thread_count, + int use_numa_count, + int use_cores_per_numa = 0); - inline static unsigned max_hardware_threads() { return thread_pool_size(0); } + inline + static int thread_pool_size( int depth ); - KOKKOS_INLINE_FUNCTION static - unsigned hardware_thread_id() { return thread_pool_rank(); } + static void sleep() {}; + static void wake() {}; - static const char* name(); + // use UniqueToken + static int concurrency(); + + // use UniqueToken + inline + static int max_hardware_threads() noexcept; + + // use UniqueToken + KOKKOS_INLINE_FUNCTION + static int hardware_thread_id() noexcept; +#endif + + static constexpr const char* name() noexcept { return "OpenMP"; } }; } // namespace Kokkos @@ -195,6 +240,7 @@ struct VerifyExecutionCanAccessMemorySpace /*--------------------------------------------------------------------------*/ #include +#include #include #include diff --git a/lib/kokkos/core/src/Kokkos_Parallel.hpp b/lib/kokkos/core/src/Kokkos_Parallel.hpp index e412e608b2..fc8d6bec81 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel.hpp @@ -177,22 +177,23 @@ void parallel_for( const ExecPolicy & policy ) { #if defined(KOKKOS_ENABLE_PROFILING) - uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::beginParallelFor("" == str ? typeid(FunctorType).name() : str, 0, &kpID); - } + uint64_t kpID = 0; + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName name(str); + Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); + } #endif - Kokkos::Impl::shared_allocation_tracking_claim_and_disable(); + Kokkos::Impl::shared_allocation_tracking_disable(); Impl::ParallelFor< FunctorType , ExecPolicy > closure( functor , policy ); - Kokkos::Impl::shared_allocation_tracking_release_and_enable(); + 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 } @@ -210,14 +211,15 @@ void parallel_for( const size_t work_count #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::beginParallelFor("" == str ? typeid(FunctorType).name() : str, 0, &kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName name(str); + Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); + } #endif - Kokkos::Impl::shared_allocation_tracking_claim_and_disable(); + Kokkos::Impl::shared_allocation_tracking_disable(); Impl::ParallelFor< FunctorType , policy > closure( functor , policy(0,work_count) ); - Kokkos::Impl::shared_allocation_tracking_release_and_enable(); + Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); @@ -420,21 +422,22 @@ void parallel_scan( const ExecutionPolicy & policy { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::beginParallelScan("" == str ? typeid(FunctorType).name() : str, 0, &kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName name(str); + Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); + } #endif - Kokkos::Impl::shared_allocation_tracking_claim_and_disable(); + Kokkos::Impl::shared_allocation_tracking_disable(); Impl::ParallelScan< FunctorType , ExecutionPolicy > closure( functor , policy ); - Kokkos::Impl::shared_allocation_tracking_release_and_enable(); + Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelScan(kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelScan(kpID); + } #endif } @@ -453,21 +456,22 @@ void parallel_scan( const size_t work_count #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::beginParallelScan("" == str ? typeid(FunctorType).name() : str, 0, &kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName name(str); + Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); + } #endif - Kokkos::Impl::shared_allocation_tracking_claim_and_disable(); + Kokkos::Impl::shared_allocation_tracking_disable(); Impl::ParallelScan< FunctorType , policy > closure( functor , policy(0,work_count) ); - Kokkos::Impl::shared_allocation_tracking_release_and_enable(); + Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelScan(kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelScan(kpID); + } #endif } diff --git a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp index 8ea5183e35..9df6d4ba09 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp @@ -872,13 +872,14 @@ namespace Impl { const FunctorType& functor, ReturnType& return_value) { #if defined(KOKKOS_ENABLE_PROFILING) - uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::beginParallelReduce("" == label ? typeid(FunctorType).name() : label, 0, &kpID); - } + 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_claim_and_disable(); + Kokkos::Impl::shared_allocation_tracking_disable(); #ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER Impl::ParallelReduce closure(functor_adaptor::functor(functor), @@ -890,13 +891,13 @@ namespace Impl { policy, return_value_adapter::return_value(return_value,functor)); #endif - Kokkos::Impl::shared_allocation_tracking_release_and_enable(); + Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelReduce(kpID); - } + if(Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelReduce(kpID); + } #endif } diff --git a/lib/kokkos/core/src/Kokkos_Serial.hpp b/lib/kokkos/core/src/Kokkos_Serial.hpp index 73e8ae3030..539761a1f9 100644 --- a/lib/kokkos/core/src/Kokkos_Serial.hpp +++ b/lib/kokkos/core/src/Kokkos_Serial.hpp @@ -66,6 +66,7 @@ #include +#include namespace Kokkos { @@ -526,6 +527,7 @@ public: } }; + /*--------------------------------------------------------------------------*/ template< class FunctorType , class ... Traits > @@ -604,6 +606,178 @@ public: {} }; +} // namespace Impl +} // namespace Kokkos + + +/*--------------------------------------------------------------------------*/ +/*--------------------------------------------------------------------------*/ +/* Parallel patterns for Kokkos::Serial with MDRangePolicy */ + +namespace Kokkos { +namespace Impl { + +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType , + Kokkos::Experimental::MDRangePolicy< Traits ... > , + Kokkos::Serial + > +{ +private: + + typedef Kokkos::Experimental::MDRangePolicy< Traits ... > MDRangePolicy ; + typedef typename MDRangePolicy::impl_range_policy Policy ; + + typedef typename Kokkos::Experimental::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(); } + + 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 FunctorType , class ReducerType , class ... Traits > +class ParallelReduce< FunctorType + , Kokkos::Experimental::MDRangePolicy< Traits ... > + , ReducerType + , Kokkos::Serial + > +{ +private: + + typedef Kokkos::Experimental::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 typename ReducerConditional::type ReducerTypeFwd; + + typedef typename ReducerTypeFwd::value_type ValueType; + + typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + + typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTag > ValueInit ; + + typedef typename Analysis::pointer_type pointer_type ; + typedef typename Analysis::reference_type reference_type ; + + + using iterate_type = typename Kokkos::Experimental::Impl::HostIterateTile< MDRangePolicy + , FunctorType + , WorkTag + , ValueType + >; + + + 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 + + serial_resize_thread_team_data( pool_reduce_size + , team_reduce_size + , team_shared_size + , thread_local_size ); + + HostThreadTeamData & data = *serial_get_thread_team_data(); + + 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 ); + + this-> exec( update ); + + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTag >:: + 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" ); + } + + 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 @@ -819,6 +993,60 @@ public: /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ +namespace Kokkos { namespace Experimental { + +template<> +class UniqueToken< Serial, UniqueTokenScope::Instance> +{ +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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + inline + int size() const noexcept { return 1; } + + /// \brief acquire value such that 0 <= value < size() + inline + int acquire() const noexcept { return 0; } + + /// \brief release a value acquired by generate + inline + void release( int ) const noexcept {} +}; + +template<> +class UniqueToken< Serial, UniqueTokenScope::Global> +{ +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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + inline + int size() const noexcept { return 1; } + + /// \brief acquire value such that 0 <= value < size() + inline + int acquire() const noexcept { return 0; } + + /// \brief release a value acquired by generate + inline + void release( int ) const noexcept {} +}; + +}} // namespace Kokkos::Experimental + #include #endif // defined( KOKKOS_ENABLE_SERIAL ) diff --git a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp index 7edda7aa75..fcfc91a4ee 100644 --- a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp @@ -148,7 +148,7 @@ private: typename std::conditional< Arg2_is_space , Arg2 , void >::type >::type ; - using task_base = Impl::TaskBase< Space , ValueType , void > ; + using task_base = Impl::TaskBase< void , void , void > ; using queue_type = Impl::TaskQueue< Space > ; task_base * m_task ; @@ -293,13 +293,17 @@ public: //---------------------------------------- KOKKOS_INLINE_FUNCTION - typename task_base::get_return_type + 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()"); } - return m_task->get(); + return Impl::TaskResult< ValueType >::get( m_task ); } }; @@ -396,7 +400,7 @@ private: using track_type = Kokkos::Impl::SharedAllocationTracker ; using queue_type = Kokkos::Impl::TaskQueue< ExecSpace > ; - using task_base = Impl::TaskBase< ExecSpace , void , void > ; + using task_base = Impl::TaskBase< void , void , void > ; track_type m_track ; queue_type * m_queue ; @@ -464,29 +468,19 @@ public: KOKKOS_INLINE_FUNCTION memory_pool * memory() const noexcept - { return m_queue ? m_queue->m_memory : (memory_pool*) 0 ; } + { 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 - { - using task_type = Impl::TaskBase< execution_space - , typename FunctorType::value_type - , FunctorType > ; - - return m_queue->allocate_block_size( sizeof(task_type) ); - } + { return m_queue->template spawn_allocation_size< FunctorType >(); } /**\brief Allocation size for a when_all aggregate */ KOKKOS_FUNCTION size_t when_all_allocation_size( int narg ) const - { - using task_base = Kokkos::Impl::TaskBase< ExecSpace , void , void > ; - - return m_queue->allocate_block_size( sizeof(task_base) + narg * sizeof(task_base*) ); - } + { return m_queue->when_all_allocation_size( narg ); } //---------------------------------------- @@ -507,7 +501,7 @@ public: queue_type * const queue = arg_policy.m_scheduler ? arg_policy.m_scheduler->m_queue : ( arg_policy.m_dependence.m_task - ? arg_policy.m_dependence.m_task->m_queue + ? static_cast(arg_policy.m_dependence.m_task->m_queue) : (queue_type*) 0 ); if ( 0 == queue ) { @@ -530,8 +524,12 @@ public: future_type f ; // Allocate task from memory pool + + const size_t alloc_size = + queue->template spawn_allocation_size< FunctorType >(); + f.m_task = - reinterpret_cast< task_type * >(queue->allocate(sizeof(task_type))); + reinterpret_cast< task_type * >(queue->allocate(alloc_size) ); if ( f.m_task ) { @@ -539,15 +537,17 @@ public: // Reference count starts at two: // +1 for the matching decrement when task is complete // +1 for the future - new ( f.m_task ) - task_type( arg_function - , queue - , arg_policy.m_dependence.m_task /* dependence */ - , 2 /* reference count */ - , int(sizeof(task_type)) /* allocation size */ - , int(arg_policy.m_task_type) - , int(arg_policy.m_priority) - , std::move(arg_functor) ); + new ( f.m_task ) task_type( std::move(arg_functor) ); + + f.m_task->m_apply = arg_function ; + f.m_task->m_queue = queue ; + f.m_task->m_next = arg_policy.m_dependence.m_task ; + f.m_task->m_ref_count = 2 ; + f.m_task->m_alloc_size = alloc_size ; + f.m_task->m_task_type = arg_policy.m_task_type ; + f.m_task->m_priority = arg_policy.m_priority ; + + Kokkos::memory_fence(); // The dependence (if any) is processed immediately // within the schedule function, as such the dependence's @@ -586,6 +586,30 @@ public: // Postcondition: task is in Executing-Respawn state } + template< typename FunctorType > + KOKKOS_FUNCTION static + void + respawn( FunctorType * arg_self + , TaskScheduler const & + , TaskPriority const & arg_priority + ) + { + // Precondition: task is in Executing state + + using value_type = typename FunctorType::value_type ; + using task_type = Impl::TaskBase< execution_space + , value_type + , FunctorType > ; + + task_type * const task = static_cast< task_type * >( arg_self ); + + task->m_priority = static_cast(arg_priority); + + task->add_dependence( (task_base*) 0 ); + + // Postcondition: task is in Executing-Respawn state + } + //---------------------------------------- /**\brief Return a future that is complete * when all input futures are complete. @@ -596,7 +620,7 @@ public: when_all( Future< A1 , A2 > const arg[] , int narg ) { using future_type = Future< execution_space > ; - using task_base = Kokkos::Impl::TaskBase< execution_space , void , void > ; + using task_base = Kokkos::Impl::TaskBase< void , void , void > ; future_type f ; @@ -610,9 +634,9 @@ public: // Increment reference count to track subsequent assignment. Kokkos::atomic_increment( &(t->m_ref_count) ); if ( queue == 0 ) { - queue = t->m_queue ; + queue = static_cast< queue_type * >( t->m_queue ); } - else if ( queue != t->m_queue ) { + else if ( queue != static_cast< queue_type * >( t->m_queue ) ) { Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" ); } } @@ -620,28 +644,34 @@ public: if ( queue != 0 ) { - size_t const size = sizeof(task_base) + narg * sizeof(task_base*); + size_t const alloc_size = queue->when_all_allocation_size( narg ); f.m_task = - reinterpret_cast< task_base * >( queue->allocate( size ) ); + reinterpret_cast< task_base * >( 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( queue - , 2 /* reference count */ - , size /* allocation size */ - , narg /* dependence count */ - ); + + new( f.m_task ) task_base(); + + f.m_task->m_queue = queue ; + f.m_task->m_ref_count = 2 ; + f.m_task->m_alloc_size = alloc_size ; + 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 ** 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 ; } + Kokkos::memory_fence(); + queue->schedule_aggregate( f.m_task ); // this when_all may be processed at any moment } diff --git a/lib/kokkos/core/src/Kokkos_UniqueToken.hpp b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp new file mode 100644 index 0000000000..1ffb07a6db --- /dev/null +++ b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp @@ -0,0 +1,88 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_UNIQUE_TOKEN_HPP +#define KOKKOS_UNIQUE_TOKEN_HPP + +#include + +namespace Kokkos { namespace Experimental { + +enum class UniqueTokenScope : int +{ + Instance, + Global +}; + +/// \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: + 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() ); + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + KOKKOS_INLINE_FUNCTION + size_type size() const ; + + /// \brief acquire value such that 0 <= value < size() + KOKKOS_INLINE_FUNCTION + size_type acquire() const ; + + /// \brief release a value acquired by generate + KOKKOS_INLINE_FUNCTION + void release( size_type ) const ; +}; + +}} // namespace Kokkos::Experimental + +#endif //KOKKOS_UNIQUE_TOKEN_HPP diff --git a/lib/kokkos/core/src/Kokkos_View.hpp b/lib/kokkos/core/src/Kokkos_View.hpp index 3312aa6a96..1754e4a8fb 100644 --- a/lib/kokkos/core/src/Kokkos_View.hpp +++ b/lib/kokkos/core/src/Kokkos_View.hpp @@ -1,13 +1,13 @@ /* //@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: @@ -36,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -54,11 +54,14 @@ #include #include +#if defined(KOKKOS_ENABLE_PROFILING) +#include +#endif + //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { template< class DataType > @@ -73,16 +76,6 @@ struct ViewDataAnalysis ; template< class , class ... > class ViewMapping { public: enum { is_assignable = false }; }; -} /* namespace Impl */ -} /* namespace Experimental */ -} /* namespace Kokkos */ - -namespace Kokkos { -namespace Impl { - -using Kokkos::Experimental::Impl::ViewMapping ; -using Kokkos::Experimental::Impl::ViewDataAnalysis ; - } /* namespace Impl */ } /* namespace Kokkos */ @@ -1563,12 +1556,12 @@ namespace Kokkos { namespace Impl { inline -void shared_allocation_tracking_claim_and_disable() -{ Kokkos::Impl::SharedAllocationRecord::tracking_claim_and_disable(); } +void shared_allocation_tracking_disable() +{ Kokkos::Impl::SharedAllocationRecord::tracking_disable(); } inline -void shared_allocation_tracking_release_and_enable() -{ Kokkos::Impl::SharedAllocationRecord::tracking_release_and_enable(); } +void shared_allocation_tracking_enable() +{ Kokkos::Impl::SharedAllocationRecord::tracking_enable(); } } /* namespace Impl */ } /* namespace Kokkos */ @@ -1795,6 +1788,20 @@ void deep_copy if ( (void *) dst.data() != (void*) src.data() ) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + const size_t nbytes = sizeof(typename dst_type::value_type) * dst.span(); + 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(), + nbytes); + } +#endif + // Concern: If overlapping views then a parallel copy will be erroneous. // ... @@ -1882,7 +1889,14 @@ void deep_copy else { Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation"); } - } + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif + + } // ( (void *) dst.data() != (void*) src.data() ) } } /* namespace Kokkos */ @@ -2249,6 +2263,82 @@ resize( Kokkos::View & v , 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< view_type , view_type >( v_resized , v ); @@ -2317,6 +2407,106 @@ void realloc( Kokkos::View & v , } } /* namespace Kokkos */ +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +namespace Kokkos { namespace Impl { + +template < class Specialize, typename A, typename B > +struct CommonViewValueType; + +template < typename A, typename B > +struct CommonViewValueType< void, A, B > +{ + using value_type = typename std::common_type< A , B >::type; +}; + + +template < class Specialize, class ValueType > +struct CommonViewAllocProp; + +template < class ValueType > +struct CommonViewAllocProp< void, ValueType > +{ + using value_type = ValueType; + + template < class ... Views > + CommonViewAllocProp( const Views & ... ) {} +}; + + +template < class ... Views > +struct DeduceCommonViewAllocProp; + +// Base case must provide types for: +// 1. specialize 2. value_type 3. is_view 4. prop_type +template < class FirstView > +struct DeduceCommonViewAllocProp< FirstView > +{ + using specialize = typename FirstView::traits::specialize; + + using value_type = typename FirstView::traits::value_type; + + enum : bool { is_view = is_view< FirstView >::value }; + + using prop_type = CommonViewAllocProp< specialize, value_type >; +}; + + +template < class FirstView, class ... NextViews > +struct DeduceCommonViewAllocProp< FirstView, NextViews... > +{ + using NextTraits = DeduceCommonViewAllocProp< NextViews... >; + + using first_specialize = typename FirstView::traits::specialize; + using first_value_type = typename FirstView::traits::value_type; + + enum : bool { first_is_view = is_view< FirstView >::value }; + + using next_specialize = typename NextTraits::specialize; + using next_value_type = typename NextTraits::value_type; + + enum : bool { next_is_view = NextTraits::is_view }; + + // common types + + // determine specialize type + // if first and next specialize differ, but are not the same specialize, error out + static_assert( !(!std::is_same< first_specialize, next_specialize >::value && !std::is_same< first_specialize, void>::value && !std::is_same< void, next_specialize >::value) , "Kokkos DeduceCommonViewAllocProp ERROR: Only one non-void specialize trait allowed" ); + + // otherwise choose non-void specialize if either/both are non-void + using specialize = typename std::conditional< std::is_same< first_specialize, next_specialize >::value + , first_specialize + , typename std::conditional< ( std::is_same< first_specialize, void >::value + && !std::is_same< next_specialize, void >::value) + , next_specialize + , first_specialize + >::type + >::type; + + using value_type = typename CommonViewValueType< specialize, first_value_type, next_value_type >::value_type; + + enum : bool { is_view = (first_is_view && next_is_view) }; + + using prop_type = CommonViewAllocProp< specialize, value_type >; +}; + +} // end namespace Impl + +template < class ... Views > +using DeducedCommonPropsType = typename Impl::DeduceCommonViewAllocProp::prop_type ; + +// User function +template < class ... Views > +DeducedCommonPropsType +common_view_alloc_prop( Views const & ... views ) +{ + return DeducedCommonPropsType( views... ); +} + +} // namespace Kokkos + + //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- // For backward compatibility: @@ -2350,6 +2540,9 @@ using Kokkos::Impl::WithoutInitializing_t ; using Kokkos::Impl::AllowPadding_t ; using Kokkos::Impl::SharedAllocationRecord ; using Kokkos::Impl::SharedAllocationTracker ; +using Kokkos::Impl::ViewMapping ; +using Kokkos::Impl::ViewDataAnalysis ; + } /* namespace Impl */ } /* namespace Experimental */ diff --git a/lib/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp b/lib/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp new file mode 100644 index 0000000000..58b0f72f51 --- /dev/null +++ b/lib/kokkos/core/src/Kokkos_WorkGraphPolicy.hpp @@ -0,0 +1,265 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_WORKGRAPHPOLICY_HPP +#define KOKKOS_WORKGRAPHPOLICY_HPP + +namespace Kokkos { +namespace Impl { +namespace Experimental { + +template< class functor_type , class execution_space, class ... policy_args > +class WorkGraphExec; + +}}} // namespace Kokkos::Impl::Experimental + +namespace Kokkos { +namespace Experimental { + +template< class ... Properties > +class WorkGraphPolicy +{ +public: + + using self_type = WorkGraphPolicy; + using traits = Kokkos::Impl::PolicyTraits; + using index_type = typename traits::index_type; + using execution_space = typename traits::execution_space; + using work_tag = typename traits::work_tag; + using memory_space = typename execution_space::memory_space; + using graph_type = Kokkos::Experimental::Crs; + using member_type = index_type; + +private: + + graph_type m_graph; + + using ints_type = Kokkos::View; + using range_type = Kokkos::pair; + using ranges_type = Kokkos::View; + const std::int32_t m_total_work; + ints_type m_counts; + ints_type m_queue; + ranges_type m_ranges; + +public: + + struct TagZeroRanges {}; + KOKKOS_INLINE_FUNCTION + void operator()(TagZeroRanges, std::int32_t i) const { + m_ranges[i] = range_type(0, 0); + } + void zero_ranges() { + using policy_type = RangePolicy; + using closure_type = Kokkos::Impl::ParallelFor; + const closure_type closure(*this, policy_type(0, 1)); + closure.execute(); + execution_space::fence(); + } + + struct TagFillQueue {}; + KOKKOS_INLINE_FUNCTION + void operator()(TagFillQueue, std::int32_t i) const { + if (*((volatile std::int32_t*)(&m_counts(i))) == 0) push_work(i); + } + void fill_queue() { + using policy_type = RangePolicy; + using closure_type = Kokkos::Impl::ParallelFor; + const closure_type closure(*this, policy_type(0, m_total_work)); + closure.execute(); + execution_space::fence(); + } + +private: + + inline + void setup() { + if (m_graph.numRows() > std::numeric_limits::max()) { + Kokkos::abort("WorkGraphPolicy work must be indexable using int32_t"); + } + get_crs_transpose_counts(m_counts, m_graph); + m_queue = ints_type(ViewAllocateWithoutInitializing("queue"), m_total_work); + deep_copy(m_queue, std::int32_t(-1)); + m_ranges = ranges_type("ranges", 1); + fill_queue(); + } + + KOKKOS_INLINE_FUNCTION + std::int32_t pop_work() const { + range_type w(-1,-1); + while (true) { + const range_type w_new( w.first + 1 , w.second ); + w = atomic_compare_exchange( &m_ranges(0) , w , w_new ); + if ( w.first < w.second ) { // there was work in the queue + if ( w_new.first == w.first + 1 && w_new.second == w.second ) { + // we got a work item + std::int32_t i; + // the push_work function may have incremented the end counter + // but not yet written the work index into the queue. + // wait until the entry is valid. + while ( -1 == ( i = *((volatile std::int32_t*)(&m_queue( w.first ))) ) ); + return i; + } // we got a work item + } else { // there was no work in the queue +#ifdef KOKKOS_DEBUG + if ( w_new.first == w.first + 1 && w_new.second == w.second ) { + Kokkos::abort("bug in pop_work"); + } +#endif + if (w.first == m_total_work) { // all work is done + return -1; + } else { // need to wait for more work to be pushed + // take a guess that one work item will be pushed + // the key thing is we can't leave (w) alone, because + // otherwise the next compare_exchange may succeed in + // popping work from an empty queue + w.second++; + } + } // there was no work in the queue + } // while (true) + } + + KOKKOS_INLINE_FUNCTION + void push_work(std::int32_t i) const { + range_type w(-1,-1); + while (true) { + const range_type w_new( w.first , w.second + 1 ); + // try to increment the end counter + w = atomic_compare_exchange( &m_ranges(0) , w , w_new ); + // stop trying if the increment was successful + if ( w.first == w_new.first && w.second + 1 == w_new.second ) break; + } + // write the work index into the claimed spot in the queue + *((volatile std::int32_t*)(&m_queue( w.second ))) = i; + // push this write out into the memory system + memory_fence(); + } + + template< class functor_type , class execution_space, class ... policy_args > + friend class Kokkos::Impl::Experimental::WorkGraphExec; + +public: + + WorkGraphPolicy(graph_type arg_graph) + : m_graph(arg_graph) + , m_total_work( arg_graph.numRows() ) + { + setup(); + } + +}; + +}} // namespace Kokkos::Experimental + +/*--------------------------------------------------------------------------*/ + +/*--------------------------------------------------------------------------*/ + +namespace Kokkos { +namespace Impl { +namespace Experimental { + +template< class functor_type , class execution_space, class ... policy_args > +class WorkGraphExec +{ + public: + + using self_type = WorkGraphExec< functor_type, execution_space, policy_args ... >; + using policy_type = Kokkos::Experimental::WorkGraphPolicy< policy_args ... >; + using member_type = typename policy_type::member_type; + using memory_space = typename execution_space::memory_space; + + protected: + + const functor_type m_functor; + const policy_type m_policy; + + protected: + + KOKKOS_INLINE_FUNCTION + std::int32_t before_work() const { + return m_policy.pop_work(); + } + + KOKKOS_INLINE_FUNCTION + void after_work(std::int32_t i) const { + /* fence any writes that were done by the work item itself + (usually writing its result to global memory) */ + memory_fence(); + const std::int32_t begin = m_policy.m_graph.row_map( i ); + const std::int32_t end = m_policy.m_graph.row_map( i + 1 ); + for (std::int32_t j = begin; j < end; ++j) { + const std::int32_t next = m_policy.m_graph.entries( j ); + const std::int32_t old_count = atomic_fetch_add( &(m_policy.m_counts(next)), -1 ); + if ( old_count == 1 ) m_policy.push_work( next ); + } + } + + inline + WorkGraphExec( const functor_type & arg_functor + , const policy_type & arg_policy ) + : m_functor( arg_functor ) + , m_policy( arg_policy ) + { + } +}; + +}}} // namespace Kokkos::Impl::Experimental + +#ifdef KOKKOS_ENABLE_SERIAL +#include "impl/Kokkos_Serial_WorkGraphPolicy.hpp" +#endif + +#ifdef KOKKOS_ENABLE_OPENMP +#include "OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp" +#endif + +#ifdef KOKKOS_ENABLE_CUDA +#include "Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp" +#endif + +#ifdef KOKKOS_ENABLE_THREADS +#include "Threads/Kokkos_Threads_WorkGraphPolicy.hpp" +#endif + +#endif /* #define KOKKOS_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.cpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.cpp index 4e0ea93920..915fbe52c1 100644 --- a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.cpp +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.cpp @@ -45,75 +45,100 @@ #if defined( KOKKOS_ENABLE_OPENMP ) #include +#include + #include #include #include + #include + #include -#include #include #include namespace Kokkos { namespace Impl { -namespace { -KOKKOS_INLINE_FUNCTION -int kokkos_omp_in_parallel(); +int g_openmp_hardware_max_threads = 1; -int kokkos_omp_in_critical_region = ( Kokkos::HostSpace::register_in_parallel( kokkos_omp_in_parallel ) , 0 ); +__thread int t_openmp_hardware_id = 0; +__thread Impl::OpenMPExec * t_openmp_instance = nullptr; -KOKKOS_INLINE_FUNCTION -int kokkos_omp_in_parallel() +void OpenMPExec::validate_partition( const int nthreads + , int & num_partitions + , int & partition_size + ) { -#ifndef __CUDA_ARCH__ - return omp_in_parallel() && ! kokkos_omp_in_critical_region ; -#else - return 0; -#endif + if (nthreads == 1) { + num_partitions = 1; + partition_size = 1; + } + else if( num_partitions < 1 && partition_size < 1) { + int idle = nthreads; + for (int np = 2; np <= nthreads ; ++np) { + for (int ps = 1; ps <= nthreads/np; ++ps) { + if (nthreads - np*ps < idle) { + idle = nthreads - np*ps; + num_partitions = np; + partition_size = ps; + } + if (idle == 0) { + break; + } + } + } + } + else if( num_partitions < 1 && partition_size > 0 ) { + if ( partition_size <= nthreads ) { + num_partitions = nthreads / partition_size; + } + else { + num_partitions = 1; + partition_size = nthreads; + } + } + else if( num_partitions > 0 && partition_size < 1 ) { + if ( num_partitions <= nthreads ) { + partition_size = nthreads / num_partitions; + } + else { + num_partitions = nthreads; + partition_size = 1; + } + } + else if ( num_partitions * partition_size > nthreads ) { + int idle = nthreads; + const int NP = num_partitions; + const int PS = partition_size; + for (int np = NP; np > 0; --np) { + for (int ps = PS; ps > 0; --ps) { + if ( (np*ps <= nthreads) + && (nthreads - np*ps < idle) ) { + idle = nthreads - np*ps; + num_partitions = np; + partition_size = ps; + } + if (idle == 0) { + break; + } + } + } + } + } -bool s_using_hwloc = false; - -} // namespace -} // namespace Impl -} // namespace Kokkos - - -namespace Kokkos { -namespace Impl { - -int OpenMPExec::m_map_rank[ OpenMPExec::MAX_THREAD_COUNT ] = { 0 }; - -int OpenMPExec::m_pool_topo[ 4 ] = { 0 }; - -HostThreadTeamData * OpenMPExec::m_pool[ OpenMPExec::MAX_THREAD_COUNT ] = { 0 }; - -void OpenMPExec::verify_is_process( const char * const label ) +void OpenMPExec::verify_is_master( const char * const label ) { - if ( omp_in_parallel() ) { + if ( !t_openmp_instance ) + { std::string msg( label ); - msg.append( " ERROR: in parallel" ); + msg.append( " ERROR: in parallel or not initialized" ); Kokkos::Impl::throw_runtime_exception( msg ); } } -void OpenMPExec::verify_initialized( const char * const label ) -{ - if ( 0 == m_pool[0] ) { - std::string msg( label ); - msg.append( " ERROR: not initialized" ); - Kokkos::Impl::throw_runtime_exception( msg ); - } - - if ( omp_get_max_threads() != Kokkos::OpenMP::thread_pool_size(0) ) { - std::string msg( label ); - msg.append( " ERROR: Initialized but threads modified inappropriately" ); - Kokkos::Impl::throw_runtime_exception( msg ); - } - -} } // namespace Impl } // namespace Kokkos @@ -133,11 +158,11 @@ void OpenMPExec::clear_thread_data() const int old_alloc_bytes = m_pool[0] ? ( member_bytes + m_pool[0]->scratch_bytes() ) : 0 ; - Kokkos::HostSpace space ; + OpenMP::memory_space space ; -#pragma omp parallel + #pragma omp parallel num_threads( m_pool_size ) { - const int rank = m_map_rank[ omp_get_thread_num() ]; + const int rank = omp_get_thread_num(); if ( 0 != m_pool[rank] ) { @@ -189,13 +214,13 @@ void OpenMPExec::resize_thread_data( size_t pool_reduce_bytes , team_shared_bytes , thread_local_bytes ); - const int pool_size = omp_get_max_threads(); + OpenMP::memory_space space ; - Kokkos::HostSpace space ; + memory_fence(); -#pragma omp parallel + #pragma omp parallel num_threads(m_pool_size) { - const int rank = m_map_rank[ omp_get_thread_num() ]; + const int rank = omp_get_thread_num(); if ( 0 != m_pool[rank] ) { @@ -214,11 +239,14 @@ void OpenMPExec::resize_thread_data( size_t pool_reduce_bytes , pool_reduce_bytes , team_reduce_bytes , team_shared_bytes - , thread_local_bytes ); + , thread_local_bytes + ); + + memory_fence(); } /* END #pragma omp parallel */ - HostThreadTeamData::organize_pool( m_pool , pool_size ); + HostThreadTeamData::organize_pool( m_pool , m_pool_size ); } } @@ -232,16 +260,8 @@ namespace Kokkos { //---------------------------------------------------------------------------- -int OpenMP::is_initialized() -{ return 0 != Impl::OpenMPExec::m_pool[0]; } - -void OpenMP::initialize( unsigned thread_count , - unsigned use_numa_count , - unsigned use_cores_per_numa ) +int OpenMP::get_current_max_threads() noexcept { - // Before any other call to OMP query the maximum number of threads - // and save the value for re-initialization unit testing. - // Using omp_get_max_threads(); is problematic in conjunction with // Hwloc on Intel (essentially an initial call to the OpenMP runtime // without a parallel region before will set a process mask for a single core @@ -250,110 +270,99 @@ void OpenMP::initialize( unsigned thread_count , // 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(); - int nthreads = 0; + + int count = 0; #pragma omp parallel { #pragma omp atomic - nthreads++; + ++count; } + return count; +} - static int omp_max_threads = nthreads; - - const bool is_initialized = 0 != Impl::OpenMPExec::m_pool[0] ; - - bool thread_spawn_failed = false ; - - if ( ! is_initialized ) { - - // Use hwloc thread pinning if concerned with locality. - // If spreading threads across multiple NUMA regions. - // If hyperthreading is enabled. - Impl::s_using_hwloc = hwloc::available() && ( - ( 1 < Kokkos::hwloc::get_available_numa_count() ) || - ( 1 < Kokkos::hwloc::get_available_threads_per_core() ) ); - - std::pair threads_coord[ Impl::OpenMPExec::MAX_THREAD_COUNT ]; - - // If hwloc available then use it's maximum value. - - if ( thread_count == 0 ) { - thread_count = Impl::s_using_hwloc - ? Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa() * - Kokkos::hwloc::get_available_threads_per_core() - : omp_max_threads ; - } - - if(Impl::s_using_hwloc) - hwloc::thread_mapping( "Kokkos::OpenMP::initialize" , - false /* do not allow asynchronous */ , - thread_count , - use_numa_count , - use_cores_per_numa , - threads_coord ); - - // Spawn threads: - - omp_set_num_threads( thread_count ); - - // Verify OMP interaction: - if ( int(thread_count) != omp_get_max_threads() ) { - thread_spawn_failed = true ; - } - - // Verify spawning and bind threads: -#pragma omp parallel - { -#pragma omp critical - { - if ( int(thread_count) != omp_get_num_threads() ) { - thread_spawn_failed = true ; - } - - // Call to 'bind_this_thread' is not thread safe so place this whole block in a critical region. - // Call to 'new' may not be thread safe as well. - - const unsigned omp_rank = omp_get_thread_num(); - const unsigned thread_r = Impl::s_using_hwloc && Kokkos::hwloc::can_bind_threads() - ? Kokkos::hwloc::bind_this_thread( thread_count , threads_coord ) - : omp_rank ; - - Impl::OpenMPExec::m_map_rank[ omp_rank ] = thread_r ; - } -/* END #pragma omp critical */ - } -/* END #pragma omp parallel */ - - if ( ! thread_spawn_failed ) { - Impl::OpenMPExec::m_pool_topo[0] = thread_count ; - Impl::OpenMPExec::m_pool_topo[1] = Impl::s_using_hwloc ? thread_count / use_numa_count : thread_count; - Impl::OpenMPExec::m_pool_topo[2] = Impl::s_using_hwloc ? thread_count / ( use_numa_count * use_cores_per_numa ) : 1; - - // New, unified host thread team data: - { - size_t pool_reduce_bytes = 32 * thread_count ; - size_t team_reduce_bytes = 32 * thread_count ; - size_t team_shared_bytes = 1024 * thread_count ; - size_t thread_local_bytes = 1024 ; - - Impl::OpenMPExec::resize_thread_data( pool_reduce_bytes - , team_reduce_bytes - , team_shared_bytes - , thread_local_bytes - ); - } - } - } - - if ( is_initialized || thread_spawn_failed ) { - std::string msg("Kokkos::OpenMP::initialize ERROR"); - - if ( is_initialized ) { msg.append(" : already initialized"); } - if ( thread_spawn_failed ) { msg.append(" : failed spawning threads"); } +void OpenMP::initialize( int thread_count ) +{ + if ( omp_in_parallel() ) { + std::string msg("Kokkos::OpenMP::initialize ERROR : in parallel"); Kokkos::Impl::throw_runtime_exception(msg); } + if ( Impl::t_openmp_instance ) + { + finalize(); + } + + { + if (nullptr == std::getenv("OMP_PROC_BIND") ) { + printf("Kokkos::OpenMP::initialize WARNING: OMP_PROC_BIND environment variable not set\n"); + printf(" In general, for best performance with OpenMP 4.0 or better set OMP_PROC_BIND=spread and OMP_PLACES=threads\n"); + printf(" For best performance with OpenMP 3.1 set OMP_PROC_BIND=true\n"); + printf(" For unit testing set OMP_PROC_BIND=false\n"); + } + + OpenMP::memory_space space ; + + // Before any other call to OMP query the maximum number of threads + // and save the value for re-initialization unit testing. + + Impl::g_openmp_hardware_max_threads = get_current_max_threads(); + + int process_num_threads = Impl::g_openmp_hardware_max_threads; + + if ( Kokkos::hwloc::available() ) { + process_num_threads = Kokkos::hwloc::get_available_numa_count() + * Kokkos::hwloc::get_available_cores_per_numa() + * Kokkos::hwloc::get_available_threads_per_core(); + } + + // if thread_count < 0, use g_openmp_hardware_max_threads; + // if thread_count == 0, set g_openmp_hardware_max_threads to process_num_threads + // if thread_count > 0, set g_openmp_hardware_max_threads to thread_count + if (thread_count < 0 ) { + thread_count = Impl::g_openmp_hardware_max_threads; + } + else if( thread_count == 0 && Impl::g_openmp_hardware_max_threads != process_num_threads ) { + Impl::g_openmp_hardware_max_threads = process_num_threads; + omp_set_num_threads(Impl::g_openmp_hardware_max_threads); + } + else { + if( thread_count > process_num_threads ) { + printf( "Kokkos::OpenMP::initialize WARNING: You are likely oversubscribing your CPU cores.\n"); + printf( " process threads available : %3d, requested thread : %3d\n", process_num_threads, thread_count ); + } + Impl::g_openmp_hardware_max_threads = thread_count; + omp_set_num_threads(Impl::g_openmp_hardware_max_threads); + } + + // setup thread local + #pragma omp parallel num_threads(Impl::g_openmp_hardware_max_threads) + { + Impl::t_openmp_instance = nullptr; + Impl::t_openmp_hardware_id = omp_get_thread_num(); + Impl::SharedAllocationRecord< void, void >::tracking_enable(); + } + + void * const ptr = space.allocate( sizeof(Impl::OpenMPExec) ); + + Impl::t_openmp_instance = new (ptr) Impl::OpenMPExec( Impl::g_openmp_hardware_max_threads ); + + // New, unified host thread team data: + { + size_t pool_reduce_bytes = 32 * thread_count ; + size_t team_reduce_bytes = 32 * thread_count ; + size_t team_shared_bytes = 1024 * thread_count ; + size_t thread_local_bytes = 1024 ; + + Impl::t_openmp_instance->resize_thread_data( pool_reduce_bytes + , team_reduce_bytes + , team_shared_bytes + , thread_local_bytes + ); + } + } + + // Check for over-subscription //if( Impl::mpi_ranks_per_node() * long(thread_count) > Impl::processors_per_node() ) { // std::cout << "Kokkos::OpenMP::initialize WARNING: You are likely oversubscribing your CPU cores." << std::endl; @@ -373,20 +382,38 @@ void OpenMP::initialize( unsigned thread_count , void OpenMP::finalize() { - Impl::OpenMPExec::verify_initialized( "OpenMP::finalize" ); - Impl::OpenMPExec::verify_is_process( "OpenMP::finalize" ); + if ( omp_in_parallel() ) + { + std::string msg("Kokkos::OpenMP::finalize ERROR "); + if( !Impl::t_openmp_instance ) msg.append(": not initialized"); + if( omp_in_parallel() ) msg.append(": in parallel"); + Kokkos::Impl::throw_runtime_exception(msg); + } - // New, unified host thread team data: - Impl::OpenMPExec::clear_thread_data(); + if ( Impl::t_openmp_instance ) { - Impl::OpenMPExec::m_pool_topo[0] = 0 ; - Impl::OpenMPExec::m_pool_topo[1] = 0 ; - Impl::OpenMPExec::m_pool_topo[2] = 0 ; + const int nthreads = Impl::t_openmp_instance->m_pool_size <= Impl::g_openmp_hardware_max_threads + ? Impl::g_openmp_hardware_max_threads + : Impl::t_openmp_instance->m_pool_size; - omp_set_num_threads(1); + using Exec = Impl::OpenMPExec; + Exec * instance = Impl::t_openmp_instance; + instance->~Exec(); - if ( Impl::s_using_hwloc && Kokkos::hwloc::can_bind_threads() ) { - hwloc::unbind_this_thread(); + OpenMP::memory_space space; + space.deallocate( instance, sizeof(Exec) ); + + #pragma omp parallel num_threads(nthreads) + { + Impl::t_openmp_hardware_id = 0; + Impl::t_openmp_instance = nullptr; + Impl::SharedAllocationRecord< void, void >::tracking_disable(); + } + + // allow main thread to track + Impl::SharedAllocationRecord< void, void >::tracking_enable(); + + Impl::g_openmp_hardware_max_threads = 1; } #if defined(KOKKOS_ENABLE_PROFILING) @@ -396,70 +423,48 @@ void OpenMP::finalize() //---------------------------------------------------------------------------- -void OpenMP::print_configuration( std::ostream & s , const bool detail ) +void OpenMP::print_configuration( std::ostream & s , const bool verbose ) { - Impl::OpenMPExec::verify_is_process( "OpenMP::print_configuration" ); - s << "Kokkos::OpenMP" ; -#if defined( KOKKOS_ENABLE_OPENMP ) - s << " KOKKOS_ENABLE_OPENMP" ; -#endif -#if defined( KOKKOS_ENABLE_HWLOC ) - - const unsigned numa_count_ = Kokkos::hwloc::get_available_numa_count(); - const unsigned cores_per_numa = Kokkos::hwloc::get_available_cores_per_numa(); - const unsigned threads_per_core = Kokkos::hwloc::get_available_threads_per_core(); - - s << " hwloc[" << numa_count_ << "x" << cores_per_numa << "x" << threads_per_core << "]" - << " hwloc_binding_" << ( Impl::s_using_hwloc ? "enabled" : "disabled" ) - ; -#endif - - const bool is_initialized = 0 != Impl::OpenMPExec::m_pool[0] ; + const bool is_initialized = Impl::t_openmp_instance != nullptr; if ( is_initialized ) { - const int numa_count = Kokkos::Impl::OpenMPExec::m_pool_topo[0] / Kokkos::Impl::OpenMPExec::m_pool_topo[1] ; - const int core_per_numa = Kokkos::Impl::OpenMPExec::m_pool_topo[1] / Kokkos::Impl::OpenMPExec::m_pool_topo[2] ; - const int thread_per_core = Kokkos::Impl::OpenMPExec::m_pool_topo[2] ; + Impl::OpenMPExec::verify_is_master( "OpenMP::print_configuration" ); + + const int numa_count = 1; + const int core_per_numa = Impl::g_openmp_hardware_max_threads; + const int thread_per_core = 1; s << " thread_pool_topology[ " << numa_count << " x " << core_per_numa << " x " << thread_per_core << " ]" << std::endl ; - - if ( detail ) { - std::vector< std::pair > coord( Kokkos::Impl::OpenMPExec::m_pool_topo[0] ); - -#pragma omp parallel - { -#pragma omp critical - { - coord[ omp_get_thread_num() ] = hwloc::get_this_thread_coordinate(); - } -/* END #pragma omp critical */ - } -/* END #pragma omp parallel */ - - for ( unsigned i = 0 ; i < coord.size() ; ++i ) { - s << " thread omp_rank[" << i << "]" - << " kokkos_rank[" << Impl::OpenMPExec::m_map_rank[ i ] << "]" - << " hwloc_coord[" << coord[i].first << "." << coord[i].second << "]" - << std::endl ; - } - } } else { s << " not initialized" << std::endl ; } } +std::vector OpenMP::partition(...) +{ return std::vector(1); } + +OpenMP OpenMP::create_instance(...) { return OpenMP(); } + + +#if !defined( KOKKOS_DISABLE_DEPRECATED ) + int OpenMP::concurrency() { - return thread_pool_size(0); + return Impl::g_openmp_hardware_max_threads; } -const char* OpenMP::name() { return "OpenMP"; } +void OpenMP::initialize( int thread_count , int, int ) +{ + initialize(thread_count); +} + +#endif } // namespace Kokkos diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.hpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.hpp index 75b7f5da4a..37d2ac8318 100644 --- a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.hpp +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Exec.hpp @@ -47,6 +47,10 @@ #include #if defined( KOKKOS_ENABLE_OPENMP ) +#if !defined(_OPENMP) +#error "You enabled Kokkos OpenMP support without enabling OpenMP in the compiler!" +#endif + #include #include @@ -54,6 +58,8 @@ #include +#include + #include #include #include @@ -63,8 +69,14 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -namespace Kokkos { -namespace Impl { +namespace Kokkos { namespace Impl { + +class OpenMPExec; + +extern int g_openmp_hardware_max_threads; + +extern __thread int t_openmp_hardware_id; +extern __thread OpenMPExec * t_openmp_instance; //---------------------------------------------------------------------------- /** \brief Data for OpenMP thread execution */ @@ -74,279 +86,279 @@ public: friend class Kokkos::OpenMP ; - enum { MAX_THREAD_COUNT = 4096 }; + enum { MAX_THREAD_COUNT = 512 }; + + void clear_thread_data(); + + static void validate_partition( const int nthreads + , int & num_partitions + , int & partition_size + ); private: + OpenMPExec( int arg_pool_size ) + : m_pool_size{ arg_pool_size } + , m_level{ omp_get_level() } + , m_pool() + {} - static int m_pool_topo[ 4 ]; - static int m_map_rank[ MAX_THREAD_COUNT ]; + ~OpenMPExec() + { + clear_thread_data(); + } - static HostThreadTeamData * m_pool[ MAX_THREAD_COUNT ]; + int m_pool_size; + int m_level; - static - void clear_thread_data(); + HostThreadTeamData * m_pool[ MAX_THREAD_COUNT ]; public: - // Topology of a cache coherent thread pool: - // TOTAL = NUMA x GRAIN - // pool_size( depth = 0 ) - // pool_size(0) = total number of threads - // pool_size(1) = number of threads per NUMA - // pool_size(2) = number of threads sharing finest grain memory hierarchy + static void verify_is_master( const char * const ); - inline static - int pool_size( int depth = 0 ) { return m_pool_topo[ depth ]; } - - static void finalize(); - - static void initialize( const unsigned team_count , - const unsigned threads_per_team , - const unsigned numa_count , - const unsigned cores_per_numa ); - - static void verify_is_process( const char * const ); - static void verify_initialized( const char * const ); - - - static void resize_thread_data( size_t pool_reduce_bytes , size_t team_reduce_bytes , size_t team_shared_bytes , size_t thread_local_bytes ); - inline static - HostThreadTeamData * get_thread_data() noexcept - { return m_pool[ m_map_rank[ omp_get_thread_num() ] ]; } + inline + HostThreadTeamData * get_thread_data() const noexcept + { return m_pool[ m_level == omp_get_level() ? 0 : omp_get_thread_num() ]; } - inline static - HostThreadTeamData * get_thread_data( int i ) noexcept - { return m_pool[i]; } + inline + HostThreadTeamData * get_thread_data( int i ) const noexcept + { return m_pool[i]; } }; -} // namespace Impl -} // namespace Kokkos - -//---------------------------------------------------------------------------- -//---------------------------------------------------------------------------- - -namespace Kokkos { -namespace Impl { - -template< class ... Properties > -class TeamPolicyInternal< Kokkos::OpenMP, Properties ... >: public PolicyTraits -{ -public: - - //! Tag this class as a kokkos execution policy - typedef TeamPolicyInternal execution_policy ; - - typedef PolicyTraits traits; - - TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_team_alloc = p.m_team_alloc; - m_team_iter = p.m_team_iter; - 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_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; - return *this; - } - - //---------------------------------------- - - template< class FunctorType > - inline static - int team_size_max( const FunctorType & ) { - int pool_size = traits::execution_space::thread_pool_size(1); - int max_host_team_size = Impl::HostThreadTeamData::max_team_members; - return pool_size - inline static - int team_size_recommended( const FunctorType & ) - { return traits::execution_space::thread_pool_size(2); } - - template< class FunctorType > - inline static - int team_size_recommended( const FunctorType &, const int& ) - { return traits::execution_space::thread_pool_size(2); } - - //---------------------------------------- - -private: - - int m_league_size ; - int m_team_size ; - int m_team_alloc ; - int m_team_iter ; - - size_t m_team_scratch_size[2]; - size_t m_thread_scratch_size[2]; - - int m_chunk_size; - - inline void init( const int league_size_request - , const int team_size_request ) - { - const int pool_size = traits::execution_space::thread_pool_size(0); - const int max_host_team_size = Impl::HostThreadTeamData::max_team_members; - const int team_max = pool_size 0) { - if(!Impl::is_integral_power_of_two( m_chunk_size )) - Kokkos::abort("TeamPolicy blocking granularity must be power of two" ); - } - - int new_chunk_size = 1; - while(new_chunk_size*100*concurrency < m_league_size) - new_chunk_size *= 2; - if(new_chunk_size < 128) { - new_chunk_size = 1; - while( (new_chunk_size*40*concurrency < m_league_size ) && (new_chunk_size<128) ) - new_chunk_size*=2; - } - m_chunk_size = new_chunk_size; - } - -public: - typedef Impl::HostThreadTeamMember< Kokkos::OpenMP > member_type ; -}; -} // namespace Impl - -} // namespace Kokkos +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -inline -bool OpenMP::in_parallel() -{ return omp_in_parallel(); } +inline OpenMP::OpenMP() noexcept +{} inline -int OpenMP::thread_pool_size( int depth ) +bool OpenMP::is_initialized() noexcept +{ return Impl::t_openmp_instance != nullptr; } + +inline +bool OpenMP::in_parallel( OpenMP const& ) noexcept { - return Impl::OpenMPExec::pool_size(depth); + //t_openmp_instance is only non-null on a master thread + return !Impl::t_openmp_instance + || Impl::t_openmp_instance->m_level < omp_get_level() + ; +} + +inline +int OpenMP::thread_pool_size() noexcept +{ + return OpenMP::in_parallel() + ? omp_get_num_threads() + : Impl::t_openmp_instance->m_pool_size + ; } KOKKOS_INLINE_FUNCTION -int OpenMP::thread_pool_rank() +int OpenMP::thread_pool_rank() noexcept { #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - return Impl::OpenMPExec::m_map_rank[ omp_get_thread_num() ]; + return Impl::t_openmp_instance ? 0 : omp_get_thread_num(); #else return -1 ; #endif } +inline +void OpenMP::fence( OpenMP const& instance ) noexcept {} + +inline +bool OpenMP::is_asynchronous( OpenMP const& instance ) noexcept +{ return false; } + +template +void OpenMP::partition_master( F const& f + , int num_partitions + , int partition_size + ) +{ + if (omp_get_nested()) { + using Exec = Impl::OpenMPExec; + + Exec * prev_instance = Impl::t_openmp_instance; + + Exec::validate_partition( prev_instance->m_pool_size, num_partitions, partition_size ); + + OpenMP::memory_space space; + + #pragma omp parallel num_threads(num_partitions) + { + void * const ptr = space.allocate( sizeof(Exec) ); + + Impl::t_openmp_instance = new (ptr) Exec( partition_size ); + + size_t pool_reduce_bytes = 32 * partition_size ; + size_t team_reduce_bytes = 32 * partition_size ; + size_t team_shared_bytes = 1024 * partition_size ; + size_t thread_local_bytes = 1024 ; + + Impl::t_openmp_instance->resize_thread_data( pool_reduce_bytes + , team_reduce_bytes + , team_shared_bytes + , thread_local_bytes + ); + + f( omp_get_thread_num(), omp_get_num_threads() ); + + Impl::t_openmp_instance->~Exec(); + space.deallocate( Impl::t_openmp_instance, sizeof(Exec) ); + Impl::t_openmp_instance = nullptr; + } + + Impl::t_openmp_instance = prev_instance; + } + else { + // nested openmp not enabled + f(0,1); + } +} + + +namespace Experimental { + +template<> +class MasterLock +{ +public: + void lock() { omp_set_lock( &m_lock ); } + void unlock() { omp_unset_lock( &m_lock ); } + bool try_lock() { return static_cast(omp_test_lock( &m_lock )); } + + MasterLock() { omp_init_lock( &m_lock ); } + ~MasterLock() { omp_destroy_lock( &m_lock ); } + + MasterLock( MasterLock const& ) = delete; + MasterLock( MasterLock && ) = delete; + MasterLock & operator=( MasterLock const& ) = delete; + MasterLock & operator=( MasterLock && ) = delete; + +private: + omp_lock_t m_lock; + +}; + +template<> +class UniqueToken< OpenMP, UniqueTokenScope::Instance> +{ +public: + using execution_space = OpenMP; + 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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + KOKKOS_INLINE_FUNCTION + int size() const noexcept + { + #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + return Kokkos::OpenMP::thread_pool_size(); + #else + return 0 ; + #endif + } + + /// \brief acquire value such that 0 <= value < size() + KOKKOS_INLINE_FUNCTION + int acquire() const noexcept + { + #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + return Kokkos::OpenMP::thread_pool_rank(); + #else + return 0 ; + #endif + } + + /// \brief release a value acquired by generate + KOKKOS_INLINE_FUNCTION + void release( int ) const noexcept {} +}; + +template<> +class UniqueToken< OpenMP, UniqueTokenScope::Global> +{ +public: + using execution_space = OpenMP; + 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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + KOKKOS_INLINE_FUNCTION + int size() const noexcept + { + #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + return Kokkos::Impl::g_openmp_hardware_max_threads ; + #else + return 0 ; + #endif + } + + /// \brief acquire value such that 0 <= value < size() + KOKKOS_INLINE_FUNCTION + int acquire() const noexcept + { + #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + return Kokkos::Impl::t_openmp_hardware_id ; + #else + return 0 ; + #endif + } + + /// \brief release a value acquired by generate + KOKKOS_INLINE_FUNCTION + void release( int ) const noexcept {} +}; + +} // namespace Experimental + + +#if !defined( KOKKOS_DISABLE_DEPRECATED ) + +inline +int OpenMP::thread_pool_size( int depth ) +{ + return depth < 2 + ? thread_pool_size() + : 1; +} + +KOKKOS_INLINE_FUNCTION +int OpenMP::hardware_thread_id() noexcept +{ +#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + return Impl::t_openmp_hardware_id; +#else + return -1 ; +#endif +} + +inline +int OpenMP::max_hardware_threads() noexcept +{ + return Impl::g_openmp_hardware_max_threads; +} + +#endif // KOKKOS_DISABLE_DEPRECATED + } // namespace Kokkos #endif diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Parallel.hpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Parallel.hpp index c47e0fc654..b54abb0068 100644 --- a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Parallel.hpp +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Parallel.hpp @@ -52,6 +52,8 @@ #include #include +#include + //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -71,8 +73,9 @@ private: typedef typename Policy::WorkRange WorkRange ; typedef typename Policy::member_type Member ; - const FunctorType m_functor ; - const Policy m_policy ; + OpenMPExec * m_instance ; + const FunctorType m_functor ; + const Policy m_policy ; template< class TagType > inline static @@ -110,16 +113,120 @@ private: public: inline void execute() const + { + enum { is_dynamic = std::is_same< typename Policy::schedule_type::type + , Kokkos::Dynamic >::value + }; + + if ( OpenMP::in_parallel() ) { + exec_range< WorkTag >( m_functor + , m_policy.begin() + , m_policy.end() ); + } + else { + + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_for"); + + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) + { + HostThreadTeamData & data = *(m_instance->get_thread_data()); + + data.set_work_partition( m_policy.end() - m_policy.begin() + , m_policy.chunk_size() ); + + if ( is_dynamic ) { + // Make sure work partition is set before stealing + if ( data.pool_rendezvous() ) data.pool_rendezvous_release(); + } + + std::pair range(0,0); + + do { + + range = is_dynamic ? data.get_work_stealing_chunk() + : data.get_work_partition(); + + ParallelFor::template + exec_range< WorkTag >( m_functor + , range.first + m_policy.begin() + , range.second + m_policy.begin() ); + + } while ( is_dynamic && 0 <= range.first ); + } + } + } + + inline + ParallelFor( const FunctorType & arg_functor + , Policy arg_policy ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) + , m_policy( arg_policy ) + {} +}; + + +// MDRangePolicy impl +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType + , Kokkos::Experimental::MDRangePolicy< Traits ... > + , Kokkos::OpenMP + > +{ +private: + + typedef Kokkos::Experimental::MDRangePolicy< Traits ... > MDRangePolicy ; + typedef typename MDRangePolicy::impl_range_policy Policy ; + typedef typename MDRangePolicy::work_tag WorkTag ; + + typedef typename Policy::WorkRange WorkRange ; + typedef typename Policy::member_type Member ; + + typedef typename Kokkos::Experimental::Impl::HostIterateTile< MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void > iterate_type; + + OpenMPExec * m_instance ; + const FunctorType m_functor ; + const MDRangePolicy m_mdr_policy ; + const Policy m_policy ; // construct as RangePolicy( 0, num_tiles ).set_chunk_size(1) in ctor + + inline static + void + exec_range( const MDRangePolicy & mdr_policy + , const FunctorType & functor + , const Member ibeg , const Member iend ) { + #ifdef KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION + #ifdef KOKKOS_ENABLE_PRAGMA_IVDEP + #pragma ivdep + #endif + #endif + for ( Member iwork = ibeg ; iwork < iend ; ++iwork ) { + iterate_type( mdr_policy, functor )( iwork ); + } + } + +public: + + inline void execute() const + { enum { is_dynamic = std::is_same< typename Policy::schedule_type::type , Kokkos::Dynamic >::value }; - OpenMPExec::verify_is_process("Kokkos::OpenMP parallel_for"); - OpenMPExec::verify_initialized("Kokkos::OpenMP parallel_for"); + if ( OpenMP::in_parallel() ) { + ParallelFor::exec_range ( m_mdr_policy + , m_functor + , m_policy.begin() + , m_policy.end() ); + } + else { -#pragma omp parallel + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_for"); + + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) { - HostThreadTeamData & data = *OpenMPExec::get_thread_data(); + HostThreadTeamData & data = *(m_instance->get_thread_data()); data.set_work_partition( m_policy.end() - m_policy.begin() , m_policy.chunk_size() ); @@ -136,8 +243,8 @@ public: range = is_dynamic ? data.get_work_stealing_chunk() : data.get_work_partition(); - ParallelFor::template - exec_range< WorkTag >( m_functor + ParallelFor::exec_range( m_mdr_policy + , m_functor , range.first + m_policy.begin() , range.second + m_policy.begin() ); @@ -145,12 +252,15 @@ public: } // END #pragma omp parallel } + } inline ParallelFor( const FunctorType & arg_functor - , Policy arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) + , MDRangePolicy arg_policy ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) + , m_mdr_policy( arg_policy ) + , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) {} }; @@ -191,10 +301,11 @@ private: 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 ; + OpenMPExec * m_instance; + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; template< class TagType > inline static @@ -228,21 +339,21 @@ public: enum { is_dynamic = std::is_same< typename Policy::schedule_type::type , Kokkos::Dynamic >::value }; - OpenMPExec::verify_is_process("Kokkos::OpenMP parallel_reduce"); - OpenMPExec::verify_initialized("Kokkos::OpenMP parallel_reduce"); + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_reduce"); const size_t pool_reduce_bytes = Analysis::value_size( ReducerConditional::select(m_functor, m_reducer)); - OpenMPExec::resize_thread_data( pool_reduce_bytes + m_instance->resize_thread_data( pool_reduce_bytes , 0 // team_reduce_bytes , 0 // team_shared_bytes , 0 // thread_local_bytes ); -#pragma omp parallel + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) { - HostThreadTeamData & data = *OpenMPExec::get_thread_data(); + HostThreadTeamData & data = *(m_instance->get_thread_data()); data.set_work_partition( m_policy.end() - m_policy.begin() , m_policy.chunk_size() ); @@ -271,16 +382,15 @@ public: } while ( is_dynamic && 0 <= range.first ); } -// END #pragma omp parallel // Reduction: - const pointer_type ptr = pointer_type( OpenMPExec::get_thread_data(0)->pool_reduce_local() ); + const pointer_type ptr = pointer_type( m_instance->get_thread_data(0)->pool_reduce_local() ); - for ( int i = 1 ; i < OpenMPExec::pool_size() ; ++i ) { + for ( int i = 1 ; i < pool_size ; ++i ) { ValueJoin::join( ReducerConditional::select(m_functor , m_reducer) , ptr - , OpenMPExec::get_thread_data(i)->pool_reduce_local() ); + , m_instance->get_thread_data(i)->pool_reduce_local() ); } Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTag >::final( ReducerConditional::select(m_functor , m_reducer) , ptr ); @@ -303,7 +413,8 @@ public: Kokkos::is_view< ViewType >::value && !Kokkos::is_reducer_type::value ,void*>::type = NULL) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) , m_reducer( InvalidType() ) , m_result_ptr( arg_view.data() ) @@ -317,7 +428,8 @@ public: ParallelReduce( const FunctorType & arg_functor , Policy arg_policy , const ReducerType& reducer ) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) , m_reducer( reducer ) , m_result_ptr( reducer.view().data() ) @@ -329,6 +441,173 @@ public: }; + +// MDRangePolicy impl +template< class FunctorType , class ReducerType, class ... Traits > +class ParallelReduce< FunctorType + , Kokkos::Experimental::MDRangePolicy< Traits ...> + , ReducerType + , Kokkos::OpenMP + > +{ +private: + + typedef Kokkos::Experimental::MDRangePolicy< Traits ... > MDRangePolicy ; + typedef typename MDRangePolicy::impl_range_policy Policy ; + + typedef typename MDRangePolicy::work_tag WorkTag ; + typedef typename Policy::WorkRange WorkRange ; + typedef typename Policy::member_type Member ; + + typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + + typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + + typedef typename ReducerTypeFwd::value_type ValueType; + + typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTag > ValueInit ; + typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTag > ValueJoin ; + + typedef typename Analysis::pointer_type pointer_type ; + typedef typename Analysis::reference_type reference_type ; + + using iterate_type = typename Kokkos::Experimental::Impl::HostIterateTile< MDRangePolicy + , FunctorType + , WorkTag + , ValueType + >; + + OpenMPExec * m_instance ; + const FunctorType m_functor ; + const MDRangePolicy m_mdr_policy ; + const Policy m_policy ; // construct as RangePolicy( 0, num_tiles ).set_chunk_size(1) in ctor + const ReducerType m_reducer ; + const pointer_type m_result_ptr ; + + inline static + void + exec_range( const MDRangePolicy & mdr_policy + , const FunctorType & functor + , const Member ibeg , const Member iend + , reference_type update ) + { + for ( Member iwork = ibeg ; iwork < iend ; ++iwork ) { + iterate_type( mdr_policy, functor, update )( iwork ); + } + } + +public: + + inline void execute() const + { + enum { is_dynamic = std::is_same< typename Policy::schedule_type::type + , Kokkos::Dynamic >::value }; + + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_reduce"); + + const size_t pool_reduce_bytes = + Analysis::value_size( ReducerConditional::select(m_functor, m_reducer)); + + m_instance->resize_thread_data( pool_reduce_bytes + , 0 // team_reduce_bytes + , 0 // team_shared_bytes + , 0 // thread_local_bytes + ); + + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) + { + HostThreadTeamData & data = *(m_instance->get_thread_data()); + + data.set_work_partition( m_policy.end() - m_policy.begin() + , m_policy.chunk_size() ); + + if ( is_dynamic ) { + // Make sure work partition is set before stealing + if ( data.pool_rendezvous() ) data.pool_rendezvous_release(); + } + + reference_type update = + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) + , data.pool_reduce_local() ); + + std::pair range(0,0); + + do { + + range = is_dynamic ? data.get_work_stealing_chunk() + : data.get_work_partition(); + + ParallelReduce::exec_range ( m_mdr_policy, m_functor + , range.first + m_policy.begin() + , range.second + m_policy.begin() + , update ); + + } while ( is_dynamic && 0 <= range.first ); + } +// END #pragma omp parallel + + // Reduction: + + const pointer_type ptr = pointer_type( m_instance->get_thread_data(0)->pool_reduce_local() ); + + for ( int i = 1 ; i < pool_size ; ++i ) { + ValueJoin::join( ReducerConditional::select(m_functor , m_reducer) + , ptr + , m_instance->get_thread_data(i)->pool_reduce_local() ); + } + + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTag >::final( ReducerConditional::select(m_functor , m_reducer) , ptr ); + + if ( m_result_ptr ) { + const int n = Analysis::value_count( ReducerConditional::select(m_functor , m_reducer) ); + + for ( int j = 0 ; j < n ; ++j ) { m_result_ptr[j] = ptr[j] ; } + } + } + + //---------------------------------------- + + template< class ViewType > + inline + ParallelReduce( const FunctorType & arg_functor + , MDRangePolicy arg_policy + , const ViewType & arg_view + , typename std::enable_if< + Kokkos::is_view< ViewType >::value && + !Kokkos::is_reducer_type::value + ,void*>::type = NULL) + : m_instance( t_openmp_instance ) + , 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() ) + { + /*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_instance( t_openmp_instance ) + , 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 @@ -361,8 +640,9 @@ private: typedef typename Analysis::pointer_type pointer_type ; typedef typename Analysis::reference_type reference_type ; - const FunctorType m_functor ; - const Policy m_policy ; + OpenMPExec * m_instance; + const FunctorType m_functor; + const Policy m_policy; template< class TagType > inline static @@ -394,23 +674,23 @@ public: inline void execute() const { - OpenMPExec::verify_is_process("Kokkos::OpenMP parallel_scan"); - OpenMPExec::verify_initialized("Kokkos::OpenMP parallel_scan"); + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_scan"); const int value_count = Analysis::value_count( m_functor ); const size_t pool_reduce_bytes = 2 * Analysis::value_size( m_functor ); - OpenMPExec::resize_thread_data( pool_reduce_bytes + m_instance->resize_thread_data( pool_reduce_bytes , 0 // team_reduce_bytes , 0 // team_shared_bytes , 0 // thread_local_bytes ); -#pragma omp parallel + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) { - HostThreadTeamData & data = *OpenMPExec::get_thread_data(); + HostThreadTeamData & data = *(m_instance->get_thread_data()); - const WorkRange range( m_policy, data.pool_rank(), data.pool_size() ); + const WorkRange range( m_policy, omp_get_thread_num(), omp_get_num_threads() ); reference_type update_sum = ValueInit::init( m_functor , data.pool_reduce_local() ); @@ -422,7 +702,7 @@ public: pointer_type ptr_prev = 0 ; - const int n = data.pool_size(); + const int n = omp_get_num_threads(); for ( int i = 0 ; i < n ; ++i ) { @@ -452,7 +732,6 @@ public: ParallelScan::template exec_range< WorkTag > ( m_functor , range.begin() , range.end() , update_base , true ); } -/* END #pragma omp parallel */ } @@ -461,7 +740,8 @@ public: inline ParallelScan( const FunctorType & arg_functor , const Policy & arg_policy ) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) {} @@ -492,9 +772,10 @@ private: typedef typename Policy::schedule_type::type SchedTag ; typedef typename Policy::member_type Member ; - const FunctorType m_functor ; - const Policy m_policy ; - const int m_shmem_size ; + OpenMPExec * m_instance; + const FunctorType m_functor; + const Policy m_policy; + const int m_shmem_size; template< class TagType > inline static @@ -548,22 +829,22 @@ public: { enum { is_dynamic = std::is_same< SchedTag , Kokkos::Dynamic >::value }; - OpenMPExec::verify_is_process("Kokkos::OpenMP parallel_for"); - OpenMPExec::verify_initialized("Kokkos::OpenMP parallel_for"); + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_for"); const size_t pool_reduce_size = 0 ; // Never shrinks const size_t team_reduce_size = TEAM_REDUCE_SIZE * m_policy.team_size(); const size_t team_shared_size = m_shmem_size + m_policy.scratch_size(1); const size_t thread_local_size = 0 ; // Never shrinks - OpenMPExec::resize_thread_data( pool_reduce_size + m_instance->resize_thread_data( pool_reduce_size , team_reduce_size , team_shared_size , thread_local_size ); -#pragma omp parallel + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) { - HostThreadTeamData & data = *OpenMPExec::get_thread_data(); + HostThreadTeamData & data = *(m_instance->get_thread_data()); const int active = data.organize_team( m_policy.team_size() ); @@ -598,14 +879,14 @@ public: data.disband_team(); } -// END #pragma omp parallel } inline ParallelFor( const FunctorType & arg_functor , const Policy & arg_policy ) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) , m_shmem_size( arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + @@ -646,11 +927,12 @@ private: 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 int m_shmem_size ; + OpenMPExec * m_instance; + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const int m_shmem_size; template< class TagType > inline static @@ -706,8 +988,7 @@ public: { enum { is_dynamic = std::is_same< SchedTag , Kokkos::Dynamic >::value }; - OpenMPExec::verify_is_process("Kokkos::OpenMP parallel_reduce"); - OpenMPExec::verify_initialized("Kokkos::OpenMP parallel_reduce"); + OpenMPExec::verify_is_master("Kokkos::OpenMP parallel_reduce"); const size_t pool_reduce_size = Analysis::value_size( ReducerConditional::select(m_functor, m_reducer)); @@ -716,14 +997,15 @@ public: const size_t team_shared_size = m_shmem_size + m_policy.scratch_size(1); const size_t thread_local_size = 0 ; // Never shrinks - OpenMPExec::resize_thread_data( pool_reduce_size + m_instance->resize_thread_data( pool_reduce_size , team_reduce_size , team_shared_size , thread_local_size ); -#pragma omp parallel + const int pool_size = OpenMP::thread_pool_size(); + #pragma omp parallel num_threads(pool_size) { - HostThreadTeamData & data = *OpenMPExec::get_thread_data(); + HostThreadTeamData & data = *(m_instance->get_thread_data()); const int active = data.organize_team( m_policy.team_size() ); @@ -763,17 +1045,26 @@ public: } data.disband_team(); + + // This thread has updated 'pool_reduce_local()' with its + // contributions to the reduction. The parallel region is + // about to terminate and the master thread will load and + // reduce each 'pool_reduce_local()' contribution. + // Must 'memory_fence()' to guarantee that storing the update to + // 'pool_reduce_local()' will complete before this thread + // exits the parallel region. + + memory_fence(); } -// END #pragma omp parallel // Reduction: - const pointer_type ptr = pointer_type( OpenMPExec::get_thread_data(0)->pool_reduce_local() ); + const pointer_type ptr = pointer_type( m_instance->get_thread_data(0)->pool_reduce_local() ); - for ( int i = 1 ; i < OpenMPExec::pool_size() ; ++i ) { + for ( int i = 1 ; i < pool_size ; ++i ) { ValueJoin::join( ReducerConditional::select(m_functor , m_reducer) , ptr - , OpenMPExec::get_thread_data(i)->pool_reduce_local() ); + , m_instance->get_thread_data(i)->pool_reduce_local() ); } Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTag >::final( ReducerConditional::select(m_functor , m_reducer) , ptr ); @@ -796,7 +1087,8 @@ public: Kokkos::is_view< ViewType >::value && !Kokkos::is_reducer_type::value ,void*>::type = NULL) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) , m_reducer( InvalidType() ) , m_result_ptr( arg_result.ptr_on_device() ) @@ -810,7 +1102,8 @@ public: ParallelReduce( const FunctorType & arg_functor , Policy arg_policy , const ReducerType& reducer ) - : m_functor( arg_functor ) + : m_instance( t_openmp_instance ) + , m_functor( arg_functor ) , m_policy( arg_policy ) , m_reducer( reducer ) , m_result_ptr( reducer.view().data() ) diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.cpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.cpp index d4ade211f8..77363876b0 100644 --- a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.cpp +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.cpp @@ -105,7 +105,7 @@ void TaskQueueSpecialization< Kokkos::OpenMP >::execute { using execution_space = Kokkos::OpenMP ; using queue_type = TaskQueue< execution_space > ; - using task_root_type = TaskBase< execution_space , void , void > ; + using task_root_type = TaskBase< void , void , void > ; using Member = Impl::HostThreadTeamMember< execution_space > ; static task_root_type * const end = @@ -115,23 +115,19 @@ void TaskQueueSpecialization< Kokkos::OpenMP >::execute HostThreadTeamData & team_data_single = HostThreadTeamDataSingleton::singleton(); - const int team_size = Impl::OpenMPExec::pool_size(2); // Threads per core - // const int team_size = Impl::OpenMPExec::pool_size(1); // Threads per NUMA + Impl::OpenMPExec * instance = t_openmp_instance; + const int pool_size = OpenMP::thread_pool_size(); -#if 0 -fprintf(stdout,"TaskQueue execute %d\n", team_size ); -fflush(stdout); -#endif + const int team_size = 1; // Threads per core + instance->resize_thread_data( 0 /* global reduce buffer */ + , 512 * team_size /* team reduce buffer */ + , 0 /* team shared buffer */ + , 0 /* thread local buffer */ + ); - OpenMPExec::resize_thread_data( 0 /* global reduce buffer */ - , 512 * team_size /* team reduce buffer */ - , 0 /* team shared buffer */ - , 0 /* thread local buffer */ - ); - -#pragma omp parallel + #pragma omp parallel num_threads(pool_size) { - Impl::HostThreadTeamData & self = *Impl::OpenMPExec::get_thread_data(); + Impl::HostThreadTeamData & self = *(instance->get_thread_data()); // Organizing threads into a team performs a barrier across the // entire pool to insure proper initialization of the team @@ -142,18 +138,6 @@ fflush(stdout); Member single_exec( team_data_single ); Member team_exec( self ); -#if 0 -fprintf(stdout,"TaskQueue pool(%d of %d) team(%d of %d) league(%d of %d) running\n" - , self.pool_rank() - , self.pool_size() - , team_exec.team_rank() - , team_exec.team_size() - , team_exec.league_rank() - , team_exec.league_size() - ); -fflush(stdout); -#endif - // Loop until all queues are empty and no tasks in flight task_root_type * task = 0 ; @@ -197,15 +181,6 @@ fflush(stdout); // if a single thread task then execute now -#if 0 -fprintf(stdout,"TaskQueue pool(%d of %d) executing single task 0x%lx\n" - , self.pool_rank() - , self.pool_size() - , int64_t(task) - ); -fflush(stdout); -#endif - (*task->m_apply)( task , & single_exec ); leader_loop = true ; @@ -220,57 +195,14 @@ fflush(stdout); if ( 0 != task ) { // Thread Team Task -#if 0 -fprintf(stdout,"TaskQueue pool(%d of %d) team((%d of %d) league(%d of %d) executing team task 0x%lx\n" - , self.pool_rank() - , self.pool_size() - , team_exec.team_rank() - , team_exec.team_size() - , team_exec.league_rank() - , team_exec.league_size() - , int64_t(task) - ); -fflush(stdout); -#endif - (*task->m_apply)( task , & team_exec ); // The m_apply function performs a barrier } } while( 0 != task ); - -#if 0 -fprintf(stdout,"TaskQueue pool(%d of %d) team(%d of %d) league(%d of %d) ending\n" - , self.pool_rank() - , self.pool_size() - , team_exec.team_rank() - , team_exec.team_size() - , team_exec.league_rank() - , team_exec.league_size() - ); -fflush(stdout); -#endif - } - self.disband_team(); - -#if 0 -fprintf(stdout,"TaskQueue pool(%d of %d) disbanded\n" - , self.pool_rank() - , self.pool_size() - ); -fflush(stdout); -#endif - } -// END #pragma omp parallel - -#if 0 -fprintf(stdout,"TaskQueue execute %d end\n", team_size ); -fflush(stdout); -#endif - } void TaskQueueSpecialization< Kokkos::OpenMP >:: @@ -279,10 +211,10 @@ void TaskQueueSpecialization< Kokkos::OpenMP >:: { using execution_space = Kokkos::OpenMP ; using queue_type = TaskQueue< execution_space > ; - using task_root_type = TaskBase< execution_space , void , void > ; + using task_root_type = TaskBase< void , void , void > ; using Member = Impl::HostThreadTeamMember< execution_space > ; - if ( 1 == omp_get_num_threads() ) { + if ( 1 == OpenMP::thread_pool_size() ) { task_root_type * const end = (task_root_type *) task_root_type::EndTag ; diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.hpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.hpp index 82fbef255b..dfa1635e08 100644 --- a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.hpp +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Task.hpp @@ -45,7 +45,7 @@ #define KOKKOS_IMPL_OPENMP_TASK_HPP #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined( KOKKOS_ENABLE_OPENMP ) && defined( KOKKOS_ENABLE_TASKDAG ) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -60,7 +60,7 @@ public: using execution_space = Kokkos::OpenMP ; using queue_type = Kokkos::Impl::TaskQueue< execution_space > ; - using task_base_type = Kokkos::Impl::TaskBase< execution_space , void , void > ; + using task_base_type = Kokkos::Impl::TaskBase< void , void , void > ; using member_type = Kokkos::Impl::HostThreadTeamMember< execution_space > ; // Must specify memory space diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Team.hpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Team.hpp new file mode 100644 index 0000000000..743e6b6e62 --- /dev/null +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_Team.hpp @@ -0,0 +1,245 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_OPENMP_TEAM_HPP +#define KOKKOS_OPENMP_TEAM_HPP + +#include +#if defined( KOKKOS_ENABLE_OPENMP ) + +#include + +namespace Kokkos { namespace Impl { + +template< class ... Properties > +class TeamPolicyInternal< Kokkos::OpenMP, Properties ... >: public PolicyTraits +{ +public: + + //! Tag this class as a kokkos execution policy + typedef TeamPolicyInternal execution_policy ; + + typedef PolicyTraits traits; + + TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_team_alloc = p.m_team_alloc; + m_team_iter = p.m_team_iter; + 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_thread_scratch_size[1] = p.m_thread_scratch_size[1]; + m_chunk_size = p.m_chunk_size; + return *this; + } + + //---------------------------------------- + + template< class FunctorType > + inline static + int team_size_max( const FunctorType & ) { + int pool_size = traits::execution_space::thread_pool_size(1); + int max_host_team_size = Impl::HostThreadTeamData::max_team_members; + return pool_size + inline static + int team_size_recommended( const FunctorType & ) + { return traits::execution_space::thread_pool_size(2); } + + template< class FunctorType > + inline static + int team_size_recommended( const FunctorType &, const int& ) + { return traits::execution_space::thread_pool_size(2); } + + //---------------------------------------- + +private: + + int m_league_size ; + int m_team_size ; + int m_team_alloc ; + int m_team_iter ; + + size_t m_team_scratch_size[2]; + size_t m_thread_scratch_size[2]; + + int m_chunk_size; + + inline void init( const int league_size_request + , const int team_size_request ) + { + const int pool_size = traits::execution_space::thread_pool_size(0); + const int max_host_team_size = Impl::HostThreadTeamData::max_team_members; + const int team_max = pool_size 0) { + if(!Impl::is_integral_power_of_two( m_chunk_size )) + Kokkos::abort("TeamPolicy blocking granularity must be power of two" ); + } + + int new_chunk_size = 1; + while(new_chunk_size*100*concurrency < m_league_size) + new_chunk_size *= 2; + if(new_chunk_size < 128) { + new_chunk_size = 1; + while( (new_chunk_size*40*concurrency < m_league_size ) && (new_chunk_size<128) ) + new_chunk_size*=2; + } + m_chunk_size = new_chunk_size; + } + +public: + typedef Impl::HostThreadTeamMember< Kokkos::OpenMP > member_type ; +}; + +}} // namespace Kokkos::Impl + +#endif +#endif /* KOKKOS_OPENMP_TEAM_HPP */ + + diff --git a/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp new file mode 100644 index 0000000000..289ad15451 --- /dev/null +++ b/lib/kokkos/core/src/OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp @@ -0,0 +1,107 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_OPENMP_WORKGRAPHPOLICY_HPP +#define KOKKOS_OPENMP_WORKGRAPHPOLICY_HPP + +namespace Kokkos { +namespace Impl { + +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType , + Kokkos::Experimental::WorkGraphPolicy< Traits ... > , + Kokkos::OpenMP + > + : public Kokkos::Impl::Experimental:: + WorkGraphExec< FunctorType, + Kokkos::OpenMP, + Traits ... + > +{ +private: + + typedef Kokkos::Experimental::WorkGraphPolicy< Traits ... > Policy ; + typedef Kokkos::Impl::Experimental:: + WorkGraphExec Base ; + + template< class TagType > + typename std::enable_if< std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + Base::m_functor( i ); + } + + template< class TagType > + typename std::enable_if< ! std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + const TagType t{} ; + Base::m_functor( t , i ); + } + +public: + + inline + void execute() + { + const int pool_size = OpenMP::thread_pool_size(); + + #pragma omp parallel num_threads(pool_size) + { + for (std::int32_t i; (-1 != (i = Base::before_work())); ) { + exec_one< typename Policy::work_tag >( i ); + Base::after_work(i); + } + } + } + + inline + ParallelFor( const FunctorType & arg_functor + , const Policy & arg_policy ) + : Base( arg_functor, arg_policy ) + { + } +}; + +} // namespace Impl +} // namespace Kokkos + +#endif /* #define KOKKOS_OPENMP_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp b/lib/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp index bec7844ed6..258a9d2ff7 100644 --- a/lib/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp +++ b/lib/kokkos/core/src/OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp @@ -1,13 +1,13 @@ /* //@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: @@ -36,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -45,7 +45,7 @@ #define KOKKOS_OPENMPTARGETEXEC_HPP #include -#include +#include #include #include @@ -59,10 +59,10 @@ namespace Impl { class OpenMPTargetExec { -public: +public: enum { MAX_ACTIVE_THREADS = 256*8*56*4 }; enum { MAX_ACTIVE_TEAMS = MAX_ACTIVE_THREADS/32 }; - + private: static void* scratch_ptr; @@ -70,7 +70,7 @@ public: static void verify_is_process( const char * const ); static void verify_initialized( const char * const ); - static void* get_scratch_ptr(); + static void* get_scratch_ptr(); static void clear_scratch(); static void resize_scratch( int64_t reduce_bytes , int64_t team_reduce_bytes, int64_t team_shared_bytes, int64_t thread_local_bytes ); @@ -159,7 +159,7 @@ public: KOKKOS_INLINE_FUNCTION void team_barrier() const { - #pragma omp barrier + #pragma omp barrier } template @@ -191,13 +191,13 @@ public: typedef ValueType value_type; const JoinLambdaAdapter op(op_in); - + // Make sure there is enough scratch space: typedef typename if_c< sizeof(value_type) < TEAM_REDUCE_SIZE , value_type , void >::type type ; const int n_values = TEAM_REDUCE_SIZE/sizeof(value_type); - type * team_scratch = (type*) ((char*)m_glb_scratch + TEAM_REDUCE_SIZE*omp_get_team_num()); + type * team_scratch = (type*) ((char*)m_glb_scratch + TEAM_REDUCE_SIZE*omp_get_team_num()); for(int i = m_team_rank; i < n_values; i+= m_team_size) { team_scratch[i] = value_type(); } @@ -209,7 +209,7 @@ public: team_scratch[m_team_rank%n_values]+=value; #pragma omp barrier } - + for(int d = 1; d #if defined( KOKKOS_ENABLE_QTHREADS ) -#include +#include //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp index 4c805310cc..35b2163ae5 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp +++ b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.cpp @@ -45,14 +45,14 @@ #include #if defined( KOKKOS_ENABLE_THREADS ) -#include - #include #include #include #include #include + #include + #include #include #include @@ -80,9 +80,7 @@ const void * volatile s_current_function_arg = 0 ; struct Sentinel { Sentinel() - { - HostSpace::register_in_parallel( ThreadsExec::in_parallel ); - } + {} ~Sentinel() { @@ -122,6 +120,8 @@ void execute_function_noop( ThreadsExec & , const void * ) {} void ThreadsExec::driver(void) { + SharedAllocationRecord< void, void >::tracking_enable(); + ThreadsExec this_thread ; while ( ThreadsExec::Active == this_thread.m_pool_state ) { @@ -726,6 +726,8 @@ void ThreadsExec::initialize( unsigned thread_count , // Init the array for used for arbitrarily sized atomics Impl::init_lock_array_host_space(); + Impl::SharedAllocationRecord< void, void >::tracking_enable(); + #if defined(KOKKOS_ENABLE_PROFILING) Kokkos::Profiling::initialize(); #endif diff --git a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.hpp b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.hpp index 74de3a2596..7557bad7d9 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.hpp +++ b/lib/kokkos/core/src/Threads/Kokkos_ThreadsExec.hpp @@ -50,11 +50,12 @@ #include #include -#include +#include #include #include +#include //---------------------------------------------------------------------------- namespace Kokkos { @@ -275,6 +276,17 @@ public: if ( ! rev_rank ) { Final::final( f , reduce_memory() ); } + + // This thread has updated 'reduce_memory()' and upon returning + // from this function will set 'm_pool_state' to inactive. + // If this is a non-root thread then setting 'm_pool_state' + // to inactive triggers another thread to exit a spinwait + // and read the 'reduce_memory'. + // Must 'memory_fence()' to guarantee that storing the update to + // 'reduce_memory()' will complete before storing the the update to + // 'm_pool_state'. + + memory_fence(); } inline @@ -627,6 +639,62 @@ inline void Threads::fence() } /* namespace Kokkos */ +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +namespace Kokkos { namespace Experimental { + +template<> +class UniqueToken< Threads, UniqueTokenScope::Instance> +{ +public: + using execution_space = Threads; + 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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + inline + int size() const noexcept { return Threads::thread_pool_size(); } + + /// \brief acquire value such that 0 <= value < size() + inline + int acquire() const noexcept { return Threads::thread_pool_rank(); } + + /// \brief release a value acquired by generate + inline + void release( int ) const noexcept {} +}; + +template<> +class UniqueToken< Threads, UniqueTokenScope::Global> +{ +public: + using execution_space = Threads; + 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 {} + + /// \brief upper bound for acquired values, i.e. 0 <= value < size() + inline + int size() const noexcept { return Threads::thread_pool_size(); } + + /// \brief acquire value such that 0 <= value < size() + inline + int acquire() const noexcept { return Threads::thread_pool_rank(); } + + /// \brief release a value acquired by generate + inline + void release( int ) const noexcept {} +}; + +}} // namespace Kokkos::Experimental //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif diff --git a/lib/kokkos/core/src/Threads/Kokkos_ThreadsTeam.hpp b/lib/kokkos/core/src/Threads/Kokkos_ThreadsTeam.hpp index c12019413b..6060bf191f 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_ThreadsTeam.hpp +++ b/lib/kokkos/core/src/Threads/Kokkos_ThreadsTeam.hpp @@ -50,7 +50,7 @@ #include #include -#include +#include #include #include @@ -482,6 +482,8 @@ public: void next_static() { if ( m_league_rank < m_league_end ) { + // Make sure all stores are complete before entering the barrier + memory_fence(); team_barrier(); set_team_shared(); } @@ -518,6 +520,8 @@ public: return; if ( m_league_rank < m_league_chunk_end ) { + // Make sure all stores are complete before entering the barrier + memory_fence(); team_barrier(); set_team_shared(); } diff --git a/lib/kokkos/core/src/Threads/Kokkos_Threads_Parallel.hpp b/lib/kokkos/core/src/Threads/Kokkos_Threads_Parallel.hpp index 0ee0cd3280..18ac7d26ad 100644 --- a/lib/kokkos/core/src/Threads/Kokkos_Threads_Parallel.hpp +++ b/lib/kokkos/core/src/Threads/Kokkos_Threads_Parallel.hpp @@ -55,6 +55,8 @@ #include #include +#include + //---------------------------------------------------------------------------- namespace Kokkos { @@ -174,6 +176,108 @@ public: {} }; + +// MDRangePolicy impl +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType + , Kokkos::Experimental::MDRangePolicy< Traits ... > + , Kokkos::Threads + > +{ +private: + typedef Kokkos::Experimental::MDRangePolicy< Traits ... > MDRangePolicy ; + typedef typename MDRangePolicy::impl_range_policy Policy ; + + typedef typename MDRangePolicy::work_tag WorkTag ; + + typedef typename Policy::WorkRange WorkRange ; + typedef typename Policy::member_type Member ; + + typedef typename Kokkos::Experimental::Impl::HostIterateTile< MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void > iterate_type; + + const FunctorType m_functor ; + const MDRangePolicy m_mdr_policy ; + const Policy m_policy ; // construct as RangePolicy( 0, num_tiles ).set_chunk_size(1) in ctor + + inline static + void + exec_range( const MDRangePolicy & mdr_policy + , const FunctorType & functor + , const Member ibeg , const Member iend ) + { + #if defined( KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION ) && \ + defined( KOKKOS_ENABLE_PRAGMA_IVDEP ) + #pragma ivdep + #endif + for ( Member i = ibeg ; i < iend ; ++i ) { + iterate_type( mdr_policy, functor )( i ); + } + } + + static void exec( ThreadsExec & exec , const void * arg ) + { + exec_schedule(exec,arg); + } + + template + static + typename std::enable_if< std::is_same::value >::type + exec_schedule( ThreadsExec & exec , const void * arg ) + { + const ParallelFor & self = * ((const ParallelFor *) arg ); + + WorkRange range( self.m_policy , exec.pool_rank() , exec.pool_size() ); + + ParallelFor::exec_range + ( self.m_mdr_policy, self.m_functor , range.begin() , range.end() ); + + exec.fan_in(); + } + + template + static + typename std::enable_if< std::is_same::value >::type + exec_schedule( ThreadsExec & exec , const void * arg ) + { + const ParallelFor & self = * ((const ParallelFor *) arg ); + + WorkRange range( self.m_policy , exec.pool_rank() , exec.pool_size() ); + + exec.set_work_range(range.begin(),range.end(),self.m_policy.chunk_size()); + exec.reset_steal_target(); + exec.barrier(); + + long work_index = exec.get_work_index(); + + while(work_index != -1) { + const Member begin = static_cast(work_index) * self.m_policy.chunk_size(); + const Member end = begin + self.m_policy.chunk_size() < self.m_policy.end()?begin+self.m_policy.chunk_size():self.m_policy.end(); + + ParallelFor::exec_range + ( self.m_mdr_policy, self.m_functor , begin , end ); + work_index = exec.get_work_index(); + } + + exec.fan_in(); + } + +public: + + inline + void execute() const + { + ThreadsExec::start( & ParallelFor::exec , this ); + ThreadsExec::fence(); + } + + 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) ) + {} +}; + //---------------------------------------------------------------------------- /* ParallelFor Kokkos::Threads with TeamPolicy */ @@ -440,6 +544,169 @@ public: }; + +// MDRangePolicy impl +template< class FunctorType , class ReducerType, class ... Traits > +class ParallelReduce< FunctorType + , Kokkos::Experimental::MDRangePolicy< Traits ... > + , ReducerType + , Kokkos::Threads + > +{ +private: + + typedef Kokkos::Experimental::MDRangePolicy< Traits ... > MDRangePolicy ; + typedef typename MDRangePolicy::impl_range_policy Policy ; + + typedef typename MDRangePolicy::work_tag WorkTag ; + typedef typename Policy::WorkRange WorkRange ; + typedef typename Policy::member_type Member ; + + typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + + typedef typename ReducerTypeFwd::value_type ValueType; + + typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTag > ValueTraits ; + typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTag > ValueInit ; + + typedef typename ValueTraits::pointer_type pointer_type ; + typedef typename ValueTraits::reference_type reference_type ; + + using iterate_type = typename Kokkos::Experimental::Impl::HostIterateTile< MDRangePolicy + , FunctorType + , WorkTag + , ValueType + >; + + const FunctorType m_functor ; + const MDRangePolicy m_mdr_policy ; + const Policy m_policy ; // construct as RangePolicy( 0, num_tiles ).set_chunk_size(1) in ctor + const ReducerType m_reducer ; + const pointer_type m_result_ptr ; + + inline static + void + exec_range( const MDRangePolicy & mdr_policy + , const FunctorType & functor + , const Member & ibeg , const Member & iend + , reference_type update ) + { + #if defined( KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION ) && \ + defined( KOKKOS_ENABLE_PRAGMA_IVDEP ) + #pragma ivdep + #endif + for ( Member i = ibeg ; i < iend ; ++i ) { + iterate_type( mdr_policy, functor, update )( i ); + } + } + + static void + exec( ThreadsExec & exec , const void * arg ) { + exec_schedule(exec, arg); + } + + template + static + typename std::enable_if< std::is_same::value >::type + exec_schedule( ThreadsExec & exec , const void * arg ) + { + const ParallelReduce & self = * ((const ParallelReduce *) arg ); + const WorkRange range( self.m_policy, exec.pool_rank(), exec.pool_size() ); + + ParallelReduce::exec_range + ( self.m_mdr_policy, self.m_functor , range.begin() , range.end() + , ValueInit::init( ReducerConditional::select(self.m_functor , self.m_reducer) , exec.reduce_memory() ) ); + + exec.template fan_in_reduce< ReducerTypeFwd , WorkTag >( ReducerConditional::select(self.m_functor , self.m_reducer) ); + } + + template + static + typename std::enable_if< std::is_same::value >::type + exec_schedule( ThreadsExec & exec , const void * arg ) + { + const ParallelReduce & self = * ((const ParallelReduce *) arg ); + const WorkRange range( self.m_policy, exec.pool_rank(), exec.pool_size() ); + + exec.set_work_range(range.begin(),range.end(),self.m_policy.chunk_size()); + exec.reset_steal_target(); + exec.barrier(); + + long work_index = exec.get_work_index(); + reference_type update = ValueInit::init( ReducerConditional::select(self.m_functor , self.m_reducer) , exec.reduce_memory() ); + while(work_index != -1) { + const Member begin = static_cast(work_index) * self.m_policy.chunk_size(); + const Member end = begin + self.m_policy.chunk_size() < self.m_policy.end()?begin+self.m_policy.chunk_size():self.m_policy.end(); + ParallelReduce::exec_range + ( self.m_mdr_policy, self.m_functor , begin , end + , update ); + work_index = exec.get_work_index(); + } + + exec.template fan_in_reduce< ReducerTypeFwd , WorkTag >( ReducerConditional::select(self.m_functor , self.m_reducer) ); + } + +public: + + inline + void execute() const + { + ThreadsExec::resize_scratch( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) , 0 ); + + ThreadsExec::start( & ParallelReduce::exec , this ); + + ThreadsExec::fence(); + + if ( m_result_ptr ) { + + const pointer_type data = + (pointer_type) ThreadsExec::root_reduce_scratch(); + + const unsigned n = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); + for ( unsigned i = 0 ; i < n ; ++i ) { m_result_ptr[i] = data[i]; } + } + } + + 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.ptr_on_device() ) + { + static_assert( Kokkos::is_view< HostViewType >::value + , "Kokkos::Threads reduce result must be a View" ); + + static_assert( std::is_same< typename HostViewType::memory_space , HostSpace >::value + , "Kokkos::Threads 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" );*/ + } + +}; + + //---------------------------------------------------------------------------- /* ParallelReduce with Kokkos::Threads and TeamPolicy */ diff --git a/lib/kokkos/core/src/Threads/Kokkos_Threads_WorkGraphPolicy.hpp b/lib/kokkos/core/src/Threads/Kokkos_Threads_WorkGraphPolicy.hpp new file mode 100644 index 0000000000..be904a1670 --- /dev/null +++ b/lib/kokkos/core/src/Threads/Kokkos_Threads_WorkGraphPolicy.hpp @@ -0,0 +1,115 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_THREADS_WORKGRAPHPOLICY_HPP +#define KOKKOS_THREADS_WORKGRAPHPOLICY_HPP + +namespace Kokkos { +namespace Impl { + +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType , + Kokkos::Experimental::WorkGraphPolicy< Traits ... > , + Kokkos::Threads + > + : public Kokkos::Impl::Experimental:: + WorkGraphExec< FunctorType, + Kokkos::Threads, + Traits ... + > +{ +private: + + typedef Kokkos::Experimental::WorkGraphPolicy< Traits ... > Policy ; + typedef Kokkos::Impl::Experimental:: + WorkGraphExec Base ; + typedef ParallelFor, + Kokkos::Threads> Self ; + + template< class TagType > + typename std::enable_if< std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + Base::m_functor( i ); + } + + template< class TagType > + typename std::enable_if< ! std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + const TagType t{} ; + Base::m_functor( t , i ); + } + + inline void exec_one_thread() const { + for (std::int32_t i; (-1 != (i = Base::before_work())); ) { + exec_one< typename Policy::work_tag >( i ); + Base::after_work(i); + } + } + + static inline void thread_main( ThreadsExec&, const void* arg ) { + const Self& self = *(static_cast(arg)); + self.exec_one_thread(); + } + +public: + + inline + void execute() + { + ThreadsExec::start( & Self::thread_main, this ); + ThreadsExec::fence(); + } + + inline + ParallelFor( const FunctorType & arg_functor + , const Policy & arg_policy ) + : Base( arg_functor, arg_policy ) + { + } +}; + +} // namespace Impl +} // namespace Kokkos + +#endif /* #define KOKKOS_THREADS_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/impl/KokkosExp_Host_IterateTile.hpp b/lib/kokkos/core/src/impl/KokkosExp_Host_IterateTile.hpp index 77a1e8754d..0171b209e5 100644 --- a/lib/kokkos/core/src/impl/KokkosExp_Host_IterateTile.hpp +++ b/lib/kokkos/core/src/impl/KokkosExp_Host_IterateTile.hpp @@ -141,7 +141,6 @@ namespace Kokkos { namespace Experimental { namespace Impl { #define LOOP_ARGS_8 LOOP_ARGS_7, i7 + m_offset[7] - // New Loop Macros... // parallel_for, non-tagged #define APPLY( func, ... ) \ @@ -1010,8 +1009,6 @@ namespace Kokkos { namespace Experimental { namespace Impl { // end tagged macros - - // Structs for calling loops template < int Rank, bool IsLeft, typename IType, typename Tagged, typename Enable = void > struct Tile_Loop_Type; @@ -1279,6 +1276,19 @@ struct Tile_Loop_Type<8, IsLeft, IType, Tagged, typename std::enable_if< !std::i template using is_void = std::is_same< T , void >; +template +struct is_type_array : std::false_type +{ + using value_type = T; +}; + +template +struct is_type_array< T[] > : std::true_type +{ + using value_type = T; +}; + + template < typename RP , typename Functor , typename Tag = void @@ -1761,18 +1771,17 @@ struct HostIterateTile < RP , Functor , Tag , ValueType , typename std::enable_i RP const& m_rp; Functor const& m_func; typename std::conditional< std::is_same::value,int,Tag>::type m_tag; -// value_type & m_v; - }; -// ValueType: For reductions +// For ParallelReduce +// ValueType - scalar: For reductions template < typename RP , typename Functor , typename Tag , typename ValueType > -struct HostIterateTile < RP , Functor , Tag , ValueType , typename std::enable_if< !is_void::value >::type > +struct HostIterateTile < RP , Functor , Tag , ValueType , typename std::enable_if< !is_void::value && !is_type_array::value >::type > { using index_type = typename RP::index_type; using point_type = typename RP::point_type; @@ -2251,12 +2260,497 @@ struct HostIterateTile < RP , Functor , Tag , ValueType , typename std::enable_i }; +// For ParallelReduce +// Extra specialization for array reductions +// ValueType[]: For array reductions +template < typename RP + , typename Functor + , typename Tag + , typename ValueType + > +struct HostIterateTile < RP , Functor , Tag , ValueType , typename std::enable_if< !is_void::value && is_type_array::value >::type > +{ + using index_type = typename RP::index_type; + using point_type = typename RP::point_type; + + using value_type = typename is_type_array::value_type; // strip away the 'array-ness' [], only underlying type remains + + inline + HostIterateTile( RP const& rp, Functor const& func, value_type *v ) // v should be an array; treat as pointer for compatibility since size is not known nor needed here + : m_rp(rp) //Cuda 7.0 does not like braces... + , m_func(func) + , m_v(v) // use with non-void ValueType struct + {} + + inline + bool check_iteration_bounds( point_type& partial_tile , point_type& offset ) const { + bool is_full_tile = true; + + for ( int i = 0; i < RP::rank; ++i ) { + if ((offset[i] + m_rp.m_tile[i]) <= m_rp.m_upper[i]) { + partial_tile[i] = m_rp.m_tile[i] ; + } + else { + is_full_tile = false ; + partial_tile[i] = (m_rp.m_upper[i] - 1 - offset[i]) == 0 ? 1 + : (m_rp.m_upper[i] - m_rp.m_tile[i]) > 0 ? (m_rp.m_upper[i] - offset[i]) + : (m_rp.m_upper[i] - m_rp.m_lower[i]) ; // when single tile encloses range + } + } + + return is_full_tile ; + } // end check bounds + + + template + struct RankTag + { + typedef RankTag type; + enum { value = (int)Rank }; + }; + + +#if KOKKOS_ENABLE_NEW_LOOP_MACROS + template + inline + void + operator()(IType tile_idx) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + Tile_Loop_Type< RP::rank, (RP::inner_direction == RP::Left), index_type, Tag >::apply( m_v, m_func, full_tile, m_offset, m_rp.m_tile, m_tiledims ); + + } + +#else + template + inline + void + operator()(IType tile_idx) const + { operator_impl( tile_idx , RankTag() ); } + // added due to compiler error when using sfinae to choose operator based on rank + + + template + inline + void operator_impl( IType tile_idx , const RankTag<2> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_2L(index_type, m_tiledims) { + apply( LOOP_ARGS_2 ); + } + } else { +// #pragma simd + LOOP_2L(index_type, m_tiledims) { + apply( LOOP_ARGS_2 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_2R(index_type, m_tiledims) { + apply( LOOP_ARGS_2 ); + } + } else { +// #pragma simd + LOOP_2R(index_type, m_tiledims) { + apply( LOOP_ARGS_2 ); + } + } + } // end RP::Right + + } //end op() rank == 2 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<3> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_3L(index_type, m_tiledims) { + apply( LOOP_ARGS_3 ); + } + } else { +// #pragma simd + LOOP_3L(index_type, m_tiledims) { + apply( LOOP_ARGS_3 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_3R(index_type, m_tiledims) { + apply( LOOP_ARGS_3 ); + } + } else { +// #pragma simd + LOOP_3R(index_type, m_tiledims) { + apply( LOOP_ARGS_3 ); + } + } + } // end RP::Right + + } //end op() rank == 3 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<4> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_4L(index_type, m_tiledims) { + apply( LOOP_ARGS_4 ); + } + } else { +// #pragma simd + LOOP_4L(index_type, m_tiledims) { + apply( LOOP_ARGS_4 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_4R(index_type, m_tiledims) { + apply( LOOP_ARGS_4 ); + } + } else { +// #pragma simd + LOOP_4R(index_type, m_tiledims) { + apply( LOOP_ARGS_4 ); + } + } + } // end RP::Right + + } //end op() rank == 4 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<5> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_5L(index_type, m_tiledims) { + apply( LOOP_ARGS_5 ); + } + } else { +// #pragma simd + LOOP_5L(index_type, m_tiledims) { + apply( LOOP_ARGS_5 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_5R(index_type, m_tiledims) { + apply( LOOP_ARGS_5 ); + } + } else { +// #pragma simd + LOOP_5R(index_type, m_tiledims) { + apply( LOOP_ARGS_5 ); + } + } + } // end RP::Right + + } //end op() rank == 5 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<6> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_6L(index_type, m_tiledims) { + apply( LOOP_ARGS_6 ); + } + } else { +// #pragma simd + LOOP_6L(index_type, m_tiledims) { + apply( LOOP_ARGS_6 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_6R(index_type, m_tiledims) { + apply( LOOP_ARGS_6 ); + } + } else { +// #pragma simd + LOOP_6R(index_type, m_tiledims) { + apply( LOOP_ARGS_6 ); + } + } + } // end RP::Right + + } //end op() rank == 6 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<7> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_7L(index_type, m_tiledims) { + apply( LOOP_ARGS_7 ); + } + } else { +// #pragma simd + LOOP_7L(index_type, m_tiledims) { + apply( LOOP_ARGS_7 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_7R(index_type, m_tiledims) { + apply( LOOP_ARGS_7 ); + } + } else { +// #pragma simd + LOOP_7R(index_type, m_tiledims) { + apply( LOOP_ARGS_7 ); + } + } + } // end RP::Right + + } //end op() rank == 7 + + + template + inline + void operator_impl( IType tile_idx , const RankTag<8> ) const + { + point_type m_offset; + point_type m_tiledims; + + if (RP::outer_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] ; + tile_idx /= m_rp.m_tile_end[i]; + } + } + + //Check if offset+tiledim in bounds - if not, replace tile dims with the partial tile dims + const bool full_tile = check_iteration_bounds(m_tiledims , m_offset) ; + + if (RP::inner_direction == RP::Left) { + if ( full_tile ) { +// #pragma simd + LOOP_8L(index_type, m_tiledims) { + apply( LOOP_ARGS_8 ); + } + } else { +// #pragma simd + LOOP_8L(index_type, m_tiledims) { + apply( LOOP_ARGS_8 ); + } + } + } // end RP::Left + else { + if ( full_tile ) { +// #pragma simd + LOOP_8R(index_type, m_tiledims) { + apply( LOOP_ARGS_8 ); + } + } else { +// #pragma simd + LOOP_8R(index_type, m_tiledims) { + apply( LOOP_ARGS_8 ); + } + } + } // end RP::Right + + } //end op() rank == 8 +#endif + + + template + typename std::enable_if<( sizeof...(Args) == RP::rank && std::is_same::value), void>::type + apply(Args &&... args) const + { + m_func(args... , m_v); + } + + template + typename std::enable_if<( sizeof...(Args) == RP::rank && !std::is_same::value), void>::type + apply(Args &&... args) const + { + m_func( m_tag, args... , m_v); + } + + + RP const& m_rp; + Functor const& m_func; + value_type * m_v; + typename std::conditional< std::is_same::value,int,Tag>::type m_tag; + +}; + + // ------------------------------------------------------------------ // // MDFunctor - wraps the range_policy and functor to pass to IterateTile -// Serial, Threads, OpenMP +// Used for md_parallel_{for,reduce} with Serial, Threads, OpenMP // Cuda uses DeviceIterateTile directly within md_parallel_for -// ParallelReduce +// TODO Once md_parallel_{for,reduce} removed, this can be removed + +// ParallelReduce - scalar reductions template < typename MDRange, typename Functor, typename ValueType = void > struct MDFunctor { @@ -2273,7 +2767,7 @@ struct MDFunctor inline - MDFunctor( MDRange const& range, Functor const& f, ValueType & v ) + MDFunctor( MDRange const& range, Functor const& f ) : m_range( range ) , m_func( f ) {} @@ -2290,7 +2784,6 @@ struct MDFunctor inline MDFunctor& operator=( MDFunctor && ) = default; -// KOKKOS_FORCEINLINE_FUNCTION //Caused cuda warning - __host__ warning inline void operator()(index_type t, value_type & v) const { @@ -2301,6 +2794,56 @@ struct MDFunctor Functor m_func; }; + +// ParallelReduce - array reductions +template < typename MDRange, typename Functor, typename ValueType > +struct MDFunctor< MDRange, Functor, ValueType[] > +{ + using range_policy = MDRange; + using functor_type = Functor; + using value_type = ValueType[]; + using work_tag = typename range_policy::work_tag; + using index_type = typename range_policy::index_type; + using iterate_type = typename Kokkos::Experimental::Impl::HostIterateTile< MDRange + , Functor + , work_tag + , value_type + >; + + + inline + MDFunctor( MDRange const& range, Functor const& f ) + : m_range( range ) + , m_func( f ) + , value_count( f.value_count ) + {} + + inline + MDFunctor( MDFunctor const& ) = default; + + inline + MDFunctor& operator=( MDFunctor const& ) = default; + + inline + MDFunctor( MDFunctor && ) = default; + + inline + MDFunctor& operator=( MDFunctor && ) = default; + + // FIXME Init and Join, as defined in m_func, are not working through the MDFunctor + // Best path forward is to eliminate need for MDFunctor, directly use MDRangePolicy within Parallel{For,Reduce} ?? + inline + void operator()(index_type t, value_type v) const + { + iterate_type(m_range, m_func, v)(t); + } + + MDRange m_range; + Functor m_func; + size_t value_count; +}; + + // ParallelFor template < typename MDRange, typename Functor > struct MDFunctor< MDRange, Functor, void > @@ -2349,4 +2892,3 @@ struct MDFunctor< MDRange, Functor, void > } } } //end namespace Kokkos::Experimental::Impl #endif - diff --git a/lib/kokkos/core/src/impl/Kokkos_AnalyzePolicy.hpp b/lib/kokkos/core/src/impl/Kokkos_AnalyzePolicy.hpp index c5685c5b62..3fb15c8d1e 100644 --- a/lib/kokkos/core/src/impl/Kokkos_AnalyzePolicy.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_AnalyzePolicy.hpp @@ -55,16 +55,19 @@ template < typename ExecutionSpace = void , typename WorkTag = void , typename IndexType = void , typename IterationPattern = void + , typename LaunchBounds = void > struct PolicyTraitsBase { - using type = PolicyTraitsBase< ExecutionSpace, Schedule, WorkTag, IndexType, IterationPattern>; + using type = PolicyTraitsBase< ExecutionSpace, Schedule, WorkTag, IndexType, + IterationPattern, LaunchBounds>; using execution_space = ExecutionSpace; using schedule_type = Schedule; using work_tag = WorkTag; using index_type = IndexType; using iteration_pattern = IterationPattern; + using launch_bounds = LaunchBounds; }; @@ -78,6 +81,7 @@ struct SetExecutionSpace , typename PolicyBase::work_tag , typename PolicyBase::index_type , typename PolicyBase::iteration_pattern + , typename PolicyBase::launch_bounds >; }; @@ -91,6 +95,7 @@ struct SetSchedule , typename PolicyBase::work_tag , typename PolicyBase::index_type , typename PolicyBase::iteration_pattern + , typename PolicyBase::launch_bounds >; }; @@ -104,6 +109,7 @@ struct SetWorkTag , WorkTag , typename PolicyBase::index_type , typename PolicyBase::iteration_pattern + , typename PolicyBase::launch_bounds >; }; @@ -117,6 +123,7 @@ struct SetIndexType , typename PolicyBase::work_tag , IndexType , typename PolicyBase::iteration_pattern + , typename PolicyBase::launch_bounds >; }; @@ -131,6 +138,22 @@ struct SetIterationPattern , typename PolicyBase::work_tag , typename PolicyBase::index_type , IterationPattern + , typename PolicyBase::launch_bounds + >; +}; + + +template +struct SetLaunchBounds +{ + static_assert( is_void::value + , "Kokkos Error: More than one launch_bounds given" ); + using type = PolicyTraitsBase< typename PolicyBase::execution_space + , typename PolicyBase::schedule_type + , typename PolicyBase::work_tag + , typename PolicyBase::index_type + , typename PolicyBase::iteration_pattern + , LaunchBounds >; }; @@ -146,8 +169,9 @@ struct AnalyzePolicy : public , typename std::conditional< is_index_type::value , SetIndexType , typename std::conditional< std::is_integral::value , SetIndexType > , typename std::conditional< is_iteration_pattern::value, SetIterationPattern + , typename std::conditional< is_launch_bounds::value , SetLaunchBounds , SetWorkTag - >::type >::type >::type >::type>::type::type + >::type >::type >::type >::type >::type>::type::type , Traits... > {}; @@ -178,11 +202,18 @@ struct AnalyzePolicy , void // TODO set default iteration pattern , typename Base::iteration_pattern >::type; + + using launch_bounds = typename std::conditional< is_void< typename Base::launch_bounds >::value + , LaunchBounds<> + , typename Base::launch_bounds + >::type; + using type = PolicyTraitsBase< execution_space , schedule_type , work_tag , index_type , iteration_pattern + , launch_bounds >; }; diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp index 010b15064e..5b894b037b 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_COMPARE_EXCHANGE_STRONG_HPP ) #define KOKKOS_ATOMIC_COMPARE_EXCHANGE_STRONG_HPP @@ -126,11 +130,21 @@ T atomic_compare_exchange( volatile T * const dest , const T & compare , inline int atomic_compare_exchange( volatile int * const dest, const int compare, const int val) -{ return __sync_val_compare_and_swap(dest,compare,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_val_compare_and_swap(dest,compare,val); +} inline long atomic_compare_exchange( volatile long * const dest, const long compare, const long val ) -{ return __sync_val_compare_and_swap(dest,compare,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_val_compare_and_swap(dest,compare,val); +} #if defined( KOKKOS_ENABLE_GNU_ATOMICS ) @@ -159,6 +173,10 @@ T atomic_compare_exchange( volatile T * const dest, const T & compare, KOKKOS_INLINE_FUNCTION U() {}; } tmp ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + tmp.i = __sync_val_compare_and_swap( (int*) dest , *((int*)&compare) , *((int*)&val) ); return tmp.t ; } @@ -175,6 +193,10 @@ T atomic_compare_exchange( volatile T * const dest, const T & compare, KOKKOS_INLINE_FUNCTION U() {}; } tmp ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + tmp.i = __sync_val_compare_and_swap( (long*) dest , *((long*)&compare) , *((long*)&val) ); return tmp.t ; } @@ -193,6 +215,10 @@ T atomic_compare_exchange( volatile T * const dest, const T & compare, KOKKOS_INLINE_FUNCTION U() {}; } tmp ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + tmp.i = Impl::cas128( (Impl::cas128_t*) dest , *((Impl::cas128_t*)&compare) , *((Impl::cas128_t*)&val) ); return tmp.t ; } @@ -209,6 +235,10 @@ T atomic_compare_exchange( volatile T * const dest , const T compare , #endif , const T >::type& val ) { +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + while( !Impl::lock_address_host_space( (void*) dest ) ); T return_val = *dest; if( return_val == compare ) { diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Decrement.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Decrement.hpp index 127de528f5..2a13a4865c 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Decrement.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Decrement.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP) && ! defined( KOKKOS_ATOMIC_DECREMENT_HPP ) #define KOKKOS_ATOMIC_DECREMENT_HPP @@ -54,6 +58,10 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile char* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif + __asm__ __volatile__( "lock decb %0" : /* no output registers */ @@ -69,6 +77,10 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile short* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif + __asm__ __volatile__( "lock decw %0" : /* no output registers */ @@ -84,6 +96,10 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile int* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif + __asm__ __volatile__( "lock decl %0" : /* no output registers */ @@ -99,6 +115,9 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile long long int* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif __asm__ __volatile__( "lock decq %0" : /* no output registers */ diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Exchange.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Exchange.hpp index a1ff47abce..9ba3cae9fc 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Exchange.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Exchange.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_EXCHANGE_HPP ) #define KOKKOS_ATOMIC_EXCHANGE_HPP @@ -81,6 +85,10 @@ T atomic_exchange( typename Kokkos::Impl::enable_if< sizeof(T) == sizeof(int) , const T & >::type val ) { // int tmp = __ullAtomicExch( (int*) dest , *((int*)&val) ); +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + int tmp = atomicExch( ((int*)dest) , *((int*)&val) ); return *((T*)&tmp); } @@ -93,6 +101,11 @@ T atomic_exchange( sizeof(T) == sizeof(unsigned long long int) , const T & >::type val ) { typedef unsigned long long int type ; + +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + // type tmp = __ullAtomicExch( (type*) dest , *((type*)&val) ); type tmp = atomicExch( ((type*)dest) , *((type*)&val) ); return *((T*)&tmp); @@ -108,6 +121,10 @@ T atomic_exchange( volatile T * const dest , { T return_val; // This is a way to (hopefully) avoid dead lock in a warp +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + int done = 0; unsigned int active = __ballot(1); unsigned int done_active = 0; @@ -173,6 +190,9 @@ T atomic_exchange( volatile T * const dest , , const T & >::type val ) { typedef typename Kokkos::Impl::if_c< sizeof(T) == sizeof(int) , int , long >::type type ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif const type v = *((type*)&val); // Extract to be sure the value doesn't change @@ -201,6 +221,10 @@ T atomic_exchange( volatile T * const dest , typename Kokkos::Impl::enable_if< sizeof(T) == sizeof(Impl::cas128_t) , const T & >::type val ) { +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + union U { Impl::cas128_t i ; T t ; @@ -260,6 +284,10 @@ void atomic_assign( volatile T * const dest , { typedef typename Kokkos::Impl::if_c< sizeof(T) == sizeof(int) , int , long >::type type ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + const type v = *((type*)&val); // Extract to be sure the value doesn't change type assumed ; @@ -285,6 +313,10 @@ void atomic_assign( volatile T * const dest , typename Kokkos::Impl::enable_if< sizeof(T) == sizeof(Impl::cas128_t) , const T & >::type val ) { +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + union U { Impl::cas128_t i ; T t ; diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Add.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Add.hpp index 860c8e0e43..084c55efed 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Add.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Add.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_FETCH_ADD_HPP ) #define KOKKOS_ATOMIC_FETCH_ADD_HPP @@ -161,36 +165,60 @@ T atomic_fetch_add( volatile T * const dest , inline int atomic_fetch_add( volatile int * dest , const int val ) { - int original = val; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif - __asm__ __volatile__( - "lock xadd %1, %0" - : "+m" (*dest), "+r" (original) - : "m" (*dest), "r" (original) - : "memory" + int original = val; + + __asm__ __volatile__( + "lock xadd %1, %0" + : "+m" (*dest), "+r" (original) + : "m" (*dest), "r" (original) + : "memory" ); - return original; + return original; } #else inline int atomic_fetch_add( volatile int * const dest , const int val ) -{ return __sync_fetch_and_add(dest, val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_add(dest, val); +} #endif inline long int atomic_fetch_add( volatile long int * const dest , const long int val ) -{ return __sync_fetch_and_add(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_add(dest,val); +} #if defined( KOKKOS_ENABLE_GNU_ATOMICS ) inline unsigned int atomic_fetch_add( volatile unsigned int * const dest , const unsigned int val ) -{ return __sync_fetch_and_add(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_add(dest,val); +} inline unsigned long int atomic_fetch_add( volatile unsigned long int * const dest , const unsigned long int val ) -{ return __sync_fetch_and_add(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_add(dest,val); +} #endif @@ -205,6 +233,10 @@ T atomic_fetch_add( volatile T * const dest , inline U() {}; } assume , oldval , newval ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + oldval.t = *dest ; do { @@ -228,6 +260,10 @@ T atomic_fetch_add( volatile T * const dest , inline U() {}; } assume , oldval , newval ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + oldval.t = *dest ; do { @@ -253,6 +289,10 @@ T atomic_fetch_add( volatile T * const dest , inline U() {}; } assume , oldval , newval ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + oldval.t = *dest ; do { diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_And.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_And.hpp index 83f5b2a5aa..6ecb65336c 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_And.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_And.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_FETCH_AND_HPP ) #define KOKKOS_ATOMIC_FETCH_AND_HPP @@ -76,21 +80,41 @@ unsigned long long int atomic_fetch_and( volatile unsigned long long int * const inline int atomic_fetch_and( volatile int * const dest , const int val ) -{ return __sync_fetch_and_and(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_and(dest,val); +} inline long int atomic_fetch_and( volatile long int * const dest , const long int val ) -{ return __sync_fetch_and_and(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_and(dest,val); +} #if defined( KOKKOS_ENABLE_GNU_ATOMICS ) inline unsigned int atomic_fetch_and( volatile unsigned int * const dest , const unsigned int val ) -{ return __sync_fetch_and_and(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_and(dest,val); +} inline unsigned long int atomic_fetch_and( volatile unsigned long int * const dest , const unsigned long int val ) -{ return __sync_fetch_and_and(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_and(dest,val); +} #endif diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Or.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Or.hpp index 8c73b4c3ef..ed3b438f89 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Or.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Or.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_FETCH_OR_HPP ) #define KOKKOS_ATOMIC_FETCH_OR_HPP @@ -76,21 +80,41 @@ unsigned long long int atomic_fetch_or( volatile unsigned long long int * const inline int atomic_fetch_or( volatile int * const dest , const int val ) -{ return __sync_fetch_and_or(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_or(dest,val); +} inline long int atomic_fetch_or( volatile long int * const dest , const long int val ) -{ return __sync_fetch_and_or(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_or(dest,val); +} #if defined( KOKKOS_ENABLE_GNU_ATOMICS ) inline unsigned int atomic_fetch_or( volatile unsigned int * const dest , const unsigned int val ) -{ return __sync_fetch_and_or(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_or(dest,val); +} inline unsigned long int atomic_fetch_or( volatile unsigned long int * const dest , const unsigned long int val ) -{ return __sync_fetch_and_or(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_or(dest,val); +} #endif diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp index 504731d3a2..038cc13e9a 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP ) && ! defined( KOKKOS_ATOMIC_FETCH_SUB_HPP ) #define KOKKOS_ATOMIC_FETCH_SUB_HPP @@ -136,21 +140,41 @@ T atomic_fetch_sub( volatile T * const dest , inline int atomic_fetch_sub( volatile int * const dest , const int val ) -{ return __sync_fetch_and_sub(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_sub(dest,val); +} inline long int atomic_fetch_sub( volatile long int * const dest , const long int val ) -{ return __sync_fetch_and_sub(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_sub(dest,val); +} #if defined( KOKKOS_ENABLE_GNU_ATOMICS ) inline unsigned int atomic_fetch_sub( volatile unsigned int * const dest , const unsigned int val ) -{ return __sync_fetch_and_sub(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_sub(dest,val); +} inline unsigned long int atomic_fetch_sub( volatile unsigned long int * const dest , const unsigned long int val ) -{ return __sync_fetch_and_sub(dest,val); } +{ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + return __sync_fetch_and_sub(dest,val); +} #endif @@ -161,6 +185,10 @@ T atomic_fetch_sub( volatile T * const dest , { union { int i ; T t ; } assume , oldval , newval ; +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + oldval.t = *dest ; do { @@ -178,6 +206,10 @@ T atomic_fetch_sub( volatile T * const dest , typename Kokkos::Impl::enable_if< sizeof(T) != sizeof(int) && sizeof(T) == sizeof(long) , const T >::type val ) { +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + union { long i ; T t ; } assume , oldval , newval ; oldval.t = *dest ; @@ -202,6 +234,10 @@ T atomic_fetch_sub( volatile T * const dest , && ( sizeof(T) != 8 ) , const T >::type& val ) { +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) dest, _MM_HINT_ET0 ); +#endif + while( !Impl::lock_address_host_space( (void*) dest ) ); T return_val = *dest; *dest = return_val - val; diff --git a/lib/kokkos/core/src/impl/Kokkos_Atomic_Increment.hpp b/lib/kokkos/core/src/impl/Kokkos_Atomic_Increment.hpp index 2985fad95e..e7626603fc 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Atomic_Increment.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Atomic_Increment.hpp @@ -41,6 +41,10 @@ //@HEADER */ +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) +#include +#endif + #include #if defined( KOKKOS_ATOMIC_HPP) && ! defined( KOKKOS_ATOMIC_INCREMENT_HPP ) #define KOKKOS_ATOMIC_INCREMENT_HPP @@ -52,6 +56,9 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_increment(volatile char* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif __asm__ __volatile__( "lock incb %0" : /* no output registers */ @@ -67,6 +74,9 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_increment(volatile short* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif __asm__ __volatile__( "lock incw %0" : /* no output registers */ @@ -82,6 +92,9 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_increment(volatile int* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif __asm__ __volatile__( "lock incl %0" : /* no output registers */ @@ -97,6 +110,9 @@ template<> KOKKOS_INLINE_FUNCTION void atomic_increment(volatile long long int* a) { #if defined( KOKKOS_ENABLE_ASM ) && defined( KOKKOS_ENABLE_ISA_X86_64 ) && ! defined(_WIN32) && ! defined(__CUDA_ARCH__) +#if defined( KOKKOS_ENABLE_RFO_PREFETCH ) + _mm_prefetch( (const char*) a, _MM_HINT_ET0 ); +#endif __asm__ __volatile__( "lock incq %0" : /* no output registers */ diff --git a/lib/kokkos/core/src/impl/Kokkos_Core.cpp b/lib/kokkos/core/src/impl/Kokkos_Core.cpp index f0ff6d78ec..f52cc469ac 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Core.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_Core.cpp @@ -87,17 +87,12 @@ setenv("MEMKIND_HBW_NODES", "1", 0); #if defined( KOKKOS_ENABLE_OPENMP ) if( std::is_same< Kokkos::OpenMP , Kokkos::DefaultExecutionSpace >::value || std::is_same< Kokkos::OpenMP , Kokkos::HostSpace::execution_space >::value ) { - if(num_threads>0) { - if(use_numa>0) { - Kokkos::OpenMP::initialize(num_threads,use_numa); - } - else { - Kokkos::OpenMP::initialize(num_threads); - } - } else { - Kokkos::OpenMP::initialize(); + if(use_numa>0) { + Kokkos::OpenMP::initialize(num_threads,use_numa); + } + else { + Kokkos::OpenMP::initialize(num_threads); } - //std::cout << "Kokkos::initialize() fyi: OpenMP enabled and initialized" << std::endl ; } else { //std::cout << "Kokkos::initialize() fyi: OpenMP enabled but not initialized" << std::endl ; @@ -437,10 +432,7 @@ void initialize(int& narg, char* arg[]) iarg++; } - InitArguments arguments; - arguments.num_threads = num_threads; - arguments.num_numa = numa; - arguments.device_id = device; + InitArguments arguments{num_threads, numa, device}; Impl::initialize_internal(arguments); } diff --git a/lib/kokkos/core/src/impl/Kokkos_FunctorAdapter.hpp b/lib/kokkos/core/src/impl/Kokkos_FunctorAdapter.hpp index dc75fb072f..fccd8e090f 100644 --- a/lib/kokkos/core/src/impl/Kokkos_FunctorAdapter.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_FunctorAdapter.hpp @@ -170,28 +170,31 @@ struct FunctorValueTraits< FunctorType , ArgTag , true /* == exists FunctorType: static_assert( 0 == ( sizeof(value_type) % sizeof(int) ) , "Reduction functor's declared value_type requires: 0 == sizeof(value_type) % sizeof(int)" ); + /* this cast to bool is needed for correctness by NVCC */ + enum : bool { IsArray = static_cast(Impl::is_array< typename FunctorType::value_type >::value) }; + // If not an array then what is the sizeof(value_type) - enum { StaticValueSize = Impl::is_array< typename FunctorType::value_type >::value ? 0 : sizeof(value_type) }; + enum { StaticValueSize = IsArray ? 0 : sizeof(value_type) }; typedef value_type * pointer_type ; // The reference_type for an array is 'value_type *' // The reference_type for a single value is 'value_type &' - typedef typename Impl::if_c< ! StaticValueSize , value_type * - , value_type & >::type reference_type ; + typedef typename Impl::if_c< IsArray , value_type * + , value_type & >::type reference_type ; // Number of values if single value template< class F > KOKKOS_FORCEINLINE_FUNCTION static - typename Impl::enable_if< std::is_same::value && StaticValueSize , unsigned >::type + typename Impl::enable_if< std::is_same::value && ! IsArray , unsigned >::type value_count( const F & ) { return 1 ; } // Number of values if an array, protect via templating because 'f.value_count' // will only exist when the functor declares the value_type to be an array. template< class F > KOKKOS_FORCEINLINE_FUNCTION static - typename Impl::enable_if< std::is_same::value && ! StaticValueSize , unsigned >::type + typename Impl::enable_if< std::is_same::value && IsArray , unsigned >::type value_count( const F & f ) { return f.value_count ; } // Total size of the value diff --git a/lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp b/lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp index 8cb7430035..e11f8b6d34 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp @@ -70,62 +70,6 @@ #ifdef KOKKOS_ENABLE_HBWSPACE #define MEMKIND_TYPE MEMKIND_HBW //hbw_get_kind(HBW_PAGESIZE_4KB) -namespace Kokkos { -namespace Experimental { -namespace { - -static const int QUERY_SPACE_IN_PARALLEL_MAX = 16 ; - -typedef int (* QuerySpaceInParallelPtr )(); - -QuerySpaceInParallelPtr s_in_parallel_query[ QUERY_SPACE_IN_PARALLEL_MAX ] ; -int s_in_parallel_query_count = 0 ; - -} // namespace - -void HBWSpace::register_in_parallel( int (*device_in_parallel)() ) -{ - if ( 0 == device_in_parallel ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Experimental::HBWSpace::register_in_parallel ERROR : given NULL" ) ); - } - - int i = -1 ; - - if ( ! (device_in_parallel)() ) { - for ( i = 0 ; i < s_in_parallel_query_count && ! (*(s_in_parallel_query[i]))() ; ++i ); - } - - if ( i < s_in_parallel_query_count ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Experimental::HBWSpace::register_in_parallel_query ERROR : called in_parallel" ) ); - - } - - if ( QUERY_SPACE_IN_PARALLEL_MAX <= i ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Experimental::HBWSpace::register_in_parallel_query ERROR : exceeded maximum" ) ); - - } - - for ( i = 0 ; i < s_in_parallel_query_count && s_in_parallel_query[i] != device_in_parallel ; ++i ); - - if ( i == s_in_parallel_query_count ) { - s_in_parallel_query[s_in_parallel_query_count++] = device_in_parallel ; - } -} - -int HBWSpace::in_parallel() -{ - const int n = s_in_parallel_query_count ; - - int i = 0 ; - - while ( i < n && ! (*(s_in_parallel_query[i]))() ) { ++i ; } - - return i < n ; -} - -} // namespace Experiemtal -} // namespace Kokkos - /*--------------------------------------------------------------------------*/ namespace Kokkos { diff --git a/lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp b/lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp index 2a5c34c375..a5a73ddebb 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp @@ -106,62 +106,6 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -namespace Kokkos { -namespace { - -static const int QUERY_SPACE_IN_PARALLEL_MAX = 16 ; - -typedef int (* QuerySpaceInParallelPtr )(); - -QuerySpaceInParallelPtr s_in_parallel_query[ QUERY_SPACE_IN_PARALLEL_MAX ] ; -int s_in_parallel_query_count = 0 ; - -} // namespace - -void HostSpace::register_in_parallel( int (*device_in_parallel)() ) -{ - if ( 0 == device_in_parallel ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::HostSpace::register_in_parallel ERROR : given NULL" ) ); - } - - int i = -1 ; - - if ( ! (device_in_parallel)() ) { - for ( i = 0 ; i < s_in_parallel_query_count && ! (*(s_in_parallel_query[i]))() ; ++i ); - } - - if ( i < s_in_parallel_query_count ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::HostSpace::register_in_parallel_query ERROR : called in_parallel" ) ); - - } - - if ( QUERY_SPACE_IN_PARALLEL_MAX <= i ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::HostSpace::register_in_parallel_query ERROR : exceeded maximum" ) ); - - } - - for ( i = 0 ; i < s_in_parallel_query_count && s_in_parallel_query[i] != device_in_parallel ; ++i ); - - if ( i == s_in_parallel_query_count ) { - s_in_parallel_query[s_in_parallel_query_count++] = device_in_parallel ; - } -} - -int HostSpace::in_parallel() -{ - const int n = s_in_parallel_query_count ; - - int i = 0 ; - - while ( i < n && ! (*(s_in_parallel_query[i]))() ) { ++i ; } - - return i < n ; -} - -} // namespace Kokkos - -/*--------------------------------------------------------------------------*/ - namespace Kokkos { /* Default allocation mechanism */ @@ -340,9 +284,6 @@ void HostSpace::deallocate( void * const arg_alloc_ptr , const size_t arg_alloc_ } } -constexpr const char* HostSpace::name() { - return m_name; -} } // namespace Kokkos //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp index ac200209c7..d2446bde09 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.cpp @@ -45,7 +45,7 @@ #include #include #include -#include +#include //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -58,9 +58,11 @@ void HostThreadTeamData::organize_pool { bool ok = true ; + memory_fence(); + // Verify not already a member of a pool: for ( int rank = 0 ; rank < size && ok ; ++rank ) { - ok = ( 0 != members[rank] ) && ( 0 == members[rank]->m_pool_scratch ); + ok = ( nullptr != members[rank] ) && ( 0 == members[rank]->m_pool_scratch ); } if ( ok ) { @@ -89,7 +91,6 @@ void HostThreadTeamData::organize_pool mem->m_team_alloc = 1 ; mem->m_league_rank = rank ; mem->m_league_size = size ; - mem->m_pool_rendezvous_step = 0 ; mem->m_team_rendezvous_step = 0 ; pool[ rank ] = mem ; } @@ -116,7 +117,6 @@ void HostThreadTeamData::disband_pool() m_team_alloc = 1 ; m_league_rank = 0 ; m_league_size = 1 ; - m_pool_rendezvous_step = 0 ; m_team_rendezvous_step = 0 ; } @@ -256,11 +256,6 @@ int HostThreadTeamData::rendezvous( int64_t * const buffer const int sync_offset = ( step & mask_mem_cycle ) + size_mem_cycle ; - union { - int64_t full ; - int8_t byte[8] ; - } value ; - if ( rank ) { const int group_begin = rank << shift_byte ; // == rank * size_byte @@ -275,13 +270,14 @@ int HostThreadTeamData::rendezvous( int64_t * const buffer const int end = group_begin + size_byte < size ? size_byte : size - group_begin ; - value.full = 0 ; - for ( int i = 0 ; i < end ; ++i ) value.byte[i] = int8_t( step ); + int64_t value = 0 ; - store_fence(); // This should not be needed but fixes #742 + for ( int i = 0 ; i < end ; ++i ) { + ((int8_t*) & value )[i] = int8_t( step ); + } spinwait_until_equal( buffer[ (rank << shift_mem_cycle) + sync_offset ] - , value.full ); + , value ); } { @@ -316,10 +312,12 @@ int HostThreadTeamData::rendezvous( int64_t * const buffer const int end = size_byte < size ? 8 : size ; - value.full = 0 ; - for ( int i = 1 ; i < end ; ++i ) value.byte[i] = int8_t( step ); + int64_t value = 0 ; + for ( int i = 1 ; i < end ; ++i ) { + ((int8_t *) & value)[i] = int8_t( step ); + } - spinwait_until_equal( buffer[ sync_offset ], value.full ); + spinwait_until_equal( buffer[ sync_offset ], value ); } return rank ? 0 : 1 ; diff --git a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.hpp b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.hpp index c050a16eae..7facc0a410 100644 --- a/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_HostThreadTeam.hpp @@ -50,6 +50,7 @@ #include #include #include +#include //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -67,14 +68,12 @@ public: // Assume upper bounds on number of threads: // pool size <= 1024 threads - // pool rendezvous <= ( 1024 / 8 ) * 4 + 4 = 2052 // team size <= 64 threads - // team rendezvous <= ( 64 / 8 ) * 4 + 4 = 36 enum : int { max_pool_members = 1024 }; enum : int { max_team_members = 64 }; - enum : int { max_pool_rendezvous = ( max_pool_members / 8 ) * 4 + 4 }; - enum : int { max_team_rendezvous = ( max_team_members / 8 ) * 4 + 4 }; + enum : int { max_pool_rendezvous = rendezvous_buffer_size( max_pool_members ) }; + enum : int { max_team_rendezvous = rendezvous_buffer_size( max_team_members ) }; private: @@ -114,7 +113,6 @@ private: int m_league_size ; int m_work_chunk ; int m_steal_rank ; // work stealing rank - int mutable m_pool_rendezvous_step ; int mutable m_team_rendezvous_step ; HostThreadTeamData * team_member( int r ) const noexcept @@ -147,6 +145,7 @@ public: int team_rendezvous( int const root ) const noexcept { return 1 == m_team_size ? 1 : + HostThreadTeamData:: rendezvous( m_team_scratch + m_team_rendezvous , m_team_rendezvous_step , m_team_size @@ -157,6 +156,7 @@ public: int team_rendezvous() const noexcept { return 1 == m_team_size ? 1 : + HostThreadTeamData:: rendezvous( m_team_scratch + m_team_rendezvous , m_team_rendezvous_step , m_team_size @@ -167,6 +167,7 @@ public: void team_rendezvous_release() const noexcept { if ( 1 < m_team_size ) { + HostThreadTeamData:: rendezvous_release( m_team_scratch + m_team_rendezvous , m_team_rendezvous_step ); } @@ -175,19 +176,30 @@ public: inline int pool_rendezvous() const noexcept { + static constexpr int yield_wait = + #if defined( KOKKOS_COMPILER_IBM ) + // If running on IBM POWER architecture the global + // level rendzvous should immediately yield when + // waiting for other threads in the pool to arrive. + 1 + #else + 0 + #endif + ; return 1 == m_pool_size ? 1 : + Kokkos::Impl:: rendezvous( m_pool_scratch + m_pool_rendezvous - , m_pool_rendezvous_step , m_pool_size - , m_pool_rank ); + , m_pool_rank + , yield_wait ); } inline void pool_rendezvous_release() const noexcept { if ( 1 < m_pool_size ) { - rendezvous_release( m_pool_scratch + m_pool_rendezvous - , m_pool_rendezvous_step ); + Kokkos::Impl:: + rendezvous_release( m_pool_scratch + m_pool_rendezvous ); } } @@ -213,7 +225,6 @@ public: , m_league_size(1) , m_work_chunk(0) , m_steal_rank(0) - , m_pool_rendezvous_step(0) , m_team_rendezvous_step(0) {} @@ -406,7 +417,7 @@ fflush(stdout); // Steal from next team, round robin // The next team is offset by m_team_alloc if it fits in the pool. - m_steal_rank = m_team_base + m_team_alloc + m_team_size <= m_pool_size ? + m_steal_rank = m_team_base + m_team_alloc + m_team_size <= m_pool_size ? m_team_base + m_team_alloc : 0 ; } diff --git a/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.cpp b/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.cpp index 98482cfab6..608d514c79 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.cpp @@ -50,51 +50,70 @@ namespace Kokkos { namespace Profiling { +static initFunction initProfileLibrary = nullptr; +static finalizeFunction finalizeProfileLibrary = nullptr; + +static beginFunction beginForCallee = nullptr; +static beginFunction beginScanCallee = nullptr; +static beginFunction beginReduceCallee = nullptr; +static endFunction endForCallee = nullptr; +static endFunction endScanCallee = nullptr; +static endFunction endReduceCallee = nullptr; + +static pushFunction pushRegionCallee = nullptr; +static popFunction popRegionCallee = nullptr; + +static allocateDataFunction allocateDataCallee = nullptr; +static deallocateDataFunction deallocateDataCallee = nullptr; + +static beginDeepCopyFunction beginDeepCopyCallee = nullptr; +static endDeepCopyFunction endDeepCopyCallee = nullptr; + SpaceHandle::SpaceHandle(const char* space_name) { strncpy(name,space_name,64); } bool profileLibraryLoaded() { - return (NULL != initProfileLibrary); + return (nullptr != initProfileLibrary); } void beginParallelFor(const std::string& kernelPrefix, const uint32_t devID, uint64_t* kernelID) { - if(NULL != beginForCallee) { + if(nullptr != beginForCallee) { Kokkos::fence(); (*beginForCallee)(kernelPrefix.c_str(), devID, kernelID); } } void endParallelFor(const uint64_t kernelID) { - if(NULL != endForCallee) { + if(nullptr != endForCallee) { Kokkos::fence(); (*endForCallee)(kernelID); } } void beginParallelScan(const std::string& kernelPrefix, const uint32_t devID, uint64_t* kernelID) { - if(NULL != beginScanCallee) { + if(nullptr != beginScanCallee) { Kokkos::fence(); (*beginScanCallee)(kernelPrefix.c_str(), devID, kernelID); } } void endParallelScan(const uint64_t kernelID) { - if(NULL != endScanCallee) { + if(nullptr != endScanCallee) { Kokkos::fence(); (*endScanCallee)(kernelID); } } void beginParallelReduce(const std::string& kernelPrefix, const uint32_t devID, uint64_t* kernelID) { - if(NULL != beginReduceCallee) { + if(nullptr != beginReduceCallee) { Kokkos::fence(); (*beginReduceCallee)(kernelPrefix.c_str(), devID, kernelID); } } void endParallelReduce(const uint64_t kernelID) { - if(NULL != endReduceCallee) { + if(nullptr != endReduceCallee) { Kokkos::fence(); (*endReduceCallee)(kernelID); } @@ -102,31 +121,47 @@ void endParallelReduce(const uint64_t kernelID) { void pushRegion(const std::string& kName) { - if( NULL != pushRegionCallee ) { + if( nullptr != pushRegionCallee ) { Kokkos::fence(); (*pushRegionCallee)(kName.c_str()); } } void popRegion() { - if( NULL != popRegionCallee ) { + if( nullptr != popRegionCallee ) { Kokkos::fence(); (*popRegionCallee)(); } } void allocateData(const SpaceHandle space, const std::string label, const void* ptr, const uint64_t size) { - if(NULL != allocateDataCallee) { + if(nullptr != allocateDataCallee) { (*allocateDataCallee)(space,label.c_str(),ptr,size); } } void deallocateData(const SpaceHandle space, const std::string label, const void* ptr, const uint64_t size) { - if(NULL != allocateDataCallee) { + if(nullptr != deallocateDataCallee) { (*deallocateDataCallee)(space,label.c_str(),ptr,size); } } +void beginDeepCopy(const SpaceHandle dst_space, const std::string dst_label, const void* dst_ptr, + const SpaceHandle src_space, const std::string src_label, const void* src_ptr, + const uint64_t size) { + if(nullptr != beginDeepCopyCallee) { + (*beginDeepCopyCallee)(dst_space, dst_label.c_str(), dst_ptr, + src_space, src_label.c_str(), src_ptr, + size); + } +} + +void endDeepCopy() { + if(nullptr != endDeepCopyCallee) { + (*endDeepCopyCallee)(); + } +} + void initialize() { // Make sure initialize calls happens only once @@ -140,7 +175,7 @@ void initialize() { // If we do not find a profiling library in the environment then exit // early. - if( NULL == envProfileLibrary ) { + if( nullptr == envProfileLibrary ) { return ; } @@ -149,10 +184,10 @@ void initialize() { char* profileLibraryName = strtok(envProfileCopy, ";"); - if( (NULL != profileLibraryName) && (strcmp(profileLibraryName, "") != 0) ) { + if( (nullptr != profileLibraryName) && (strcmp(profileLibraryName, "") != 0) ) { firstProfileLibrary = dlopen(profileLibraryName, RTLD_NOW | RTLD_GLOBAL); - if(NULL == firstProfileLibrary) { + if(nullptr == firstProfileLibrary) { std::cerr << "Error: Unable to load KokkosP library: " << profileLibraryName << std::endl; } else { @@ -191,14 +226,19 @@ void initialize() { auto p12 = dlsym(firstProfileLibrary, "kokkosp_deallocate_data"); deallocateDataCallee = *((deallocateDataFunction*) &p12); + auto p13 = dlsym(firstProfileLibrary, "kokkosp_begin_deep_copy"); + beginDeepCopyCallee = *((beginDeepCopyFunction*) &p13); + auto p14 = dlsym(firstProfileLibrary, "kokkosp_end_deep_copy"); + endDeepCopyCallee = *((endDeepCopyFunction*) &p14); + } } - if(NULL != initProfileLibrary) { + if(nullptr != initProfileLibrary) { (*initProfileLibrary)(0, (uint64_t) KOKKOSP_INTERFACE_VERSION, (uint32_t) 0, - NULL); + nullptr); } free(envProfileCopy); @@ -210,28 +250,30 @@ void finalize() { if(is_finalized) return; is_finalized = 1; - if(NULL != finalizeProfileLibrary) { + if(nullptr != finalizeProfileLibrary) { (*finalizeProfileLibrary)(); - // Set all profile hooks to NULL to prevent + // Set all profile hooks to nullptr to prevent // any additional calls. Once we are told to // finalize, we mean it - initProfileLibrary = NULL; - finalizeProfileLibrary = NULL; + initProfileLibrary = nullptr; + finalizeProfileLibrary = nullptr; - beginForCallee = NULL; - beginScanCallee = NULL; - beginReduceCallee = NULL; - endScanCallee = NULL; - endForCallee = NULL; - endReduceCallee = NULL; + beginForCallee = nullptr; + beginScanCallee = nullptr; + beginReduceCallee = nullptr; + endScanCallee = nullptr; + endForCallee = nullptr; + endReduceCallee = nullptr; - pushRegionCallee = NULL; - popRegionCallee = NULL; + pushRegionCallee = nullptr; + popRegionCallee = nullptr; - allocateDataCallee = NULL; - deallocateDataCallee = NULL; + allocateDataCallee = nullptr; + deallocateDataCallee = nullptr; + beginDeepCopyCallee = nullptr; + endDeepCopyCallee = nullptr; } } } diff --git a/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.hpp b/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.hpp index f76e5dfa04..2c2e524d9d 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Profiling_Interface.hpp @@ -81,23 +81,11 @@ typedef void (*popFunction)(); typedef void (*allocateDataFunction)(const SpaceHandle, const char*, const void*, const uint64_t); typedef void (*deallocateDataFunction)(const SpaceHandle, const char*, const void*, const uint64_t); - -static initFunction initProfileLibrary = NULL; -static finalizeFunction finalizeProfileLibrary = NULL; - -static beginFunction beginForCallee = NULL; -static beginFunction beginScanCallee = NULL; -static beginFunction beginReduceCallee = NULL; -static endFunction endForCallee = NULL; -static endFunction endScanCallee = NULL; -static endFunction endReduceCallee = NULL; - -static pushFunction pushRegionCallee = NULL; -static popFunction popRegionCallee = NULL; - -static allocateDataFunction allocateDataCallee = NULL; -static deallocateDataFunction deallocateDataCallee = NULL; - +typedef void (*beginDeepCopyFunction)( + SpaceHandle, const char*, const void*, + SpaceHandle, const char*, const void*, + uint64_t); +typedef void (*endDeepCopyFunction)(); bool profileLibraryLoaded(); @@ -114,35 +102,14 @@ void popRegion(); void allocateData(const SpaceHandle space, const std::string label, const void* ptr, const uint64_t size); void deallocateData(const SpaceHandle space, const std::string label, const void* ptr, const uint64_t size); +void beginDeepCopy(const SpaceHandle dst_space, const std::string dst_label, const void* dst_ptr, + const SpaceHandle src_space, const std::string src_label, const void* src_ptr, + const uint64_t size); +void endDeepCopy(); + void initialize(); void finalize(); -//Define finalize_fake inline to get rid of warnings for unused static variables -inline void finalize_fake() { - if(NULL != finalizeProfileLibrary) { - (*finalizeProfileLibrary)(); - - // Set all profile hooks to NULL to prevent - // any additional calls. Once we are told to - // finalize, we mean it - beginForCallee = NULL; - beginScanCallee = NULL; - beginReduceCallee = NULL; - endScanCallee = NULL; - endForCallee = NULL; - endReduceCallee = NULL; - - allocateDataCallee = NULL; - deallocateDataCallee = NULL; - - initProfileLibrary = NULL; - finalizeProfileLibrary = NULL; - pushRegionCallee = NULL; - popRegionCallee = NULL; - } -} - - } } diff --git a/lib/kokkos/core/src/impl/Kokkos_Rendezvous.cpp b/lib/kokkos/core/src/impl/Kokkos_Rendezvous.cpp new file mode 100644 index 0000000000..ac697fce4b --- /dev/null +++ b/lib/kokkos/core/src/impl/Kokkos_Rendezvous.cpp @@ -0,0 +1,208 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include +#include +#include + +namespace Kokkos { namespace Impl { + +//---------------------------------------------------------------------------- +/* pattern for rendezvous + * + * if ( rendezvous() ) { + * ... all other threads are still in team_rendezvous() ... + * rendezvous_release(); + * ... all other threads are released from team_rendezvous() ... + * } + */ + +int rendezvous( volatile int64_t * const buffer + , int const size + , int const rank + , int const slow + ) noexcept +{ + enum : int { shift_byte = 3 }; + enum : int { size_byte = ( 01 << shift_byte ) }; // == 8 + enum : int { mask_byte = size_byte - 1 }; + + enum : int { shift_mem_cycle = 2 }; + enum : int { size_mem_cycle = ( 01 << shift_mem_cycle ) }; // == 4 + enum : int { mask_mem_cycle = size_mem_cycle - 1 }; + + // Cycle step values: 1 <= step <= size_val_cycle + // An odd multiple of memory cycle so that when a memory location + // is reused it has a different value. + // Must be representable within a single byte: size_val_cycle < 16 + + enum : int { size_val_cycle = 3 * size_mem_cycle }; + + // Requires: + // Called by rank = [ 0 .. size ) + // buffer aligned to int64_t[4] + + // A sequence of rendezvous uses four cycled locations in memory + // and non-equal cycled synchronization values to + // 1) prevent rendezvous from overtaking one another and + // 2) give each spin wait location an int64_t[4] span + // so that it has its own cache line. + + const int64_t step = (buffer[0] % size_val_cycle ) + 1 ; + + // The leading int64_t[4] span is for thread 0 to write + // and all other threads to read spin-wait. + // sync_offset is the index into this array for this step. + + const int sync_offset = ( step & mask_mem_cycle ) + size_mem_cycle + size_mem_cycle ; + + if ( rank ) { + + const int group_begin = rank << shift_byte ; // == rank * size_byte + + if ( group_begin < size ) { + + // This thread waits for threads + // [ group_begin .. group_begin + 8 ) + // [ rank*8 .. rank*8 + 8 ) + // to write to their designated bytes. + + const int end = group_begin + size_byte < size + ? size_byte : size - group_begin ; + + int64_t value = 0; + for ( int i = 0 ; i < end ; ++i ) { + value |= step << (i * size_byte ); + } + + store_fence(); // This should not be needed but fixes #742 + + if ( slow ) { + yield_until_equal( buffer[ (rank << shift_mem_cycle) + sync_offset ] + , value ); + } + else { + spinwait_until_equal( buffer[ (rank << shift_mem_cycle) + sync_offset ] + , value ); + } + } + + { + // This thread sets its designated byte. + // ( rank % size_byte ) + + // ( ( rank / size_byte ) * size_byte * size_mem_cycle ) + + // ( sync_offset * size_byte ) + const int offset = ( rank & mask_byte ) + + ( ( rank & ~mask_byte ) << shift_mem_cycle ) + + ( sync_offset << shift_byte ); + + // All of this thread's previous memory stores must be complete before + // this thread stores the step value at this thread's designated byte + // in the shared synchronization array. + + Kokkos::memory_fence(); + + ((volatile int8_t*) buffer)[ offset ] = int8_t( step ); + + // Memory fence to push the previous store out + Kokkos::memory_fence(); + } + + // Wait for thread 0 to release all other threads + + if ( slow ) { + yield_until_equal( buffer[ (step & mask_mem_cycle) + size_mem_cycle ] , int64_t(step) ); + } + else { + spinwait_until_equal( buffer[ (step & mask_mem_cycle) + size_mem_cycle ] , int64_t(step) ); + } + } + else { + // Thread 0 waits for threads [1..7] + // to write to their designated bytes. + + const int end = size_byte < size ? 8 : size ; + + int64_t value = 0; + for ( int i = 1 ; i < end ; ++i ) { + value |= step << (i * size_byte ); + } + + if ( slow ) { + yield_until_equal( buffer[ sync_offset ], value ); + } + else { + spinwait_until_equal( buffer[ sync_offset ], value ); + } + } + + return rank ? 0 : 1 ; +} + +void rendezvous_release( volatile int64_t * const buffer ) noexcept +{ + enum : int { shift_mem_cycle = 2 }; + enum : int { size_mem_cycle = ( 01 << shift_mem_cycle ) }; // == 4 + enum : int { mask_mem_cycle = size_mem_cycle - 1 }; + enum : int { size_val_cycle = 3 * size_mem_cycle }; + + // Requires: + // Called after team_rendezvous + // Called only by true == team_rendezvous(root) + + // update step + const int64_t step = (buffer[0] % size_val_cycle ) + 1; + buffer[0] = step; + + // Memory fence to be sure all previous writes are complete: + Kokkos::memory_fence(); + + buffer[ (step & mask_mem_cycle) + size_mem_cycle ] = step; + + // Memory fence to push the store out + Kokkos::memory_fence(); +} + +}} // namespace Kokkos::Impl + diff --git a/lib/kokkos/core/src/impl/Kokkos_Rendezvous.hpp b/lib/kokkos/core/src/impl/Kokkos_Rendezvous.hpp new file mode 100644 index 0000000000..57f8633bca --- /dev/null +++ b/lib/kokkos/core/src/impl/Kokkos_Rendezvous.hpp @@ -0,0 +1,87 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_IMPL_RENDEZVOUS_HPP +#define KOKKOS_IMPL_RENDEZVOUS_HPP + +#include + +namespace Kokkos { namespace Impl { + +inline +constexpr int rendezvous_buffer_size( int max_members ) noexcept +{ + return (((max_members + 7) / 8) * 4) + 4 + 4; +} + +/** \brief Thread pool rendezvous + * + * Rendezvous pattern: + * if ( rendezvous(root) ) { + * ... only root thread here while all others wait ... + * rendezvous_release(); + * } + * else { + * ... all other threads release here ... + * } + * + * Requires: buffer[ rendezvous_buffer_size( max_threads ) ]; + * + * When slow != 0 the expectation is thread arrival will be + * slow so the threads that arrive early should quickly yield + * their core to the runtime thus possibly allowing the late + * arriving threads to have more resources + * (e.g., power and clock frequency). + */ +int rendezvous( volatile int64_t * const buffer + , int const size + , int const rank + , int const slow = 0 ) noexcept ; + +void rendezvous_release( volatile int64_t * const buffer ) noexcept ; + + +}} // namespace Kokkos::Impl + +#endif // KOKKOS_IMPL_RENDEZVOUS_HPP + diff --git a/lib/kokkos/core/src/impl/Kokkos_Serial.cpp b/lib/kokkos/core/src/impl/Kokkos_Serial.cpp index 755271c07e..dfbeba461e 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Serial.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_Serial.cpp @@ -50,6 +50,7 @@ #include #include +#include /*--------------------------------------------------------------------------*/ @@ -123,7 +124,6 @@ void serial_resize_thread_team_data( size_t pool_reduce_bytes } } -// Get thread team data structure for omp_get_thread_num() HostThreadTeamData * serial_get_thread_team_data() { return & g_serial_thread_team_data ; @@ -151,6 +151,8 @@ void Serial::initialize( unsigned threads_count (void) use_cores_per_numa; (void) allow_asynchronous_threadpool; + Impl::SharedAllocationRecord< void, void >::tracking_enable(); + // Init the array of locks used for arbitrarily sized atomics Impl::init_lock_array_host_space(); #if defined(KOKKOS_ENABLE_PROFILING) diff --git a/lib/kokkos/core/src/impl/Kokkos_Serial_Task.cpp b/lib/kokkos/core/src/impl/Kokkos_Serial_Task.cpp index 76297161b1..0b6fbd9af0 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Serial_Task.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_Serial_Task.cpp @@ -62,7 +62,7 @@ void TaskQueueSpecialization< Kokkos::Serial >::execute { using execution_space = Kokkos::Serial ; using queue_type = TaskQueue< execution_space > ; - using task_root_type = TaskBase< execution_space , void , void > ; + using task_root_type = TaskBase< void , void , void > ; using Member = Impl::HostThreadTeamMember< execution_space > ; task_root_type * const end = (task_root_type *) task_root_type::EndTag ; @@ -122,7 +122,7 @@ void TaskQueueSpecialization< Kokkos::Serial > :: { using execution_space = Kokkos::Serial ; using queue_type = TaskQueue< execution_space > ; - using task_root_type = TaskBase< execution_space , void , void > ; + using task_root_type = TaskBase< void , void , void > ; using Member = Impl::HostThreadTeamMember< execution_space > ; task_root_type * const end = (task_root_type *) task_root_type::EndTag ; diff --git a/lib/kokkos/core/src/impl/Kokkos_Serial_Task.hpp b/lib/kokkos/core/src/impl/Kokkos_Serial_Task.hpp index 2eb2b5cf52..39deebbbf1 100644 --- a/lib/kokkos/core/src/impl/Kokkos_Serial_Task.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Serial_Task.hpp @@ -65,7 +65,7 @@ public: using execution_space = Kokkos::Serial ; using memory_space = Kokkos::HostSpace ; using queue_type = Kokkos::Impl::TaskQueue< execution_space > ; - using task_base_type = Kokkos::Impl::TaskBase< execution_space , void , void > ; + using task_base_type = Kokkos::Impl::TaskBase< void , void , void > ; using member_type = Kokkos::Impl::HostThreadTeamMember< execution_space > ; static diff --git a/lib/kokkos/core/src/impl/Kokkos_Serial_WorkGraphPolicy.hpp b/lib/kokkos/core/src/impl/Kokkos_Serial_WorkGraphPolicy.hpp new file mode 100644 index 0000000000..dc30ffe9e0 --- /dev/null +++ b/lib/kokkos/core/src/impl/Kokkos_Serial_WorkGraphPolicy.hpp @@ -0,0 +1,102 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_SERIAL_WORKGRAPHPOLICY_HPP +#define KOKKOS_SERIAL_WORKGRAPHPOLICY_HPP + +namespace Kokkos { +namespace Impl { + +template< class FunctorType , class ... Traits > +class ParallelFor< FunctorType , + Kokkos::Experimental::WorkGraphPolicy< Traits ... > , + Kokkos::Serial + > + : public Kokkos::Impl::Experimental:: + WorkGraphExec< FunctorType, + Kokkos::Serial, + Traits ... + > +{ +private: + + typedef Kokkos::Experimental::WorkGraphPolicy< Traits ... > Policy ; + typedef Kokkos::Impl::Experimental:: + WorkGraphExec Base ; + + template< class TagType > + typename std::enable_if< std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + Base::m_functor( i ); + } + + template< class TagType > + typename std::enable_if< ! std::is_same< TagType , void >::value >::type + exec_one(const typename Policy::member_type& i) const { + const TagType t{} ; + Base::m_functor( t , i ); + } + +public: + + inline + void execute() + { + for (std::int32_t i; (-1 != (i = Base::before_work())); ) { + exec_one< typename Policy::work_tag >( i ); + Base::after_work(i); + } + } + + inline + ParallelFor( const FunctorType & arg_functor + , const Policy & arg_policy ) + : Base( arg_functor, arg_policy ) + { + } +}; + +} // namespace Impl +} // namespace Kokkos + +#endif /* #define KOKKOS_SERIAL_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.cpp b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.cpp index e28c1194a7..af79523e0c 100644 --- a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.cpp +++ b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.cpp @@ -46,23 +46,23 @@ namespace Kokkos { namespace Impl { -int SharedAllocationRecord< void , void >::s_tracking_enabled = 1 ; +namespace { -void SharedAllocationRecord< void , void >::tracking_claim_and_disable() -{ - // A host thread claim and disable tracking flag +__thread int t_tracking_enabled = 1; - while ( ! Kokkos::atomic_compare_exchange_strong( & s_tracking_enabled, 1, 0 ) ); } -void SharedAllocationRecord< void , void >::tracking_release_and_enable() -{ - // The host thread that claimed and disabled the tracking flag - // now release and enable tracking. +int SharedAllocationRecord< void , void >::tracking_enabled() +{ return t_tracking_enabled; } - if ( ! Kokkos::atomic_compare_exchange_strong( & s_tracking_enabled, 0, 1 ) ){ - Kokkos::Impl::throw_runtime_exception("Kokkos::Impl::SharedAllocationRecord<>::tracking_release_and_enable FAILED, this host process thread did not hold the lock" ); - } +void SharedAllocationRecord< void , void >::tracking_disable() +{ + t_tracking_enabled = 0; +} + +void SharedAllocationRecord< void , void >::tracking_enable() +{ + t_tracking_enabled = 1; } //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp index 4dc61bb02e..2e3cc1a163 100644 --- a/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_SharedAlloc.hpp @@ -71,6 +71,9 @@ public: KOKKOS_INLINE_FUNCTION static const SharedAllocationHeader * get_header( void * alloc_ptr ) { return reinterpret_cast( reinterpret_cast(alloc_ptr) - sizeof(SharedAllocationHeader) ); } + + KOKKOS_INLINE_FUNCTION + const char* label() const { return m_label; } }; template<> @@ -83,8 +86,6 @@ protected: typedef void (* function_type )( SharedAllocationRecord * ); - static int s_tracking_enabled ; - SharedAllocationHeader * const m_alloc_ptr ; size_t const m_alloc_size ; function_type const m_dealloc ; @@ -110,17 +111,17 @@ protected: public: inline std::string get_label() const { return std::string("Unmanaged"); } - static int tracking_enabled() { return s_tracking_enabled ; } + static int tracking_enabled(); /**\brief A host process thread claims and disables the * shared allocation tracking flag. */ - static void tracking_claim_and_disable(); + static void tracking_disable(); /**\brief A host process thread releases and enables the * shared allocation tracking flag. */ - static void tracking_release_and_enable(); + static void tracking_enable(); ~SharedAllocationRecord() = default ; @@ -317,6 +318,11 @@ public: #endif } + KOKKOS_INLINE_FUNCTION + bool has_record() const { + return (m_record_bits & (~DO_NOT_DEREF_FLAG)) != 0; + } + KOKKOS_FORCEINLINE_FUNCTION ~SharedAllocationTracker() { KOKKOS_IMPL_SHARED_ALLOCATION_TRACKER_DECREMENT } diff --git a/lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp b/lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp new file mode 100644 index 0000000000..3d3f83ed85 --- /dev/null +++ b/lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp @@ -0,0 +1,210 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + +#include +#include +#include + +#if defined( KOKKOS_ENABLE_STDTHREAD ) + #include +#elif !defined( _WIN32 ) + #include + #include +#else + #include + #include + #include +#endif + +/*--------------------------------------------------------------------------*/ + +namespace Kokkos { +namespace Impl { +namespace { + +void host_thread_yield( const uint32_t i , const int force_yield ) +{ + static constexpr uint32_t sleep_limit = 1 << 13 ; + static constexpr uint32_t yield_limit = 1 << 12 ; + + const int c = Kokkos::Impl::bit_scan_reverse(i); + + if ( sleep_limit < i ) { + + // Attempt to put the thread to sleep for 'c' milliseconds + + #if defined( KOKKOS_ENABLE_STDTHREAD ) + std::this_thread::sleep_for( std::chrono::nanoseconds( c * 1000 ) ) + #elif !defined( _WIN32 ) + timespec req ; + req.tv_sec = 0 ; + req.tv_nsec = 1000 * c ; + nanosleep( &req, nullptr ); + #else /* defined( _WIN32 ) IS Microsoft Windows */ + Sleep(c); + #endif + } + + else if ( force_yield || yield_limit < i ) { + + // Attempt to yield thread resources to runtime + + #if defined( KOKKOS_ENABLE_STDTHREAD ) + std::this_thread::yield(); + #elif !defined( _WIN32 ) + sched_yield(); + #else /* defined( _WIN32 ) IS Microsoft Windows */ + YieldProcessor(); + #endif + } + + #if defined( KOKKOS_ENABLE_ASM ) + + else if ( (1u<<4) < i ) { + + // Insert a few no-ops to quiet the thread: + + for ( int k = 0 ; k < c ; ++k ) { + #if defined( __amd64 ) || defined( __amd64__ ) || \ + defined( __x86_64 ) || defined( __x86_64__ ) + #if !defined( _WIN32 ) /* IS NOT Microsoft Windows */ + asm volatile( "nop\n" ); + #else + __asm__ __volatile__( "nop\n" ); + #endif + #elif defined(__PPC64__) + asm volatile( "nop\n" ); + #endif + } + } + + { + // Insert memory pause + #if defined( __amd64 ) || defined( __amd64__ ) || \ + defined( __x86_64 ) || defined( __x86_64__ ) + #if !defined( _WIN32 ) /* IS NOT Microsoft Windows */ + asm volatile( "pause\n":::"memory" ); + #else + __asm__ __volatile__( "pause\n":::"memory" ); + #endif + #elif defined(__PPC64__) + asm volatile( "or 27, 27, 27" ::: "memory" ); + #endif + } + + #endif /* defined( KOKKOS_ENABLE_ASM ) */ +} + +}}} // namespace Kokkos::Impl::{anonymous} + +/*--------------------------------------------------------------------------*/ + +namespace Kokkos { +namespace Impl { + +void spinwait_while_equal( volatile int32_t & flag , const int32_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value == flag ) host_thread_yield(++i,0); + Kokkos::load_fence(); +} + +void spinwait_until_equal( volatile int32_t & flag , const int32_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value != flag ) host_thread_yield(++i,0); + Kokkos::load_fence(); +} + +void spinwait_while_equal( volatile int64_t & flag , const int64_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value == flag ) host_thread_yield(++i,0); + Kokkos::load_fence(); +} + +void spinwait_until_equal( volatile int64_t & flag , const int64_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value != flag ) host_thread_yield(++i,0); + Kokkos::load_fence(); +} + +void yield_while_equal( volatile int32_t & flag , const int32_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value == flag ) host_thread_yield(++i,1); + Kokkos::load_fence(); +} + +void yield_until_equal( volatile int32_t & flag , const int32_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value != flag ) host_thread_yield(++i,1); + Kokkos::load_fence(); +} + +void yield_while_equal( volatile int64_t & flag , const int64_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value == flag ) host_thread_yield(++i,1); + Kokkos::load_fence(); +} + +void yield_until_equal( volatile int64_t & flag , const int64_t value ) +{ + Kokkos::store_fence(); + uint32_t i = 0 ; while( value != flag ) host_thread_yield(++i,1); + Kokkos::load_fence(); +} + +} /* namespace Impl */ +} /* namespace Kokkos */ + +#else +void KOKKOS_CORE_SRC_IMPL_SPINWAIT_PREVENT_LINK_ERROR() {} +#endif + diff --git a/lib/kokkos/core/src/impl/Kokkos_spinwait.hpp b/lib/kokkos/core/src/impl/Kokkos_Spinwait.hpp similarity index 82% rename from lib/kokkos/core/src/impl/Kokkos_spinwait.hpp rename to lib/kokkos/core/src/impl/Kokkos_Spinwait.hpp index 6e34b8a943..b49e308566 100644 --- a/lib/kokkos/core/src/impl/Kokkos_spinwait.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_Spinwait.hpp @@ -59,6 +59,13 @@ void spinwait_until_equal( volatile int32_t & flag , const int32_t value ); void spinwait_while_equal( volatile int64_t & flag , const int64_t value ); void spinwait_until_equal( volatile int64_t & flag , const int64_t value ); + +void yield_while_equal( volatile int32_t & flag , const int32_t value ); +void yield_until_equal( volatile int32_t & flag , const int32_t value ); + +void yield_while_equal( volatile int64_t & flag , const int64_t value ); +void yield_until_equal( volatile int64_t & flag , const int64_t value ); + #else KOKKOS_INLINE_FUNCTION @@ -71,6 +78,16 @@ void spinwait_while_equal( volatile int64_t & , const int64_t ) {} KOKKOS_INLINE_FUNCTION void spinwait_until_equal( volatile int64_t & , const int64_t ) {} +KOKKOS_INLINE_FUNCTION +void yield_while_equal( volatile int32_t & , const int32_t ) {} +KOKKOS_INLINE_FUNCTION +void yield_until_equal( volatile int32_t & , const int32_t ) {} + +KOKKOS_INLINE_FUNCTION +void yield_while_equal( volatile int64_t & , const int64_t ) {} +KOKKOS_INLINE_FUNCTION +void yield_until_equal( volatile int64_t & , const int64_t ) {} + #endif } /* namespace Impl */ diff --git a/lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp b/lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp index bee98e6745..5f8699302d 100644 --- a/lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp @@ -59,24 +59,15 @@ namespace Kokkos { namespace Impl { -/*\brief Implementation data for task data management, access, and execution. - * - * Curiously recurring template pattern (CRTP) - * to allow static_cast from the - * task root type and a task's FunctorType. - * - * TaskBase< Space , ResultType , FunctorType > - * : TaskBase< Space , ResultType , void > - * , FunctorType - * { ... }; - * - * TaskBase< Space , ResultType , void > - * : TaskBase< Space , void , void > - * { ... }; - */ -template< typename Space , typename ResultType , typename FunctorType > +template< class Space , typename ResultType , class FunctorType > class TaskBase ; +template< typename Space > +class TaskQueue ; + +template< typename Space > +class TaskQueueSpecialization ; + } /* namespace Impl */ } /* namespace Kokkos */ @@ -86,8 +77,217 @@ class TaskBase ; namespace Kokkos { namespace Impl { -template< typename Space > -class TaskQueueSpecialization ; +/** \brief Base class for task management, access, and execution. + * + * Inheritance structure to allow static_cast from the task root type + * and a task's FunctorType. + * + * // Enable a functor to access the base class + * // and provide memory for result value. + * TaskBase< Space , ResultType , FunctorType > + * : TaskBase< void , void , void > + * , FunctorType + * { ... }; + * Followed by memory allocated for result value. + * + * + * States of a task: + * + * Constructing State, NOT IN a linked list + * m_wait == 0 + * m_next == 0 + * + * Scheduling transition : Constructing -> Waiting + * before: + * m_wait == 0 + * m_next == this task's initial dependence, 0 if none + * after: + * m_wait == EndTag + * m_next == EndTag + * + * Waiting State, IN a linked list + * m_apply != 0 + * m_queue != 0 + * m_ref_count > 0 + * m_wait == head of linked list of tasks waiting on this task + * m_next == next of linked list of tasks + * + * transition : Waiting -> Executing + * before: + * m_next == EndTag + * after:: + * m_next == LockTag + * + * Executing State, NOT IN a linked list + * m_apply != 0 + * m_queue != 0 + * m_ref_count > 0 + * m_wait == head of linked list of tasks waiting on this task + * m_next == LockTag + * + * Respawn transition : Executing -> Executing-Respawn + * before: + * m_next == LockTag + * after: + * m_next == this task's updated dependence, 0 if none + * + * Executing-Respawn State, NOT IN a linked list + * m_apply != 0 + * m_queue != 0 + * m_ref_count > 0 + * m_wait == head of linked list of tasks waiting on this task + * m_next == this task's updated dependence, 0 if none + * + * transition : Executing -> Complete + * before: + * m_wait == head of linked list + * after: + * m_wait == LockTag + * + * Complete State, NOT IN a linked list + * m_wait == LockTag: cannot add dependence (<=> complete) + * m_next == LockTag: not a member of a wait queue + * + */ +template<> +class TaskBase< void , void , void > +{ +public: + + enum : int16_t { TaskTeam = 0 , TaskSingle = 1 , Aggregate = 2 }; + enum : uintptr_t { LockTag = ~uintptr_t(0) , EndTag = ~uintptr_t(1) }; + + template< typename > friend class Kokkos::TaskScheduler ; + + typedef TaskQueue< void > queue_type ; + + typedef void (* function_type) ( TaskBase * , void * ); + + // sizeof(TaskBase) == 48 + + function_type m_apply ; ///< Apply function pointer + queue_type * m_queue ; ///< Pointer to queue + TaskBase * m_wait ; ///< Linked list of tasks waiting on this + TaskBase * m_next ; ///< Waiting linked-list next + int32_t m_ref_count ; ///< Reference count + int32_t m_alloc_size ; ///< Allocation size + int32_t m_dep_count ; ///< Aggregate's number of dependences + int16_t m_task_type ; ///< Type of task + int16_t m_priority ; ///< Priority of runnable task + + TaskBase( TaskBase && ) = delete ; + TaskBase( const TaskBase & ) = delete ; + TaskBase & operator = ( TaskBase && ) = delete ; + TaskBase & operator = ( const TaskBase & ) = delete ; + + KOKKOS_INLINE_FUNCTION ~TaskBase() = default ; + + KOKKOS_INLINE_FUNCTION constexpr + TaskBase() + : m_apply( 0 ) + , m_queue( 0 ) + , m_wait( 0 ) + , m_next( 0 ) + , m_ref_count( 0 ) + , m_alloc_size( 0 ) + , m_dep_count( 0 ) + , m_task_type( 0 ) + , m_priority( 0 ) + {} + + //---------------------------------------- + + KOKKOS_INLINE_FUNCTION + TaskBase * volatile * aggregate_dependences() volatile + { return reinterpret_cast( this + 1 ); } + + KOKKOS_INLINE_FUNCTION + bool requested_respawn() + { + // This should only be called when a task has finished executing and is + // in the transition to either the complete or executing-respawn state. + TaskBase * const lock = reinterpret_cast< TaskBase * >( LockTag ); + return lock != m_next; + } + + KOKKOS_INLINE_FUNCTION + void add_dependence( TaskBase* dep ) + { + // Precondition: lock == m_next + + TaskBase * const lock = (TaskBase *) LockTag ; + + // Assign dependence to m_next. It will be processed in the subsequent + // call to schedule. Error if the dependence is reset. + if ( lock != Kokkos::atomic_exchange( & m_next, dep ) ) { + Kokkos::abort("TaskScheduler ERROR: resetting task dependence"); + } + + if ( 0 != dep ) { + // The future may be destroyed upon returning from this call + // so increment reference count to track this assignment. + Kokkos::atomic_increment( &(dep->m_ref_count) ); + } + } + + //---------------------------------------- + + KOKKOS_INLINE_FUNCTION + int32_t reference_count() const + { return *((int32_t volatile *)( & m_ref_count )); } + +}; + +static_assert( sizeof(TaskBase) == 48 + , "Verifying expected sizeof(TaskBase)" ); + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +template< typename ResultType > +struct TaskResult { + + enum : int32_t { size = sizeof(ResultType) }; + + using reference_type = ResultType & ; + + KOKKOS_INLINE_FUNCTION static + ResultType * ptr( TaskBase * task ) + { + return reinterpret_cast< ResultType * > + ( reinterpret_cast< char * >(task) + task->m_alloc_size - sizeof(ResultType) ); + } + + KOKKOS_INLINE_FUNCTION static + reference_type get( TaskBase * task ) + { return *ptr( task ); } +}; + +template<> +struct TaskResult< void > { + + enum : int32_t { size = 0 }; + + using reference_type = void ; + + KOKKOS_INLINE_FUNCTION static + void * ptr( TaskBase * ) { return (void*) 0 ; } + + KOKKOS_INLINE_FUNCTION static + reference_type get( TaskBase * ) {} +}; + +} /* namespace Impl */ +} /* namespace Kokkos */ + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +namespace Kokkos { +namespace Impl { + +template<> +class TaskQueue< void > {}; /** \brief Manage task allocation, deallocation, and scheduling. * @@ -95,7 +295,7 @@ class TaskQueueSpecialization ; * All other aspects of task management have shared implementation. */ template< typename ExecSpace > -class TaskQueue { +class TaskQueue : public TaskQueue { private: friend class TaskQueueSpecialization< ExecSpace > ; @@ -106,7 +306,7 @@ private: using memory_space = typename specialization::memory_space ; using device_type = Kokkos::Device< execution_space , memory_space > ; using memory_pool = Kokkos::MemoryPool< device_type > ; - using task_root_type = Kokkos::Impl::TaskBase ; + using task_root_type = Kokkos::Impl::TaskBase ; struct Destroy { TaskQueue * m_queue ; @@ -198,12 +398,10 @@ public: } // Assign task pointer with reference counting of assigned tasks - template< typename LV , typename RV > KOKKOS_FUNCTION static - void assign( TaskBase< execution_space,LV,void> ** const lhs - , TaskBase< execution_space,RV,void> * const rhs ) + void assign( task_root_type ** const lhs + , task_root_type * const rhs ) { - using task_lhs = TaskBase< execution_space,LV,void> ; #if 0 { printf( "assign( 0x%lx { 0x%lx %d %d } , 0x%lx { 0x%lx %d %d } )\n" @@ -225,7 +423,7 @@ public: // Force write of *lhs - *static_cast< task_lhs * volatile * >(lhs) = rhs ; + *static_cast< task_root_type * volatile * >(lhs) = rhs ; Kokkos::memory_fence(); } @@ -238,6 +436,38 @@ public: KOKKOS_FUNCTION void deallocate( void * p , size_t n ); ///< Deallocate to the memory pool + + + //---------------------------------------- + /**\brief Allocation size for a spawned task */ + + template< typename FunctorType > + KOKKOS_FUNCTION + size_t spawn_allocation_size() const + { + using value_type = typename FunctorType::value_type ; + + using task_type = Impl::TaskBase< execution_space + , value_type + , FunctorType > ; + + enum : size_t { align = ( 1 << 4 ) , align_mask = align - 1 }; + enum : size_t { task_size = sizeof(task_type) }; + enum : size_t { result_size = Impl::TaskResult< value_type >::size }; + enum : size_t { alloc_size = + ( ( task_size + align_mask ) & ~align_mask ) + + ( ( result_size + align_mask ) & ~align_mask ) }; + + return m_memory.allocate_block_size( task_size ); + } + + /**\brief Allocation size for a when_all aggregate */ + + KOKKOS_FUNCTION + size_t when_all_allocation_size( int narg ) const + { + return m_memory.allocate_block_size( sizeof(task_root_type) + narg * sizeof(task_root_type*) ); + } }; } /* namespace Impl */ @@ -249,261 +479,9 @@ public: namespace Kokkos { namespace Impl { -template<> -class TaskBase< void , void , void > { -public: - enum : int16_t { TaskTeam = 0 , TaskSingle = 1 , Aggregate = 2 }; - enum : uintptr_t { LockTag = ~uintptr_t(0) , EndTag = ~uintptr_t(1) }; -}; - -/** \brief Base class for task management, access, and execution. - * - * Inheritance structure to allow static_cast from the task root type - * and a task's FunctorType. - * - * // Enable a Future to access result data - * TaskBase< Space , ResultType , void > - * : TaskBase< void , void , void > - * { ... }; - * - * // Enable a functor to access the base class - * TaskBase< Space , ResultType , FunctorType > - * : TaskBase< Space , ResultType , void > - * , FunctorType - * { ... }; - * - * - * States of a task: - * - * Constructing State, NOT IN a linked list - * m_wait == 0 - * m_next == 0 - * - * Scheduling transition : Constructing -> Waiting - * before: - * m_wait == 0 - * m_next == this task's initial dependence, 0 if none - * after: - * m_wait == EndTag - * m_next == EndTag - * - * Waiting State, IN a linked list - * m_apply != 0 - * m_queue != 0 - * m_ref_count > 0 - * m_wait == head of linked list of tasks waiting on this task - * m_next == next of linked list of tasks - * - * transition : Waiting -> Executing - * before: - * m_next == EndTag - * after:: - * m_next == LockTag - * - * Executing State, NOT IN a linked list - * m_apply != 0 - * m_queue != 0 - * m_ref_count > 0 - * m_wait == head of linked list of tasks waiting on this task - * m_next == LockTag - * - * Respawn transition : Executing -> Executing-Respawn - * before: - * m_next == LockTag - * after: - * m_next == this task's updated dependence, 0 if none - * - * Executing-Respawn State, NOT IN a linked list - * m_apply != 0 - * m_queue != 0 - * m_ref_count > 0 - * m_wait == head of linked list of tasks waiting on this task - * m_next == this task's updated dependence, 0 if none - * - * transition : Executing -> Complete - * before: - * m_wait == head of linked list - * after: - * m_wait == LockTag - * - * Complete State, NOT IN a linked list - * m_wait == LockTag: cannot add dependence - * m_next == LockTag: not a member of a wait queue - * - */ -template< typename ExecSpace > -class TaskBase< ExecSpace , void , void > -{ -public: - - enum : int16_t { TaskTeam = TaskBase::TaskTeam - , TaskSingle = TaskBase::TaskSingle - , Aggregate = TaskBase::Aggregate }; - - enum : uintptr_t { LockTag = TaskBase::LockTag - , EndTag = TaskBase::EndTag }; - - using execution_space = ExecSpace ; - using queue_type = TaskQueue< execution_space > ; - - template< typename > friend class Kokkos::TaskScheduler ; - - typedef void (* function_type) ( TaskBase * , void * ); - - // sizeof(TaskBase) == 48 - - function_type m_apply ; ///< Apply function pointer - queue_type * m_queue ; ///< Queue in which this task resides - TaskBase * m_wait ; ///< Linked list of tasks waiting on this - TaskBase * m_next ; ///< Waiting linked-list next - int32_t m_ref_count ; ///< Reference count - int32_t m_alloc_size ; ///< Allocation size - int32_t m_dep_count ; ///< Aggregate's number of dependences - int16_t m_task_type ; ///< Type of task - int16_t m_priority ; ///< Priority of runnable task - - TaskBase() = delete ; - TaskBase( TaskBase && ) = delete ; - TaskBase( const TaskBase & ) = delete ; - TaskBase & operator = ( TaskBase && ) = delete ; - TaskBase & operator = ( const TaskBase & ) = delete ; - - KOKKOS_INLINE_FUNCTION ~TaskBase() = default ; - - // Constructor for a runnable task - KOKKOS_INLINE_FUNCTION - constexpr TaskBase( function_type arg_apply - , queue_type * arg_queue - , TaskBase * arg_dependence - , int arg_ref_count - , int arg_alloc_size - , int arg_task_type - , int arg_priority - ) noexcept - : m_apply( arg_apply ) - , m_queue( arg_queue ) - , m_wait( 0 ) - , m_next( arg_dependence ) - , m_ref_count( arg_ref_count ) - , m_alloc_size( arg_alloc_size ) - , m_dep_count( 0 ) - , m_task_type( arg_task_type ) - , m_priority( arg_priority ) - {} - - // Constructor for an aggregate task - KOKKOS_INLINE_FUNCTION - constexpr TaskBase( queue_type * arg_queue - , int arg_ref_count - , int arg_alloc_size - , int arg_dep_count - ) noexcept - : m_apply( 0 ) - , m_queue( arg_queue ) - , m_wait( 0 ) - , m_next( 0 ) - , m_ref_count( arg_ref_count ) - , m_alloc_size( arg_alloc_size ) - , m_dep_count( arg_dep_count ) - , m_task_type( Aggregate ) - , m_priority( 0 ) - {} - - //---------------------------------------- - - KOKKOS_INLINE_FUNCTION - TaskBase ** aggregate_dependences() - { return reinterpret_cast( this + 1 ); } - - KOKKOS_INLINE_FUNCTION - bool requested_respawn() - { - // This should only be called when a task has finished executing and is - // in the transition to either the complete or executing-respawn state. - TaskBase * const lock = reinterpret_cast< TaskBase * >( LockTag ); - return lock != m_next; - } - - KOKKOS_INLINE_FUNCTION - void add_dependence( TaskBase* dep ) - { - // Precondition: lock == m_next - - TaskBase * const lock = (TaskBase *) LockTag ; - - // Assign dependence to m_next. It will be processed in the subsequent - // call to schedule. Error if the dependence is reset. - if ( lock != Kokkos::atomic_exchange( & m_next, dep ) ) { - Kokkos::abort("TaskScheduler ERROR: resetting task dependence"); - } - - if ( 0 != dep ) { - // The future may be destroyed upon returning from this call - // so increment reference count to track this assignment. - Kokkos::atomic_increment( &(dep->m_ref_count) ); - } - } - - using get_return_type = void ; - - KOKKOS_INLINE_FUNCTION - get_return_type get() const {} -}; - -template < typename ExecSpace , typename ResultType > -class TaskBase< ExecSpace , ResultType , void > - : public TaskBase< ExecSpace , void , void > -{ -private: - - using root_type = TaskBase ; - using function_type = typename root_type::function_type ; - using queue_type = typename root_type::queue_type ; - - static_assert( sizeof(root_type) == 48 , "" ); - - TaskBase() = delete ; - TaskBase( TaskBase && ) = delete ; - TaskBase( const TaskBase & ) = delete ; - TaskBase & operator = ( TaskBase && ) = delete ; - TaskBase & operator = ( const TaskBase & ) = delete ; - -public: - - ResultType m_result ; - - KOKKOS_INLINE_FUNCTION ~TaskBase() = default ; - - // Constructor for runnable task - KOKKOS_INLINE_FUNCTION - constexpr TaskBase( function_type arg_apply - , queue_type * arg_queue - , root_type * arg_dependence - , int arg_ref_count - , int arg_alloc_size - , int arg_task_type - , int arg_priority - ) - : root_type( arg_apply - , arg_queue - , arg_dependence - , arg_ref_count - , arg_alloc_size - , arg_task_type - , arg_priority - ) - , m_result() - {} - - using get_return_type = ResultType const & ; - - KOKKOS_INLINE_FUNCTION - get_return_type get() const { return m_result ; } -}; - -template< typename ExecSpace , typename ResultType , typename FunctorType > +template< class ExecSpace , typename ResultType , class FunctorType > class TaskBase - : public TaskBase< ExecSpace , ResultType , void > + : public TaskBase< void , void , void > , public FunctorType { private: @@ -516,50 +494,31 @@ private: public: - using root_type = TaskBase< ExecSpace , void , void > ; - using base_type = TaskBase< ExecSpace , ResultType , void > ; - using specialization = TaskQueueSpecialization< ExecSpace > ; - using function_type = typename root_type::function_type ; - using queue_type = typename root_type::queue_type ; - using member_type = typename specialization::member_type ; + using root_type = TaskBase< void , void , void > ; using functor_type = FunctorType ; using result_type = ResultType ; - template< typename Type > - KOKKOS_INLINE_FUNCTION static - void apply_functor - ( Type * const task - , typename std::enable_if - < std::is_same< typename Type::result_type , void >::value - , member_type * const - >::type member - ) - { - using fType = typename Type::functor_type ; - static_cast(task)->operator()( *member ); - } + using specialization = TaskQueueSpecialization< ExecSpace > ; + using member_type = typename specialization::member_type ; - template< typename Type > - KOKKOS_INLINE_FUNCTION static - void apply_functor - ( Type * const task - , typename std::enable_if - < ! std::is_same< typename Type::result_type , void >::value - , member_type * const - >::type member - ) - { - using fType = typename Type::functor_type ; - static_cast(task)->operator()( *member , task->m_result ); - } + KOKKOS_INLINE_FUNCTION + void apply_functor( member_type * const member , void * ) + { functor_type::operator()( *member ); } + + template< typename T > + KOKKOS_INLINE_FUNCTION + void apply_functor( member_type * const member + , T * const result ) + { functor_type::operator()( *member , *result ); } KOKKOS_FUNCTION static void apply( root_type * root , void * exec ) { TaskBase * const task = static_cast< TaskBase * >( root ); member_type * const member = reinterpret_cast< member_type * >( exec ); + result_type * const result = TaskResult< result_type >::ptr( task ); - TaskBase::template apply_functor( task , member ); + task->apply_functor( member , result ); // Task may be serial or team. // If team then must synchronize before querying if respawn was requested. @@ -576,26 +535,9 @@ public: } // Constructor for runnable task - KOKKOS_INLINE_FUNCTION - constexpr TaskBase( function_type arg_apply - , queue_type * arg_queue - , root_type * arg_dependence - , int arg_ref_count - , int arg_alloc_size - , int arg_task_type - , int arg_priority - , FunctorType && arg_functor - ) - : base_type( arg_apply - , arg_queue - , arg_dependence - , arg_ref_count - , arg_alloc_size - , arg_task_type - , arg_priority - ) - , functor_type( arg_functor ) - {} + KOKKOS_INLINE_FUNCTION constexpr + TaskBase( FunctorType && arg_functor ) + : root_type() , functor_type( std::move(arg_functor) ) {} KOKKOS_INLINE_FUNCTION ~TaskBase() {} diff --git a/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp b/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp index aee381afad..1974f7e1ca 100644 --- a/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_TaskQueue_impl.hpp @@ -44,6 +44,8 @@ #include #if defined( KOKKOS_ENABLE_TASKDAG ) +#define KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING 0 + namespace Kokkos { namespace Impl { @@ -100,9 +102,11 @@ KOKKOS_FUNCTION void TaskQueue< ExecSpace >::decrement ( TaskQueue< ExecSpace >::task_root_type * task ) { - const int count = Kokkos::atomic_fetch_add(&(task->m_ref_count),-1); + task_root_type volatile & t = *task ; -#if 0 + const int count = Kokkos::atomic_fetch_add(&(t.m_ref_count),-1); + +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING if ( 1 == count ) { printf( "decrement-destroy( 0x%lx { 0x%lx %d %d } )\n" , uintptr_t( task ) @@ -114,9 +118,13 @@ void TaskQueue< ExecSpace >::decrement #endif if ( ( 1 == count ) && - ( task->m_next == (task_root_type *) task_root_type::LockTag ) ) { + ( t.m_next == (task_root_type *) task_root_type::LockTag ) ) { // Reference count is zero and task is complete, deallocate. - task->m_queue->deallocate( task , task->m_alloc_size ); + + TaskQueue< ExecSpace > * const queue = + static_cast< TaskQueue< ExecSpace > * >( t.m_queue ); + + queue->deallocate( task , t.m_alloc_size ); } else if ( count <= 1 ) { Kokkos::abort("TaskScheduler task has negative reference count or is incomplete" ); @@ -171,7 +179,7 @@ bool TaskQueue< ExecSpace >::push_task // Fail the push attempt if the queue is locked; // otherwise retry until the push succeeds. -#if 0 +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING printf( "push_task( 0x%lx { 0x%lx } 0x%lx { 0x%lx 0x%lx %d %d %d } )\n" , uintptr_t(queue) , uintptr_t(*queue) @@ -186,9 +194,9 @@ bool TaskQueue< ExecSpace >::push_task task_root_type * const zero = (task_root_type *) 0 ; task_root_type * const lock = (task_root_type *) task_root_type::LockTag ; - task_root_type * volatile * const next = & task->m_next ; + task_root_type * volatile & next = task->m_next ; - if ( zero != *next ) { + if ( zero != next ) { Kokkos::abort("TaskQueue::push_task ERROR: already a member of another queue" ); } @@ -196,9 +204,9 @@ bool TaskQueue< ExecSpace >::push_task while ( lock != y ) { - *next = y ; + next = y ; - // Do not proceed until '*next' has been stored. + // Do not proceed until 'next' has been stored. Kokkos::memory_fence(); task_root_type * const x = y ; @@ -211,9 +219,9 @@ bool TaskQueue< ExecSpace >::push_task // Failed, replace 'task->m_next' value since 'task' remains // not a member of a queue. - *next = zero ; + next = zero ; - // Do not proceed until '*next' has been stored. + // Do not proceed until 'next' has been stored. Kokkos::memory_fence(); return false ; @@ -270,11 +278,13 @@ TaskQueue< ExecSpace >::pop_ready_task // This thread has exclusive access to // the queue and the popped task's m_next. - *queue = task->m_next ; task->m_next = lock ; + task_root_type * volatile & next = task->m_next ; + + *queue = next ; next = lock ; Kokkos::memory_fence(); -#if 0 +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING printf( "pop_ready_task( 0x%lx 0x%lx { 0x%lx 0x%lx %d %d %d } )\n" , uintptr_t(queue) , uintptr_t(task) @@ -323,7 +333,7 @@ void TaskQueue< ExecSpace >::schedule_runnable // task->m_wait == head of linked list (queue) // task->m_next == member of linked list (queue) -#if 0 +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING printf( "schedule_runnable( 0x%lx { 0x%lx 0x%lx %d %d %d }\n" , uintptr_t(task) , uintptr_t(task->m_wait) @@ -337,20 +347,22 @@ void TaskQueue< ExecSpace >::schedule_runnable task_root_type * const lock = (task_root_type *) task_root_type::LockTag ; task_root_type * const end = (task_root_type *) task_root_type::EndTag ; + task_root_type volatile & t = *task ; + bool respawn = false ; //---------------------------------------- - if ( zero == task->m_wait ) { + if ( zero == t.m_wait ) { // Task in Constructing state // - Transition to Waiting state // Preconditions: // - call occurs exclusively within a single thread - task->m_wait = end ; + t.m_wait = end ; // Task in Waiting state } - else if ( lock != task->m_wait ) { + else if ( lock != t.m_wait ) { // Task in Executing state with Respawn request // - Update dependence // - Transition to Waiting state @@ -373,7 +385,9 @@ void TaskQueue< ExecSpace >::schedule_runnable // Exclusive access so don't need an atomic exchange // task_root_type * dep = Kokkos::atomic_exchange( & task->m_next , zero ); - task_root_type * dep = task->m_next ; task->m_next = zero ; + task_root_type * dep = t.m_next ; t.m_next = zero ; + + Kokkos::memory_fence(); const bool is_ready = ( 0 == dep ) || ( ! push_task( & dep->m_wait , task ) ); @@ -398,7 +412,7 @@ void TaskQueue< ExecSpace >::schedule_runnable Kokkos::atomic_increment( & m_ready_count ); task_root_type * volatile * const ready_queue = - & m_ready[ task->m_priority ][ task->m_task_type ]; + & m_ready[ t.m_priority ][ t.m_task_type ]; // A push_task fails if the ready queue is locked. // A ready queue is only locked during a push or pop; @@ -441,7 +455,7 @@ void TaskQueue< ExecSpace >::schedule_aggregate // task->m_wait == head of linked list (queue) // task->m_next == member of linked list (queue) -#if 0 +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING printf( "schedule_aggregate( 0x%lx { 0x%lx 0x%lx %d %d %d }\n" , uintptr_t(task) , uintptr_t(task->m_wait) @@ -455,18 +469,20 @@ void TaskQueue< ExecSpace >::schedule_aggregate task_root_type * const lock = (task_root_type *) task_root_type::LockTag ; task_root_type * const end = (task_root_type *) task_root_type::EndTag ; + task_root_type volatile & t = *task ; + //---------------------------------------- - if ( zero == task->m_wait ) { + if ( zero == t.m_wait ) { // Task in Constructing state // - Transition to Waiting state // Preconditions: // - call occurs exclusively within a single thread - task->m_wait = end ; + t.m_wait = end ; // Task in Waiting state } - else if ( lock == task->m_wait ) { + else if ( lock == t.m_wait ) { // Task in Complete state Kokkos::abort("TaskQueue::schedule_aggregate ERROR: task is complete"); } @@ -477,14 +493,14 @@ void TaskQueue< ExecSpace >::schedule_aggregate // (1) created or // (2) being removed from a completed task's wait list. - task_root_type ** const aggr = task->aggregate_dependences(); + task_root_type * volatile * const aggr = t.aggregate_dependences(); // Assume the 'when_all' is complete until a dependence is // found that is not complete. bool is_complete = true ; - for ( int i = task->m_dep_count ; 0 < i && is_complete ; ) { + for ( int i = t.m_dep_count ; 0 < i && is_complete ; ) { --i ; @@ -523,7 +539,7 @@ void TaskQueue< ExecSpace >::schedule_aggregate // Complete the when_all 'task' to schedule other tasks // that are waiting for the when_all 'task' to complete. - task->m_next = lock ; + t.m_next = lock ; complete( task ); @@ -573,7 +589,7 @@ void TaskQueue< ExecSpace >::complete task_root_type * const lock = (task_root_type *) task_root_type::LockTag ; task_root_type * const end = (task_root_type *) task_root_type::EndTag ; -#if 0 +#if KOKKOS_IMPL_DEBUG_TASKDAG_SCHEDULING printf( "complete( 0x%lx { 0x%lx 0x%lx %d %d %d }\n" , uintptr_t(task) , uintptr_t(task->m_wait) @@ -584,11 +600,13 @@ void TaskQueue< ExecSpace >::complete fflush( stdout ); #endif - const bool runnable = task_root_type::Aggregate != task->m_task_type ; + task_root_type volatile & t = *task ; + + const bool runnable = task_root_type::Aggregate != t.m_task_type ; //---------------------------------------- - if ( runnable && lock != task->m_next ) { + if ( runnable && lock != t.m_next ) { // Is a runnable task has finished executing and requested respawn. // Schedule the task for subsequent execution. @@ -607,7 +625,7 @@ void TaskQueue< ExecSpace >::complete // Stop other tasks from adding themselves to this task's wait queue // by locking the head of this task's wait queue. - task_root_type * x = Kokkos::atomic_exchange( & task->m_wait , lock ); + task_root_type * x = Kokkos::atomic_exchange( & t.m_wait , lock ); if ( x != (task_root_type *) lock ) { @@ -627,9 +645,13 @@ void TaskQueue< ExecSpace >::complete // Have exclusive access to 'x' until it is scheduled // Set x->m_next = zero <= no dependence, not a respawn - task_root_type * const next = x->m_next ; x->m_next = 0 ; + task_root_type volatile & vx = *x ; - if ( task_root_type::Aggregate != x->m_task_type ) { + task_root_type * const next = vx.m_next ; vx.m_next = 0 ; + + Kokkos::memory_fence(); + + if ( task_root_type::Aggregate != vx.m_task_type ) { schedule_runnable( x ); } else { diff --git a/lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp b/lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp index c55636b64e..ed1a71bea7 100644 --- a/lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp @@ -1,13 +1,13 @@ /* //@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: @@ -36,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -47,7 +47,6 @@ #include namespace Kokkos { -namespace Experimental { namespace Impl { template< class DataType , class ArrayLayout , class V , size_t N , class P > @@ -94,13 +93,12 @@ public: typedef typename ViewDataType< non_const_scalar_type , array_scalar_dimension >::type non_const_scalar_array_type ; }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { /** \brief View mapping for non-specialized data type and standard layout */ @@ -597,7 +595,7 @@ public: } }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp b/lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp index 6381aee468..f32c6bb2ee 100644 --- a/lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp @@ -96,6 +96,27 @@ struct is_view_label< const char[N] > : public std::true_type {}; template< typename ... P > struct ViewCtorProp ; +// Forward declare +template< typename Specialize , typename T > +struct CommonViewAllocProp ; + +/* Common value_type stored as ViewCtorProp + */ +template< typename Specialize , typename T > +struct ViewCtorProp< void , CommonViewAllocProp > +{ + ViewCtorProp() = default ; + ViewCtorProp( const ViewCtorProp & ) = default ; + ViewCtorProp & operator = ( const ViewCtorProp & ) = default ; + + using type = CommonViewAllocProp ; + + ViewCtorProp( const type & arg ) : value( arg ) {} + ViewCtorProp( type && arg ) : value( arg ) {} + + type value ; +}; + /* std::integral_constant are dummy arguments * that avoid duplicate base class errors */ diff --git a/lib/kokkos/core/src/impl/Kokkos_ViewMapping.hpp b/lib/kokkos/core/src/impl/Kokkos_ViewMapping.hpp index 900bd88f1c..d346f9e639 100644 --- a/lib/kokkos/core/src/impl/Kokkos_ViewMapping.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_ViewMapping.hpp @@ -62,7 +62,6 @@ //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { template< unsigned I , size_t ... Args > @@ -250,7 +249,7 @@ struct ViewDimensionAssignable< ViewDimension< DstArgs ... > }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -266,14 +265,11 @@ struct ALL_t { }} // namespace Kokkos::Impl namespace Kokkos { -namespace Experimental { namespace Impl { -using Kokkos::Impl::ALL_t ; - template< class T > struct is_integral_extent_type -{ enum { value = std::is_same::value ? 1 : 0 }; }; +{ enum { value = std::is_same::value ? 1 : 0 }; }; template< class iType > struct is_integral_extent_type< std::pair > @@ -314,10 +310,10 @@ struct SubviewLegalArgsCompileTime; template struct SubviewLegalArgsCompileTime { - enum { value =(((CurrentArg==RankDest-1) && (Kokkos::Experimental::Impl::is_integral_extent_type::value)) || + enum { value =(((CurrentArg==RankDest-1) && (Kokkos::Impl::is_integral_extent_type::value)) || ((CurrentArg>=RankDest) && (std::is_integral::value)) || ((CurrentArg::value)) || - ((CurrentArg==0) && (Kokkos::Experimental::Impl::is_integral_extent_type::value)) + ((CurrentArg==0) && (Kokkos::Impl::is_integral_extent_type::value)) ) && (SubviewLegalArgsCompileTime::value)}; }; @@ -331,7 +327,7 @@ struct SubviewLegalArgsCompileTime struct SubviewLegalArgsCompileTime { - enum { value =(((CurrentArg==RankSrc-RankDest) && (Kokkos::Experimental::Impl::is_integral_extent_type::value)) || + enum { value =(((CurrentArg==RankSrc-RankDest) && (Kokkos::Impl::is_integral_extent_type::value)) || ((CurrentArg::value)) || ((CurrentArg>=RankSrc-RankDest) && (std::is_same::value)) ) && (SubviewLegalArgsCompileTime::value)}; @@ -403,7 +399,7 @@ private: bool set( unsigned domain_rank , unsigned range_rank , const ViewDimension< DimArgs ... > & dim - , const Kokkos::Experimental::Impl::ALL_t + , const Kokkos::Impl::ALL_t , Args ... args ) { m_begin[ domain_rank ] = 0 ; @@ -519,7 +515,7 @@ private: , unsigned domain_rank , unsigned range_rank , const ViewDimension< DimArgs ... > & dim - , const Kokkos::Experimental::Impl::ALL_t + , const Kokkos::Impl::ALL_t , Args ... args ) const { const int n = std::min( buf_len , @@ -670,13 +666,12 @@ public: { return unsigned(i) < InternalRangeRank ? m_index[i] : ~0u ; } }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { /** \brief Given a value type and dimension generate the View data type */ @@ -814,13 +809,12 @@ public: typedef non_const_type non_const_scalar_array_type ; }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { template < class Dimension , class Layout , typename Enable = void > @@ -1228,14 +1222,14 @@ private: // If memory alignment is a multiple of the trivial scalar size then attempt to align. enum { align = 0 != TrivialScalarSize && 0 == mod ? div : 0 }; - enum { div_ok = div ? div : 1 }; // To valid modulo zero in constexpr + enum { div_ok = (div != 0) ? div : 1 }; // To valid modulo zero in constexpr KOKKOS_INLINE_FUNCTION static constexpr size_t stride( size_t const N ) - { - return ( align && ( Kokkos::Impl::MEMORY_ALIGNMENT_THRESHOLD * align < N ) && ( N % div_ok ) ) - ? N + align - ( N % div_ok ) : N ; - } + { + return ( (align != 0) && ((Kokkos::Impl::MEMORY_ALIGNMENT_THRESHOLD * align) < N) && ((N % div_ok) != 0) ) + ? N + align - ( N % div_ok ) : N ; + } }; public: @@ -1707,12 +1701,12 @@ private: // If memory alignment is a multiple of the trivial scalar size then attempt to align. enum { align = 0 != TrivialScalarSize && 0 == mod ? div : 0 }; - enum { div_ok = div ? div : 1 }; // To valid modulo zero in constexpr + enum { div_ok = (div != 0) ? div : 1 }; // To valid modulo zero in constexpr KOKKOS_INLINE_FUNCTION static constexpr size_t stride( size_t const N ) { - return ( align && ( Kokkos::Impl::MEMORY_ALIGNMENT_THRESHOLD * align < N ) && ( N % div_ok ) ) + return ( (align != 0) && ((Kokkos::Impl::MEMORY_ALIGNMENT_THRESHOLD * align) < N) && ((N % div_ok) != 0) ) ? N + align - ( N % div_ok ) : N ; } }; @@ -2225,13 +2219,12 @@ public: {} }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { /** \brief ViewDataHandle provides the type of the 'data handle' which the view @@ -2422,13 +2415,12 @@ struct ViewDataHandle< Traits , return handle_type( arg_data_ptr + offset ); } }; -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { //---------------------------------------------------------------------------- @@ -2451,8 +2443,9 @@ template< class ExecSpace , class ValueType > struct ViewValueFunctor< ExecSpace , ValueType , false /* is_scalar */ > { typedef Kokkos::RangePolicy< ExecSpace > PolicyType ; + typedef typename ExecSpace::execution_space Exec; - ExecSpace space ; + Exec space ; ValueType * ptr ; size_t n ; bool destroy ; @@ -2597,6 +2590,9 @@ private: public: + typedef void printable_label_typedef; + enum { is_managed = Traits::is_managed }; + //---------------------------------------- // Domain dimensions @@ -2944,7 +2940,7 @@ public: Kokkos::abort("View Assignment: trying to assign runtime dimension to non matching compile time dimension."); } dst.m_offset = dst_offset_type( src.m_offset ); - dst.m_handle = Kokkos::Experimental::Impl::ViewDataHandle< DstTraits >::assign( src.m_handle , src_track ); + dst.m_handle = Kokkos::Impl::ViewDataHandle< DstTraits >::assign( src.m_handle , src_track ); } }; @@ -3102,7 +3098,7 @@ public: //---------------------------------------------------------------------------- -}}} // namespace Kokkos::Experimental::Impl +}} // namespace Kokkos::Impl //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -3151,6 +3147,77 @@ void view_error_operator_bounds view_error_operator_bounds(buf+n,len-n,map,args...); } +#if ! defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + +/* Check #3: is the View managed as determined by the MemoryTraits? */ +template< class MapType, + bool is_managed = (MapType::is_managed != 0) > +struct OperatorBoundsErrorOnDevice; + +template< class MapType > +struct OperatorBoundsErrorOnDevice< MapType, false > { +KOKKOS_INLINE_FUNCTION +static void run(MapType const&) { + Kokkos::abort("View bounds error"); +} +}; + +template< class MapType > +struct OperatorBoundsErrorOnDevice< MapType, true > { +KOKKOS_INLINE_FUNCTION +static void run(MapType const& map) { + char const* const user_alloc_start = reinterpret_cast(map.data()); + char const* const header_start = user_alloc_start - sizeof(SharedAllocationHeader); + SharedAllocationHeader const* const header = + reinterpret_cast(header_start); + char const* const label = header->label(); + enum { LEN = 128 }; + char msg[LEN]; + char const* const first_part = "View bounds error of view "; + char* p = msg; + char* const end = msg + LEN - 1; + for (char const* p2 = first_part; (*p2 != '\0') && (p < end); ++p, ++p2) { + *p = *p2; + } + for (char const* p2 = label; (*p2 != '\0') && (p < end); ++p, ++p2) { + *p = *p2; + } + *p = '\0'; + Kokkos::abort(msg); +} +}; + +/* Check #2: does the ViewMapping have the printable_label_typedef defined? + See above that only the non-specialized standard-layout ViewMapping has + this defined by default. + The existence of this typedef indicates the existence of MapType::is_managed */ +template< class T, class Enable = void > +struct has_printable_label_typedef : public std::false_type {}; + +template +struct has_printable_label_typedef< + T, typename enable_if_type::type> + : public std::true_type +{}; + +template< class MapType > +KOKKOS_INLINE_FUNCTION +void operator_bounds_error_on_device( + MapType const&, + std::false_type) { + Kokkos::abort("View bounds error"); +} + +template< class MapType > +KOKKOS_INLINE_FUNCTION +void operator_bounds_error_on_device( + MapType const& map, + std::true_type) { + OperatorBoundsErrorOnDevice< MapType >::run(map); +} + +#endif // ! defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + template< class MemorySpace , class MapType , class ... Args > KOKKOS_INLINE_FUNCTION void view_verify_operator_bounds @@ -3166,7 +3233,17 @@ void view_verify_operator_bounds view_error_operator_bounds<0>( buffer + n , LEN - n , map , args ... ); Kokkos::Impl::throw_runtime_exception(std::string(buffer)); #else - Kokkos::abort("View bounds error"); + /* Check #1: is there a SharedAllocationRecord? + (we won't use it, but if its not there then there isn't + a corresponding SharedAllocationHeader containing a label). + This check should cover the case of Views that don't + have the Unmanaged trait but were initialized by pointer. */ + if (tracker.has_record()) { + operator_bounds_error_on_device( + map, has_printable_label_typedef()); + } else { + Kokkos::abort("View bounds error"); + } #endif } } diff --git a/lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp b/lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp index ecbcf72fe0..5a8600e0ae 100644 --- a/lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp +++ b/lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp @@ -1,13 +1,13 @@ /* //@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: @@ -36,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact H. Carter Edwards (hcedwar@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -48,7 +48,6 @@ //---------------------------------------------------------------------------- namespace Kokkos { -namespace Experimental { namespace Impl { // View mapping for rank two tiled array @@ -195,11 +194,9 @@ struct ViewMapping }; } /* namespace Impl */ -} /* namespace Experimental */ } /* namespace Kokkos */ namespace Kokkos { -namespace Experimental { template< typename T , unsigned N0 , unsigned N1 , class ... P > KOKKOS_INLINE_FUNCTION @@ -217,7 +214,6 @@ tile_subview( const Kokkos::View,P...> & ( src , SrcLayout() , i_tile0 , i_tile1 ); } -} /* namespace Experimental */ } /* namespace Kokkos */ //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/impl/Kokkos_spinwait.cpp b/lib/kokkos/core/src/impl/Kokkos_spinwait.cpp deleted file mode 100644 index 101b714fcd..0000000000 --- a/lib/kokkos/core/src/impl/Kokkos_spinwait.cpp +++ /dev/null @@ -1,183 +0,0 @@ -/* -//@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 H. Carter Edwards (hcedwar@sandia.gov) -// -// ************************************************************************ -//@HEADER -*/ - -#include -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - -#include - -#include -#include - -/*--------------------------------------------------------------------------*/ - -#if !defined( _WIN32 ) - #if defined( KOKKOS_ENABLE_ASM ) - #if defined( __arm__ ) || defined( __aarch64__ ) - /* No-operation instruction to idle the thread. */ - #define KOKKOS_INTERNAL_PAUSE - #else - /* Pause instruction to prevent excess processor bus usage */ - #define KOKKOS_INTERNAL_PAUSE asm volatile("pause\n":::"memory") - #endif - #define KOKKOS_INTERNAL_NOP2 asm volatile("nop\n" "nop\n") - #define KOKKOS_INTERNAL_NOP4 KOKKOS_INTERNAL_NOP2; KOKKOS_INTERNAL_NOP2 - #define KOKKOS_INTERNAL_NOP8 KOKKOS_INTERNAL_NOP4; KOKKOS_INTERNAL_NOP4; - #define KOKKOS_INTERNAL_NOP16 KOKKOS_INTERNAL_NOP8; KOKKOS_INTERNAL_NOP8; - #define KOKKOS_INTERNAL_NOP32 KOKKOS_INTERNAL_NOP16; KOKKOS_INTERNAL_NOP16; - namespace { - inline void kokkos_internal_yield( const unsigned i ) noexcept { - switch (Kokkos::Impl::bit_scan_reverse((i >> 2)+1u)) { - case 0u: KOKKOS_INTERNAL_NOP2; break; - case 1u: KOKKOS_INTERNAL_NOP4; break; - case 2u: KOKKOS_INTERNAL_NOP8; break; - case 3u: KOKKOS_INTERNAL_NOP16; break; - default: KOKKOS_INTERNAL_NOP32; - } - KOKKOS_INTERNAL_PAUSE; - } - } - #else - #include - namespace { - inline void kokkos_internal_yield( const unsigned ) noexcept { - sched_yield(); - } - } - #endif -#else // defined( _WIN32 ) - #if defined ( KOKKOS_ENABLE_WINTHREAD ) - #include - namespace { - inline void kokkos_internal_yield( const unsigned ) noexcept { - Sleep(0); - } - } - #elif defined( _MSC_VER ) - #define NOMINMAX - #include - #include - namespace { - inline void kokkos_internal_yield( const unsigned ) noexcept { - YieldProcessor(); - } - } - #else - #define KOKKOS_INTERNAL_PAUSE __asm__ __volatile__("pause\n":::"memory") - #define KOKKOS_INTERNAL_NOP2 __asm__ __volatile__("nop\n" "nop") - #define KOKKOS_INTERNAL_NOP4 KOKKOS_INTERNAL_NOP2; KOKKOS_INTERNAL_NOP2 - #define KOKKOS_INTERNAL_NOP8 KOKKOS_INTERNAL_NOP4; KOKKOS_INTERNAL_NOP4; - #define KOKKOS_INTERNAL_NOP16 KOKKOS_INTERNAL_NOP8; KOKKOS_INTERNAL_NOP8; - #define KOKKOS_INTERNAL_NOP32 KOKKOS_INTERNAL_NOP16; KOKKOS_INTERNAL_NOP16; - namespace { - inline void kokkos_internal_yield( const unsigned i ) noexcept { - switch (Kokkos::Impl::bit_scan_reverse((i >> 2)+1u)) { - case 0: KOKKOS_INTERNAL_NOP2; break; - case 1: KOKKOS_INTERNAL_NOP4; break; - case 2: KOKKOS_INTERNAL_NOP8; break; - case 3: KOKKOS_INTERNAL_NOP16; break; - default: KOKKOS_INTERNAL_NOP32; - } - KOKKOS_INTERNAL_PAUSE; - } - } - #endif -#endif - - -/*--------------------------------------------------------------------------*/ - -namespace Kokkos { -namespace Impl { - -void spinwait_while_equal( volatile int32_t & flag , const int32_t value ) -{ - Kokkos::store_fence(); - unsigned i = 0; - while ( value == flag ) { - kokkos_internal_yield(i); - ++i; - } - Kokkos::load_fence(); -} - -void spinwait_until_equal( volatile int32_t & flag , const int32_t value ) -{ - Kokkos::store_fence(); - unsigned i = 0; - while ( value != flag ) { - kokkos_internal_yield(i); - ++i; - } - Kokkos::load_fence(); -} - -void spinwait_while_equal( volatile int64_t & flag , const int64_t value ) -{ - Kokkos::store_fence(); - unsigned i = 0; - while ( value == flag ) { - kokkos_internal_yield(i); - ++i; - } - Kokkos::load_fence(); -} - -void spinwait_until_equal( volatile int64_t & flag , const int64_t value ) -{ - Kokkos::store_fence(); - unsigned i = 0; - while ( value != flag ) { - kokkos_internal_yield(i); - ++i; - } - Kokkos::load_fence(); -} - -} /* namespace Impl */ -} /* namespace Kokkos */ - -#else -void KOKKOS_CORE_SRC_IMPL_SPINWAIT_PREVENT_LINK_ERROR() {} -#endif - diff --git a/lib/kokkos/core/unit_test/CMakeLists.txt b/lib/kokkos/core/unit_test/CMakeLists.txt index 5d6f25ac95..475b6bb48a 100644 --- a/lib/kokkos/core/unit_test/CMakeLists.txt +++ b/lib/kokkos/core/unit_test/CMakeLists.txt @@ -57,6 +57,7 @@ IF(Kokkos_ENABLE_Serial) serial/TestSerial_ViewMapping_b.cpp serial/TestSerial_ViewMapping_subview.cpp serial/TestSerial_ViewOfClass.cpp + serial/TestSerial_WorkGraph.cpp COMM serial mpi NUM_MPI_PROCS 1 FAIL_REGULAR_EXPRESSION " FAILED " @@ -102,6 +103,7 @@ IF(Kokkos_ENABLE_Pthread) threads/TestThreads_ViewMapping_b.cpp threads/TestThreads_ViewMapping_subview.cpp threads/TestThreads_ViewOfClass.cpp + threads/TestThreads_WorkGraph.cpp COMM serial mpi NUM_MPI_PROCS 1 FAIL_REGULAR_EXPRESSION " FAILED " @@ -147,6 +149,8 @@ IF(Kokkos_ENABLE_OpenMP) openmp/TestOpenMP_ViewMapping_b.cpp openmp/TestOpenMP_ViewMapping_subview.cpp openmp/TestOpenMP_ViewOfClass.cpp + openmp/TestOpenMP_WorkGraph.cpp + openmp/TestOpenMP_UniqueToken.cpp COMM serial mpi NUM_MPI_PROCS 1 FAIL_REGULAR_EXPRESSION " FAILED " @@ -237,6 +241,7 @@ IF(Kokkos_ENABLE_Cuda) cuda/TestCuda_ViewMapping_b.cpp cuda/TestCuda_ViewMapping_subview.cpp cuda/TestCuda_ViewOfClass.cpp + cuda/TestCuda_WorkGraph.cpp COMM serial mpi NUM_MPI_PROCS 1 FAIL_REGULAR_EXPRESSION " FAILED " @@ -253,6 +258,7 @@ TRIBITS_ADD_EXECUTABLE_AND_TEST( default/TestDefaultDeviceType_b.cpp default/TestDefaultDeviceType_c.cpp default/TestDefaultDeviceType_d.cpp + default/TestDefaultDeviceTypeResize.cpp COMM serial mpi NUM_MPI_PROCS 1 FAIL_REGULAR_EXPRESSION " FAILED " diff --git a/lib/kokkos/core/unit_test/Makefile b/lib/kokkos/core/unit_test/Makefile index 41f192a486..c877aa7dd2 100644 --- a/lib/kokkos/core/unit_test/Makefile +++ b/lib/kokkos/core/unit_test/Makefile @@ -62,8 +62,9 @@ endif OBJ_CUDA += TestCuda_TeamReductionScan.o OBJ_CUDA += TestCuda_Other.o OBJ_CUDA += TestCuda_MDRange.o - OBJ_CUDA += TestCuda_Task.o + OBJ_CUDA += TestCuda_Task.o TestCuda_WorkGraph.o OBJ_CUDA += TestCuda_Spaces.o + OBJ_CUDA += TestCuda_UniqueToken.o TARGETS += KokkosCore_UnitTest_Cuda @@ -121,7 +122,8 @@ endif OBJ_OPENMP += TestOpenMP_TeamReductionScan.o OBJ_OPENMP += TestOpenMP_Other.o OBJ_OPENMP += TestOpenMP_MDRange.o - OBJ_OPENMP += TestOpenMP_Task.o + OBJ_OPENMP += TestOpenMP_Task.o TestOpenMP_WorkGraph.o + OBJ_OPENMP += TestOpenMP_UniqueToken.o TARGETS += KokkosCore_UnitTest_OpenMP @@ -208,7 +210,7 @@ endif OBJ_SERIAL += TestSerial_TeamReductionScan.o OBJ_SERIAL += TestSerial_Other.o OBJ_SERIAL += TestSerial_MDRange.o - OBJ_SERIAL += TestSerial_Task.o + OBJ_SERIAL += TestSerial_Task.o TestSerial_WorkGraph.o TARGETS += KokkosCore_UnitTest_Serial diff --git a/lib/kokkos/core/unit_test/TestAggregate.hpp b/lib/kokkos/core/unit_test/TestAggregate.hpp index 6896a27bfb..87440c36be 100644 --- a/lib/kokkos/core/unit_test/TestAggregate.hpp +++ b/lib/kokkos/core/unit_test/TestAggregate.hpp @@ -58,7 +58,7 @@ template< class DeviceType > void TestViewAggregate() { typedef Kokkos::Array< double, 32 > value_type; - typedef Kokkos::Experimental::Impl::ViewDataAnalysis< value_type *, Kokkos::LayoutLeft, value_type > analysis_1d; + typedef Kokkos::Impl::ViewDataAnalysis< value_type *, Kokkos::LayoutLeft, value_type > analysis_1d; static_assert( std::is_same< typename analysis_1d::specialize, Kokkos::Array<> >::value, "" ); diff --git a/lib/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp b/lib/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp index 401da58a58..68864c8d66 100644 --- a/lib/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp +++ b/lib/kokkos/core/unit_test/TestDefaultDeviceTypeInit.hpp @@ -186,6 +186,21 @@ void check_correct_initialization( const Kokkos::InitArguments & argstruct ) { // Figure out the number of threads the HostSpace ExecutionSpace should have initialized to. int expected_nthreads = argstruct.num_threads; +#ifdef KOKKOS_ENABLE_OPENMP + if ( std::is_same< Kokkos::HostSpace::execution_space, Kokkos::OpenMP >::value ) { + // use openmp default num threads + if ( expected_nthreads < 0 || ( expected_nthreads == 0 && !Kokkos::hwloc::available() ) ) { + expected_nthreads = omp_get_max_threads(); + } + // use hwloc if available + else if ( expected_nthreads == 0 && Kokkos::hwloc::available() ) { + expected_nthreads = Kokkos::hwloc::get_available_numa_count() + * Kokkos::hwloc::get_available_cores_per_numa() + * Kokkos::hwloc::get_available_threads_per_core(); + } + } +#endif + if ( expected_nthreads < 1 ) { if ( Kokkos::hwloc::available() ) { expected_nthreads = Kokkos::hwloc::get_available_numa_count() @@ -193,12 +208,6 @@ void check_correct_initialization( const Kokkos::InitArguments & argstruct ) { * Kokkos::hwloc::get_available_threads_per_core(); } else { -#ifdef KOKKOS_ENABLE_OPENMP - if ( std::is_same< Kokkos::HostSpace::execution_space, Kokkos::OpenMP >::value ) { - expected_nthreads = omp_get_max_threads(); - } - else -#endif expected_nthreads = 1; } diff --git a/lib/kokkos/core/unit_test/TestMDRange.hpp b/lib/kokkos/core/unit_test/TestMDRange.hpp index 091591bcbf..f579ddf02c 100644 --- a/lib/kokkos/core/unit_test/TestMDRange.hpp +++ b/lib/kokkos/core/unit_test/TestMDRange.hpp @@ -51,6 +51,180 @@ namespace Test { namespace { +template +struct TestMDRange_ReduceArray_2D { + + using DataType = int; + using ViewType_2 = typename Kokkos::View< DataType**, ExecSpace >; + using HostViewType_2 = typename ViewType_2::HostMirror; + + ViewType_2 input_view; + + using scalar_type = double; + using value_type = scalar_type[]; + const unsigned value_count; + + TestMDRange_ReduceArray_2D( const int N0, const int N1, const unsigned array_size ) + : input_view( "input_view", N0, N1 ) + , value_count( array_size ) + {} + + KOKKOS_INLINE_FUNCTION + void init( scalar_type dst[] ) const + { + for ( unsigned i = 0; i < value_count; ++i ) { + dst[i] = 0.0; + } + } + + KOKKOS_INLINE_FUNCTION + void join( volatile scalar_type dst[], + const volatile scalar_type src[] ) const + { + for ( unsigned i = 0; i < value_count; ++i ) { + dst[i] += src[i]; + } + } + + + KOKKOS_INLINE_FUNCTION + void operator()( const int i, const int j ) const + { + input_view( i, j ) = 1; + } + + KOKKOS_INLINE_FUNCTION + void operator()( const int i, const int j, value_type lsum ) const + { + lsum[0] += input_view( i, j ) * 2; //+=6 each time if InitTag => N0*N1*6 + lsum[1] += input_view( i, j ) ; //+=3 each time if InitTag => N0*N1*3 + } + + // tagged operators + struct InitTag {}; + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j ) const + { + input_view( i, j ) = 3; + } + + static void test_arrayreduce2( const int N0, const int N1 ) + { + using namespace Kokkos::Experimental; + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2>, Kokkos::IndexType, InitTag > range_type_init; + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type_init range_init( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); + range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); + + const unsigned array_size = 2; + + TestMDRange_ReduceArray_2D functor( N0, N1, array_size ); + + parallel_for( range_init, functor ); // Init the view to 3's + + double sums[ array_size ]; + parallel_reduce( range, functor, sums ); + + // Check output + //printf("Array Reduce result. N0 = %d N1 = %d N0*N1 = %d sums[0] = %lf sums[1] = %lf \n", N0, N1, N0*N1, sums[0], sums[1]); + + ASSERT_EQ( sums[0], 6 * N0 * N1 ); + ASSERT_EQ( sums[1], 3 * N0 * N1 ); + } + } +}; + +template +struct TestMDRange_ReduceArray_3D { + + using DataType = int; + using ViewType_3 = typename Kokkos::View< DataType***, ExecSpace >; + using HostViewType_3 = typename ViewType_3::HostMirror; + + ViewType_3 input_view; + + using scalar_type = double; + using value_type = scalar_type[]; + const unsigned value_count; + + TestMDRange_ReduceArray_3D( const int N0, const int N1, const int N2, const unsigned array_size ) + : input_view( "input_view", N0, N1, N2 ) + , value_count( array_size ) + {} + + KOKKOS_INLINE_FUNCTION + void init( scalar_type dst[] ) const + { + for ( unsigned i = 0; i < value_count; ++i ) { + dst[i] = 0.0; + } + } + + KOKKOS_INLINE_FUNCTION + void join( volatile scalar_type dst[], + const volatile scalar_type src[] ) const + { + for ( unsigned i = 0; i < value_count; ++i ) { + dst[i] += src[i]; + } + } + + + KOKKOS_INLINE_FUNCTION + void operator()( const int i, const int j, const int k ) const + { + input_view( i, j, k ) = 1; + } + + KOKKOS_INLINE_FUNCTION + void operator()( const int i, const int j, const int k, value_type lsum ) const + { + lsum[0] += input_view( i, j, k ) * 2; //+=6 each time if InitTag => N0*N1*N2*6 + lsum[1] += input_view( i, j, k ) ; //+=3 each time if InitTag => N0*N1*N2*3 + } + + // tagged operators + struct InitTag {}; + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, const int k ) const + { + input_view( i, j, k ) = 3; + } + + static void test_arrayreduce3( const int N0, const int N1, const int N2 ) + { + using namespace Kokkos::Experimental; + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3>, Kokkos::IndexType, InitTag > range_type_init; + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type_init range_init( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 3, 3, 3 } } ); + range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 3, 3, 3 } } ); + + const unsigned array_size = 2; + + TestMDRange_ReduceArray_3D functor( N0, N1, N2, array_size ); + + parallel_for( range_init, functor ); // Init the view to 3's + + double sums[ array_size ]; + parallel_reduce( range, functor, sums ); + + ASSERT_EQ( sums[0], 6 * N0 * N1 * N2 ); + ASSERT_EQ( sums[1], 3 * N0 * N1 * N2 ); + } + } +}; + + template struct TestMDRange_2D { using DataType = int; @@ -58,6 +232,7 @@ struct TestMDRange_2D { using HostViewType = typename ViewType::HostMirror; ViewType input_view; + using value_type = double; TestMDRange_2D( const DataType N0, const DataType N1 ) : input_view( "input_view", N0, N1 ) {} @@ -68,7 +243,7 @@ struct TestMDRange_2D { } KOKKOS_INLINE_FUNCTION - void operator()( const int i, const int j, double &lsum ) const + void operator()( const int i, const int j, value_type &lsum ) const { lsum += input_view( i, j ) * 2; } @@ -81,6 +256,13 @@ struct TestMDRange_2D { input_view( i, j ) = 3; } + // reduction tagged operators + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, value_type &lsum ) const + { + lsum += input_view( i, j ) * 3; + } + static void test_reduce2( const int N0, const int N1 ) { using namespace Kokkos::Experimental; @@ -94,13 +276,85 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } + // Test with reducers - scalar + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0 }}, {{ N0, N1 }}, {{ 3, 3 }} ); + + TestMDRange_2D functor( N0, N1 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::Experimental::Sum< value_type > reducer_scalar( sum ); + + parallel_reduce( range, functor, reducer_scalar ); + + ASSERT_EQ( sum, 2 * N0 * N1 ); + } + // Test with reducers - scalar view + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0 }}, {{ N0, N1 }}, {{ 3, 3 }} ); + + TestMDRange_2D functor( N0, N1 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::View< value_type, Kokkos::HostSpace > sum_view("sum_view"); + sum_view() = sum; + Kokkos::Experimental::Sum< value_type > reducer_view( sum_view ); + + parallel_reduce( range, functor, reducer_view); + sum = sum_view(); + + ASSERT_EQ( sum, 2 * N0 * N1 ); + } + + // Tagged operator test + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2, Iterate::Default, Iterate::Default >, Kokkos::IndexType, InitTag > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 2, 4 } } ); + + TestMDRange_2D functor( N0, N1 ); + + parallel_for( range, functor ); + + // check parallel_for results correct with InitTag + HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); + Kokkos::deep_copy( h_view, functor.input_view ); + int counter = 0; + for ( int i = 0; i < N0; ++i ) + for ( int j = 0; j < N1; ++j ) + { + if ( h_view( i, j ) != 3 ) { + ++counter; + } + } + + if ( counter != 0 ) { + printf( "Defaults + InitTag op(): Errors in test_for3; mismatches = %d\n\n", counter ); + } + ASSERT_EQ( counter, 0 ); + + + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 9 * N0 * N1 ); + } + { typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<2, Iterate::Default, Iterate::Default>, Kokkos::IndexType > range_type; typedef typename range_type::tile_type tile_type; @@ -110,9 +364,9 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } @@ -126,9 +380,9 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } @@ -142,9 +396,9 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } @@ -158,9 +412,9 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } @@ -174,9 +428,9 @@ struct TestMDRange_2D { TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 ); } @@ -194,7 +448,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -223,7 +477,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -251,7 +505,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -280,7 +534,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -309,7 +563,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 4, 4 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -338,7 +592,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 3, 3 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -367,7 +621,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 7, 7 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -396,7 +650,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 16, 16 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -425,7 +679,7 @@ struct TestMDRange_2D { range_type range( point_type{ { 0, 0 } }, point_type{ { N0, N1 } }, tile_type{ { 5, 16 } } ); TestMDRange_2D functor( N0, N1 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -455,6 +709,7 @@ struct TestMDRange_3D { using HostViewType = typename ViewType::HostMirror; ViewType input_view; + using value_type = double; TestMDRange_3D( const DataType N0, const DataType N1, const DataType N2 ) : input_view( "input_view", N0, N1, N2 ) {} @@ -478,6 +733,13 @@ struct TestMDRange_3D { input_view( i, j, k ) = 3; } + // reduction tagged operators + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, const int k, value_type &lsum ) const + { + lsum += input_view( i, j, k ) * 3; + } + static void test_reduce3( const int N0, const int N1, const int N2 ) { using namespace Kokkos::Experimental; @@ -491,13 +753,86 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } + // Test with reducers - scalar + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0 }}, {{ N0, N1, N2 }}, {{ 3, 3, 3 }} ); + + TestMDRange_3D functor( N0, N1, N2 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::Experimental::Sum< value_type > reducer_scalar( sum ); + + parallel_reduce( range, functor, reducer_scalar ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); + } + // Test with reducers - scalar view + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0 }}, {{ N0, N1, N2 }}, {{ 3, 3, 3 }} ); + + TestMDRange_3D functor( N0, N1, N2 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::View< value_type, Kokkos::HostSpace > sum_view("sum_view"); + sum_view() = sum; + Kokkos::Experimental::Sum< value_type > reducer_view( sum_view ); + + parallel_reduce( range, functor, reducer_view); + sum = sum_view(); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); + } + + // Tagged operator test + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3, Iterate::Default, Iterate::Default >, Kokkos::IndexType, InitTag > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 2, 4, 6 } } ); + + TestMDRange_3D functor( N0, N1, N2 ); + + parallel_for( range, functor ); + + // check parallel_for results correct with InitTag + HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); + Kokkos::deep_copy( h_view, functor.input_view ); + int counter = 0; + for ( int i = 0; i < N0; ++i ) + for ( int j = 0; j < N1; ++j ) + for ( int k = 0; k < N2; ++k ) + { + if ( h_view( i, j, k ) != 3 ) { + ++counter; + } + } + + if ( counter != 0 ) { + printf( "Defaults + InitTag op(): Errors in test_for3; mismatches = %d\n\n", counter ); + } + ASSERT_EQ( counter, 0 ); + + + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 9 * N0 * N1 * N2 ); + } + { typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<3, Iterate::Default, Iterate::Default >, Kokkos::IndexType > range_type; typedef typename range_type::tile_type tile_type; @@ -507,9 +842,9 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } @@ -523,9 +858,9 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } @@ -539,9 +874,9 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } @@ -555,9 +890,9 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } @@ -571,9 +906,9 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); double sum = 0.0; - md_parallel_reduce( range, functor, sum ); + parallel_reduce( range, functor, sum ); ASSERT_EQ( sum, 2 * N0 * N1 * N2 ); } @@ -590,7 +925,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -620,7 +955,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 3, 3, 3 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -651,7 +986,7 @@ struct TestMDRange_3D { TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -681,7 +1016,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 3, 3, 3 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -711,7 +1046,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 2, 4, 2 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -741,7 +1076,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 3, 5, 7 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -771,7 +1106,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 8, 8, 8 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -801,7 +1136,7 @@ struct TestMDRange_3D { range_type range( point_type{ { 0, 0, 0 } }, point_type{ { N0, N1, N2 } }, tile_type{ { 2, 4, 2 } } ); TestMDRange_3D functor( N0, N1, N2 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -832,6 +1167,7 @@ struct TestMDRange_4D { using HostViewType = typename ViewType::HostMirror; ViewType input_view; + using value_type = double; TestMDRange_4D( const DataType N0, const DataType N1, const DataType N2, const DataType N3 ) : input_view( "input_view", N0, N1, N2, N3 ) {} @@ -855,6 +1191,191 @@ struct TestMDRange_4D { input_view( i, j, k, l ) = 3; } + // reduction tagged operators + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, const int k, const int l, value_type &lsum ) const + { + lsum += input_view( i, j, k, l ) * 3; + } + + static void test_reduce4( const int N0, const int N1, const int N2, const int N3 ) + { + using namespace Kokkos::Experimental; + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 3, 3, 3, 3 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + // Test with reducers - scalar + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0 }}, {{ N0, N1, N2, N3 }}, {{ 3, 3, 3, 3 }} ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::Experimental::Sum< value_type > reducer_scalar( sum ); + + parallel_reduce( range, functor, reducer_scalar ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + // Test with reducers - scalar view + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0 }}, {{ N0, N1, N2, N3 }}, {{ 3, 3, 3, 3 }} ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::View< value_type, Kokkos::HostSpace > sum_view("sum_view"); + sum_view() = sum; + Kokkos::Experimental::Sum< value_type > reducer_view( sum_view ); + + parallel_reduce( range, functor, reducer_view); + sum = sum_view(); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + // Tagged operator test + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Default, Iterate::Default >, Kokkos::IndexType, InitTag > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + + // check parallel_for results correct with InitTag + HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); + Kokkos::deep_copy( h_view, functor.input_view ); + int counter = 0; + for ( int i = 0; i < N0; ++i ) + for ( int j = 0; j < N1; ++j ) + for ( int k = 0; k < N2; ++k ) + for ( int l = 0; l < N3; ++l ) + { + if ( h_view( i, j, k, l ) != 3 ) { + ++counter; + } + } + + if ( counter != 0 ) { + printf( "Defaults + InitTag op(): Errors in test_reduce4 parallel_for init; mismatches = %d\n\n", counter ); + } + ASSERT_EQ( counter, 0 ); + + + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 9 * N0 * N1 * N2 * N3 ); + } + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Default, Iterate::Default >, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Left, Iterate::Left>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Left, Iterate::Right>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Right, Iterate::Left>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<4, Iterate::Right, Iterate::Right>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 2, 4, 6, 2 } } ); + + TestMDRange_4D functor( N0, N1, N2, N3 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 ); + } + } // end test_reduce + + + static void test_for4( const int N0, const int N1, const int N2, const int N3 ) { using namespace Kokkos::Experimental; @@ -866,7 +1387,7 @@ struct TestMDRange_4D { range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } } ); TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -897,7 +1418,7 @@ struct TestMDRange_4D { range_type range( point_type{ { 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3 } }, tile_type{ { 3, 11, 3, 3 } } ); TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -929,7 +1450,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -961,7 +1482,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -993,7 +1514,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1025,7 +1546,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1057,7 +1578,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1089,7 +1610,7 @@ struct TestMDRange_4D { TestMDRange_4D functor( N0, N1, N2, N3 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1121,6 +1642,7 @@ struct TestMDRange_5D { using HostViewType = typename ViewType::HostMirror; ViewType input_view; + using value_type = double; TestMDRange_5D( const DataType N0, const DataType N1, const DataType N2, const DataType N3, const DataType N4 ) : input_view( "input_view", N0, N1, N2, N3, N4 ) {} @@ -1131,7 +1653,7 @@ struct TestMDRange_5D { } KOKKOS_INLINE_FUNCTION - void operator()( const int i, const int j, const int k, const int l, const int m, double &lsum ) const + void operator()( const int i, const int j, const int k, const int l, const int m, value_type &lsum ) const { lsum += input_view( i, j, k, l, m ) * 2; } @@ -1144,6 +1666,110 @@ struct TestMDRange_5D { input_view( i, j, k, l, m ) = 3; } + // reduction tagged operators + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, const int k, const int l, const int m, value_type &lsum ) const + { + lsum += input_view( i, j, k, l, m ) * 3; + } + + static void test_reduce5( const int N0, const int N1, const int N2, const int N3, const int N4 ) + { + using namespace Kokkos::Experimental; + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<5>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4 } }, tile_type{ { 3, 3, 3, 3, 3 } } ); + + TestMDRange_5D functor( N0, N1, N2, N3, N4 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 ); + } + + // Test with reducers - scalar + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<5>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0, 0 }}, {{ N0, N1, N2, N3, N4 }}, {{ 3, 3, 3, 3, 3 }} ); + + TestMDRange_5D functor( N0, N1, N2, N3, N4 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::Experimental::Sum< value_type > reducer_scalar( sum ); + + parallel_reduce( range, functor, reducer_scalar ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 ); + } + + // Test with reducers - scalar view + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<5>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0, 0 }}, {{ N0, N1, N2, N3, N4 }}, {{ 3, 3, 3, 3, 3 }} ); + + TestMDRange_5D functor( N0, N1, N2, N3, N4 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::View< value_type, Kokkos::HostSpace > sum_view("sum_view"); + sum_view() = sum; + Kokkos::Experimental::Sum< value_type > reducer_view( sum_view ); + + parallel_reduce( range, functor, reducer_view); + sum = sum_view(); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 ); + } + + // Tagged operator test + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<5, Iterate::Default, Iterate::Default >, Kokkos::IndexType, InitTag > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4 } }, tile_type{ { 2, 4, 6, 2, 2 } } ); + + TestMDRange_5D functor( N0, N1, N2, N3, N4 ); + + parallel_for( range, functor ); + + // check parallel_for results correct with InitTag + HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); + Kokkos::deep_copy( h_view, functor.input_view ); + int counter = 0; + for ( int i = 0; i < N0; ++i ) + for ( int j = 0; j < N1; ++j ) + for ( int k = 0; k < N2; ++k ) + for ( int l = 0; l < N3; ++l ) + for ( int m = 0; m < N4; ++m ) + { + if ( h_view( i, j, k, l, m ) != 3 ) { + ++counter; + } + } + + if ( counter != 0 ) { + printf( "Defaults + InitTag op(): Errors in test_reduce5 parallel_for init; mismatches = %d\n\n", counter ); + } + ASSERT_EQ( counter, 0 ); + + + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 9 * N0 * N1 * N2 * N3 * N4 ); + } + } + static void test_for5( const int N0, const int N1, const int N2, const int N3, const int N4 ) { using namespace Kokkos::Experimental; @@ -1155,7 +1781,7 @@ struct TestMDRange_5D { range_type range( point_type{ { 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4 } } ); TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1184,10 +1810,10 @@ struct TestMDRange_5D { typedef typename range_type::tile_type tile_type; typedef typename range_type::point_type point_type; - range_type range( point_type{ { 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4 } }, tile_type{ { 3, 3, 3, 3, 7 } } ); + range_type range( point_type{ { 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4 } }, tile_type{ { 3, 3, 3, 3, 5 } } ); TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1220,7 +1846,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1253,7 +1879,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1286,7 +1912,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1319,7 +1945,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1352,7 +1978,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1385,7 +2011,7 @@ struct TestMDRange_5D { TestMDRange_5D functor( N0, N1, N2, N3, N4 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1418,6 +2044,7 @@ struct TestMDRange_6D { using HostViewType = typename ViewType::HostMirror; ViewType input_view; + using value_type = double; TestMDRange_6D( const DataType N0, const DataType N1, const DataType N2, const DataType N3, const DataType N4, const DataType N5 ) : input_view( "input_view", N0, N1, N2, N3, N4, N5 ) {} @@ -1428,7 +2055,7 @@ struct TestMDRange_6D { } KOKKOS_INLINE_FUNCTION - void operator()( const int i, const int j, const int k, const int l, const int m, const int n, double &lsum ) const + void operator()( const int i, const int j, const int k, const int l, const int m, const int n, value_type &lsum ) const { lsum += input_view( i, j, k, l, m, n ) * 2; } @@ -1441,6 +2068,111 @@ struct TestMDRange_6D { input_view( i, j, k, l, m, n ) = 3; } + // reduction tagged operators + KOKKOS_INLINE_FUNCTION + void operator()( const InitTag &, const int i, const int j, const int k, const int l, const int m, const int n, value_type &lsum ) const + { + lsum += input_view( i, j, k, l, m, n ) * 3; + } + + static void test_reduce6( const int N0, const int N1, const int N2, const int N3, const int N4, const int N5 ) + { + using namespace Kokkos::Experimental; + + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<6>, Kokkos::IndexType > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4, N5 } }, tile_type{ { 3, 3, 3, 3, 3, 2 } } ); + + TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); + + parallel_for( range, functor ); + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 * N5 ); + } + + // Test with reducers - scalar + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<6>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0, 0, 0 }}, {{ N0, N1, N2, N3, N4, N5 }}, {{ 3, 3, 3, 3, 3, 2 }} ); + + TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::Experimental::Sum< value_type > reducer_scalar( sum ); + + parallel_reduce( range, functor, reducer_scalar ); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 * N5 ); + } + + // Test with reducers - scalar view + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<6>, Kokkos::IndexType > range_type; + range_type range( {{ 0, 0, 0, 0, 0, 0 }}, {{ N0, N1, N2, N3, N4, N5 }}, {{ 3, 3, 3, 3, 3, 2 }} ); + + TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); + + parallel_for( range, functor ); + + value_type sum = 0.0; + Kokkos::View< value_type, Kokkos::HostSpace > sum_view("sum_view"); + sum_view() = sum; + Kokkos::Experimental::Sum< value_type > reducer_view( sum_view ); + + parallel_reduce( range, functor, reducer_view); + sum = sum_view(); + + ASSERT_EQ( sum, 2 * N0 * N1 * N2 * N3 * N4 * N5 ); + } + + // Tagged operator test + { + typedef typename Kokkos::Experimental::MDRangePolicy< ExecSpace, Rank<6, Iterate::Default, Iterate::Default >, Kokkos::IndexType, InitTag > range_type; + typedef typename range_type::tile_type tile_type; + typedef typename range_type::point_type point_type; + + range_type range( point_type{ { 0, 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4, N5 } }, tile_type{ { 2, 4, 6, 2, 2, 2 } } ); + + TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); + + parallel_for( range, functor ); + + // check parallel_for results correct with InitTag + HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); + Kokkos::deep_copy( h_view, functor.input_view ); + int counter = 0; + for ( int i = 0; i < N0; ++i ) + for ( int j = 0; j < N1; ++j ) + for ( int k = 0; k < N2; ++k ) + for ( int l = 0; l < N3; ++l ) + for ( int m = 0; m < N4; ++m ) + for ( int n = 0; n < N5; ++n ) + { + if ( h_view( i, j, k, l, m, n ) != 3 ) { + ++counter; + } + } + + if ( counter != 0 ) { + printf( "Defaults + InitTag op(): Errors in test_reduce6 parallel_for init; mismatches = %d\n\n", counter ); + } + ASSERT_EQ( counter, 0 ); + + + double sum = 0.0; + parallel_reduce( range, functor, sum ); + + ASSERT_EQ( sum, 9 * N0 * N1 * N2 * N3 * N4 * N5 ); + } + } + static void test_for6( const int N0, const int N1, const int N2, const int N3, const int N4, const int N5 ) { using namespace Kokkos::Experimental; @@ -1452,7 +2184,7 @@ struct TestMDRange_6D { range_type range( point_type{ { 0, 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4, N5 } } ); TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1485,7 +2217,7 @@ struct TestMDRange_6D { range_type range( point_type{ { 0, 0, 0, 0, 0, 0 } }, point_type{ { N0, N1, N2, N3, N4, N5 } }, tile_type{ { 3, 3, 3, 3, 2, 3 } } ); //tile dims 3,3,3,3,3,3 more than cuda can handle with debugging TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1519,7 +2251,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1553,7 +2285,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1587,7 +2319,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1621,7 +2353,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1655,7 +2387,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1689,7 +2421,7 @@ struct TestMDRange_6D { TestMDRange_6D functor( N0, N1, N2, N3, N4, N5 ); - md_parallel_for( range, functor ); + parallel_for( range, functor ); HostViewType h_view = Kokkos::create_mirror_view( functor.input_view ); Kokkos::deep_copy( h_view, functor.input_view ); @@ -1726,11 +2458,19 @@ TEST_F( TEST_CATEGORY , mdrange_for ) { TestMDRange_6D< TEST_EXECSPACE >::test_for6( 10, 10, 10, 10, 5, 5 ); } -#ifndef KOKKOS_ENABLE_CUDA TEST_F( TEST_CATEGORY , mdrange_reduce ) { TestMDRange_2D< TEST_EXECSPACE >::test_reduce2( 100, 100 ); TestMDRange_3D< TEST_EXECSPACE >::test_reduce3( 100, 10, 100 ); + TestMDRange_4D< TEST_EXECSPACE >::test_reduce4( 100, 10, 10, 10 ); + TestMDRange_5D< TEST_EXECSPACE >::test_reduce5( 100, 10, 10, 10, 5 ); + TestMDRange_6D< TEST_EXECSPACE >::test_reduce6( 100, 10, 10, 10, 5, 5 ); } -#endif + +//#ifndef KOKKOS_ENABLE_CUDA +TEST_F( TEST_CATEGORY , mdrange_array_reduce ) { + TestMDRange_ReduceArray_2D< TEST_EXECSPACE >::test_arrayreduce2( 4, 5 ); + TestMDRange_ReduceArray_3D< TEST_EXECSPACE >::test_arrayreduce3( 4, 5, 10 ); +} +//#endif } // namespace Test diff --git a/lib/kokkos/core/unit_test/TestMemoryPool.hpp b/lib/kokkos/core/unit_test/TestMemoryPool.hpp index 941cd6c26d..9f708390c2 100644 --- a/lib/kokkos/core/unit_test/TestMemoryPool.hpp +++ b/lib/kokkos/core/unit_test/TestMemoryPool.hpp @@ -54,6 +54,96 @@ namespace TestMemoryPool { +template< typename MemSpace = Kokkos::HostSpace > +void test_host_memory_pool_defaults() +{ + typedef typename MemSpace::execution_space Space ; + typedef typename Kokkos::MemoryPool< Space > MemPool ; + + { + const size_t MemoryCapacity = 32000 ; + const size_t MinBlockSize = 64 ; + const size_t MaxBlockSize = 1024 ; + const size_t SuperBlockSize = 4096 ; + + MemPool pool( MemSpace() + , MemoryCapacity + , MinBlockSize + , MaxBlockSize + , SuperBlockSize + ); + + typename MemPool::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + ASSERT_LE( MemoryCapacity , stats.capacity_bytes ); + ASSERT_LE( MinBlockSize , stats.min_block_bytes ); + ASSERT_LE( MaxBlockSize , stats.max_block_bytes ); + ASSERT_LE( SuperBlockSize , stats.superblock_bytes ); + } + + { + const size_t MemoryCapacity = 10000 ; + + MemPool pool( MemSpace() + , MemoryCapacity + ); + + typename MemPool::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + ASSERT_LE( MemoryCapacity , stats.capacity_bytes ); + ASSERT_LE( 64u /* default */ , stats.min_block_bytes ); + ASSERT_LE( stats.min_block_bytes , stats.max_block_bytes ); + ASSERT_LE( stats.max_block_bytes , stats.superblock_bytes ); + ASSERT_LE( stats.superblock_bytes , stats.capacity_bytes ); + } + + { + const size_t MemoryCapacity = 10000 ; + const size_t MinBlockSize = 32 ; // power of two is exact + + MemPool pool( MemSpace() + , MemoryCapacity + , MinBlockSize + ); + + typename MemPool::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + ASSERT_LE( MemoryCapacity , stats.capacity_bytes ); + ASSERT_EQ( MinBlockSize , stats.min_block_bytes ); + ASSERT_LE( stats.min_block_bytes , stats.max_block_bytes ); + ASSERT_LE( stats.max_block_bytes , stats.superblock_bytes ); + ASSERT_LE( stats.superblock_bytes , stats.capacity_bytes ); + } + + { + const size_t MemoryCapacity = 32000 ; + const size_t MinBlockSize = 32 ; // power of two is exact + const size_t MaxBlockSize = 1024 ; // power of two is exact + + MemPool pool( MemSpace() + , MemoryCapacity + , MinBlockSize + , MaxBlockSize + ); + + typename MemPool::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + ASSERT_LE( MemoryCapacity , stats.capacity_bytes ); + ASSERT_EQ( MinBlockSize , stats.min_block_bytes ); + ASSERT_EQ( MaxBlockSize , stats.max_block_bytes ); + ASSERT_LE( stats.max_block_bytes , stats.superblock_bytes ); + ASSERT_LE( stats.superblock_bytes , stats.capacity_bytes ); + } +} + template< typename MemSpace = Kokkos::HostSpace > void test_host_memory_pool_stats() { @@ -188,8 +278,8 @@ void print_memory_pool_stats << " bytes reserved = " << stats.reserved_bytes << std::endl << " bytes free = " << ( stats.capacity_bytes - ( stats.consumed_bytes + stats.reserved_bytes ) ) << std::endl - << " alloc used = " << stats.consumed_blocks << std::endl - << " alloc reserved = " << stats.reserved_blocks << std::endl + << " block used = " << stats.consumed_blocks << std::endl + << " block reserved = " << stats.reserved_blocks << std::endl << " super used = " << stats.consumed_superblocks << std::endl << " super reserved = " << ( stats.capacity_superblocks - stats.consumed_superblocks ) << std::endl @@ -302,15 +392,147 @@ void test_memory_pool_v2( const bool print_statistics //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -} // namespace TestMemoryPool { +template< class DeviceType > +struct TestMemoryPoolCorners { + + typedef Kokkos::View< uintptr_t * , DeviceType > ptrs_type ; + typedef Kokkos::MemoryPool< DeviceType > pool_type ; + + pool_type pool ; + ptrs_type ptrs ; + uint32_t size ; + uint32_t stride ; + + TestMemoryPoolCorners( const pool_type & arg_pool + , const ptrs_type & arg_ptrs + , const uint32_t arg_base + , const uint32_t arg_stride + ) + : pool( arg_pool ) + , ptrs( arg_ptrs ) + , size( arg_base ) + , stride( arg_stride ) + {} + + // Specify reduction argument value_type to + // avoid confusion with tag-dispatch. + + using value_type = long ; + + KOKKOS_INLINE_FUNCTION + void operator()( int i , long & err ) const noexcept + { + unsigned alloc_size = size << ( i % stride ); + if ( 0 == ptrs(i) ) { + ptrs(i) = (uintptr_t) pool.allocate( alloc_size ); + if ( ptrs(i) && ! alloc_size ) { ++err ; } + } + } + + struct TagDealloc {}; + + KOKKOS_INLINE_FUNCTION + void operator()( int i ) const noexcept + { + unsigned alloc_size = size << ( i % stride ); + if ( ptrs(i) ) { pool.deallocate( (void*) ptrs(i) , alloc_size ); } + ptrs(i) = 0 ; + } +}; + +template< class DeviceType > +void test_memory_pool_corners( const bool print_statistics + , const bool print_superblocks ) +{ + typedef typename DeviceType::memory_space memory_space ; + typedef typename DeviceType::execution_space execution_space ; + typedef Kokkos::MemoryPool< DeviceType > pool_type ; + typedef TestMemoryPoolCorners< DeviceType > functor_type ; + typedef typename functor_type::ptrs_type ptrs_type ; + + { + // superblock size 1 << 14 + const size_t min_superblock_size = 1u << 14 ; + + // four superblocks + const size_t total_alloc_size = min_superblock_size * 4 ; + + // block sizes { 64 , 128 , 256 , 512 } + // block counts { 256 , 128 , 64 , 32 } + const unsigned min_block_size = 64 ; + const unsigned max_block_size = 512 ; + const unsigned num_blocks = 480 ; + + pool_type pool( memory_space() + , total_alloc_size + , min_block_size + , max_block_size + , min_superblock_size ); + + // Allocate one block from each superblock to lock that + // superblock into the block size. + + ptrs_type ptrs("ptrs",num_blocks); + + long err = 0 ; + + Kokkos::parallel_reduce + ( Kokkos::RangePolicy< execution_space >(0,4) + , functor_type( pool , ptrs , 64 , 4 ) + , err + ); + + if ( print_statistics || err ) { + + typename pool_type::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + print_memory_pool_stats< pool_type >( stats ); + } + + if ( print_superblocks || err ) { + pool.print_state( std::cout ); + } + + // Now fill remaining allocations with small size + + Kokkos::parallel_reduce + ( Kokkos::RangePolicy< execution_space >(0,num_blocks) + , functor_type( pool , ptrs , 64 , 1 ) + , err + ); + + if ( print_statistics || err ) { + + typename pool_type::usage_statistics stats ; + + pool.get_usage_statistics( stats ); + + print_memory_pool_stats< pool_type >( stats ); + } + + if ( print_superblocks || err ) { + pool.print_state( std::cout ); + } + } +} + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +} // namespace TestMemoryPool namespace Test { TEST_F( TEST_CATEGORY, memory_pool ) { + TestMemoryPool::test_host_memory_pool_defaults<>(); TestMemoryPool::test_host_memory_pool_stats<>(); TestMemoryPool::test_memory_pool_v2< TEST_EXECSPACE >(false,false); + TestMemoryPool::test_memory_pool_corners< TEST_EXECSPACE >(false,false); } + } #endif diff --git a/lib/kokkos/core/unit_test/TestRange.hpp b/lib/kokkos/core/unit_test/TestRange.hpp index f55574761b..3cea1ad4a0 100644 --- a/lib/kokkos/core/unit_test/TestRange.hpp +++ b/lib/kokkos/core/unit_test/TestRange.hpp @@ -72,8 +72,33 @@ struct TestRange { typename view_type::HostMirror host_flags = Kokkos::create_mirror_view( m_flags ); Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace, ScheduleType >( 0, N ), *this ); + +#if defined(KOKKOS_ENABLE_PROFILING) + { + typedef TestRange< ExecSpace, ScheduleType > ThisType; + std::string label("parallel_for"); + Kokkos::Impl::ParallelConstructName< ThisType, void> pcn(label); + ASSERT_EQ( pcn.get(), label ); + std::string empty_label(""); + Kokkos::Impl::ParallelConstructName< ThisType, void> empty_pcn(empty_label); + ASSERT_EQ( empty_pcn.get(), typeid(ThisType).name() ); + } +#endif + Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace, ScheduleType, VerifyInitTag >( 0, N ), *this ); +#if defined(KOKKOS_ENABLE_PROFILING) + { + typedef TestRange< ExecSpace, ScheduleType > ThisType; + std::string label("parallel_for"); + Kokkos::Impl::ParallelConstructName< ThisType, VerifyInitTag> pcn(label); + ASSERT_EQ( pcn.get(), label ); + std::string empty_label(""); + Kokkos::Impl::ParallelConstructName< ThisType, VerifyInitTag> empty_pcn(empty_label); + ASSERT_EQ( empty_pcn.get(), std::string(typeid(ThisType).name()) + "/" + typeid(VerifyInitTag).name() ); + } +#endif + Kokkos::deep_copy( host_flags, m_flags ); int error_count = 0; diff --git a/lib/kokkos/core/unit_test/TestResize.hpp b/lib/kokkos/core/unit_test/TestResize.hpp new file mode 100644 index 0000000000..aaf0422b19 --- /dev/null +++ b/lib/kokkos/core/unit_test/TestResize.hpp @@ -0,0 +1,140 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ +#ifndef TESTVIEWSUBVIEW_HPP_ +#define TESTVIEWSUBVIEW_HPP_ + +#include +#include + +namespace TestViewResize { + +template +void testResize () +{ + const int sizes[8] = {2, 3, 4, 5, 6, 7, 8, 9}; + + // Check #904 fix (no reallocation if dimensions didn't change). + { + typedef Kokkos::View view_type; + view_type view_1d ("view_1d", sizes[0]); + const int* oldPointer = view_1d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_1d, sizes[0]); + const int* newPointer = view_1d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_2d ("view_2d", sizes[0], sizes[1]); + const int* oldPointer = view_2d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_2d, sizes[0], sizes[1]); + const int* newPointer = view_2d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_3d ("view_3d", sizes[0], sizes[1], sizes[2]); + const int* oldPointer = view_3d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_3d, sizes[0], sizes[1], sizes[2]); + const int* newPointer = view_3d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_4d ("view_4d", sizes[0], sizes[1], sizes[2], sizes[3]); + const int* oldPointer = view_4d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_4d, sizes[0], sizes[1], sizes[2], sizes[3]); + const int* newPointer = view_4d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_5d ("view_5d", sizes[0], sizes[1], sizes[2], sizes[3], + sizes[4]); + const int* oldPointer = view_5d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_5d, sizes[0], sizes[1], sizes[2], sizes[3], sizes[4]); + const int* newPointer = view_5d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_6d ("view_6d", sizes[0], sizes[1], sizes[2], sizes[3], + sizes[4], sizes[5]); + const int* oldPointer = view_6d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_6d, sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], + sizes[5]); + const int* newPointer = view_6d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_7d ("view_7d", sizes[0], sizes[1], sizes[2], sizes[3], + sizes[4], sizes[5], sizes[6]); + const int* oldPointer = view_7d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_7d, sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], + sizes[5], sizes[6]); + const int* newPointer = view_7d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } + { + typedef Kokkos::View view_type; + view_type view_8d ("view_8d", sizes[0], sizes[1], sizes[2], sizes[3], + sizes[4], sizes[5], sizes[6], sizes[7]); + const int* oldPointer = view_8d.data (); + EXPECT_TRUE( oldPointer != NULL ); + Kokkos::resize (view_8d, sizes[0], sizes[1], sizes[2], sizes[3], sizes[4], + sizes[5], sizes[6], sizes[7]); + const int* newPointer = view_8d.data (); + EXPECT_TRUE( oldPointer == newPointer ); + } +} + +} // namespace TestViewSubview + +#endif // TESTVIEWSUBVIEW_HPP_ diff --git a/lib/kokkos/core/unit_test/TestTaskScheduler.hpp b/lib/kokkos/core/unit_test/TestTaskScheduler.hpp index 3a88475620..4e66543857 100644 --- a/lib/kokkos/core/unit_test/TestTaskScheduler.hpp +++ b/lib/kokkos/core/unit_test/TestTaskScheduler.hpp @@ -250,13 +250,21 @@ struct TestTaskDependence { const int n = CHUNK < m_count ? CHUNK : m_count; if ( 1 < m_count ) { - future_type f[ CHUNK ]; + // Test use of memory pool for temporary allocation: + + // Raw allocation: + future_type * const f = + (future_type *) m_sched.memory()->allocate( sizeof(future_type) * n ); + + // In-place construction: + for ( int i = 0; i < n; ++i ) new(f+i) future_type(); const int inc = ( m_count + n - 1 ) / n; for ( int i = 0; i < n; ++i ) { long begin = i * inc; long count = begin + inc < m_count ? inc : m_count - begin; + f[i] = Kokkos::task_spawn( Kokkos::TaskSingle( m_sched ) , TestTaskDependence( count, m_sched, m_accum ) ); } @@ -264,6 +272,12 @@ struct TestTaskDependence { m_count = 0; Kokkos::respawn( this, Kokkos::when_all( f, n ) ); + + // In-place destruction to release future: + for ( int i = 0; i < n; ++i ) (f+i)->~future_type(); + + // Raw deallocation: + m_sched.memory()->deallocate( f , sizeof(future_type) * n ); } else if ( 1 == m_count ) { Kokkos::atomic_increment( & m_accum() ); @@ -641,19 +655,12 @@ namespace Test { TEST_F( TEST_CATEGORY, task_fib ) { - const int N = 24 ; // 25 triggers tbd bug on Cuda/Pascal + const int N = 27 ; for ( int i = 0; i < N; ++i ) { - TestTaskScheduler::TestFib< TEST_EXECSPACE >::run( i , ( i + 1 ) * ( i + 1 ) * 10000 ); + TestTaskScheduler::TestFib< TEST_EXECSPACE >::run( i , ( i + 1 ) * ( i + 1 ) * 2000 ); } } -#if defined(KOKKOS_ARCH_MAXWELL) || defined(KOKKOS_ARCH_PASCAL) - // TODO: Resolve bug in task DAG for Pascal - #define KOKKOS_IMPL_DISABLE_UNIT_TEST_TASK_DAG_PASCAL -#endif - -#ifndef KOKKOS_IMPL_DISABLE_UNIT_TEST_TASK_DAG_PASCAL - TEST_F( TEST_CATEGORY, task_depend ) { for ( int i = 0; i < 25; ++i ) { @@ -667,11 +674,8 @@ TEST_F( TEST_CATEGORY, task_team ) //TestTaskScheduler::TestTaskTeamValue< TEST_EXECSPACE >::run( 1000 ); // Put back after testing. } -#else //ndef KOKKOS_IMPL_DISABLE_UNIT_TEST_TASK_DAG_PASCAL -#undef KOKKOS_IMPL_DISABLE_UNIT_TEST_TASK_DAG_PASCAL -#endif //ndef KOKKOS_IMPL_DISABLE_UNIT_TEST_TASK_DAG_PASCAL - } + #endif // #if defined( KOKKOS_ENABLE_TASKDAG ) #endif // #ifndef KOKKOS_UNITTEST_TASKSCHEDULER_HPP diff --git a/lib/kokkos/core/unit_test/TestTeamVector.hpp b/lib/kokkos/core/unit_test/TestTeamVector.hpp index e9e2f7548a..7f4663d0f9 100644 --- a/lib/kokkos/core/unit_test/TestTeamVector.hpp +++ b/lib/kokkos/core/unit_test/TestTeamVector.hpp @@ -838,6 +838,18 @@ public: }, result ); const ScalarType solution = (ScalarType) nrows * (ScalarType) ncols; + + if ( int64_t(solution) != int64_t(result) ) { + printf( " TestTripleNestedReduce failed solution(%ld) != result(%ld), nrows(%d) ncols(%d) league_size(%d) team_size(%d)\n" + , int64_t(solution) + , int64_t(result) + , int32_t(nrows) + , int32_t(ncols) + , int32_t(nrows/chunk_size) + , int32_t(team_size) + ); + } + ASSERT_EQ( solution, result ); } }; diff --git a/lib/kokkos/core/unit_test/TestTile.hpp b/lib/kokkos/core/unit_test/TestTile.hpp index 8f57dfea75..f15667322f 100644 --- a/lib/kokkos/core/unit_test/TestTile.hpp +++ b/lib/kokkos/core/unit_test/TestTile.hpp @@ -94,7 +94,7 @@ struct ReduceTileErrors const size_t jtile = iwork / tile_dim0; if ( jtile < tile_dim1 ) { - tile_type tile = Kokkos::Experimental::tile_subview( m_array, itile, jtile ); + tile_type tile = Kokkos::tile_subview( m_array, itile, jtile ); if ( tile( 0, 0 ) != ptrdiff_t( ( itile + jtile * tile_dim0 ) * TileLayout::N0 * TileLayout::N1 ) ) { ++errors; diff --git a/lib/kokkos/core/unit_test/TestUniqueToken.hpp b/lib/kokkos/core/unit_test/TestUniqueToken.hpp new file mode 100644 index 0000000000..28add61a8a --- /dev/null +++ b/lib/kokkos/core/unit_test/TestUniqueToken.hpp @@ -0,0 +1,138 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include + +#include + +namespace Test { + +template< class Space > +class TestUniqueToken +{ +public: + typedef typename Space::execution_space execution_space; + typedef Kokkos::View< int * , execution_space > view_type ; + + Kokkos::Experimental::UniqueToken< execution_space , Kokkos::Experimental::UniqueTokenScope::Global > tokens ; + + view_type verify ; + view_type counts ; + view_type errors ; + + KOKKOS_INLINE_FUNCTION + void operator()( long ) const + { + const int32_t t = tokens.acquire(); + + bool ok = true ; + + ok = ok && 0 <= t ; + ok = ok && t < tokens.size(); + ok = ok && 0 == Kokkos::atomic_fetch_add( & verify(t) , 1 ); + + Kokkos::atomic_fetch_add( & counts(t) , 1 ); + + ok = ok && 1 == Kokkos::atomic_fetch_add( & verify(t) , -1 ); + + if ( ! ok ) { Kokkos::atomic_fetch_add( & errors(0) , 1 ) ; } + + tokens.release(t); + } + + TestUniqueToken() + : tokens( execution_space() ) + , verify( "TestUniqueTokenVerify" , tokens.size() ) + , counts( "TestUniqueTokenCounts" , tokens.size() ) + , errors( "TestUniqueTokenErrors" , 1 ) + {} + + static void run() + { + using policy = Kokkos::RangePolicy ; + + TestUniqueToken self ; + + { + const int duplicate = 100 ; + const long n = duplicate * self.tokens.size(); + + Kokkos::parallel_for( policy(0,n) , self ); + Kokkos::parallel_for( policy(0,n) , self ); + Kokkos::parallel_for( policy(0,n) , self ); + Kokkos::fence(); + } + + typename view_type::HostMirror host_counts = + Kokkos::create_mirror_view( self.counts ); + + Kokkos::deep_copy( host_counts , self.counts ); + + int32_t max = 0 ; + + { + const long n = host_counts.extent(0); + for ( long i = 0 ; i < n ; ++i ) { + if ( max < host_counts[i] ) max = host_counts[i] ; + } + } + + std::cout << "TestUniqueToken max reuse = " << max << std::endl ; + + typename view_type::HostMirror host_errors = + Kokkos::create_mirror_view( self.errors ); + + Kokkos::deep_copy( host_errors , self.errors ); + + ASSERT_EQ( host_errors(0) , 0 ); + } +}; + + +TEST_F( TEST_CATEGORY, unique_token ) +{ + TestUniqueToken< TEST_EXECSPACE >::run(); +} + +} // namespace Test + diff --git a/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp new file mode 100644 index 0000000000..305ddb2a1d --- /dev/null +++ b/lib/kokkos/core/unit_test/TestViewCtorPropEmbeddedDim.hpp @@ -0,0 +1,160 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include + +#include + +#include + +#include +#include + +namespace Test { + +namespace { + +template +struct TestViewCtorProp_EmbeddedDim { + + using ViewIntType = typename Kokkos::View< int**, ExecSpace >; + using ViewDoubleType = typename Kokkos::View< double*, ExecSpace >; + + // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the view - replace with this functor + template < class ViewType > + struct Functor { + + ViewType v; + + Functor( const ViewType & v_ ) : v(v_) {} + + KOKKOS_INLINE_FUNCTION + void operator()( const int i ) const { + v(i) = i; + } + + }; + + + static void test_vcpt( const int N0, const int N1 ) + { + + // Create views to test + { + 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 + { + // 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 ); + + Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), + Functor(cv1) + ); + + HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); + Kokkos::deep_copy( hcv1, cv1 ); + + ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ; + #if 0 + // debug output + for ( int i = 0; i < N0*N1; ++i ) { + printf(" Output check: hcv1(%d) = %lf\n ", i, hcv1(i) ); + } + + printf( " Common value type view: %s \n", typeid( CVT() ).name() ); + printf( " Common value type: %s \n", typeid( CommonViewValueType() ).name() ); + if ( std::is_same< CommonViewValueType, double >::value == true ) { + printf("Proper common value_type\n"); + } + else { + printf("WRONG common value_type\n"); + } + // end debug output + #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; + + // 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) + ); + + HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); + Kokkos::deep_copy( hcv1, cv1 ); + + ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ; + } + + } + + } // end test_vcpt + +}; // end struct + +} // namespace + +TEST_F( TEST_CATEGORY , viewctorprop_embedded_dim ) { + TestViewCtorProp_EmbeddedDim< TEST_EXECSPACE >::test_vcpt( 2, 3 ); +} + +} // namespace Test diff --git a/lib/kokkos/core/unit_test/TestViewMapping_a.hpp b/lib/kokkos/core/unit_test/TestViewMapping_a.hpp index 6830c2e049..810ae72e73 100644 --- a/lib/kokkos/core/unit_test/TestViewMapping_a.hpp +++ b/lib/kokkos/core/unit_test/TestViewMapping_a.hpp @@ -56,24 +56,24 @@ void test_view_mapping() { typedef typename Space::execution_space ExecSpace; - typedef Kokkos::Experimental::Impl::ViewDimension<> dim_0; - typedef Kokkos::Experimental::Impl::ViewDimension< 2 > dim_s2; - typedef Kokkos::Experimental::Impl::ViewDimension< 2, 3 > dim_s2_s3; - typedef Kokkos::Experimental::Impl::ViewDimension< 2, 3, 4 > dim_s2_s3_s4; + typedef Kokkos::Impl::ViewDimension<> dim_0; + typedef Kokkos::Impl::ViewDimension< 2 > dim_s2; + typedef Kokkos::Impl::ViewDimension< 2, 3 > dim_s2_s3; + typedef Kokkos::Impl::ViewDimension< 2, 3, 4 > dim_s2_s3_s4; - typedef Kokkos::Experimental::Impl::ViewDimension< 0 > dim_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 3 > dim_s0_s3; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 3, 4 > dim_s0_s3_s4; + typedef Kokkos::Impl::ViewDimension< 0 > dim_s0; + typedef Kokkos::Impl::ViewDimension< 0, 3 > dim_s0_s3; + typedef Kokkos::Impl::ViewDimension< 0, 3, 4 > dim_s0_s3_s4; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0 > dim_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 4 > dim_s0_s0_s4; + typedef Kokkos::Impl::ViewDimension< 0, 0 > dim_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 4 > dim_s0_s0_s4; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0 > dim_s0_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0 > dim_s0_s0_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0 > dim_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0, 0 > dim_s0_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0, 0, 0, 0, 0, 0 > dim_s0_s0_s0_s0_s0_s0_s0_s0; // Fully static dimensions should not be larger than an int. ASSERT_LE( sizeof( dim_0 ), sizeof( int ) ); @@ -186,12 +186,12 @@ void test_view_mapping() //---------------------------------------- - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s0, Kokkos::LayoutStride > stride_s0_s0_s0; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s0, Kokkos::LayoutStride > stride_s0_s0_s0; //---------------------------------------- // Static dimension. { - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutLeft > left_s2_s3_s4; + typedef Kokkos::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutLeft > left_s2_s3_s4; ASSERT_EQ( sizeof( left_s2_s3_s4 ), sizeof( dim_s2_s3_s4 ) ); @@ -223,7 +223,7 @@ void test_view_mapping() //---------------------------------------- // Small dimension is unpadded. { - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutLeft( 2, 3, 0, 0, 0, 0, 0, 0 ) ); @@ -275,7 +275,7 @@ void test_view_mapping() constexpr int N0 = 2000; constexpr int N1 = 300; - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutLeft( N0, N1, 0, 0, 0, 0, 0, 0 ) ); @@ -314,7 +314,7 @@ void test_view_mapping() //---------------------------------------- // Static dimension. { - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutRight > right_s2_s3_s4; + typedef Kokkos::Impl::ViewOffset< dim_s2_s3_s4, Kokkos::LayoutRight > right_s2_s3_s4; ASSERT_EQ( sizeof( right_s2_s3_s4 ), sizeof( dim_s2_s3_s4 ) ); @@ -350,7 +350,7 @@ void test_view_mapping() //---------------------------------------- // Small dimension is unpadded. { - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutRight( 2, 3, 0, 0, 0, 0, 0, 0 ) ); @@ -391,7 +391,7 @@ void test_view_mapping() constexpr int N0 = 2000; constexpr int N1 = 300; - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutRight( N0, N1, 0, 0, 0, 0, 0, 0 ) ); @@ -431,18 +431,18 @@ void test_view_mapping() // Subview. { // Mapping rank 4 to rank 3 - typedef Kokkos::Experimental::Impl::SubviewExtents< 4, 3 > SubviewExtents; + typedef Kokkos::Impl::SubviewExtents< 4, 3 > SubviewExtents; constexpr int N0 = 1000; constexpr int N1 = 2000; constexpr int N2 = 3000; constexpr int N3 = 4000; - Kokkos::Experimental::Impl::ViewDimension< N0, N1, N2, N3 > dim; + Kokkos::Impl::ViewDimension< N0, N1, N2, N3 > dim; SubviewExtents tmp( dim , N0 / 2 - , Kokkos::Experimental::ALL + , Kokkos::ALL , std::pair< int, int >( N2 / 4, 10 + N2 / 4 ) , Kokkos::pair< int, int >( N3 / 4, 20 + N3 / 4 ) ); @@ -469,12 +469,12 @@ void test_view_mapping() constexpr int sub_N1 = 200; constexpr int sub_N2 = 4; - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutLeft > left_s0_s0_s4; left_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutLeft( N0, N1, 0, 0, 0, 0, 0, 0 ) ); - Kokkos::Experimental::Impl::SubviewExtents< 3, 3 > + Kokkos::Impl::SubviewExtents< 3, 3 > sub( dyn_off3.m_dim , Kokkos::pair< int, int >( 0, sub_N0 ) , Kokkos::pair< int, int >( 0, sub_N1 ) @@ -509,12 +509,12 @@ void test_view_mapping() constexpr int sub_N1 = 200; constexpr int sub_N2 = 4; - typedef Kokkos::Experimental::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; + typedef Kokkos::Impl::ViewOffset< dim_s0_s0_s4, Kokkos::LayoutRight > right_s0_s0_s4; right_s0_s0_s4 dyn_off3( std::integral_constant< unsigned, sizeof( int ) >() , Kokkos::LayoutRight( N0, N1, 0, 0, 0, 0, 0, 0 ) ); - Kokkos::Experimental::Impl::SubviewExtents< 3, 3 > + Kokkos::Impl::SubviewExtents< 3, 3 > sub( dyn_off3.m_dim , Kokkos::pair< int, int >( 0, sub_N0 ) , Kokkos::pair< int, int >( 0, sub_N1 ) @@ -544,7 +544,7 @@ void test_view_mapping() //---------------------------------------- // View data analysis. { - using namespace Kokkos::Experimental::Impl; + using namespace Kokkos::Impl; static_assert( rank_dynamic<>::value == 0, "" ); static_assert( rank_dynamic< 1 >::value == 0, "" ); @@ -554,7 +554,7 @@ void test_view_mapping() } { - using namespace Kokkos::Experimental::Impl; + using namespace Kokkos::Impl; typedef ViewArrayAnalysis< int[] > a_int_r1; typedef ViewArrayAnalysis< int**[4][5][6] > a_int_r5; @@ -598,7 +598,7 @@ void test_view_mapping() } { - using namespace Kokkos::Experimental::Impl; + using namespace Kokkos::Impl; typedef int t_i4[4]; @@ -616,12 +616,12 @@ void test_view_mapping() } { - using namespace Kokkos::Experimental::Impl; + using namespace Kokkos::Impl; typedef ViewDataAnalysis< const int[], void > a_const_int_r1; static_assert( std::is_same< typename a_const_int_r1::specialize, void >::value, "" ); - static_assert( std::is_same< typename a_const_int_r1::dimension, Kokkos::Experimental::Impl::ViewDimension<0> >::value, "" ); + static_assert( std::is_same< typename a_const_int_r1::dimension, Kokkos::Impl::ViewDimension<0> >::value, "" ); static_assert( std::is_same< typename a_const_int_r1::type, const int * >::value, "" ); static_assert( std::is_same< typename a_const_int_r1::value_type, const int >::value, "" ); @@ -637,7 +637,7 @@ void test_view_mapping() static_assert( std::is_same< typename a_const_int_r3::specialize, void >::value, "" ); - static_assert( std::is_same< typename a_const_int_r3::dimension, Kokkos::Experimental::Impl::ViewDimension<0, 0, 4> >::value, "" ); + static_assert( std::is_same< typename a_const_int_r3::dimension, Kokkos::Impl::ViewDimension<0, 0, 4> >::value, "" ); static_assert( std::is_same< typename a_const_int_r3::type, const int**[4] >::value, "" ); static_assert( std::is_same< typename a_const_int_r3::value_type, const int >::value, "" ); @@ -786,7 +786,7 @@ void test_view_mapping() // The execution space of the memory space must be available for view data initialization. if ( std::is_same< ExecSpace, typename ExecSpace::memory_space::execution_space >::value ) { - using namespace Kokkos::Experimental; + using namespace Kokkos; typedef typename ExecSpace::memory_space memory_space; typedef View< int*, memory_space > V; @@ -811,8 +811,8 @@ void test_view_mapping() { typedef Kokkos::ViewTraits< int***, Kokkos::LayoutStride, ExecSpace > traits_t; - typedef Kokkos::Experimental::Impl::ViewDimension< 0, 0, 0 > dims_t; - typedef Kokkos::Experimental::Impl::ViewOffset< dims_t, Kokkos::LayoutStride > offset_t; + typedef Kokkos::Impl::ViewDimension< 0, 0, 0 > dims_t; + typedef Kokkos::Impl::ViewOffset< dims_t, Kokkos::LayoutStride > offset_t; Kokkos::LayoutStride stride; @@ -836,8 +836,8 @@ void test_view_mapping() ASSERT_EQ( offset.span(), 60 ); ASSERT_TRUE( offset.span_is_contiguous() ); - Kokkos::Experimental::Impl::ViewMapping< traits_t, void > - v( Kokkos::Experimental::Impl::ViewCtorProp< int* >( (int*) 0 ), stride ); + Kokkos::Impl::ViewMapping< traits_t, void > + v( Kokkos::Impl::ViewCtorProp< int* >( (int*) 0 ), stride ); } { @@ -849,8 +849,8 @@ void test_view_mapping() constexpr int N1 = 11; V a( "a", N0, N1 ); - M b = Kokkos::Experimental::create_mirror( a ); - M c = Kokkos::Experimental::create_mirror_view( a ); + M b = Kokkos::create_mirror( a ); + M c = Kokkos::create_mirror_view( a ); M d; for ( int i0 = 0; i0 < N0; ++i0 ) @@ -859,8 +859,8 @@ void test_view_mapping() b( i0, i1 ) = 1 + i0 + i1 * N0; } - Kokkos::Experimental::deep_copy( a, b ); - Kokkos::Experimental::deep_copy( c, a ); + Kokkos::deep_copy( a, b ); + Kokkos::deep_copy( c, a ); for ( int i0 = 0; i0 < N0; ++i0 ) for ( int i1 = 0; i1 < N1; ++i1 ) @@ -868,7 +868,7 @@ void test_view_mapping() ASSERT_EQ( b( i0, i1 ), c( i0, i1 ) ); } - Kokkos::Experimental::resize( b, 5, 6 ); + Kokkos::resize( b, 5, 6 ); for ( int i0 = 0; i0 < 5; ++i0 ) for ( int i1 = 0; i1 < 6; ++i1 ) @@ -878,8 +878,8 @@ void test_view_mapping() ASSERT_EQ( b( i0, i1 ), val ); } - Kokkos::Experimental::realloc( c, 5, 6 ); - Kokkos::Experimental::realloc( d, 5, 6 ); + Kokkos::realloc( c, 5, 6 ); + Kokkos::realloc( d, 5, 6 ); ASSERT_EQ( b.dimension_0(), 5 ); ASSERT_EQ( b.dimension_1(), 6 ); @@ -889,7 +889,7 @@ void test_view_mapping() ASSERT_EQ( d.dimension_1(), 6 ); layout_type layout( 7, 8 ); - Kokkos::Experimental::resize( b, layout ); + Kokkos::resize( b, layout ); for ( int i0 = 0; i0 < 7; ++i0 ) for ( int i1 = 6; i1 < 8; ++i1 ) { @@ -909,8 +909,8 @@ void test_view_mapping() ASSERT_EQ( b( i0, i1 ), val ); } - Kokkos::Experimental::realloc( c, layout ); - Kokkos::Experimental::realloc( d, layout ); + Kokkos::realloc( c, layout ); + Kokkos::realloc( d, layout ); ASSERT_EQ( b.dimension_0(), 7 ); ASSERT_EQ( b.dimension_1(), 8 ); @@ -932,8 +932,8 @@ void test_view_mapping() const int order[] = { 1, 0 }; V a( "a", Kokkos::LayoutStride::order_dimensions( 2, order, dimensions ) ); - M b = Kokkos::Experimental::create_mirror( a ); - M c = Kokkos::Experimental::create_mirror_view( a ); + M b = Kokkos::create_mirror( a ); + M c = Kokkos::create_mirror_view( a ); M d; for ( int i0 = 0; i0 < N0; ++i0 ) @@ -942,8 +942,8 @@ void test_view_mapping() b( i0, i1 ) = 1 + i0 + i1 * N0; } - Kokkos::Experimental::deep_copy( a, b ); - Kokkos::Experimental::deep_copy( c, a ); + Kokkos::deep_copy( a, b ); + Kokkos::deep_copy( c, a ); for ( int i0 = 0; i0 < N0; ++i0 ) for ( int i1 = 0; i1 < N1; ++i1 ) @@ -954,7 +954,7 @@ void test_view_mapping() const int dimensions2[] = { 7, 8 }; const int order2[] = { 1, 0 }; layout_type layout = layout_type::order_dimensions( 2, order2, dimensions2 ); - Kokkos::Experimental::resize( b, layout ); + Kokkos::resize( b, layout ); for ( int i0 = 0; i0 < 7; ++i0 ) for ( int i1 = 0; i1 < 8; ++i1 ) @@ -964,8 +964,8 @@ void test_view_mapping() ASSERT_EQ( b( i0, i1 ), val ); } - Kokkos::Experimental::realloc( c, layout ); - Kokkos::Experimental::realloc( d, layout ); + Kokkos::realloc( c, layout ); + Kokkos::realloc( d, layout ); ASSERT_EQ( b.dimension_0(), 7 ); ASSERT_EQ( b.dimension_1(), 8 ); diff --git a/lib/kokkos/core/unit_test/TestViewSubview.hpp b/lib/kokkos/core/unit_test/TestViewSubview.hpp index e3a12e684e..106323492a 100644 --- a/lib/kokkos/core/unit_test/TestViewSubview.hpp +++ b/lib/kokkos/core/unit_test/TestViewSubview.hpp @@ -915,134 +915,134 @@ void test_3d_subview_5d_impl_layout() { inline void test_subview_legal_args_right() { - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::pair, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutRight, Kokkos::LayoutRight, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); } inline void test_subview_legal_args_left() { - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair, int, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, int, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, int, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::pair, int, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::pair, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::pair, int >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t, int >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::Impl::ALL_t, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::Impl::ALL_t, int, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, Kokkos::pair, Kokkos::pair, int, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 5, 0, int, int, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); - ASSERT_EQ( 1, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); - ASSERT_EQ( 0, ( Kokkos::Experimental::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::pair >::value ) ); + ASSERT_EQ( 1, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::Impl::ALL_t, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::Impl::ALL_t, Kokkos::pair, Kokkos::pair >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::Impl::ALL_t >::value ) ); + ASSERT_EQ( 0, ( Kokkos::Impl::SubviewLegalArgsCompileTime< Kokkos::LayoutLeft, Kokkos::LayoutLeft, 3, 3, 0, Kokkos::pair, Kokkos::pair, Kokkos::pair >::value ) ); } } // namespace Impl diff --git a/lib/kokkos/core/unit_test/TestWorkGraph.hpp b/lib/kokkos/core/unit_test/TestWorkGraph.hpp new file mode 100644 index 0000000000..70cf6b47c0 --- /dev/null +++ b/lib/kokkos/core/unit_test/TestWorkGraph.hpp @@ -0,0 +1,172 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include + +#include + +namespace Test { + +namespace { + +/* This test is meant to be the WorkGraph equivalent of the Task DAG Scheduler test, + please see TestTaskScheduler.hpp for that test. + The algorithm computes the N-th fibonacci number as follows: + - Each "task" or "work item" computes the i-th fibonacci number + - If a task as (i < 2), it will record the known answer ahead of time. + - If a taks has (i >= 2), it will "spawn" two more tasks to compute + the (i - 1) and (i - 2) fibonacci numbers. + We do NOT do any de-duplication of these tasks. + De-duplication would result in only (N - 2) tasks which must be run in serial. + We allow duplicates both to increase the number of tasks and to increase the + amount of available parallelism. + */ + +template< class ExecSpace > +struct TestWorkGraph { + + using MemorySpace = typename ExecSpace::memory_space; + using Policy = Kokkos::Experimental::WorkGraphPolicy; + using Graph = typename Policy::graph_type; + using RowMap = typename Graph::row_map_type; + using Entries = typename Graph::entries_type; + using Values = Kokkos::View; + + long m_input; + Graph m_graph; + Graph m_transpose; + Values m_values; + + TestWorkGraph(long arg_input):m_input(arg_input) { + form_graph(); + transpose_crs(m_transpose, m_graph); + } + + inline + long full_fibonacci( long n ) { + constexpr long mask = 0x03; + long fib[4] = { 0, 1, 1, 2 }; + for ( long i = 2; i <= n; ++i ) { + fib[ i & mask ] = fib[ ( i - 1 ) & mask ] + fib[ ( i - 2 ) & mask ]; + } + return fib[ n & mask ]; + } + + struct HostEntry { + long input; + std::int32_t parent; + }; + std::vector form_host_graph() { + std::vector g; + g.push_back({ m_input , -1 }); + for (std::int32_t i = 0; i < std::int32_t(g.size()); ++i) { + auto e = g.at(std::size_t(i)); + if (e.input < 2) continue; + /* This part of the host graph formation is the equivalent of task spawning + in the Task DAG system. Notice how each task which is not a base case + spawns two more tasks, without any de-duplication */ + g.push_back({ e.input - 1, i }); + g.push_back({ e.input - 2, i }); + } + return g; + } + + void form_graph() { + auto hg = form_host_graph(); + m_graph.row_map = RowMap("row_map", hg.size() + 1); // row map always has one more + m_graph.entries = Entries("entries", hg.size() - 1); // all but the first have a parent + m_values = Values("values", hg.size()); + auto h_row_map = Kokkos::create_mirror_view(m_graph.row_map); + auto h_entries = Kokkos::create_mirror_view(m_graph.entries); + auto h_values = Kokkos::create_mirror_view(m_values); + h_row_map(0) = 0; + for (std::int32_t i = 0; i < std::int32_t(hg.size()); ++i) { + auto& e = hg.at(std::size_t(i)); + h_row_map(i + 1) = i; + if (e.input < 2) { + h_values(i) = e.input; + } + if (e.parent == -1) continue; + h_entries(i - 1) = e.parent; + } + Kokkos::deep_copy(m_graph.row_map, h_row_map); + Kokkos::deep_copy(m_graph.entries, h_entries); + Kokkos::deep_copy(m_values, h_values); + } + + KOKKOS_INLINE_FUNCTION + void operator()(std::int32_t i) const { + auto begin = m_transpose.row_map(i); + auto end = m_transpose.row_map(i + 1); + for (auto j = begin; j < end; ++j) { + auto k = m_transpose.entries(j); + m_values(i) += m_values( k ); + } + } + + void test_for() { + Kokkos::parallel_for(Policy(m_graph), *this); + auto h_values = Kokkos::create_mirror_view(m_values); + Kokkos::deep_copy(h_values, m_values); + ASSERT_EQ( h_values(0), full_fibonacci(m_input) ); + } + +}; + +} // anonymous namespace + +TEST_F( TEST_CATEGORY, DISABLED_workgraph_fib ) +{ + #ifdef KOKKOS_IMPL_CUDA_CLANG_WORKAROUND + int limit = 15; + #else + int limit = 27; + #endif + for ( int i = 0; i < limit; ++i) { + TestWorkGraph< TEST_EXECSPACE > f(i); + f.test_for(); + } +} + +} // namespace Test diff --git a/lib/kokkos/core/unit_test/UnitTestMain.cpp b/lib/kokkos/core/unit_test/UnitTestMain.cpp index 4f52fc9567..a7dc7c4973 100644 --- a/lib/kokkos/core/unit_test/UnitTestMain.cpp +++ b/lib/kokkos/core/unit_test/UnitTestMain.cpp @@ -42,6 +42,7 @@ */ #include +#include int main( int argc, char *argv[] ) { ::testing::InitGoogleTest( &argc, argv ); diff --git a/lib/kokkos/core/unit_test/UnitTestMainInit.cpp b/lib/kokkos/core/unit_test/UnitTestMainInit.cpp index 21f851274b..62a01e9033 100644 --- a/lib/kokkos/core/unit_test/UnitTestMainInit.cpp +++ b/lib/kokkos/core/unit_test/UnitTestMainInit.cpp @@ -42,6 +42,8 @@ */ #include +#include + #include int main( int argc, char *argv[] ) { diff --git a/lib/kokkos/core/unit_test/cuda/TestCuda_Other.cpp b/lib/kokkos/core/unit_test/cuda/TestCuda_Other.cpp index ba06b71192..fa6722615c 100644 --- a/lib/kokkos/core/unit_test/cuda/TestCuda_Other.cpp +++ b/lib/kokkos/core/unit_test/cuda/TestCuda_Other.cpp @@ -48,3 +48,5 @@ #include #include #include + +#include diff --git a/lib/kokkos/core/unit_test/cuda/TestCuda_UniqueToken.cpp b/lib/kokkos/core/unit_test/cuda/TestCuda_UniqueToken.cpp new file mode 100644 index 0000000000..8424ae10d6 --- /dev/null +++ b/lib/kokkos/core/unit_test/cuda/TestCuda_UniqueToken.cpp @@ -0,0 +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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include + diff --git a/lib/kokkos/core/unit_test/cuda/TestCuda_WorkGraph.cpp b/lib/kokkos/core/unit_test/cuda/TestCuda_WorkGraph.cpp new file mode 100644 index 0000000000..663ca1d560 --- /dev/null +++ b/lib/kokkos/core/unit_test/cuda/TestCuda_WorkGraph.cpp @@ -0,0 +1,45 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include diff --git a/lib/kokkos/core/unit_test/default/TestDefaultDeviceTypeResize.cpp b/lib/kokkos/core/unit_test/default/TestDefaultDeviceTypeResize.cpp new file mode 100644 index 0000000000..c02905535b --- /dev/null +++ b/lib/kokkos/core/unit_test/default/TestDefaultDeviceTypeResize.cpp @@ -0,0 +1,57 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include "TestResize.hpp" + +namespace Test { + +TEST( kokkosresize, host_space_access ) +{ + // Test with the default device type. + using TestViewResize::testResize; + typedef Kokkos::View::device_type device_type; + testResize (); +} + +} // namespace Test diff --git a/lib/kokkos/core/unit_test/openmp/TestOpenMP.hpp b/lib/kokkos/core/unit_test/openmp/TestOpenMP.hpp index 2f8daf7ad7..c12574a65a 100644 --- a/lib/kokkos/core/unit_test/openmp/TestOpenMP.hpp +++ b/lib/kokkos/core/unit_test/openmp/TestOpenMP.hpp @@ -86,25 +86,26 @@ class openmp : public ::testing::Test { protected: static void SetUpTestCase() { - const unsigned numa_count = Kokkos::hwloc::get_available_numa_count(); - const unsigned cores_per_numa = Kokkos::hwloc::get_available_cores_per_numa(); - const unsigned threads_per_core = Kokkos::hwloc::get_available_threads_per_core(); + int threads_count = 0; + #pragma omp parallel + { + #pragma omp atomic + ++threads_count; + } - const unsigned threads_count = std::max( 1u, numa_count ) * - std::max( 2u, ( cores_per_numa * threads_per_core ) / 2 ); + if (threads_count > 3) { + threads_count /= 2; + } Kokkos::OpenMP::initialize( threads_count ); Kokkos::print_configuration( std::cout, true ); + srand( 10231 ); } static void TearDownTestCase() { Kokkos::OpenMP::finalize(); - - omp_set_num_threads( 1 ); - - ASSERT_EQ( 1, omp_get_max_threads() ); } }; diff --git a/lib/kokkos/core/unit_test/openmp/TestOpenMP_Other.cpp b/lib/kokkos/core/unit_test/openmp/TestOpenMP_Other.cpp index 5e9535638d..33e7402ce6 100644 --- a/lib/kokkos/core/unit_test/openmp/TestOpenMP_Other.cpp +++ b/lib/kokkos/core/unit_test/openmp/TestOpenMP_Other.cpp @@ -48,3 +48,93 @@ #include #include #include + +#include + +#include + +namespace Test { + +TEST_F( openmp, partition_master ) +{ + using Mutex = Kokkos::Experimental::MasterLock; + + Mutex mtx; + int errors = 0; + + auto master = [&errors, &mtx](int partition_id, int num_partitions) { + + const int pool_size = Kokkos::OpenMP::thread_pool_size(); + + { + std::unique_lock lock(mtx); + if ( Kokkos::OpenMP::in_parallel() ) { + ++errors; + } + if ( Kokkos::OpenMP::thread_pool_rank() != 0 ) { + ++errors; + } + } + + { + int local_errors = 0; + Kokkos::parallel_reduce( Kokkos::RangePolicy(0,1000) + , [pool_size]( const int , int & errs ) { + if ( Kokkos::OpenMP::thread_pool_size() != pool_size ) { + ++errs; + } + } + , local_errors + ); + Kokkos::atomic_add( &errors, local_errors ); + } + + Kokkos::Experimental::UniqueToken< Kokkos::OpenMP > token; + + Kokkos::View count( "", token.size() ); + + Kokkos::parallel_for( Kokkos::RangePolicy(0,1000), + [=] ( const int ) { + int i = token.acquire(); + ++count[i]; + token.release(i); + }); + + Kokkos::View sum (""); + Kokkos::parallel_for( Kokkos::RangePolicy(0,token.size()), + [=] ( const int i ) { + Kokkos::atomic_add( sum.data(), count[i] ); + }); + + if (sum() != 1000) { + Kokkos::atomic_add( &errors, 1 ); + } + }; + + master(0,1); + + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 4, 0 ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 0, 4 ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 2, 2 ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 8, 0 ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 0, 8 ); + ASSERT_EQ( errors, 0 ); + + Kokkos::OpenMP::partition_master( master, 8, 8 ); + ASSERT_EQ( errors, 0 ); +} + +} // namespace Test diff --git a/lib/kokkos/core/unit_test/openmp/TestOpenMP_UniqueToken.cpp b/lib/kokkos/core/unit_test/openmp/TestOpenMP_UniqueToken.cpp new file mode 100644 index 0000000000..143a6d9910 --- /dev/null +++ b/lib/kokkos/core/unit_test/openmp/TestOpenMP_UniqueToken.cpp @@ -0,0 +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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include + diff --git a/lib/kokkos/core/unit_test/openmp/TestOpenMP_WorkGraph.cpp b/lib/kokkos/core/unit_test/openmp/TestOpenMP_WorkGraph.cpp new file mode 100644 index 0000000000..ec6fa1653c --- /dev/null +++ b/lib/kokkos/core/unit_test/openmp/TestOpenMP_WorkGraph.cpp @@ -0,0 +1,45 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include diff --git a/lib/kokkos/core/unit_test/serial/TestSerial_Other.cpp b/lib/kokkos/core/unit_test/serial/TestSerial_Other.cpp index a6a76a03bd..bc39b1e160 100644 --- a/lib/kokkos/core/unit_test/serial/TestSerial_Other.cpp +++ b/lib/kokkos/core/unit_test/serial/TestSerial_Other.cpp @@ -48,3 +48,5 @@ #include #include #include + +#include diff --git a/lib/kokkos/core/unit_test/serial/TestSerial_WorkGraph.cpp b/lib/kokkos/core/unit_test/serial/TestSerial_WorkGraph.cpp new file mode 100644 index 0000000000..de1638de5e --- /dev/null +++ b/lib/kokkos/core/unit_test/serial/TestSerial_WorkGraph.cpp @@ -0,0 +1,45 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include diff --git a/lib/kokkos/core/unit_test/threads/TestThreads_Other.cpp b/lib/kokkos/core/unit_test/threads/TestThreads_Other.cpp index c11155c5c0..160b37a2c8 100644 --- a/lib/kokkos/core/unit_test/threads/TestThreads_Other.cpp +++ b/lib/kokkos/core/unit_test/threads/TestThreads_Other.cpp @@ -48,3 +48,5 @@ #include #include #include + +#include diff --git a/lib/kokkos/core/unit_test/threads/TestThreads_WorkGraph.cpp b/lib/kokkos/core/unit_test/threads/TestThreads_WorkGraph.cpp new file mode 100644 index 0000000000..6b7dbb26db --- /dev/null +++ b/lib/kokkos/core/unit_test/threads/TestThreads_WorkGraph.cpp @@ -0,0 +1,45 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include diff --git a/lib/kokkos/example/cmake_build/CMakeLists.txt b/lib/kokkos/example/cmake_build/CMakeLists.txt index 4e149726ee..f92c5c6513 100644 --- a/lib/kokkos/example/cmake_build/CMakeLists.txt +++ b/lib/kokkos/example/cmake_build/CMakeLists.txt @@ -40,5 +40,7 @@ list(APPEND CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} -O3) add_subdirectory(${Example_SOURCE_DIR}/../.. ${Example_BINARY_DIR}/kokkos) +include_directories(${Kokkos_INCLUDE_DIRS_RET}) + add_executable(example cmake_example.cpp) target_link_libraries(example kokkos) diff --git a/lib/kokkos/example/feint/main.cpp b/lib/kokkos/example/feint/main.cpp index 616e584bf6..57a8f8fafb 100644 --- a/lib/kokkos/example/feint/main.cpp +++ b/lib/kokkos/example/feint/main.cpp @@ -69,12 +69,26 @@ int main() #if defined( KOKKOS_ENABLE_OPENMP ) { - // Use 4 cores per NUMA region, unless fewer available - const unsigned use_numa_count = Kokkos::hwloc::get_available_numa_count(); - const unsigned use_cores_per_numa = std::min( 4u , Kokkos::hwloc::get_available_cores_per_numa() ); + int num_threads = 0; + if ( Kokkos::hwloc::available() ) { + // Use 4 cores per NUMA region, unless fewer available + const unsigned use_numa_count = Kokkos::hwloc::get_available_numa_count(); + const unsigned use_cores_per_numa = std::min( 4u , Kokkos::hwloc::get_available_cores_per_numa() ); + num_threads = use_numa_count * use_cores_per_numa; - Kokkos::OpenMP::initialize( use_numa_count * use_cores_per_numa ); + } + else { + #pragma omp parallel + { + #pragma omp atomic + ++num_threads; + } + num_threads = std::max(4, num_threads/4); + } + + + Kokkos::OpenMP::initialize( num_threads ); std::cout << "feint< OpenMP , NotUsingAtomic >" << std::endl ; Kokkos::Example::feint< Kokkos::OpenMP , false >(); diff --git a/lib/kokkos/example/global_2_local_ids/G2L_Main.cpp b/lib/kokkos/example/global_2_local_ids/G2L_Main.cpp index fb33aef56e..b6b8b2f5e0 100644 --- a/lib/kokkos/example/global_2_local_ids/G2L_Main.cpp +++ b/lib/kokkos/example/global_2_local_ids/G2L_Main.cpp @@ -138,7 +138,16 @@ int main(int argc, char *argv[]) #endif #ifdef KOKKOS_ENABLE_OPENMP - Kokkos::OpenMP::initialize( threads_count ); + int num_threads = 0; + #pragma omp parallel + { + #pragma omp atomic + ++num_threads; + } + if( num_threads > 3 ) { + num_threads = std::max(4, num_threads/4); + } + Kokkos::OpenMP::initialize( num_threads ); num_errors += G2L::run_openmp(num_ids,num_find_iterations); Kokkos::OpenMP::finalize(); #endif diff --git a/lib/kokkos/example/grow_array/main.cpp b/lib/kokkos/example/grow_array/main.cpp index e7438a9bf4..3f1d534d93 100644 --- a/lib/kokkos/example/grow_array/main.cpp +++ b/lib/kokkos/example/grow_array/main.cpp @@ -88,7 +88,7 @@ int main( int argc , char ** argv ) #if defined( KOKKOS_ENABLE_OPENMP ) { std::cout << "Kokkos::OpenMP" << std::endl ; - Kokkos::OpenMP::initialize( num_threads , use_numa , use_core ); + Kokkos::OpenMP::initialize(); Example::grow_array< Kokkos::OpenMP >( length_array , span_values ); Kokkos::OpenMP::finalize(); } diff --git a/lib/kokkos/example/tutorial/03_simple_view/Makefile b/lib/kokkos/example/tutorial/03_simple_view/Makefile index e716b765e7..32483a2555 100644 --- a/lib/kokkos/example/tutorial/03_simple_view/Makefile +++ b/lib/kokkos/example/tutorial/03_simple_view/Makefile @@ -33,6 +33,7 @@ include $(KOKKOS_PATH)/Makefile.kokkos build: $(EXE) +#for unit testing only, for best preformance with OpenMP 4.0 or better test: $(EXE) ./$(EXE) diff --git a/lib/kokkos/example/tutorial/Advanced_Views/Makefile b/lib/kokkos/example/tutorial/Advanced_Views/Makefile index bc4012f68c..12ac5652e5 100644 --- a/lib/kokkos/example/tutorial/Advanced_Views/Makefile +++ b/lib/kokkos/example/tutorial/Advanced_Views/Makefile @@ -22,100 +22,102 @@ endif build: mkdir -p 01_data_layouts cd ./01_data_layouts; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} mkdir -p 02_memory_traits cd ./02_memory_traits; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} mkdir -p 03_subviews cd ./03_subviews; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} mkdir -p 04_dualviews cd ./04_dualviews; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} mkdir -p 05_NVIDIA_UVM cd ./05_NVIDIA_UVM; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} #mkdir -p 06_AtomicViews #cd ./06_AtomicViews; \ - #make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} #mkdir -p 07_Overlapping_DeepCopy #cd ./07_Overlapping_DeepCopy; \ - #make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} build-insource: cd ./01_data_layouts; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./02_memory_traits; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./03_subviews; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./04_dualviews; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./05_NVIDIA_UVM; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} #cd ./06_AtomicViews; \ - #make build -j 4 ${KOKKOS_SETTINGS} + #$(MAKE) build ${KOKKOS_SETTINGS} #cd ./07_Overlapping_DeepCopy; \ - #make build -j 4 ${KOKKOS_SETTINGS} + #$(MAKE) build ${KOKKOS_SETTINGS} + test: cd ./01_data_layouts; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} cd ./02_memory_traits; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} cd ./03_subviews; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} cd ./04_dualviews; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} cd ./05_NVIDIA_UVM; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} #cd ./06_AtomicViews; \ - #make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} #cd ./07_Overlapping_DeepCopy; \ - #make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} test-insource: cd ./01_data_layouts; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./02_memory_traits; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./03_subviews; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./04_dualviews; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./05_NVIDIA_UVM; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} #cd ./06_AtomicViews; \ - #make test -j 4 ${KOKKOS_SETTINGS} + #$(MAKE) test ${KOKKOS_SETTINGS} #cd ./07_Overlapping_DeepCopy; \ - #make test -j 4 ${KOKKOS_SETTINGS} + #$(MAKE) test ${KOKKOS_SETTINGS} + clean: cd ./01_data_layouts; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/01_data_layouts/Makefile ${KOKKOS_SETTINGS} cd ./02_memory_traits; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/02_memory_traits/Makefile ${KOKKOS_SETTINGS} cd ./03_subviews; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/03_subviews/Makefile ${KOKKOS_SETTINGS} cd ./04_dualviews; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/04_dualviews/Makefile ${KOKKOS_SETTINGS} cd ./05_NVIDIA_UVM; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/05_NVIDIA_UVM/Makefile ${KOKKOS_SETTINGS} #cd ./06_AtomicViews; \ - #make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/06_AtomicViews/Makefile ${KOKKOS_SETTINGS} #cd ./07_Overlapping_DeepCopy; \ - #make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} + #$(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/07_Overlapping_DeepCopy/Makefile ${KOKKOS_SETTINGS} clean-insource: cd ./01_data_layouts; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./02_memory_traits; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./03_subviews; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./04_dualviews; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./05_NVIDIA_UVM; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} #cd ./06_AtomicViews; \ - #make clean ${KOKKOS_SETTINGS} + #$(MAKE) clean ${KOKKOS_SETTINGS} #cd ./07_Overlapping_DeepCopy; \ - #make clean ${KOKKOS_SETTINGS} + #$(MAKE) clean ${KOKKOS_SETTINGS} diff --git a/lib/kokkos/example/tutorial/Algorithms/Makefile b/lib/kokkos/example/tutorial/Algorithms/Makefile index ad0b76f9d6..4e70ba7d97 100644 --- a/lib/kokkos/example/tutorial/Algorithms/Makefile +++ b/lib/kokkos/example/tutorial/Algorithms/Makefile @@ -22,22 +22,22 @@ endif build: mkdir -p 01_random_numbers cd ./01_random_numbers; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} build-insource: cd ./01_random_numbers; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} test: cd ./01_random_numbers; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} test-insource: cd ./01_random_numbers; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} clean: cd ./01_random_numbers; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Algorithms/01_random_numbers/Makefile ${KOKKOS_SETTINGS} clean-insource: cd ./01_random_numbers; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} diff --git a/lib/kokkos/example/tutorial/Hierarchical_Parallelism/Makefile b/lib/kokkos/example/tutorial/Hierarchical_Parallelism/Makefile index 44fdf90f8a..4bf6d487ae 100644 --- a/lib/kokkos/example/tutorial/Hierarchical_Parallelism/Makefile +++ b/lib/kokkos/example/tutorial/Hierarchical_Parallelism/Makefile @@ -22,74 +22,74 @@ endif build: mkdir -p 01_thread_teams cd ./01_thread_teams; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} mkdir -p 01_thread_teams_lambda cd ./01_thread_teams_lambda; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} mkdir -p 02_nested_parallel_for cd ./02_nested_parallel_for; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} mkdir -p 03_vectorization cd ./03_vectorization; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} mkdir -p 04_team_scan cd ./04_team_scan; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} build-insource: cd ./01_thread_teams; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./01_thread_teams_lambda; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./02_nested_parallel_for; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./03_vectorization; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./04_team_scan; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} test: cd ./01_thread_teams; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} cd ./01_thread_teams_lambda; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} cd ./02_nested_parallel_for; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} cd ./03_vectorization; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} cd ./04_team_scan; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} test-insource: cd ./01_thread_teams; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./01_thread_teams_lambda; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./02_nested_parallel_for; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./03_vectorization; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./04_team_scan; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} clean: cd ./01_thread_teams; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams/Makefile ${KOKKOS_SETTINGS} cd ./01_thread_teams_lambda; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/01_thread_teams_lambda/Makefile ${KOKKOS_SETTINGS} cd ./02_nested_parallel_for; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/02_nested_parallel_for/Makefile ${KOKKOS_SETTINGS} cd ./03_vectorization; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/03_vectorization/Makefile ${KOKKOS_SETTINGS} cd ./04_team_scan; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/04_team_scan/Makefile ${KOKKOS_SETTINGS} clean-insource: cd ./01_thread_teams; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./01_thread_teams_lambda; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./02_nested_parallel_for; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./03_vectorization; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./04_team_scan; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} diff --git a/lib/kokkos/example/tutorial/Makefile b/lib/kokkos/example/tutorial/Makefile index 063ace8aab..7b2732eeed 100644 --- a/lib/kokkos/example/tutorial/Makefile +++ b/lib/kokkos/example/tutorial/Makefile @@ -23,152 +23,152 @@ endif build: mkdir -p 01_hello_world cd ./01_hello_world; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} mkdir -p 01_hello_world_lambda cd ./01_hello_world_lambda; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} mkdir -p 02_simple_reduce cd ./02_simple_reduce; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} mkdir -p 02_simple_reduce_lambda cd ./02_simple_reduce_lambda; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} mkdir -p 03_simple_view cd ./03_simple_view; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} mkdir -p 03_simple_view_lambda cd ./03_simple_view_lambda; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} mkdir -p 04_simple_memoryspaces cd ./04_simple_memoryspaces; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} mkdir -p 05_simple_atomics cd ./05_simple_atomics; \ - make build -j 4 -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} mkdir -p Advanced_Views cd ./Advanced_Views; \ - make build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' mkdir -p Algorithms cd ./Algorithms; \ - make build -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' mkdir -p Hierarchical_Parallelism cd ./Hierarchical_Parallelism; \ - make build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' build-insource: cd ./01_hello_world; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./01_hello_world_lambda; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./02_simple_reduce; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./02_simple_reduce_lambda; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./03_simple_view; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./03_simple_view_lambda; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./04_simple_memoryspaces; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./05_simple_atomics; \ - make build -j 4 ${KOKKOS_SETTINGS} + $(MAKE) build ${KOKKOS_SETTINGS} cd ./Advanced_Views; \ - make build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Algorithms; \ - make build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Hierarchical_Parallelism; \ - make build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) build KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' test: cd ./01_hello_world; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} cd ./01_hello_world_lambda; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} cd ./02_simple_reduce; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} cd ./02_simple_reduce_lambda; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} cd ./03_simple_view; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} cd ./03_simple_view_lambda; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} cd ./04_simple_memoryspaces; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} cd ./05_simple_atomics; \ - make test -j 4 -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} cd ./Advanced_Views; \ - make test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Algorithms; \ - make test -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Hierarchical_Parallelism; \ - make test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' test-insource: cd ./01_hello_world; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./01_hello_world_lambda; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./02_simple_reduce; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./02_simple_reduce_lambda; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./03_simple_view; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./03_simple_view_lambda; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./04_simple_memoryspaces; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./05_simple_atomics; \ - make test -j 4 ${KOKKOS_SETTINGS} + $(MAKE) test ${KOKKOS_SETTINGS} cd ./Advanced_Views; \ - make test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Algorithms; \ - make test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Hierarchical_Parallelism; \ - make test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) test KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' clean: cd ./01_hello_world; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/01_hello_world/Makefile ${KOKKOS_SETTINGS} cd ./01_hello_world_lambda; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/01_hello_world_lambda/Makefile ${KOKKOS_SETTINGS} cd ./02_simple_reduce; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce/Makefile ${KOKKOS_SETTINGS} cd ./02_simple_reduce_lambda; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/02_simple_reduce_lambda/Makefile ${KOKKOS_SETTINGS} cd ./03_simple_view; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/03_simple_view/Makefile ${KOKKOS_SETTINGS} cd ./03_simple_view_lambda; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/03_simple_view_lambda/Makefile ${KOKKOS_SETTINGS} cd ./04_simple_memoryspaces; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/04_simple_memoryspaces/Makefile ${KOKKOS_SETTINGS} cd ./05_simple_atomics; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/05_simple_atomics/Makefile ${KOKKOS_SETTINGS} cd ./Advanced_Views; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Advanced_Views/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Algorithms; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Algorithms/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Hierarchical_Parallelism; \ - make clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean -f ${KOKKOS_PATH}/example/tutorial/Hierarchical_Parallelism/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' clean-insource: cd ./01_hello_world; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./01_hello_world_lambda; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./02_simple_reduce; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./02_simple_reduce_lambda; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./03_simple_view; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./03_simple_view_lambda; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./04_simple_memoryspaces; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./05_simple_atomics; \ - make clean ${KOKKOS_SETTINGS} + $(MAKE) clean ${KOKKOS_SETTINGS} cd ./Advanced_Views; \ - make clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Algorithms; \ - make clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' cd ./Hierarchical_Parallelism; \ - make clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' + $(MAKE) clean KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' diff --git a/lib/kokkos/example/tutorial/launch_bounds/CMakeLists.txt b/lib/kokkos/example/tutorial/launch_bounds/CMakeLists.txt new file mode 100644 index 0000000000..7c78db840f --- /dev/null +++ b/lib/kokkos/example/tutorial/launch_bounds/CMakeLists.txt @@ -0,0 +1,10 @@ + +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +# This is a tutorial, not a test, so we don't ask CTest to run it. +TRIBITS_ADD_EXECUTABLE( + tutorial_02_simple_reduce + SOURCES simple_reduce.cpp + COMM serial mpi + ) diff --git a/lib/kokkos/example/tutorial/launch_bounds/Makefile b/lib/kokkos/example/tutorial/launch_bounds/Makefile new file mode 100644 index 0000000000..5b605a4119 --- /dev/null +++ b/lib/kokkos/example/tutorial/launch_bounds/Makefile @@ -0,0 +1,56 @@ +KOKKOS_PATH = ../../.. +KOKKOS_SRC_PATH = ${KOKKOS_PATH} +SRC = $(wildcard ${KOKKOS_SRC_PATH}/example/tutorial/launch_bounds/*.cpp) +vpath %.cpp $(sort $(dir $(SRC))) + +default: build + echo "Start Build" + +ifneq (,$(findstring Cuda,$(KOKKOS_DEVICES))) +CXX = ${KOKKOS_PATH}/bin/nvcc_wrapper +CXXFLAGS = -O3 +LINK = ${CXX} +LINKFLAGS = +EXE = launch_bounds.cuda +KOKKOS_DEVICES = "Cuda,OpenMP" +KOKKOS_ARCH = "SNB,Kepler35" +else +CXX = g++ +CXXFLAGS = -O3 +LINK = ${CXX} +LINKFLAGS = +EXE = launch_bounds.host +KOKKOS_DEVICES = "OpenMP" +KOKKOS_ARCH = "SNB" +endif + +# WAR for "undefined memcpy" w/ Ubuntu + CUDA 7.5 +CXXFLAGS += -D_FORCE_INLINES +# Additional compile-time information +CXXFLAGS += -Xptxas=-v + +DEPFLAGS = -M + +OBJ = $(notdir $(SRC:.cpp=.o)) +LIB = + +include $(KOKKOS_PATH)/Makefile.kokkos + +temp: + echo $(KOKKOS_INTERNAL_USE_CUDA) $(CUDA_PATH) + +build: $(EXE) + +test: $(EXE) + ./$(EXE) + +$(EXE): $(OBJ) $(KOKKOS_LINK_DEPENDS) + $(LINK) $(KOKKOS_LDFLAGS) $(LINKFLAGS) $(EXTRA_PATH) $(OBJ) $(KOKKOS_LIBS) $(LIB) -o $(EXE) + +clean: kokkos-clean + rm -f *.o *.cuda *.host + +# Compilation rules + +%.o:%.cpp $(KOKKOS_CPP_DEPENDS) + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) $(EXTRA_INC) -c $< -o $(notdir $@) diff --git a/lib/kokkos/example/tutorial/launch_bounds/launch_bounds_reduce.cpp b/lib/kokkos/example/tutorial/launch_bounds/launch_bounds_reduce.cpp new file mode 100644 index 0000000000..9a26eda507 --- /dev/null +++ b/lib/kokkos/example/tutorial/launch_bounds/launch_bounds_reduce.cpp @@ -0,0 +1,173 @@ +/* +//@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 H. Carter Edwards (hcedwar@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#include +#include + +// +// First reduction (parallel_reduce) example: +// 1. Start up Kokkos +// 2. Execute a parallel_reduce loop in the default execution space, +// using a functor to define the loop body +// 3. Shut down Kokkos +// +struct collision { +// Reduction functor +// For each i, we generate 10 hashes, look for and count collisions +// We use parallel_reduce to count the total collisions +// Note that we're just counting collisions within the 10 generated +// one i. +// This function was chosen as one that very simply can increase the +// register count. + typedef int value_type; + + KOKKOS_INLINE_FUNCTION + int hash(int q) const { + // A simple hash by Justin Sobel + // Thanks to Arash Partow (partow.net) + char* fourchars = (char*)&q; + int hash = 1315423911; + for (int i=0; i<4; fourchars++, i++) { + hash ^= ((hash<<5) + *fourchars + (hash >> 2)); + } + return hash; + } + + KOKKOS_INLINE_FUNCTION + void operator () (const int i, int& lsum) const { + //This is a silly function which generates 10 hashes + // then checks for collisions + int a = hash(i)%64; + int b = hash(i*3)%64; + int c = hash(i*5)%64; + int d = hash(i*7)%64; + int e = hash(i*11)%64; + int f = hash(i*17)%64; + int g = hash(i*23)%64; + int h = hash(i*29)%64; + int j = hash(i*31)%64; + int k = hash(i*37)%64; + + + if (a==b) lsum++; + if (a==c) lsum++; + if (a==d) lsum++; + if (a==e) lsum++; + if (a==f) lsum++; + if (a==g) lsum++; + if (a==h) lsum++; + if (a==j) lsum++; + if (a==k) lsum++; + if (b==c) lsum++; + if (b==d) lsum++; + if (b==e) lsum++; + if (b==f) lsum++; + if (b==g) lsum++; + if (b==h) lsum++; + if (b==j) lsum++; + if (b==k) lsum++; + if (c==d) lsum++; + if (c==e) lsum++; + if (c==f) lsum++; + if (c==g) lsum++; + if (c==h) lsum++; + if (c==j) lsum++; + if (c==k) lsum++; + if (d==e) lsum++; + if (d==f) lsum++; + if (d==g) lsum++; + if (d==h) lsum++; + if (d==j) lsum++; + if (d==k) lsum++; + if (e==f) lsum++; + if (e==g) lsum++; + if (e==h) lsum++; + if (e==j) lsum++; + if (e==k) lsum++; + if (f==g) lsum++; + if (f==h) lsum++; + if (f==j) lsum++; + if (f==k) lsum++; + if (g==h) lsum++; + if (g==j) lsum++; + if (g==k) lsum++; + if (h==j) lsum++; + if (h==k) lsum++; + if (j==k) lsum++; + } + + + +}; + +int main (int argc, char* argv[]) { + Kokkos::initialize (argc, argv); + const int n = 10000; + + // Compute and count hash collisions in + // parallel, using Kokkos. + // This is not really a useful algorithm, but it demonstrates the + // LaunchBounds functionality + int sum1 = 0; + int sum2 = 0; + + //Without LaunchBounds, the kernel uses 56 registers + Kokkos::parallel_reduce (n, collision (), sum1); + + //With LaunchBounds, we can reduce the register usage to 32 + Kokkos::parallel_reduce (Kokkos::RangePolicy>(0,n), collision (), sum2); + + printf ("Number of collisions, " + "computed in parallel, is %i\n", sum1); + + if (sum1 != sum2) { + printf( "Uh-oh! Results do not match\n"); + return -1; + } + + Kokkos::finalize(); + + + return 0; +} + diff --git a/lib/kokkos/generate_makefile.bash b/lib/kokkos/generate_makefile.bash index 5f2442102d..6d636dc7e4 100755 --- a/lib/kokkos/generate_makefile.bash +++ b/lib/kokkos/generate_makefile.bash @@ -1,7 +1,6 @@ #!/bin/bash KOKKOS_DEVICES="" -MAKE_J_OPTION="32" KOKKOS_DO_EXAMPLES="1" @@ -70,7 +69,8 @@ do KOKKOS_DEBUG=yes ;; --make-j*) - MAKE_J_OPTION="${key#*=}" + echo "Warning: ${key} is deprecated" + echo "Call make with appropriate -j flag" ;; --no-examples) KOKKOS_DO_EXAMPLES="0" @@ -110,23 +110,34 @@ do 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 " [ARM]" echo " ARMv80 = ARMv8.0 Compatible CPU" echo " ARMv81 = ARMv8.1 Compatible CPU" echo " ARMv8-ThunderX = ARMv8 Cavium ThunderX CPU" + echo " [IBM]" + 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 " Maxwell50 = NVIDIA Maxwell generation CC 5.0" - echo " Power8 = IBM POWER8 CPUs" - echo " Power9 = IBM POWER9 CPUs" echo "" echo "--compiler=/Path/To/Compiler Set the compiler." echo "--debug,-dbg: Enable Debugging." @@ -142,10 +153,14 @@ do echo " tests.)" echo "--with-hwloc=/Path/To/Hwloc: Set path to hwloc." 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 "--make-j=[NUM]: Set -j flag used during build." + echo "--make-j=[NUM]: DEPRECATED: call make with appropriate" + echo " -j flag" exit 0 ;; *) @@ -237,27 +252,27 @@ else KOKKOS_INSTALL_PATH=${KOKKOS_TEST_INSTALL_PATH} fi -mkdir install +mkdir -p install echo "#Makefile to satisfy existens of target kokkos-clean before installing the library" > install/Makefile.kokkos echo "kokkos-clean:" >> install/Makefile.kokkos echo "" >> install/Makefile.kokkos -mkdir core -mkdir core/unit_test -mkdir core/perf_test -mkdir containers -mkdir containers/unit_tests -mkdir containers/performance_tests -mkdir algorithms -mkdir algorithms/unit_tests -mkdir algorithms/performance_tests -mkdir example -mkdir example/fixture -mkdir example/feint -mkdir example/fenl -mkdir example/tutorial +mkdir -p core +mkdir -p core/unit_test +mkdir -p core/perf_test +mkdir -p containers +mkdir -p containers/unit_tests +mkdir -p containers/performance_tests +mkdir -p algorithms +mkdir -p algorithms/unit_tests +mkdir -p algorithms/performance_tests +mkdir -p example +mkdir -p example/fixture +mkdir -p example/feint +mkdir -p example/fenl +mkdir -p example/tutorial if [ ${#KOKKOS_ENABLE_EXAMPLE_ICHOL} -gt 0 ]; then - mkdir example/ichol + mkdir -p example/ichol fi KOKKOS_SETTINGS="${KOKKOS_SETTINGS_NO_KOKKOS_PATH} KOKKOS_PATH=${KOKKOS_PATH}" @@ -266,115 +281,115 @@ KOKKOS_SETTINGS="${KOKKOS_SETTINGS_NO_KOKKOS_PATH} KOKKOS_PATH=${KOKKOS_PATH}" echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > core/unit_test/Makefile echo "" >> core/unit_test/Makefile echo "all:" >> core/unit_test/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS}" >> core/unit_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS}" >> core/unit_test/Makefile echo "" >> core/unit_test/Makefile echo "test: all" >> core/unit_test/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS} test" >> core/unit_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS} test" >> core/unit_test/Makefile echo "" >> core/unit_test/Makefile echo "clean:" >> core/unit_test/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS} clean" >> core/unit_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/unit_test/Makefile ${KOKKOS_SETTINGS} clean" >> core/unit_test/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > core/perf_test/Makefile echo "" >> core/perf_test/Makefile echo "all:" >> core/perf_test/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS}" >> core/perf_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS}" >> core/perf_test/Makefile echo "" >> core/perf_test/Makefile echo "test: all" >> core/perf_test/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS} test" >> core/perf_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS} test" >> core/perf_test/Makefile echo "" >> core/perf_test/Makefile echo "clean:" >> core/perf_test/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS} clean" >> core/perf_test/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/perf_test/Makefile ${KOKKOS_SETTINGS} clean" >> core/perf_test/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > containers/unit_tests/Makefile echo "" >> containers/unit_tests/Makefile echo "all:" >> containers/unit_tests/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS}" >> containers/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS}" >> containers/unit_tests/Makefile echo "" >> containers/unit_tests/Makefile echo "test: all" >> containers/unit_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS} test" >> containers/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS} test" >> containers/unit_tests/Makefile echo "" >> containers/unit_tests/Makefile echo "clean:" >> containers/unit_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS} clean" >> containers/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/unit_tests/Makefile ${KOKKOS_SETTINGS} clean" >> containers/unit_tests/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > containers/performance_tests/Makefile echo "" >> containers/performance_tests/Makefile echo "all:" >> containers/performance_tests/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS}" >> containers/performance_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS}" >> containers/performance_tests/Makefile echo "" >> containers/performance_tests/Makefile echo "test: all" >> containers/performance_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS} test" >> containers/performance_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS} test" >> containers/performance_tests/Makefile echo "" >> containers/performance_tests/Makefile echo "clean:" >> containers/performance_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS} clean" >> containers/performance_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/containers/performance_tests/Makefile ${KOKKOS_SETTINGS} clean" >> containers/performance_tests/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > algorithms/unit_tests/Makefile echo "" >> algorithms/unit_tests/Makefile echo "all:" >> algorithms/unit_tests/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS}" >> algorithms/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS}" >> algorithms/unit_tests/Makefile echo "" >> algorithms/unit_tests/Makefile echo "test: all" >> algorithms/unit_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS} test" >> algorithms/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS} test" >> algorithms/unit_tests/Makefile echo "" >> algorithms/unit_tests/Makefile echo "clean:" >> algorithms/unit_tests/Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS} clean" >> algorithms/unit_tests/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/algorithms/unit_tests/Makefile ${KOKKOS_SETTINGS} clean" >> algorithms/unit_tests/Makefile KOKKOS_SETTINGS="${KOKKOS_SETTINGS_NO_KOKKOS_PATH} KOKKOS_PATH=${KOKKOS_TEST_INSTALL_PATH}" echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > example/fixture/Makefile echo "" >> example/fixture/Makefile echo "all:" >> example/fixture/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS}" >> example/fixture/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS}" >> example/fixture/Makefile echo "" >> example/fixture/Makefile echo "test: all" >> example/fixture/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS} test" >> example/fixture/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS} test" >> example/fixture/Makefile echo "" >> example/fixture/Makefile echo "clean:" >> example/fixture/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS} clean" >> example/fixture/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fixture/Makefile ${KOKKOS_SETTINGS} clean" >> example/fixture/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > example/feint/Makefile echo "" >> example/feint/Makefile echo "all:" >> example/feint/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS}" >> example/feint/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS}" >> example/feint/Makefile echo "" >> example/feint/Makefile echo "test: all" >> example/feint/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS} test" >> example/feint/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS} test" >> example/feint/Makefile echo "" >> example/feint/Makefile echo "clean:" >> example/feint/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS} clean" >> example/feint/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/feint/Makefile ${KOKKOS_SETTINGS} clean" >> example/feint/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > example/fenl/Makefile echo "" >> example/fenl/Makefile echo "all:" >> example/fenl/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS}" >> example/fenl/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS}" >> example/fenl/Makefile echo "" >> example/fenl/Makefile echo "test: all" >> example/fenl/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS} test" >> example/fenl/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS} test" >> example/fenl/Makefile echo "" >> example/fenl/Makefile echo "clean:" >> example/fenl/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS} clean" >> example/fenl/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/fenl/Makefile ${KOKKOS_SETTINGS} clean" >> example/fenl/Makefile echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > example/tutorial/Makefile echo "" >> example/tutorial/Makefile echo "build:" >> example/tutorial/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} build">> example/tutorial/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} build">> example/tutorial/Makefile echo "" >> example/tutorial/Makefile echo "test: build" >> example/tutorial/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} test" >> example/tutorial/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} test" >> example/tutorial/Makefile echo "" >> example/tutorial/Makefile echo "clean:" >> example/tutorial/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} clean" >> example/tutorial/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/tutorial/Makefile KOKKOS_SETTINGS='${KOKKOS_SETTINGS}' KOKKOS_PATH=${KOKKOS_PATH} clean" >> example/tutorial/Makefile if [ ${#KOKKOS_ENABLE_EXAMPLE_ICHOL} -gt 0 ]; then echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > example/ichol/Makefile echo "" >> example/ichol/Makefile echo "all:" >> example/ichol/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS}" >> example/ichol/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS}" >> example/ichol/Makefile echo "" >> example/ichol/Makefile echo "test: all" >> example/ichol/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS} test" >> example/ichol/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS} test" >> example/ichol/Makefile echo "" >> example/ichol/Makefile echo "clean:" >> example/ichol/Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS} clean" >> example/ichol/Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/example/ichol/Makefile ${KOKKOS_SETTINGS} clean" >> example/ichol/Makefile fi KOKKOS_SETTINGS="${KOKKOS_SETTINGS_NO_KOKKOS_PATH} KOKKOS_PATH=${KOKKOS_PATH}" @@ -385,62 +400,64 @@ echo "KOKKOS_SETTINGS=${KOKKOS_SETTINGS}" > Makefile echo "" >> Makefile echo "kokkoslib:" >> Makefile echo -e "\tcd core; \\" >> Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_INSTALL_PATH} build-lib" >> Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_INSTALL_PATH} build-lib" >> Makefile echo "" >> Makefile echo "install: kokkoslib" >> Makefile echo -e "\tcd core; \\" >> Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_INSTALL_PATH} install" >> Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_INSTALL_PATH} install" >> Makefile echo "" >> Makefile echo "kokkoslib-test:" >> Makefile echo -e "\tcd core; \\" >> Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_TEST_INSTALL_PATH} build-lib" >> Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_TEST_INSTALL_PATH} build-lib" >> Makefile echo "" >> Makefile echo "install-test: kokkoslib-test" >> Makefile echo -e "\tcd core; \\" >> Makefile -echo -e "\tmake -j ${MAKE_J_OPTION} -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_TEST_INSTALL_PATH} install" >> Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} PREFIX=${KOKKOS_TEST_INSTALL_PATH} install" >> Makefile echo "" >> Makefile echo "build-test: install-test" >> Makefile -echo -e "\tmake -C core/unit_test" >> Makefile -echo -e "\tmake -C core/perf_test" >> Makefile -echo -e "\tmake -C containers/unit_tests" >> Makefile -echo -e "\tmake -C containers/performance_tests" >> Makefile -echo -e "\tmake -C algorithms/unit_tests" >> Makefile +echo -e "\t\$(MAKE) -C core/unit_test" >> Makefile +echo -e "\t\$(MAKE) -C core/perf_test" >> Makefile +echo -e "\t\$(MAKE) -C containers/unit_tests" >> Makefile +echo -e "\t\$(MAKE) -C containers/performance_tests" >> Makefile +echo -e "\t\$(MAKE) -C algorithms/unit_tests" >> Makefile if [ ${KOKKOS_DO_EXAMPLES} -gt 0 ]; then -echo -e "\tmake -C example/fixture" >> Makefile -echo -e "\tmake -C example/feint" >> Makefile -echo -e "\tmake -C example/fenl" >> Makefile -echo -e "\tmake -C example/tutorial build" >> Makefile +echo -e "\t\$(MAKE) -C example/fixture" >> Makefile +echo -e "\t\$(MAKE) -C example/feint" >> Makefile +echo -e "\t\$(MAKE) -C example/fenl" >> Makefile +echo -e "\t\$(MAKE) -C example/tutorial build" >> Makefile fi echo "" >> Makefile echo "test: build-test" >> Makefile -echo -e "\tmake -C core/unit_test test" >> Makefile -echo -e "\tmake -C core/perf_test test" >> Makefile -echo -e "\tmake -C containers/unit_tests test" >> Makefile -echo -e "\tmake -C containers/performance_tests test" >> Makefile -echo -e "\tmake -C algorithms/unit_tests test" >> Makefile +echo -e "\t\$(MAKE) -C core/unit_test test" >> Makefile +echo -e "\t\$(MAKE) -C core/perf_test test" >> Makefile +echo -e "\t\$(MAKE) -C containers/unit_tests test" >> Makefile +echo -e "\t\$(MAKE) -C containers/performance_tests test" >> Makefile +echo -e "\t\$(MAKE) -C algorithms/unit_tests test" >> Makefile if [ ${KOKKOS_DO_EXAMPLES} -gt 0 ]; then -echo -e "\tmake -C example/fixture test" >> Makefile -echo -e "\tmake -C example/feint test" >> Makefile -echo -e "\tmake -C example/fenl test" >> Makefile -echo -e "\tmake -C example/tutorial test" >> Makefile +echo -e "\t\$(MAKE) -C example/fixture test" >> Makefile +echo -e "\t\$(MAKE) -C example/feint test" >> Makefile +echo -e "\t\$(MAKE) -C example/fenl test" >> Makefile +echo -e "\t\$(MAKE) -C example/tutorial test" >> Makefile fi echo "" >> Makefile echo "unit-tests-only:" >> Makefile -echo -e "\tmake -C core/unit_test test" >> Makefile -echo -e "\tmake -C containers/unit_tests test" >> Makefile -echo -e "\tmake -C algorithms/unit_tests test" >> Makefile +echo -e "\t\$(MAKE) -C core/unit_test test" >> Makefile +echo -e "\t\$(MAKE) -C containers/unit_tests test" >> Makefile +echo -e "\t\$(MAKE) -C algorithms/unit_tests test" >> Makefile echo "" >> Makefile + echo "clean:" >> Makefile -echo -e "\tmake -C core/unit_test clean" >> Makefile -echo -e "\tmake -C core/perf_test clean" >> Makefile -echo -e "\tmake -C containers/unit_tests clean" >> Makefile -echo -e "\tmake -C containers/performance_tests clean" >> Makefile -echo -e "\tmake -C algorithms/unit_tests clean" >> Makefile +echo -e "\t\$(MAKE) -C core/unit_test clean" >> Makefile +echo -e "\t\$(MAKE) -C core/perf_test clean" >> Makefile +echo -e "\t\$(MAKE) -C containers/unit_tests clean" >> Makefile +echo -e "\t\$(MAKE) -C containers/performance_tests clean" >> Makefile +echo -e "\t\$(MAKE) -C algorithms/unit_tests clean" >> Makefile if [ ${KOKKOS_DO_EXAMPLES} -gt 0 ]; then -echo -e "\tmake -C example/fixture clean" >> Makefile -echo -e "\tmake -C example/feint clean" >> Makefile -echo -e "\tmake -C example/fenl clean" >> Makefile -echo -e "\tmake -C example/tutorial clean" >> Makefile +echo -e "\t\$(MAKE) -C example/fixture clean" >> Makefile +echo -e "\t\$(MAKE) -C example/feint clean" >> Makefile +echo -e "\t\$(MAKE) -C example/fenl clean" >> Makefile +echo -e "\t\$(MAKE) -C example/tutorial clean" >> Makefile fi echo -e "\tcd core; \\" >> Makefile -echo -e "\tmake -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} clean" >> Makefile +echo -e "\t\$(MAKE) -f ${KOKKOS_PATH}/core/src/Makefile ${KOKKOS_SETTINGS} clean" >> Makefile + diff --git a/lib/kokkos/tpls/gtest/gtest/LICENSE b/lib/kokkos/tpls/gtest/gtest/LICENSE new file mode 100644 index 0000000000..1941a11f8c --- /dev/null +++ b/lib/kokkos/tpls/gtest/gtest/LICENSE @@ -0,0 +1,28 @@ +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * 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. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. diff --git a/lib/kokkos/tpls/gtest/gtest/README b/lib/kokkos/tpls/gtest/gtest/README new file mode 100644 index 0000000000..82964ecc32 --- /dev/null +++ b/lib/kokkos/tpls/gtest/gtest/README @@ -0,0 +1,13 @@ +This is a fused source version of gtest 1.7.0. All that should be necessary to +start using gtest in your package is to declare the dependency and include +gtest/gtest.h. + +However, because some of the packages that are developed in Sierra do not use a +fused source version of gtest we need to make it possible for them to build with +this version as well as with their native build. To facilitate this we have +created symlinks for the other gtest headers that they use to the fused source +gtest.h. This will make it possible for them find the headers while still using +the fuse source version. This should not have any ill effects since the header is +protected and allows for only using the non-gtest.h headers in their files. + + diff --git a/lib/kokkos/tpls/gtest/gtest/gtest-all.cc b/lib/kokkos/tpls/gtest/gtest/gtest-all.cc new file mode 100644 index 0000000000..538c78db93 --- /dev/null +++ b/lib/kokkos/tpls/gtest/gtest/gtest-all.cc @@ -0,0 +1,9594 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: mheule@google.com (Markus Heule) +// +// Google C++ Testing Framework (Google Test) +// +// Sometimes it's desirable to build Google Test by compiling a single file. +// This file serves this purpose. + +// This line ensures that gtest.h can be compiled on its own, even +// when it's fused. +#include "gtest/gtest.h" + +// The following lines pull in the real gtest *.cc files. +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) + +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Utilities for testing Google Test itself and code that uses Google Test +// (e.g. frameworks built on top of Google Test). + +#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ +#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + + +namespace testing { + +// This helper class can be used to mock out Google Test failure reporting +// so that we can test Google Test or code that builds on Google Test. +// +// An object of this class appends a TestPartResult object to the +// TestPartResultArray object given in the constructor whenever a Google Test +// failure is reported. It can either intercept only failures that are +// generated in the same thread that created this object or it can intercept +// all generated failures. The scope of this mock object can be controlled with +// the second argument to the two arguments constructor. +class GTEST_API_ ScopedFakeTestPartResultReporter + : public TestPartResultReporterInterface { + public: + // The two possible mocking modes of this object. + enum InterceptMode { + INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. + INTERCEPT_ALL_THREADS // Intercepts all failures. + }; + + // The c'tor sets this object as the test part result reporter used + // by Google Test. The 'result' parameter specifies where to report the + // results. This reporter will only catch failures generated in the current + // thread. DEPRECATED + explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); + + // Same as above, but you can choose the interception scope of this object. + ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, + TestPartResultArray* result); + + // The d'tor restores the previous test part result reporter. + virtual ~ScopedFakeTestPartResultReporter(); + + // Appends the TestPartResult object to the TestPartResultArray + // received in the constructor. + // + // This method is from the TestPartResultReporterInterface + // interface. + virtual void ReportTestPartResult(const TestPartResult& result); + private: + void Init(); + + const InterceptMode intercept_mode_; + TestPartResultReporterInterface* old_reporter_; + TestPartResultArray* const result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); +}; + +namespace internal { + +// A helper class for implementing EXPECT_FATAL_FAILURE() and +// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +class GTEST_API_ SingleFailureChecker { + public: + // The constructor remembers the arguments. + SingleFailureChecker(const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr); + ~SingleFailureChecker(); + private: + const TestPartResultArray* const results_; + const TestPartResult::Type type_; + const string substr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); +}; + +} // namespace internal + +} // namespace testing + +// A set of macros for testing Google Test assertions or code that's expected +// to generate Google Test fatal failures. It verifies that the given +// statement will cause exactly one fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_FATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - 'statement' cannot reference local non-static variables or +// non-static members of the current object. +// - 'statement' cannot return a value. +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. The AcceptsMacroThatExpandsToUnprotectedComma test in +// gtest_unittest.cc will fail to compile if we do that. +#define EXPECT_FATAL_FAILURE(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do { \ + class GTestExpectFatalFailureHelper {\ + public:\ + static void Execute() { statement; }\ + };\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ALL_THREADS, >est_failures);\ + GTestExpectFatalFailureHelper::Execute();\ + }\ + } while (::testing::internal::AlwaysFalse()) + +// A macro for testing Google Test assertions or code that's expected to +// generate Google Test non-fatal failures. It asserts that the given +// statement will cause exactly one non-fatal Google Test failure with 'substr' +// being part of the failure message. +// +// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only +// affects and considers failures generated in the current thread and +// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. +// +// 'statement' is allowed to reference local variables and members of +// the current object. +// +// The verification of the assertion is done correctly even when the statement +// throws an exception or aborts the current function. +// +// Known restrictions: +// - You cannot stream a failure message to this macro. +// +// Note that even though the implementations of the following two +// macros are much alike, we cannot refactor them to use a common +// helper macro, due to some peculiarity in how the preprocessor +// works. If we do that, the code won't compile when the user gives +// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that +// expands to code containing an unprotected comma. The +// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc +// catches that. +// +// For the same reason, we have to write +// if (::testing::internal::AlwaysTrue()) { statement; } +// instead of +// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) +// to avoid an MSVC warning on unreachable code. +#define EXPECT_NONFATAL_FAILURE(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter:: \ + INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ + do {\ + ::testing::TestPartResultArray gtest_failures;\ + ::testing::internal::SingleFailureChecker gtest_checker(\ + >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ + (substr));\ + {\ + ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ + ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ + >est_failures);\ + if (::testing::internal::AlwaysTrue()) { statement; }\ + }\ + } while (::testing::internal::AlwaysFalse()) + +#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include // NOLINT +#include +#include + +#if GTEST_OS_LINUX + +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +# include // NOLINT +# include // NOLINT +# include // NOLINT +// Declares vsnprintf(). This header is not available on Windows. +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include + +#elif GTEST_OS_SYMBIAN +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +#elif GTEST_OS_ZOS +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT + +// On z/OS we additionally need strings.h for strcasecmp. +# include // NOLINT + +#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. + +# include // NOLINT + +#elif GTEST_OS_WINDOWS // We are on Windows proper. + +# include // NOLINT +# include // NOLINT +# include // NOLINT +# include // NOLINT + +# if GTEST_OS_WINDOWS_MINGW +// MinGW has gettimeofday() but not _ftime64(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +// TODO(kenton@google.com): There are other ways to get the time on +// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW +// supports these. consider using them instead. +# define GTEST_HAS_GETTIMEOFDAY_ 1 +# include // NOLINT +# endif // GTEST_OS_WINDOWS_MINGW + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT + +#else + +// Assume other platforms have gettimeofday(). +// TODO(kenton@google.com): Use autoconf to detect availability of +// gettimeofday(). +# define GTEST_HAS_GETTIMEOFDAY_ 1 + +// cpplint thinks that the header is already included, so we want to +// silence it. +# include // NOLINT +# include // NOLINT + +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. + +// Utility functions and classes used by the Google C++ testing framework. +// +// Author: wan@google.com (Zhanyong Wan) +// +// This file contains purely Google Test's internal implementation. Please +// DO NOT #INCLUDE IT IN A USER PROGRAM. + +#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ +#define GTEST_SRC_GTEST_INTERNAL_INL_H_ + +// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is +// part of Google Test's implementation; otherwise it's undefined. +#if !GTEST_IMPLEMENTATION_ +// A user is trying to include this from his code - just say no. +# error "gtest-internal-inl.h is part of Google Test's internal implementation." +# error "It must not be included except by Google Test itself." +#endif // GTEST_IMPLEMENTATION_ + +#ifndef _WIN32_WCE +# include +#endif // !_WIN32_WCE +#include +#include // For strtoll/_strtoul64/malloc/free. +#include // For memmove. + +#include +#include +#include + + +#if GTEST_CAN_STREAM_RESULTS_ +# include // NOLINT +# include // NOLINT +#endif + +#if GTEST_OS_WINDOWS +# include // NOLINT +#endif // GTEST_OS_WINDOWS + + +namespace testing { + +// Declares the flags. +// +// We don't want the users to modify this flag in the code, but want +// Google Test's own unit tests to be able to access it. Therefore we +// declare it here as opposed to in gtest.h. +GTEST_DECLARE_bool_(death_test_use_fork); + +namespace internal { + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; + +// Names of the flags (needed for parsing Google Test flags). +const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; +const char kBreakOnFailureFlag[] = "break_on_failure"; +const char kCatchExceptionsFlag[] = "catch_exceptions"; +const char kColorFlag[] = "color"; +const char kFilterFlag[] = "filter"; +const char kListTestsFlag[] = "list_tests"; +const char kOutputFlag[] = "output"; +const char kPrintTimeFlag[] = "print_time"; +const char kRandomSeedFlag[] = "random_seed"; +const char kRepeatFlag[] = "repeat"; +const char kShuffleFlag[] = "shuffle"; +const char kStackTraceDepthFlag[] = "stack_trace_depth"; +const char kStreamResultToFlag[] = "stream_result_to"; +const char kThrowOnFailureFlag[] = "throw_on_failure"; + +// A valid random seed must be in [1, kMaxRandomSeed]. +const int kMaxRandomSeed = 99999; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +GTEST_API_ extern bool g_help_flag; + +// Returns the current time in milliseconds. +GTEST_API_ TimeInMillis GetTimeInMillis(); + +// Returns true iff Google Test should use colors in the output. +GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); + +// Formats the given time in milliseconds as seconds. +GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); + +// Converts the given time in milliseconds to a date string in the ISO 8601 +// format, without the timezone information. N.B.: due to the use the +// non-reentrant localtime() function, this function is not thread safe. Do +// not use it in any code that can be called from multiple threads. +GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); + +// Parses a string for an Int32 flag, in the form of "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +GTEST_API_ bool ParseInt32Flag( + const char* str, const char* flag, Int32* value); + +// Returns a random seed in range [1, kMaxRandomSeed] based on the +// given --gtest_random_seed flag value. +inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { + const unsigned int raw_seed = (random_seed_flag == 0) ? + static_cast(GetTimeInMillis()) : + static_cast(random_seed_flag); + + // Normalizes the actual seed to range [1, kMaxRandomSeed] such that + // it's easy to type. + const int normalized_seed = + static_cast((raw_seed - 1U) % + static_cast(kMaxRandomSeed)) + 1; + return normalized_seed; +} + +// Returns the first valid random seed after 'seed'. The behavior is +// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is +// considered to be 1. +inline int GetNextRandomSeed(int seed) { + GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) + << "Invalid random seed " << seed << " - must be in [1, " + << kMaxRandomSeed << "]."; + const int next_seed = seed + 1; + return (next_seed > kMaxRandomSeed) ? 1 : next_seed; +} + +// This class saves the values of all Google Test flags in its c'tor, and +// restores them in its d'tor. +class GTestFlagSaver { + public: + // The c'tor. + GTestFlagSaver() { + also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); + break_on_failure_ = GTEST_FLAG(break_on_failure); + catch_exceptions_ = GTEST_FLAG(catch_exceptions); + color_ = GTEST_FLAG(color); + death_test_style_ = GTEST_FLAG(death_test_style); + death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); + filter_ = GTEST_FLAG(filter); + internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); + list_tests_ = GTEST_FLAG(list_tests); + output_ = GTEST_FLAG(output); + print_time_ = GTEST_FLAG(print_time); + random_seed_ = GTEST_FLAG(random_seed); + repeat_ = GTEST_FLAG(repeat); + shuffle_ = GTEST_FLAG(shuffle); + stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); + stream_result_to_ = GTEST_FLAG(stream_result_to); + throw_on_failure_ = GTEST_FLAG(throw_on_failure); + } + + // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. + ~GTestFlagSaver() { + GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; + GTEST_FLAG(break_on_failure) = break_on_failure_; + GTEST_FLAG(catch_exceptions) = catch_exceptions_; + GTEST_FLAG(color) = color_; + GTEST_FLAG(death_test_style) = death_test_style_; + GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; + GTEST_FLAG(filter) = filter_; + GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; + GTEST_FLAG(list_tests) = list_tests_; + GTEST_FLAG(output) = output_; + GTEST_FLAG(print_time) = print_time_; + GTEST_FLAG(random_seed) = random_seed_; + GTEST_FLAG(repeat) = repeat_; + GTEST_FLAG(shuffle) = shuffle_; + GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; + GTEST_FLAG(stream_result_to) = stream_result_to_; + GTEST_FLAG(throw_on_failure) = throw_on_failure_; + } + + private: + // Fields for saving the original values of flags. + bool also_run_disabled_tests_; + bool break_on_failure_; + bool catch_exceptions_; + std::string color_; + std::string death_test_style_; + bool death_test_use_fork_; + std::string filter_; + std::string internal_run_death_test_; + bool list_tests_; + std::string output_; + bool print_time_; + internal::Int32 random_seed_; + internal::Int32 repeat_; + bool shuffle_; + internal::Int32 stack_trace_depth_; + std::string stream_result_to_; + bool throw_on_failure_; +} GTEST_ATTRIBUTE_UNUSED_; + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded(); + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (e.g., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +GTEST_API_ bool ShouldShard(const char* total_shards_str, + const char* shard_index_str, + bool in_subprocess_for_death_test); + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error and +// and aborts. +GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +GTEST_API_ bool ShouldRunTestOnShard( + int total_shards, int shard_index, int test_id); + +// STL container utilities. + +// Returns the number of elements in the given container that satisfy +// the given predicate. +template +inline int CountIf(const Container& c, Predicate predicate) { + // Implemented as an explicit loop since std::count_if() in libCstd on + // Solaris has a non-standard signature. + int count = 0; + for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { + if (predicate(*it)) + ++count; + } + return count; +} + +// Applies a function/functor to each element in the container. +template +void ForEach(const Container& c, Functor functor) { + std::for_each(c.begin(), c.end(), functor); +} + +// Returns the i-th element of the vector, or default_value if i is not +// in range [0, v.size()). +template +inline E GetElementOr(const std::vector& v, int i, E default_value) { + return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; +} + +// Performs an in-place shuffle of a range of the vector's elements. +// 'begin' and 'end' are element indices as an STL-style range; +// i.e. [begin, end) are shuffled, where 'end' == size() means to +// shuffle to the end of the vector. +template +void ShuffleRange(internal::Random* random, int begin, int end, + std::vector* v) { + const int size = static_cast(v->size()); + GTEST_CHECK_(0 <= begin && begin <= size) + << "Invalid shuffle range start " << begin << ": must be in range [0, " + << size << "]."; + GTEST_CHECK_(begin <= end && end <= size) + << "Invalid shuffle range finish " << end << ": must be in range [" + << begin << ", " << size << "]."; + + // Fisher-Yates shuffle, from + // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle + for (int range_width = end - begin; range_width >= 2; range_width--) { + const int last_in_range = begin + range_width - 1; + const int selected = begin + random->Generate(range_width); + std::swap((*v)[selected], (*v)[last_in_range]); + } +} + +// Performs an in-place shuffle of the vector's elements. +template +inline void Shuffle(internal::Random* random, std::vector* v) { + ShuffleRange(random, 0, static_cast(v->size()), v); +} + +// A function for deleting an object. Handy for being used as a +// functor. +template +static void Delete(T* x) { + delete x; +} + +// A predicate that checks the key of a TestProperty against a known key. +// +// TestPropertyKeyIs is copyable. +class TestPropertyKeyIs { + public: + // Constructor. + // + // TestPropertyKeyIs has NO default constructor. + explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} + + // Returns true iff the test name of test property matches on key_. + bool operator()(const TestProperty& test_property) const { + return test_property.key() == key_; + } + + private: + std::string key_; +}; + +// Class UnitTestOptions. +// +// This class contains functions for processing options the user +// specifies when running the tests. It has only static members. +// +// In most cases, the user can specify an option using either an +// environment variable or a command line flag. E.g. you can set the +// test filter using either GTEST_FILTER or --gtest_filter. If both +// the variable and the flag are present, the latter overrides the +// former. +class GTEST_API_ UnitTestOptions { + public: + // Functions for processing the gtest_output flag. + + // Returns the output format, or "" for normal printed output. + static std::string GetOutputFormat(); + + // Returns the absolute path of the requested output file, or the + // default (test_detail.xml in the original working directory) if + // none was explicitly specified. + static std::string GetAbsolutePathToOutputFile(); + + // Functions for processing the gtest_filter flag. + + // Returns true iff the wildcard pattern matches the string. The + // first ':' or '\0' character in pattern marks the end of it. + // + // This recursive algorithm isn't very efficient, but is clear and + // works well enough for matching test names, which are short. + static bool PatternMatchesString(const char *pattern, const char *str); + + // Returns true iff the user-specified filter matches the test case + // name and the test name. + static bool FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name); + +#if GTEST_OS_WINDOWS + // Function for supporting the gtest_catch_exception flag. + + // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the + // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. + // This function is useful as an __except condition. + static int GTestShouldProcessSEH(DWORD exception_code); +#endif // GTEST_OS_WINDOWS + + // Returns true if "name" matches the ':' separated list of glob-style + // filters in "filter". + static bool MatchesFilter(const std::string& name, const char* filter); +}; + +// Returns the current application's name, removing directory path if that +// is present. Used by UnitTestOptions::GetOutputFile. +GTEST_API_ FilePath GetCurrentExecutableName(); + +// The role interface for getting the OS stack trace as a string. +class OsStackTraceGetterInterface { + public: + OsStackTraceGetterInterface() {} + virtual ~OsStackTraceGetterInterface() {} + + // Returns the current OS stack trace as an std::string. Parameters: + // + // max_depth - the maximum number of stack frames to be included + // in the trace. + // skip_count - the number of top frames to be skipped; doesn't count + // against max_depth. + virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; + + // UponLeavingGTest() should be called immediately before Google Test calls + // user code. It saves some information about the current stack that + // CurrentStackTrace() will use to find and hide Google Test stack frames. + virtual void UponLeavingGTest() = 0; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); +}; + +// A working implementation of the OsStackTraceGetterInterface interface. +class OsStackTraceGetter : public OsStackTraceGetterInterface { + public: + OsStackTraceGetter() : caller_frame_(NULL) {} + + virtual string CurrentStackTrace(int max_depth, int skip_count) + GTEST_LOCK_EXCLUDED_(mutex_); + + virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); + + // This string is inserted in place of stack frames that are part of + // Google Test's implementation. + static const char* const kElidedFramesMarker; + + private: + Mutex mutex_; // protects all internal state + + // We save the stack frame below the frame that calls user code. + // We do this because the address of the frame immediately below + // the user code changes between the call to UponLeavingGTest() + // and any calls to CurrentStackTrace() from within the user code. + void* caller_frame_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); +}; + +// Information about a Google Test trace point. +struct TraceInfo { + const char* file; + int line; + std::string message; +}; + +// This is the default global test part result reporter used in UnitTestImpl. +// This class should only be used by UnitTestImpl. +class DefaultGlobalTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. Reports the test part + // result in the current test. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); +}; + +// This is the default per thread test part result reporter used in +// UnitTestImpl. This class should only be used by UnitTestImpl. +class DefaultPerThreadTestPartResultReporter + : public TestPartResultReporterInterface { + public: + explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); + // Implements the TestPartResultReporterInterface. The implementation just + // delegates to the current global test part result reporter of *unit_test_. + virtual void ReportTestPartResult(const TestPartResult& result); + + private: + UnitTestImpl* const unit_test_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); +}; + +// The private implementation of the UnitTest class. We don't protect +// the methods under a mutex, as this class is not accessible by a +// user and the UnitTest class that delegates work to this class does +// proper locking. +class GTEST_API_ UnitTestImpl { + public: + explicit UnitTestImpl(UnitTest* parent); + virtual ~UnitTestImpl(); + + // There are two different ways to register your own TestPartResultReporter. + // You can register your own repoter to listen either only for test results + // from the current thread or for results from all threads. + // By default, each per-thread test result repoter just passes a new + // TestPartResult to the global test result reporter, which registers the + // test part result for the currently running test. + + // Returns the global test part result reporter. + TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); + + // Sets the global test part result reporter. + void SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter); + + // Returns the test part result reporter for the current thread. + TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); + + // Sets the test part result reporter for the current thread. + void SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter); + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const { return start_timestamp_; } + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const { return !Failed(); } + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const { + return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[i]; + } + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i) { + const int index = GetElementOr(test_case_indices_, i, -1); + return index < 0 ? NULL : test_cases_[index]; + } + + // Provides access to the event listener list. + TestEventListeners* listeners() { return &listeners_; } + + // Returns the TestResult for the test that's currently running, or + // the TestResult for the ad hoc test if no test is running. + TestResult* current_test_result(); + + // Returns the TestResult for the ad hoc test. + const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } + + // Sets the OS stack trace getter. + // + // Does nothing if the input and the current OS stack trace getter + // are the same; otherwise, deletes the old getter and makes the + // input the current getter. + void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); + + // Returns the current OS stack trace getter if it is not NULL; + // otherwise, creates an OsStackTraceGetter, makes it the current + // getter, and returns it. + OsStackTraceGetterInterface* os_stack_trace_getter(); + + // Returns the current OS stack trace as an std::string. + // + // The maximum number of stack frames to be included is specified by + // the gtest_stack_trace_depth flag. The skip_count parameter + // specifies the number of top frames to be skipped, which doesn't + // count against the number of frames to be included. + // + // For example, if Foo() calls Bar(), which in turn calls + // CurrentOsStackTraceExceptTop(1), Foo() will be included in the + // trace but Bar() and CurrentOsStackTraceExceptTop() won't. + std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; + + // Finds and returns a TestCase with the given name. If one doesn't + // exist, creates one and returns it. + // + // Arguments: + // + // test_case_name: name of the test case + // type_param: the name of the test's type parameter, or NULL if + // this is not a typed or a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase* GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Adds a TestInfo to the unit test. + // + // Arguments: + // + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + // test_info: the TestInfo object + void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + TestInfo* test_info) { + // In order to support thread-safe death tests, we need to + // remember the original working directory when the test program + // was first invoked. We cannot do this in RUN_ALL_TESTS(), as + // the user may have changed the current directory before calling + // RUN_ALL_TESTS(). Therefore we capture the current directory in + // AddTestInfo(), which is called to register a TEST or TEST_F + // before main() is reached. + if (original_working_dir_.IsEmpty()) { + original_working_dir_.Set(FilePath::GetCurrentDir()); + GTEST_CHECK_(!original_working_dir_.IsEmpty()) + << "Failed to get the current working directory."; + } + + GetTestCase(test_info->test_case_name(), + test_info->type_param(), + set_up_tc, + tear_down_tc)->AddTestInfo(test_info); + } + +#if GTEST_HAS_PARAM_TEST + // Returns ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { + return parameterized_test_registry_; + } +#endif // GTEST_HAS_PARAM_TEST + + // Sets the TestCase object for the test that's currently running. + void set_current_test_case(TestCase* a_current_test_case) { + current_test_case_ = a_current_test_case; + } + + // Sets the TestInfo object for the test that's currently running. If + // current_test_info is NULL, the assertion results will be stored in + // ad_hoc_test_result_. + void set_current_test_info(TestInfo* a_current_test_info) { + current_test_info_ = a_current_test_info; + } + + // Registers all parameterized tests defined using TEST_P and + // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter + // combination. This method can be called more then once; it has guards + // protecting from registering the tests more then once. If + // value-parameterized tests are disabled, RegisterParameterizedTests is + // present but does nothing. + void RegisterParameterizedTests(); + + // Runs all tests in this UnitTest object, prints the result, and + // returns true if all tests are successful. If any exception is + // thrown during a test, this test is considered to be failed, but + // the rest of the tests will still be run. + bool RunAllTests(); + + // Clears the results of all tests, except the ad hoc tests. + void ClearNonAdHocTestResult() { + ForEach(test_cases_, TestCase::ClearTestCaseResult); + } + + // Clears the results of ad-hoc test assertions. + void ClearAdHocTestResult() { + ad_hoc_test_result_.Clear(); + } + + // Adds a TestProperty to the current TestResult object when invoked in a + // context of a test or a test case, or to the global property set. If the + // result already contains a property with the same key, the value will be + // updated. + void RecordProperty(const TestProperty& test_property); + + enum ReactionToSharding { + HONOR_SHARDING_PROTOCOL, + IGNORE_SHARDING_PROTOCOL + }; + + // Matches the full name of each test against the user-specified + // filter to decide whether the test should run, then records the + // result in each TestCase and TestInfo object. + // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests + // based on sharding variables in the environment. + // Returns the number of tests that should run. + int FilterTests(ReactionToSharding shard_tests); + + // Prints the names of the tests matching the user-specified filter flag. + void ListTestsMatchingFilter(); + + const TestCase* current_test_case() const { return current_test_case_; } + TestInfo* current_test_info() { return current_test_info_; } + const TestInfo* current_test_info() const { return current_test_info_; } + + // Returns the vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector& environments() { return environments_; } + + // Getters for the per-thread Google Test trace stack. + std::vector& gtest_trace_stack() { + return *(gtest_trace_stack_.pointer()); + } + const std::vector& gtest_trace_stack() const { + return gtest_trace_stack_.get(); + } + +#if GTEST_HAS_DEATH_TEST + void InitDeathTestSubprocessControlInfo() { + internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); + } + // Returns a pointer to the parsed --gtest_internal_run_death_test + // flag, or NULL if that flag was not specified. + // This information is useful only in a death test child process. + // Must not be called before a call to InitGoogleTest. + const InternalRunDeathTestFlag* internal_run_death_test_flag() const { + return internal_run_death_test_flag_.get(); + } + + // Returns a pointer to the current death test factory. + internal::DeathTestFactory* death_test_factory() { + return death_test_factory_.get(); + } + + void SuppressTestEventsIfInSubprocess(); + + friend class ReplaceDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + + // Initializes the event listener performing XML output as specified by + // UnitTestOptions. Must not be called before InitGoogleTest. + void ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Initializes the event listener for streaming test results to a socket. + // Must not be called before InitGoogleTest. + void ConfigureStreamingOutput(); +#endif + + // Performs initialization dependent upon flag values obtained in + // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to + // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest + // this function is also called from RunAllTests. Since this function can be + // called more than once, it has to be idempotent. + void PostFlagParsingInit(); + + // Gets the random seed used at the start of the current test iteration. + int random_seed() const { return random_seed_; } + + // Gets the random number generator. + internal::Random* random() { return &random_; } + + // Shuffles all test cases, and the tests within each test case, + // making sure that death tests are still run first. + void ShuffleTests(); + + // Restores the test cases and tests to their order before the first shuffle. + void UnshuffleTests(); + + // Returns the value of GTEST_FLAG(catch_exceptions) at the moment + // UnitTest::Run() starts. + bool catch_exceptions() const { return catch_exceptions_; } + + private: + friend class ::testing::UnitTest; + + // Used by UnitTest::Run() to capture the state of + // GTEST_FLAG(catch_exceptions) at the moment it starts. + void set_catch_exceptions(bool value) { catch_exceptions_ = value; } + + // The UnitTest object that owns this implementation object. + UnitTest* const parent_; + + // The working directory when the first TEST() or TEST_F() was + // executed. + internal::FilePath original_working_dir_; + + // The default test part result reporters. + DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; + DefaultPerThreadTestPartResultReporter + default_per_thread_test_part_result_reporter_; + + // Points to (but doesn't own) the global test part result reporter. + TestPartResultReporterInterface* global_test_part_result_repoter_; + + // Protects read and write access to global_test_part_result_reporter_. + internal::Mutex global_test_part_result_reporter_mutex_; + + // Points to (but doesn't own) the per-thread test part result reporter. + internal::ThreadLocal + per_thread_test_part_result_reporter_; + + // The vector of environments that need to be set-up/torn-down + // before/after the tests are run. + std::vector environments_; + + // The vector of TestCases in their original order. It owns the + // elements in the vector. + std::vector test_cases_; + + // Provides a level of indirection for the test case list to allow + // easy shuffling and restoring the test case order. The i-th + // element of this vector is the index of the i-th test case in the + // shuffled order. + std::vector test_case_indices_; + +#if GTEST_HAS_PARAM_TEST + // ParameterizedTestRegistry object used to register value-parameterized + // tests. + internal::ParameterizedTestCaseRegistry parameterized_test_registry_; + + // Indicates whether RegisterParameterizedTests() has been called already. + bool parameterized_tests_registered_; +#endif // GTEST_HAS_PARAM_TEST + + // Index of the last death test case registered. Initially -1. + int last_death_test_case_; + + // This points to the TestCase for the currently running test. It + // changes as Google Test goes through one test case after another. + // When no test is running, this is set to NULL and Google Test + // stores assertion results in ad_hoc_test_result_. Initially NULL. + TestCase* current_test_case_; + + // This points to the TestInfo for the currently running test. It + // changes as Google Test goes through one test after another. When + // no test is running, this is set to NULL and Google Test stores + // assertion results in ad_hoc_test_result_. Initially NULL. + TestInfo* current_test_info_; + + // Normally, a user only writes assertions inside a TEST or TEST_F, + // or inside a function called by a TEST or TEST_F. Since Google + // Test keeps track of which test is current running, it can + // associate such an assertion with the test it belongs to. + // + // If an assertion is encountered when no TEST or TEST_F is running, + // Google Test attributes the assertion result to an imaginary "ad hoc" + // test, and records the result in ad_hoc_test_result_. + TestResult ad_hoc_test_result_; + + // The list of event listeners that can be used to track events inside + // Google Test. + TestEventListeners listeners_; + + // The OS stack trace getter. Will be deleted when the UnitTest + // object is destructed. By default, an OsStackTraceGetter is used, + // but the user can set this field to use a custom getter if that is + // desired. + OsStackTraceGetterInterface* os_stack_trace_getter_; + + // True iff PostFlagParsingInit() has been called. + bool post_flag_parse_init_performed_; + + // The random number seed used at the beginning of the test run. + int random_seed_; + + // Our random number generator. + internal::Random random_; + + // The time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp_; + + // How long the test took to run, in milliseconds. + TimeInMillis elapsed_time_; + +#if GTEST_HAS_DEATH_TEST + // The decomposed components of the gtest_internal_run_death_test flag, + // parsed when RUN_ALL_TESTS is called. + internal::scoped_ptr internal_run_death_test_flag_; + internal::scoped_ptr death_test_factory_; +#endif // GTEST_HAS_DEATH_TEST + + // A per-thread stack of traces created by the SCOPED_TRACE() macro. + internal::ThreadLocal > gtest_trace_stack_; + + // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() + // starts. + bool catch_exceptions_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); +}; // class UnitTestImpl + +// Convenience function for accessing the global UnitTest +// implementation object. +inline UnitTestImpl* GetUnitTestImpl() { + return UnitTest::GetInstance()->impl(); +} + +#if GTEST_USES_SIMPLE_RE + +// Internal helper functions for implementing the simple regular +// expression matcher. +GTEST_API_ bool IsInSet(char ch, const char* str); +GTEST_API_ bool IsAsciiDigit(char ch); +GTEST_API_ bool IsAsciiPunct(char ch); +GTEST_API_ bool IsRepeat(char ch); +GTEST_API_ bool IsAsciiWhiteSpace(char ch); +GTEST_API_ bool IsAsciiWordChar(char ch); +GTEST_API_ bool IsValidEscape(char ch); +GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); +GTEST_API_ bool ValidateRegex(const char* regex); +GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); +GTEST_API_ bool MatchRepetitionAndRegexAtHead( + bool escaped, char ch, char repeat, const char* regex, const char* str); +GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); + +#endif // GTEST_USES_SIMPLE_RE + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); +GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); + +#if GTEST_HAS_DEATH_TEST + +// Returns the message describing the last system error, regardless of the +// platform. +GTEST_API_ std::string GetLastErrnoDescription(); + +# if GTEST_OS_WINDOWS +// Provides leak-safe Windows kernel handle ownership. +class AutoHandle { + public: + AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} + explicit AutoHandle(HANDLE handle) : handle_(handle) {} + + ~AutoHandle() { Reset(); } + + HANDLE Get() const { return handle_; } + void Reset() { Reset(INVALID_HANDLE_VALUE); } + void Reset(HANDLE handle) { + if (handle != handle_) { + if (handle_ != INVALID_HANDLE_VALUE) + ::CloseHandle(handle_); + handle_ = handle; + } + } + + private: + HANDLE handle_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); +}; +# endif // GTEST_OS_WINDOWS + +// Attempts to parse a string into a positive integer pointed to by the +// number parameter. Returns true if that is possible. +// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use +// it here. +template +bool ParseNaturalNumber(const ::std::string& str, Integer* number) { + // Fail fast if the given string does not begin with a digit; + // this bypasses strtoXXX's "optional leading whitespace and plus + // or minus sign" semantics, which are undesirable here. + if (str.empty() || !IsDigit(str[0])) { + return false; + } + errno = 0; + + char* end; + // BiggestConvertible is the largest integer type that system-provided + // string-to-number conversion routines can return. + +# if GTEST_OS_WINDOWS && !defined(__GNUC__) + + // MSVC and C++ Builder define __int64 instead of the standard long long. + typedef unsigned __int64 BiggestConvertible; + const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); + +# else + + typedef unsigned long long BiggestConvertible; // NOLINT + const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); + +# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) + + const bool parse_success = *end == '\0' && errno == 0; + + // TODO(vladl@google.com): Convert this to compile time assertion when it is + // available. + GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); + + const Integer result = static_cast(parsed); + if (parse_success && static_cast(result) == parsed) { + *number = result; + return true; + } + return false; +} +#endif // GTEST_HAS_DEATH_TEST + +// TestResult contains some private methods that should be hidden from +// Google Test user but are required for testing. This class allow our tests +// to access them. +// +// This class is supplied only for the purpose of testing Google Test's own +// constructs. Do not use it in user tests, either directly or indirectly. +class TestResultAccessor { + public: + static void RecordProperty(TestResult* test_result, + const std::string& xml_element, + const TestProperty& property) { + test_result->RecordProperty(xml_element, property); + } + + static void ClearTestPartResults(TestResult* test_result) { + test_result->ClearTestPartResults(); + } + + static const std::vector& test_part_results( + const TestResult& test_result) { + return test_result.test_part_results(); + } +}; + +#if GTEST_CAN_STREAM_RESULTS_ + +// Streams test results to the given port on the given host machine. +class StreamingListener : public EmptyTestEventListener { + public: + // Abstract base class for writing strings to a socket. + class AbstractSocketWriter { + public: + virtual ~AbstractSocketWriter() {} + + // Sends a string to the socket. + virtual void Send(const string& message) = 0; + + // Closes the socket. + virtual void CloseConnection() {} + + // Sends a string and a newline to the socket. + void SendLn(const string& message) { + Send(message + "\n"); + } + }; + + // Concrete class for actually writing strings to a socket. + class SocketWriter : public AbstractSocketWriter { + public: + SocketWriter(const string& host, const string& port) + : sockfd_(-1), host_name_(host), port_num_(port) { + MakeConnection(); + } + + virtual ~SocketWriter() { + if (sockfd_ != -1) + CloseConnection(); + } + + // Sends a string to the socket. + virtual void Send(const string& message) { + GTEST_CHECK_(sockfd_ != -1) + << "Send() can be called only when there is a connection."; + + const int len = static_cast(message.length()); + if (write(sockfd_, message.c_str(), len) != len) { + GTEST_LOG_(WARNING) + << "stream_result_to: failed to stream to " + << host_name_ << ":" << port_num_; + } + } + + private: + // Creates a client socket and connects to the server. + void MakeConnection(); + + // Closes the socket. + void CloseConnection() { + GTEST_CHECK_(sockfd_ != -1) + << "CloseConnection() can be called only when there is a connection."; + + close(sockfd_); + sockfd_ = -1; + } + + int sockfd_; // socket file descriptor + const string host_name_; + const string port_num_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); + }; // class SocketWriter + + // Escapes '=', '&', '%', and '\n' characters in str as "%xx". + static string UrlEncode(const char* str); + + StreamingListener(const string& host, const string& port) + : socket_writer_(new SocketWriter(host, port)) { Start(); } + + explicit StreamingListener(AbstractSocketWriter* socket_writer) + : socket_writer_(socket_writer) { Start(); } + + void OnTestProgramStart(const UnitTest& /* unit_test */) { + SendLn("event=TestProgramStart"); + } + + void OnTestProgramEnd(const UnitTest& unit_test) { + // Note that Google Test current only report elapsed time for each + // test iteration, not for the entire test program. + SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); + + // Notify the streaming server to stop. + socket_writer_->CloseConnection(); + } + + void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { + SendLn("event=TestIterationStart&iteration=" + + StreamableToString(iteration)); + } + + void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { + SendLn("event=TestIterationEnd&passed=" + + FormatBool(unit_test.Passed()) + "&elapsed_time=" + + StreamableToString(unit_test.elapsed_time()) + "ms"); + } + + void OnTestCaseStart(const TestCase& test_case) { + SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); + } + + void OnTestCaseEnd(const TestCase& test_case) { + SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + + "ms"); + } + + void OnTestStart(const TestInfo& test_info) { + SendLn(std::string("event=TestStart&name=") + test_info.name()); + } + + void OnTestEnd(const TestInfo& test_info) { + SendLn("event=TestEnd&passed=" + + FormatBool((test_info.result())->Passed()) + + "&elapsed_time=" + + StreamableToString((test_info.result())->elapsed_time()) + "ms"); + } + + void OnTestPartResult(const TestPartResult& test_part_result) { + const char* file_name = test_part_result.file_name(); + if (file_name == NULL) + file_name = ""; + SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + + "&line=" + StreamableToString(test_part_result.line_number()) + + "&message=" + UrlEncode(test_part_result.message())); + } + + private: + // Sends the given message and a newline to the socket. + void SendLn(const string& message) { socket_writer_->SendLn(message); } + + // Called at the start of streaming to notify the receiver what + // protocol we are using. + void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } + + string FormatBool(bool value) { return value ? "1" : "0"; } + + const scoped_ptr socket_writer_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); +}; // class StreamingListener + +#endif // GTEST_CAN_STREAM_RESULTS_ + +} // namespace internal +} // namespace testing + +#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ +#undef GTEST_IMPLEMENTATION_ + +#if GTEST_OS_WINDOWS +# define vsnprintf _vsnprintf +#endif // GTEST_OS_WINDOWS + +namespace testing { + +using internal::CountIf; +using internal::ForEach; +using internal::GetElementOr; +using internal::Shuffle; + +// Constants. + +// A test whose test case name or test name matches this filter is +// disabled and not run. +static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; + +// A test case whose name matches this filter is considered a death +// test case and will be run before test cases whose name doesn't +// match this filter. +static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; + +// A test filter that matches everything. +static const char kUniversalFilter[] = "*"; + +// The default output file for XML output. +static const char kDefaultOutputFile[] = "test_detail.xml"; + +// The environment variable name for the test shard index. +static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; +// The environment variable name for the total number of test shards. +static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; +// The environment variable name for the test shard status file. +static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; + +namespace internal { + +// The text used in failure messages to indicate the start of the +// stack trace. +const char kStackTraceMarker[] = "\nStack trace:\n"; + +// g_help_flag is true iff the --help flag or an equivalent form is +// specified on the command line. +bool g_help_flag = false; + +} // namespace internal + +static const char* GetDefaultFilter() { + return kUniversalFilter; +} + +GTEST_DEFINE_bool_( + also_run_disabled_tests, + internal::BoolFromGTestEnv("also_run_disabled_tests", false), + "Run disabled tests too, in addition to the tests normally being run."); + +GTEST_DEFINE_bool_( + break_on_failure, + internal::BoolFromGTestEnv("break_on_failure", false), + "True iff a failed assertion should be a debugger break-point."); + +GTEST_DEFINE_bool_( + catch_exceptions, + internal::BoolFromGTestEnv("catch_exceptions", true), + "True iff " GTEST_NAME_ + " should catch exceptions and treat them as test failures."); + +GTEST_DEFINE_string_( + color, + internal::StringFromGTestEnv("color", "auto"), + "Whether to use colors in the output. Valid values: yes, no, " + "and auto. 'auto' means to use colors if the output is " + "being sent to a terminal and the TERM environment variable " + "is set to a terminal type that supports colors."); + +GTEST_DEFINE_string_( + filter, + internal::StringFromGTestEnv("filter", GetDefaultFilter()), + "A colon-separated list of glob (not regex) patterns " + "for filtering the tests to run, optionally followed by a " + "'-' and a : separated list of negative patterns (tests to " + "exclude). A test is run if it matches one of the positive " + "patterns and does not match any of the negative patterns."); + +GTEST_DEFINE_bool_(list_tests, false, + "List all tests without running them."); + +GTEST_DEFINE_string_( + output, + internal::StringFromGTestEnv("output", ""), + "A format (currently must be \"xml\"), optionally followed " + "by a colon and an output file name or directory. A directory " + "is indicated by a trailing pathname separator. " + "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " + "If a directory is specified, output files will be created " + "within that directory, with file-names based on the test " + "executable's name and, if necessary, made unique by adding " + "digits."); + +GTEST_DEFINE_bool_( + print_time, + internal::BoolFromGTestEnv("print_time", true), + "True iff " GTEST_NAME_ + " should display elapsed time in text output."); + +GTEST_DEFINE_int32_( + random_seed, + internal::Int32FromGTestEnv("random_seed", 0), + "Random number seed to use when shuffling test orders. Must be in range " + "[1, 99999], or 0 to use a seed based on the current time."); + +GTEST_DEFINE_int32_( + repeat, + internal::Int32FromGTestEnv("repeat", 1), + "How many times to repeat each test. Specify a negative number " + "for repeating forever. Useful for shaking out flaky tests."); + +GTEST_DEFINE_bool_( + show_internal_stack_frames, false, + "True iff " GTEST_NAME_ " should include internal stack frames when " + "printing test failure stack traces."); + +GTEST_DEFINE_bool_( + shuffle, + internal::BoolFromGTestEnv("shuffle", false), + "True iff " GTEST_NAME_ + " should randomize tests' order on every run."); + +GTEST_DEFINE_int32_( + stack_trace_depth, + internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), + "The maximum number of stack frames to print when an " + "assertion fails. The valid range is 0 through 100, inclusive."); + +GTEST_DEFINE_string_( + stream_result_to, + internal::StringFromGTestEnv("stream_result_to", ""), + "This flag specifies the host name and the port number on which to stream " + "test results. Example: \"localhost:555\". The flag is effective only on " + "Linux."); + +GTEST_DEFINE_bool_( + throw_on_failure, + internal::BoolFromGTestEnv("throw_on_failure", false), + "When this flag is specified, a failed assertion will throw an exception " + "if exceptions are enabled or exit the program with a non-zero code " + "otherwise."); + +namespace internal { + +// Generates a random number from [0, range), using a Linear +// Congruential Generator (LCG). Crashes if 'range' is 0 or greater +// than kMaxRange. +UInt32 Random::Generate(UInt32 range) { + // These constants are the same as are used in glibc's rand(3). + state_ = (1103515245U*state_ + 12345U) % kMaxRange; + + GTEST_CHECK_(range > 0) + << "Cannot generate a number in the range [0, 0)."; + GTEST_CHECK_(range <= kMaxRange) + << "Generation of a number in [0, " << range << ") was requested, " + << "but this can only generate numbers in [0, " << kMaxRange << ")."; + + // Converting via modulus introduces a bit of downward bias, but + // it's simple, and a linear congruential generator isn't too good + // to begin with. + return state_ % range; +} + +// GTestIsInitialized() returns true iff the user has initialized +// Google Test. Useful for catching the user mistake of not initializing +// Google Test before calling RUN_ALL_TESTS(). +// +// A user must call testing::InitGoogleTest() to initialize Google +// Test. g_init_gtest_count is set to the number of times +// InitGoogleTest() has been called. We don't protect this variable +// under a mutex as it is only accessed in the main thread. +GTEST_API_ int g_init_gtest_count = 0; +static bool GTestIsInitialized() { return g_init_gtest_count != 0; } + +// Iterates over a vector of TestCases, keeping a running sum of the +// results of calling a given int-returning method on each. +// Returns the sum. +static int SumOverTestCaseList(const std::vector& case_list, + int (TestCase::*method)() const) { + int sum = 0; + for (size_t i = 0; i < case_list.size(); i++) { + sum += (case_list[i]->*method)(); + } + return sum; +} + +// Returns true iff the test case passed. +static bool TestCasePassed(const TestCase* test_case) { + return test_case->should_run() && test_case->Passed(); +} + +// Returns true iff the test case failed. +static bool TestCaseFailed(const TestCase* test_case) { + return test_case->should_run() && test_case->Failed(); +} + +// Returns true iff test_case contains at least one test that should +// run. +static bool ShouldRunTestCase(const TestCase* test_case) { + return test_case->should_run(); +} + +// AssertHelper constructor. +AssertHelper::AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message) + : data_(new AssertHelperData(type, file, line, message)) { +} + +AssertHelper::~AssertHelper() { + delete data_; +} + +// Message assignment, for assertion streaming support. +void AssertHelper::operator=(const Message& message) const { + UnitTest::GetInstance()-> + AddTestPartResult(data_->type, data_->file, data_->line, + AppendUserMessage(data_->message, message), + UnitTest::GetInstance()->impl() + ->CurrentOsStackTraceExceptTop(1) + // Skips the stack frame for this function itself. + ); // NOLINT +} + +// Mutex for linked pointers. +GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// Application pathname gotten in InitGoogleTest. +std::string g_executable_path; + +// Returns the current application's name, removing directory path if that +// is present. +FilePath GetCurrentExecutableName() { + FilePath result; + +#if GTEST_OS_WINDOWS + result.Set(FilePath(g_executable_path).RemoveExtension("exe")); +#else + result.Set(FilePath(g_executable_path)); +#endif // GTEST_OS_WINDOWS + + return result.RemoveDirectoryName(); +} + +// Functions for processing the gtest_output flag. + +// Returns the output format, or "" for normal printed output. +std::string UnitTestOptions::GetOutputFormat() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) return std::string(""); + + const char* const colon = strchr(gtest_output_flag, ':'); + return (colon == NULL) ? + std::string(gtest_output_flag) : + std::string(gtest_output_flag, colon - gtest_output_flag); +} + +// Returns the name of the requested output file, or the default if none +// was explicitly specified. +std::string UnitTestOptions::GetAbsolutePathToOutputFile() { + const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); + if (gtest_output_flag == NULL) + return ""; + + const char* const colon = strchr(gtest_output_flag, ':'); + if (colon == NULL) + return internal::FilePath::ConcatPaths( + internal::FilePath( + UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(kDefaultOutputFile)).string(); + + internal::FilePath output_name(colon + 1); + if (!output_name.IsAbsolutePath()) + // TODO(wan@google.com): on Windows \some\path is not an absolute + // path (as its meaning depends on the current drive), yet the + // following logic for turning it into an absolute path is wrong. + // Fix it. + output_name = internal::FilePath::ConcatPaths( + internal::FilePath(UnitTest::GetInstance()->original_working_dir()), + internal::FilePath(colon + 1)); + + if (!output_name.IsDirectory()) + return output_name.string(); + + internal::FilePath result(internal::FilePath::GenerateUniqueFileName( + output_name, internal::GetCurrentExecutableName(), + GetOutputFormat().c_str())); + return result.string(); +} + +// Returns true iff the wildcard pattern matches the string. The +// first ':' or '\0' character in pattern marks the end of it. +// +// This recursive algorithm isn't very efficient, but is clear and +// works well enough for matching test names, which are short. +bool UnitTestOptions::PatternMatchesString(const char *pattern, + const char *str) { + switch (*pattern) { + case '\0': + case ':': // Either ':' or '\0' marks the end of the pattern. + return *str == '\0'; + case '?': // Matches any single character. + return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); + case '*': // Matches any string (possibly empty) of characters. + return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || + PatternMatchesString(pattern + 1, str); + default: // Non-special character. Matches itself. + return *pattern == *str && + PatternMatchesString(pattern + 1, str + 1); + } +} + +bool UnitTestOptions::MatchesFilter( + const std::string& name, const char* filter) { + const char *cur_pattern = filter; + for (;;) { + if (PatternMatchesString(cur_pattern, name.c_str())) { + return true; + } + + // Finds the next pattern in the filter. + cur_pattern = strchr(cur_pattern, ':'); + + // Returns if no more pattern can be found. + if (cur_pattern == NULL) { + return false; + } + + // Skips the pattern separater (the ':' character). + cur_pattern++; + } +} + +// Returns true iff the user-specified filter matches the test case +// name and the test name. +bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, + const std::string &test_name) { + const std::string& full_name = test_case_name + "." + test_name.c_str(); + + // Split --gtest_filter at '-', if there is one, to separate into + // positive filter and negative filter portions + const char* const p = GTEST_FLAG(filter).c_str(); + const char* const dash = strchr(p, '-'); + std::string positive; + std::string negative; + if (dash == NULL) { + positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter + negative = ""; + } else { + positive = std::string(p, dash); // Everything up to the dash + negative = std::string(dash + 1); // Everything after the dash + if (positive.empty()) { + // Treat '-test1' as the same as '*-test1' + positive = kUniversalFilter; + } + } + + // A filter is a colon-separated list of patterns. It matches a + // test if any pattern in it matches the test. + return (MatchesFilter(full_name, positive.c_str()) && + !MatchesFilter(full_name, negative.c_str())); +} + +#if GTEST_HAS_SEH +// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the +// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. +// This function is useful as an __except condition. +int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { + // Google Test should handle a SEH exception if: + // 1. the user wants it to, AND + // 2. this is not a breakpoint exception, AND + // 3. this is not a C++ exception (VC++ implements them via SEH, + // apparently). + // + // SEH exception code for C++ exceptions. + // (see http://support.microsoft.com/kb/185294 for more information). + const DWORD kCxxExceptionCode = 0xe06d7363; + + bool should_handle = true; + + if (!GTEST_FLAG(catch_exceptions)) + should_handle = false; + else if (exception_code == EXCEPTION_BREAKPOINT) + should_handle = false; + else if (exception_code == kCxxExceptionCode) + should_handle = false; + + return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; +} +#endif // GTEST_HAS_SEH + +} // namespace internal + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. Intercepts only failures from the current thread. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + TestPartResultArray* result) + : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), + result_(result) { + Init(); +} + +// The c'tor sets this object as the test part result reporter used by +// Google Test. The 'result' parameter specifies where to report the +// results. +ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( + InterceptMode intercept_mode, TestPartResultArray* result) + : intercept_mode_(intercept_mode), + result_(result) { + Init(); +} + +void ScopedFakeTestPartResultReporter::Init() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + old_reporter_ = impl->GetGlobalTestPartResultReporter(); + impl->SetGlobalTestPartResultReporter(this); + } else { + old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); + impl->SetTestPartResultReporterForCurrentThread(this); + } +} + +// The d'tor restores the test part result reporter used by Google Test +// before. +ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + if (intercept_mode_ == INTERCEPT_ALL_THREADS) { + impl->SetGlobalTestPartResultReporter(old_reporter_); + } else { + impl->SetTestPartResultReporterForCurrentThread(old_reporter_); + } +} + +// Increments the test part result count and remembers the result. +// This method is from the TestPartResultReporterInterface interface. +void ScopedFakeTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + result_->Append(result); +} + +namespace internal { + +// Returns the type ID of ::testing::Test. We should always call this +// instead of GetTypeId< ::testing::Test>() to get the type ID of +// testing::Test. This is to work around a suspected linker bug when +// using Google Test as a framework on Mac OS X. The bug causes +// GetTypeId< ::testing::Test>() to return different values depending +// on whether the call is from the Google Test framework itself or +// from user test code. GetTestTypeId() is guaranteed to always +// return the same value, as it always calls GetTypeId<>() from the +// gtest.cc, which is within the Google Test framework. +TypeId GetTestTypeId() { + return GetTypeId(); +} + +// The value of GetTestTypeId() as seen from within the Google Test +// library. This is solely for testing GetTestTypeId(). +extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); + +// This predicate-formatter checks that 'results' contains a test part +// failure of the given type and that the failure message contains the +// given substring. +AssertionResult HasOneFailure(const char* /* results_expr */, + const char* /* type_expr */, + const char* /* substr_expr */, + const TestPartResultArray& results, + TestPartResult::Type type, + const string& substr) { + const std::string expected(type == TestPartResult::kFatalFailure ? + "1 fatal failure" : + "1 non-fatal failure"); + Message msg; + if (results.size() != 1) { + msg << "Expected: " << expected << "\n" + << " Actual: " << results.size() << " failures"; + for (int i = 0; i < results.size(); i++) { + msg << "\n" << results.GetTestPartResult(i); + } + return AssertionFailure() << msg; + } + + const TestPartResult& r = results.GetTestPartResult(0); + if (r.type() != type) { + return AssertionFailure() << "Expected: " << expected << "\n" + << " Actual:\n" + << r; + } + + if (strstr(r.message(), substr.c_str()) == NULL) { + return AssertionFailure() << "Expected: " << expected << " containing \"" + << substr << "\"\n" + << " Actual:\n" + << r; + } + + return AssertionSuccess(); +} + +// The constructor of SingleFailureChecker remembers where to look up +// test part results, what type of failure we expect, and what +// substring the failure message should contain. +SingleFailureChecker:: SingleFailureChecker( + const TestPartResultArray* results, + TestPartResult::Type type, + const string& substr) + : results_(results), + type_(type), + substr_(substr) {} + +// The destructor of SingleFailureChecker verifies that the given +// TestPartResultArray contains exactly one failure that has the given +// type and contains the given substring. If that's not the case, a +// non-fatal failure will be generated. +SingleFailureChecker::~SingleFailureChecker() { + EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); +} + +DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultGlobalTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->current_test_result()->AddTestPartResult(result); + unit_test_->listeners()->repeater()->OnTestPartResult(result); +} + +DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( + UnitTestImpl* unit_test) : unit_test_(unit_test) {} + +void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( + const TestPartResult& result) { + unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); +} + +// Returns the global test part result reporter. +TestPartResultReporterInterface* +UnitTestImpl::GetGlobalTestPartResultReporter() { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + return global_test_part_result_repoter_; +} + +// Sets the global test part result reporter. +void UnitTestImpl::SetGlobalTestPartResultReporter( + TestPartResultReporterInterface* reporter) { + internal::MutexLock lock(&global_test_part_result_reporter_mutex_); + global_test_part_result_repoter_ = reporter; +} + +// Returns the test part result reporter for the current thread. +TestPartResultReporterInterface* +UnitTestImpl::GetTestPartResultReporterForCurrentThread() { + return per_thread_test_part_result_reporter_.get(); +} + +// Sets the test part result reporter for the current thread. +void UnitTestImpl::SetTestPartResultReporterForCurrentThread( + TestPartResultReporterInterface* reporter) { + per_thread_test_part_result_reporter_.set(reporter); +} + +// Gets the number of successful test cases. +int UnitTestImpl::successful_test_case_count() const { + return CountIf(test_cases_, TestCasePassed); +} + +// Gets the number of failed test cases. +int UnitTestImpl::failed_test_case_count() const { + return CountIf(test_cases_, TestCaseFailed); +} + +// Gets the number of all test cases. +int UnitTestImpl::total_test_case_count() const { + return static_cast(test_cases_.size()); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTestImpl::test_case_to_run_count() const { + return CountIf(test_cases_, ShouldRunTestCase); +} + +// Gets the number of successful tests. +int UnitTestImpl::successful_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); +} + +// Gets the number of failed tests. +int UnitTestImpl::failed_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTestImpl::reportable_disabled_test_count() const { + return SumOverTestCaseList(test_cases_, + &TestCase::reportable_disabled_test_count); +} + +// Gets the number of disabled tests. +int UnitTestImpl::disabled_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTestImpl::reportable_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); +} + +// Gets the number of all tests. +int UnitTestImpl::total_test_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); +} + +// Gets the number of tests that should run. +int UnitTestImpl::test_to_run_count() const { + return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// CurrentOsStackTraceExceptTop(1), Foo() will be included in the +// trace but Bar() and CurrentOsStackTraceExceptTop() won't. +std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { + (void)skip_count; + return ""; +} + +// Returns the current time in milliseconds. +TimeInMillis GetTimeInMillis() { +#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) + // Difference between 1970-01-01 and 1601-01-01 in milliseconds. + // http://analogous.blogspot.com/2005/04/epoch.html + const TimeInMillis kJavaEpochToWinFileTimeDelta = + static_cast(116444736UL) * 100000UL; + const DWORD kTenthMicrosInMilliSecond = 10000; + + SYSTEMTIME now_systime; + FILETIME now_filetime; + ULARGE_INTEGER now_int64; + // TODO(kenton@google.com): Shouldn't this just use + // GetSystemTimeAsFileTime()? + GetSystemTime(&now_systime); + if (SystemTimeToFileTime(&now_systime, &now_filetime)) { + now_int64.LowPart = now_filetime.dwLowDateTime; + now_int64.HighPart = now_filetime.dwHighDateTime; + now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - + kJavaEpochToWinFileTimeDelta; + return now_int64.QuadPart; + } + return 0; +#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ + __timeb64 now; + +# ifdef _MSC_VER + + // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 + // (deprecated function) there. + // TODO(kenton@google.com): Use GetTickCount()? Or use + // SystemTimeToFileTime() +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996. + _ftime64(&now); +# pragma warning(pop) // Restores the warning state. +# else + + _ftime64(&now); + +# endif // _MSC_VER + + return static_cast(now.time) * 1000 + now.millitm; +#elif GTEST_HAS_GETTIMEOFDAY_ + struct timeval now; + gettimeofday(&now, NULL); + return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; +#else +# error "Don't know how to get the current time on your system." +#endif +} + +// Utilities + +// class String. + +#if GTEST_OS_WINDOWS_MOBILE +// Creates a UTF-16 wide string from the given ANSI string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the wide string, or NULL if the +// input is NULL. +LPCWSTR String::AnsiToUtf16(const char* ansi) { + if (!ansi) return NULL; + const int length = strlen(ansi); + const int unicode_length = + MultiByteToWideChar(CP_ACP, 0, ansi, length, + NULL, 0); + WCHAR* unicode = new WCHAR[unicode_length + 1]; + MultiByteToWideChar(CP_ACP, 0, ansi, length, + unicode, unicode_length); + unicode[unicode_length] = 0; + return unicode; +} + +// Creates an ANSI string from the given wide string, allocating +// memory using new. The caller is responsible for deleting the return +// value using delete[]. Returns the ANSI string, or NULL if the +// input is NULL. +const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { + if (!utf16_str) return NULL; + const int ansi_length = + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + NULL, 0, NULL, NULL); + char* ansi = new char[ansi_length + 1]; + WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, + ansi, ansi_length, NULL, NULL); + ansi[ansi_length] = 0; + return ansi; +} + +#endif // GTEST_OS_WINDOWS_MOBILE + +// Compares two C strings. Returns true iff they have the same content. +// +// Unlike strcmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CStringEquals(const char * lhs, const char * rhs) { + if ( lhs == NULL ) return rhs == NULL; + + if ( rhs == NULL ) return false; + + return strcmp(lhs, rhs) == 0; +} + +#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +// Converts an array of wide chars to a narrow string using the UTF-8 +// encoding, and streams the result to the given Message object. +static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, + Message* msg) { + for (size_t i = 0; i != length; ) { // NOLINT + if (wstr[i] != L'\0') { + *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); + while (i != length && wstr[i] != L'\0') + i++; + } else { + *msg << '\0'; + i++; + } + } +} + +#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING + +} // namespace internal + +// Constructs an empty Message. +// We allocate the stringstream separately because otherwise each use of +// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's +// stack frame leading to huge stack frames in some cases; gcc does not reuse +// the stack space. +Message::Message() : ss_(new ::std::stringstream) { + // By default, we want there to be enough precision when printing + // a double to a Message. + *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); +} + +// These two overloads allow streaming a wide C string to a Message +// using the UTF-8 encoding. +Message& Message::operator <<(const wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} +Message& Message::operator <<(wchar_t* wide_c_str) { + return *this << internal::String::ShowWideCString(wide_c_str); +} + +#if GTEST_HAS_STD_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::std::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING +// Converts the given wide string to a narrow string using the UTF-8 +// encoding, and streams the result to this Message object. +Message& Message::operator <<(const ::wstring& wstr) { + internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); + return *this; +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Gets the text streamed to this object so far as an std::string. +// Each '\0' character in the buffer is replaced with "\\0". +std::string Message::GetString() const { + return internal::StringStreamToString(ss_.get()); +} + +// AssertionResult constructors. +// Used in EXPECT_TRUE/FALSE(assertion_result). +AssertionResult::AssertionResult(const AssertionResult& other) + : success_(other.success_), + message_(other.message_.get() != NULL ? + new ::std::string(*other.message_) : + static_cast< ::std::string*>(NULL)) { +} + +// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. +AssertionResult AssertionResult::operator!() const { + AssertionResult negation(!success_); + if (message_.get() != NULL) + negation << *message_; + return negation; +} + +// Makes a successful assertion result. +AssertionResult AssertionSuccess() { + return AssertionResult(true); +} + +// Makes a failed assertion result. +AssertionResult AssertionFailure() { + return AssertionResult(false); +} + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << message. +AssertionResult AssertionFailure(const Message& message) { + return AssertionFailure() << message; +} + +namespace internal { + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case) { + Message msg; + msg << "Value of: " << actual_expression; + if (actual_value != actual_expression) { + msg << "\n Actual: " << actual_value; + } + + msg << "\nExpected: " << expected_expression; + if (ignoring_case) { + msg << " (ignoring case)"; + } + if (expected_value != expected_expression) { + msg << "\nWhich is: " << expected_value; + } + + return AssertionFailure() << msg; +} + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value) { + const char* actual_message = assertion_result.message(); + Message msg; + msg << "Value of: " << expression_text + << "\n Actual: " << actual_predicate_value; + if (actual_message[0] != '\0') + msg << " (" << actual_message << ")"; + msg << "\nExpected: " << expected_predicate_value; + return msg.GetString(); +} + +// Helper function for implementing ASSERT_NEAR. +AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error) { + const double diff = fabs(val1 - val2); + if (diff <= abs_error) return AssertionSuccess(); + + // TODO(wan): do not print the value of an expression if it's + // already a literal. + return AssertionFailure() + << "The difference between " << expr1 << " and " << expr2 + << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" + << expr1 << " evaluates to " << val1 << ",\n" + << expr2 << " evaluates to " << val2 << ", and\n" + << abs_error_expr << " evaluates to " << abs_error << "."; +} + + +// Helper template for implementing FloatLE() and DoubleLE(). +template +AssertionResult FloatingPointLE(const char* expr1, + const char* expr2, + RawType val1, + RawType val2) { + // Returns success if val1 is less than val2, + if (val1 < val2) { + return AssertionSuccess(); + } + + // or if val1 is almost equal to val2. + const FloatingPoint lhs(val1), rhs(val2); + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + // Note that the above two checks will both fail if either val1 or + // val2 is NaN, as the IEEE floating-point standard requires that + // any predicate involving a NaN must return false. + + ::std::stringstream val1_ss; + val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val1; + + ::std::stringstream val2_ss; + val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << val2; + + return AssertionFailure() + << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" + << " Actual: " << StringStreamToString(&val1_ss) << " vs " + << StringStreamToString(&val2_ss); +} + +} // namespace internal + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2) { + return internal::FloatingPointLE(expr1, expr2, val1, val2); +} + +namespace internal { + +// The helper function for {ASSERT|EXPECT}_EQ with int or enum +// arguments. +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + if (expected == actual) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here +// just to avoid copy-and-paste of similar code. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + BiggestInt val1, BiggestInt val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +} + +// Implements the helper function for {ASSERT|EXPECT}_NE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(NE, !=) +// Implements the helper function for {ASSERT|EXPECT}_LE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LE, <=) +// Implements the helper function for {ASSERT|EXPECT}_LT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(LT, < ) +// Implements the helper function for {ASSERT|EXPECT}_GE with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GE, >=) +// Implements the helper function for {ASSERT|EXPECT}_GT with int or +// enum arguments. +GTEST_IMPL_CMP_HELPER_(GT, > ) + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + false); +} + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual) { + if (String::CaseInsensitiveCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + true); +} + +// The helper function for {ASSERT|EXPECT}_STRNE. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2) { + if (!String::CaseInsensitiveCStringEquals(s1, s2)) { + return AssertionSuccess(); + } else { + return AssertionFailure() + << "Expected: (" << s1_expression << ") != (" + << s2_expression << ") (ignoring case), actual: \"" + << s1 << "\" vs \"" << s2 << "\""; + } +} + +} // namespace internal + +namespace { + +// Helper functions for implementing IsSubString() and IsNotSubstring(). + +// This group of overloaded functions return true iff needle is a +// substring of haystack. NULL is considered a substring of itself +// only. + +bool IsSubstringPred(const char* needle, const char* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return strstr(haystack, needle) != NULL; +} + +bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { + if (needle == NULL || haystack == NULL) + return needle == haystack; + + return wcsstr(haystack, needle) != NULL; +} + +// StringType here can be either ::std::string or ::std::wstring. +template +bool IsSubstringPred(const StringType& needle, + const StringType& haystack) { + return haystack.find(needle) != StringType::npos; +} + +// This function implements either IsSubstring() or IsNotSubstring(), +// depending on the value of the expected_to_be_substring parameter. +// StringType here can be const char*, const wchar_t*, ::std::string, +// or ::std::wstring. +template +AssertionResult IsSubstringImpl( + bool expected_to_be_substring, + const char* needle_expr, const char* haystack_expr, + const StringType& needle, const StringType& haystack) { + if (IsSubstringPred(needle, haystack) == expected_to_be_substring) + return AssertionSuccess(); + + const bool is_wide_string = sizeof(needle[0]) > 1; + const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; + return AssertionFailure() + << "Value of: " << needle_expr << "\n" + << " Actual: " << begin_string_quote << needle << "\"\n" + << "Expected: " << (expected_to_be_substring ? "" : "not ") + << "a substring of " << haystack_expr << "\n" + << "Which is: " << begin_string_quote << haystack << "\""; +} + +} // namespace + +// IsSubstring() and IsNotSubstring() check whether needle is a +// substring of haystack (NULL is considered a substring of itself +// only), and return an appropriate error message when they fail. + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} + +#if GTEST_HAS_STD_WSTRING +AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); +} + +AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack) { + return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); +} +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +#if GTEST_OS_WINDOWS + +namespace { + +// Helper function for IsHRESULT{SuccessFailure} predicates +AssertionResult HRESULTFailureHelper(const char* expr, + const char* expected, + long hr) { // NOLINT +# if GTEST_OS_WINDOWS_MOBILE + + // Windows CE doesn't support FormatMessage. + const char error_text[] = ""; + +# else + + // Looks up the human-readable system message for the HRESULT code + // and since we're not passing any params to FormatMessage, we don't + // want inserts expanded. + const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS; + const DWORD kBufSize = 4096; + // Gets the system's human readable message string for this HRESULT. + char error_text[kBufSize] = { '\0' }; + DWORD message_length = ::FormatMessageA(kFlags, + 0, // no source, we're asking system + hr, // the error + 0, // no line width restrictions + error_text, // output buffer + kBufSize, // buf size + NULL); // no arguments for inserts + // Trims tailing white space (FormatMessage leaves a trailing CR-LF) + for (; message_length && IsSpace(error_text[message_length - 1]); + --message_length) { + error_text[message_length - 1] = '\0'; + } + +# endif // GTEST_OS_WINDOWS_MOBILE + + const std::string error_hex("0x" + String::FormatHexInt(hr)); + return ::testing::AssertionFailure() + << "Expected: " << expr << " " << expected << ".\n" + << " Actual: " << error_hex << " " << error_text << "\n"; +} + +} // namespace + +AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT + if (SUCCEEDED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "succeeds", hr); +} + +AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT + if (FAILED(hr)) { + return AssertionSuccess(); + } + return HRESULTFailureHelper(expr, "fails", hr); +} + +#endif // GTEST_OS_WINDOWS + +// Utility functions for encoding Unicode text (wide strings) in +// UTF-8. + +// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 +// like this: +// +// Code-point length Encoding +// 0 - 7 bits 0xxxxxxx +// 8 - 11 bits 110xxxxx 10xxxxxx +// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx +// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + +// The maximum code-point a one-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; + +// The maximum code-point a two-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; + +// The maximum code-point a three-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; + +// The maximum code-point a four-byte UTF-8 sequence can represent. +const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; + +// Chops off the n lowest bits from a bit pattern. Returns the n +// lowest bits. As a side effect, the original bit pattern will be +// shifted to the right by n bits. +inline UInt32 ChopLowBits(UInt32* bits, int n) { + const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); + *bits >>= n; + return low_bits; +} + +// Converts a Unicode code point to a narrow string in UTF-8 encoding. +// code_point parameter is of type UInt32 because wchar_t may not be +// wide enough to contain a code point. +// If the code_point is not a valid Unicode code point +// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted +// to "(Invalid Unicode 0xXXXXXXXX)". +std::string CodePointToUtf8(UInt32 code_point) { + if (code_point > kMaxCodePoint4) { + return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; + } + + char str[5]; // Big enough for the largest valid code point. + if (code_point <= kMaxCodePoint1) { + str[1] = '\0'; + str[0] = static_cast(code_point); // 0xxxxxxx + } else if (code_point <= kMaxCodePoint2) { + str[2] = '\0'; + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xC0 | code_point); // 110xxxxx + } else if (code_point <= kMaxCodePoint3) { + str[3] = '\0'; + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xE0 | code_point); // 1110xxxx + } else { // code_point <= kMaxCodePoint4 + str[4] = '\0'; + str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx + str[0] = static_cast(0xF0 | code_point); // 11110xxx + } + return str; +} + +// The following two functions only make sense if the the system +// uses UTF-16 for wide string encoding. All supported systems +// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. + +// Determines if the arguments constitute UTF-16 surrogate pair +// and thus should be combined into a single Unicode code point +// using CreateCodePointFromUtf16SurrogatePair. +inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { + return sizeof(wchar_t) == 2 && + (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; +} + +// Creates a Unicode code point from UTF16 surrogate pair. +inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, + wchar_t second) { + const UInt32 mask = (1 << 10) - 1; + return (sizeof(wchar_t) == 2) ? + (((first & mask) << 10) | (second & mask)) + 0x10000 : + // This function should not be called when the condition is + // false, but we provide a sensible default in case it is. + static_cast(first); +} + +// Converts a wide string to a narrow string in UTF-8 encoding. +// The wide string is assumed to have the following encoding: +// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) +// UTF-32 if sizeof(wchar_t) == 4 (on Linux) +// Parameter str points to a null-terminated wide string. +// Parameter num_chars may additionally limit the number +// of wchar_t characters processed. -1 is used when the entire string +// should be processed. +// If the string contains code points that are not valid Unicode code points +// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output +// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding +// and contains invalid UTF-16 surrogate pairs, values in those pairs +// will be encoded as individual Unicode characters from Basic Normal Plane. +std::string WideStringToUtf8(const wchar_t* str, int num_chars) { + if (num_chars == -1) + num_chars = static_cast(wcslen(str)); + + ::std::stringstream stream; + for (int i = 0; i < num_chars; ++i) { + UInt32 unicode_code_point; + + if (str[i] == L'\0') { + break; + } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { + unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], + str[i + 1]); + i++; + } else { + unicode_code_point = static_cast(str[i]); + } + + stream << CodePointToUtf8(unicode_code_point); + } + return StringStreamToString(&stream); +} + +// Converts a wide C string to an std::string using the UTF-8 encoding. +// NULL will be converted to "(null)". +std::string String::ShowWideCString(const wchar_t * wide_c_str) { + if (wide_c_str == NULL) return "(null)"; + + return internal::WideStringToUtf8(wide_c_str, -1); +} + +// Compares two wide C strings. Returns true iff they have the same +// content. +// +// Unlike wcscmp(), this function can handle NULL argument(s). A NULL +// C string is considered different to any non-NULL C string, +// including the empty string. +bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + + return wcscmp(lhs, rhs) == 0; +} + +// Helper function for *_STREQ on wide strings. +AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual) { + if (String::WideCStringEquals(expected, actual)) { + return AssertionSuccess(); + } + + return EqFailure(expected_expression, + actual_expression, + PrintToString(expected), + PrintToString(actual), + false); +} + +// Helper function for *_STRNE on wide strings. +AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2) { + if (!String::WideCStringEquals(s1, s2)) { + return AssertionSuccess(); + } + + return AssertionFailure() << "Expected: (" << s1_expression << ") != (" + << s2_expression << "), actual: " + << PrintToString(s1) + << " vs " << PrintToString(s2); +} + +// Compares two C strings, ignoring case. Returns true iff they have +// the same content. +// +// Unlike strcasecmp(), this function can handle NULL argument(s). A +// NULL C string is considered different to any non-NULL C string, +// including the empty string. +bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { + if (lhs == NULL) + return rhs == NULL; + if (rhs == NULL) + return false; + return posix::StrCaseCmp(lhs, rhs) == 0; +} + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. +bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs) { + if (lhs == NULL) return rhs == NULL; + + if (rhs == NULL) return false; + +#if GTEST_OS_WINDOWS + return _wcsicmp(lhs, rhs) == 0; +#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID + return wcscasecmp(lhs, rhs) == 0; +#else + // Android, Mac OS X and Cygwin don't define wcscasecmp. + // Other unknown OSes may not define it either. + wint_t left, right; + do { + left = towlower(*lhs++); + right = towlower(*rhs++); + } while (left && left == right); + return left == right; +#endif // OS selector +} + +// Returns true iff str ends with the given suffix, ignoring case. +// Any string is considered to end with an empty suffix. +bool String::EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix) { + const size_t str_len = str.length(); + const size_t suffix_len = suffix.length(); + return (str_len >= suffix_len) && + CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, + suffix.c_str()); +} + +// Formats an int value as "%02d". +std::string String::FormatIntWidth2(int value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << value; + return ss.str(); +} + +// Formats an int value as "%X". +std::string String::FormatHexInt(int value) { + std::stringstream ss; + ss << std::hex << std::uppercase << value; + return ss.str(); +} + +// Formats a byte as "%02X". +std::string String::FormatByte(unsigned char value) { + std::stringstream ss; + ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase + << static_cast(value); + return ss.str(); +} + +// Converts the buffer in a stringstream to an std::string, converting NUL +// bytes to "\\0" along the way. +std::string StringStreamToString(::std::stringstream* ss) { + const ::std::string& str = ss->str(); + const char* const start = str.c_str(); + const char* const end = start + str.length(); + + std::string result; + result.reserve(2 * (end - start)); + for (const char* ch = start; ch != end; ++ch) { + if (*ch == '\0') { + result += "\\0"; // Replaces NUL with "\\0"; + } else { + result += *ch; + } + } + + return result; +} + +// Appends the user-supplied message to the Google-Test-generated message. +std::string AppendUserMessage(const std::string& gtest_msg, + const Message& user_msg) { + // Appends the user message if it's non-empty. + const std::string user_msg_string = user_msg.GetString(); + if (user_msg_string.empty()) { + return gtest_msg; + } + + return gtest_msg + "\n" + user_msg_string; +} + +} // namespace internal + +// class TestResult + +// Creates an empty TestResult. +TestResult::TestResult() + : death_test_count_(0), + elapsed_time_(0) { +} + +// D'tor. +TestResult::~TestResult() { +} + +// Returns the i-th test part result among all the results. i can +// range from 0 to total_part_count() - 1. If i is not in that range, +// aborts the program. +const TestPartResult& TestResult::GetTestPartResult(int i) const { + if (i < 0 || i >= total_part_count()) + internal::posix::Abort(); + return test_part_results_.at(i); +} + +// Returns the i-th test property. i can range from 0 to +// test_property_count() - 1. If i is not in that range, aborts the +// program. +const TestProperty& TestResult::GetTestProperty(int i) const { + if (i < 0 || i >= test_property_count()) + internal::posix::Abort(); + return test_properties_.at(i); +} + +// Clears the test part results. +void TestResult::ClearTestPartResults() { + test_part_results_.clear(); +} + +// Adds a test part result to the list. +void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { + test_part_results_.push_back(test_part_result); +} + +// Adds a test property to the list. If a property with the same key as the +// supplied property is already represented, the value of this test_property +// replaces the old value for that key. +void TestResult::RecordProperty(const std::string& xml_element, + const TestProperty& test_property) { + if (!ValidateTestProperty(xml_element, test_property)) { + return; + } + internal::MutexLock lock(&test_properites_mutex_); + const std::vector::iterator property_with_matching_key = + std::find_if(test_properties_.begin(), test_properties_.end(), + internal::TestPropertyKeyIs(test_property.key())); + if (property_with_matching_key == test_properties_.end()) { + test_properties_.push_back(test_property); + return; + } + property_with_matching_key->SetValue(test_property.value()); +} + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuitesAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "random_seed", + "tests", + "time", + "timestamp" +}; + +// The list of reserved attributes used in the element of XML +// output. +static const char* const kReservedTestSuiteAttributes[] = { + "disabled", + "errors", + "failures", + "name", + "tests", + "time" +}; + +// The list of reserved attributes used in the element of XML output. +static const char* const kReservedTestCaseAttributes[] = { + "classname", + "name", + "status", + "time", + "type_param", + "value_param" +}; + +template +std::vector ArrayAsVector(const char* const (&array)[kSize]) { + return std::vector(array, array + kSize); +} + +static std::vector GetReservedAttributesForElement( + const std::string& xml_element) { + if (xml_element == "testsuites") { + return ArrayAsVector(kReservedTestSuitesAttributes); + } else if (xml_element == "testsuite") { + return ArrayAsVector(kReservedTestSuiteAttributes); + } else if (xml_element == "testcase") { + return ArrayAsVector(kReservedTestCaseAttributes); + } else { + GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; + } + // This code is unreachable but some compilers may not realizes that. + return std::vector(); +} + +static std::string FormatWordList(const std::vector& words) { + Message word_list; + for (size_t i = 0; i < words.size(); ++i) { + if (i > 0 && words.size() > 2) { + word_list << ", "; + } + if (i == words.size() - 1) { + word_list << "and "; + } + word_list << "'" << words[i] << "'"; + } + return word_list.GetString(); +} + +bool ValidateTestPropertyName(const std::string& property_name, + const std::vector& reserved_names) { + if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != + reserved_names.end()) { + ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name + << " (" << FormatWordList(reserved_names) + << " are reserved by " << GTEST_NAME_ << ")"; + return false; + } + return true; +} + +// Adds a failure if the key is a reserved attribute of the element named +// xml_element. Returns true if the property is valid. +bool TestResult::ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property) { + return ValidateTestPropertyName(test_property.key(), + GetReservedAttributesForElement(xml_element)); +} + +// Clears the object. +void TestResult::Clear() { + test_part_results_.clear(); + test_properties_.clear(); + death_test_count_ = 0; + elapsed_time_ = 0; +} + +// Returns true iff the test failed. +bool TestResult::Failed() const { + for (int i = 0; i < total_part_count(); ++i) { + if (GetTestPartResult(i).failed()) + return true; + } + return false; +} + +// Returns true iff the test part fatally failed. +static bool TestPartFatallyFailed(const TestPartResult& result) { + return result.fatally_failed(); +} + +// Returns true iff the test fatally failed. +bool TestResult::HasFatalFailure() const { + return CountIf(test_part_results_, TestPartFatallyFailed) > 0; +} + +// Returns true iff the test part non-fatally failed. +static bool TestPartNonfatallyFailed(const TestPartResult& result) { + return result.nonfatally_failed(); +} + +// Returns true iff the test has a non-fatal failure. +bool TestResult::HasNonfatalFailure() const { + return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; +} + +// Gets the number of all test parts. This is the sum of the number +// of successful test parts and the number of failed test parts. +int TestResult::total_part_count() const { + return static_cast(test_part_results_.size()); +} + +// Returns the number of the test properties. +int TestResult::test_property_count() const { + return static_cast(test_properties_.size()); +} + +// class Test + +// Creates a Test object. + +// The c'tor saves the values of all Google Test flags. +Test::Test() + : gtest_flag_saver_(new internal::GTestFlagSaver) { +} + +// The d'tor restores the values of all Google Test flags. +Test::~Test() { + delete gtest_flag_saver_; +} + +// Sets up the test fixture. +// +// A sub-class may override this. +void Test::SetUp() { +} + +// Tears down the test fixture. +// +// A sub-class may override this. +void Test::TearDown() { +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, const std::string& value) { + UnitTest::GetInstance()->RecordProperty(key, value); +} + +// Allows user supplied key value pairs to be recorded for later output. +void Test::RecordProperty(const std::string& key, int value) { + Message value_message; + value_message << value; + RecordProperty(key, value_message.GetString().c_str()); +} + +namespace internal { + +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message) { + // This function is a friend of UnitTest and as such has access to + // AddTestPartResult. + UnitTest::GetInstance()->AddTestPartResult( + result_type, + NULL, // No info about the source file where the exception occurred. + -1, // We have no info on which line caused the exception. + message, + ""); // No stack trace, either. +} + +} // namespace internal + +// Google Test requires all tests in the same test case to use the same test +// fixture class. This function checks if the current test has the +// same fixture class as the first test in the current test case. If +// yes, it returns true; otherwise it generates a Google Test failure and +// returns false. +bool Test::HasSameFixtureClass() { + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + const TestCase* const test_case = impl->current_test_case(); + + // Info about the first test in the current test case. + const TestInfo* const first_test_info = test_case->test_info_list()[0]; + const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; + const char* const first_test_name = first_test_info->name(); + + // Info about the current test. + const TestInfo* const this_test_info = impl->current_test_info(); + const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; + const char* const this_test_name = this_test_info->name(); + + if (this_fixture_id != first_fixture_id) { + // Is the first test defined using TEST? + const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); + // Is this test defined using TEST? + const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); + + if (first_is_TEST || this_is_TEST) { + // The user mixed TEST and TEST_F in this test case - we'll tell + // him/her how to fix it. + + // Gets the name of the TEST and the name of the TEST_F. Note + // that first_is_TEST and this_is_TEST cannot both be true, as + // the fixture IDs are different for the two tests. + const char* const TEST_name = + first_is_TEST ? first_test_name : this_test_name; + const char* const TEST_F_name = + first_is_TEST ? this_test_name : first_test_name; + + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class, so mixing TEST_F and TEST in the same test case is\n" + << "illegal. In test case " << this_test_info->test_case_name() + << ",\n" + << "test " << TEST_F_name << " is defined using TEST_F but\n" + << "test " << TEST_name << " is defined using TEST. You probably\n" + << "want to change the TEST to TEST_F or move it to another test\n" + << "case."; + } else { + // The user defined two fixture classes with the same name in + // two namespaces - we'll tell him/her how to fix it. + ADD_FAILURE() + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " + << this_test_info->test_case_name() << ",\n" + << "you defined test " << first_test_name + << " and test " << this_test_name << "\n" + << "using two different test fixture classes. This can happen if\n" + << "the two classes are from different namespaces or translation\n" + << "units and have the same name. You should probably rename one\n" + << "of the classes to put the tests into different test cases."; + } + return false; + } + + return true; +} + +#if GTEST_HAS_SEH + +// Adds an "exception thrown" fatal failure to the current test. This +// function returns its result via an output parameter pointer because VC++ +// prohibits creation of objects with destructors on stack in functions +// using __try (see error C2712). +static std::string* FormatSehExceptionMessage(DWORD exception_code, + const char* location) { + Message message; + message << "SEH exception with code 0x" << std::setbase(16) << + exception_code << std::setbase(10) << " thrown in " << location << "."; + + return new std::string(message.GetString()); +} + +#endif // GTEST_HAS_SEH + +namespace internal { + +#if GTEST_HAS_EXCEPTIONS + +// Adds an "exception thrown" fatal failure to the current test. +static std::string FormatCxxExceptionMessage(const char* description, + const char* location) { + Message message; + if (description != NULL) { + message << "C++ exception with description \"" << description << "\""; + } else { + message << "Unknown C++ exception"; + } + message << " thrown in " << location << "."; + + return message.GetString(); +} + +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result); + +GoogleTestFailureException::GoogleTestFailureException( + const TestPartResult& failure) + : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} + +#endif // GTEST_HAS_EXCEPTIONS + +// We put these helper functions in the internal namespace as IBM's xlC +// compiler rejects the code if they were declared static. + +// Runs the given method and handles SEH exceptions it throws, when +// SEH is supported; returns the 0-value for type Result in case of an +// SEH exception. (Microsoft compilers cannot handle SEH and C++ +// exceptions in the same function. Therefore, we provide a separate +// wrapper function for handling SEH exceptions.) +template +Result HandleSehExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { +#if GTEST_HAS_SEH + __try { + return (object->*method)(); + } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT + GetExceptionCode())) { + // We create the exception message on the heap because VC++ prohibits + // creation of objects with destructors on stack in functions using __try + // (see error C2712). + std::string* exception_message = FormatSehExceptionMessage( + GetExceptionCode(), location); + internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, + *exception_message); + delete exception_message; + return static_cast(0); + } +#else + (void)location; + return (object->*method)(); +#endif // GTEST_HAS_SEH +} + +// Runs the given method and catches and reports C++ and/or SEH-style +// exceptions, if they are supported; returns the 0-value for type +// Result in case of an SEH exception. +template +Result HandleExceptionsInMethodIfSupported( + T* object, Result (T::*method)(), const char* location) { + // NOTE: The user code can affect the way in which Google Test handles + // exceptions by setting GTEST_FLAG(catch_exceptions), but only before + // RUN_ALL_TESTS() starts. It is technically possible to check the flag + // after the exception is caught and either report or re-throw the + // exception based on the flag's value: + // + // try { + // // Perform the test method. + // } catch (...) { + // if (GTEST_FLAG(catch_exceptions)) + // // Report the exception as failure. + // else + // throw; // Re-throws the original exception. + // } + // + // However, the purpose of this flag is to allow the program to drop into + // the debugger when the exception is thrown. On most platforms, once the + // control enters the catch block, the exception origin information is + // lost and the debugger will stop the program at the point of the + // re-throw in this function -- instead of at the point of the original + // throw statement in the code under test. For this reason, we perform + // the check early, sacrificing the ability to affect Google Test's + // exception handling in the method where the exception is thrown. + if (internal::GetUnitTestImpl()->catch_exceptions()) { +#if GTEST_HAS_EXCEPTIONS + try { + return HandleSehExceptionsInMethodIfSupported(object, method, location); + } catch (const internal::GoogleTestFailureException&) { // NOLINT + // This exception type can only be thrown by a failed Google + // Test assertion with the intention of letting another testing + // framework catch it. Therefore we just re-throw it. + throw; + } catch (const std::exception& e) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(e.what(), location)); + } catch (...) { // NOLINT + internal::ReportFailureInUnknownLocation( + TestPartResult::kFatalFailure, + FormatCxxExceptionMessage(NULL, location)); + } + return static_cast(0); +#else + return HandleSehExceptionsInMethodIfSupported(object, method, location); +#endif // GTEST_HAS_EXCEPTIONS + } else { + return (object->*method)(); + } +} + +} // namespace internal + +// Runs the test and updates the test result. +void Test::Run() { + if (!HasSameFixtureClass()) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); + // We will run the test only if SetUp() was successful. + if (!HasFatalFailure()) { + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TestBody, "the test body"); + } + + // However, we want to clean up as much as possible. Hence we will + // always call TearDown(), even if SetUp() or the test body has + // failed. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &Test::TearDown, "TearDown()"); +} + +// Returns true iff the current test has a fatal failure. +bool Test::HasFatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); +} + +// Returns true iff the current test has a non-fatal failure. +bool Test::HasNonfatalFailure() { + return internal::GetUnitTestImpl()->current_test_result()-> + HasNonfatalFailure(); +} + +// class TestInfo + +// Constructs a TestInfo object. It assumes ownership of the test factory +// object. +TestInfo::TestInfo(const std::string& a_test_case_name, + const std::string& a_name, + const char* a_type_param, + const char* a_value_param, + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory) + : test_case_name_(a_test_case_name), + name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + value_param_(a_value_param ? new std::string(a_value_param) : NULL), + fixture_class_id_(fixture_class_id), + should_run_(false), + is_disabled_(false), + matches_filter_(false), + factory_(factory), + result_() {} + +// Destructs a TestInfo object. +TestInfo::~TestInfo() { delete factory_; } + +namespace internal { + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param: the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param: text representation of the test's value parameter, +// or NULL if this is not a value-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory) { + TestInfo* const test_info = + new TestInfo(test_case_name, name, type_param, value_param, + fixture_class_id, factory); + GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); + return test_info; +} + +#if GTEST_HAS_PARAM_TEST +void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line) { + Message errors; + errors + << "Attempted redefinition of test case " << test_case_name << ".\n" + << "All tests in the same test case must use the same test fixture\n" + << "class. However, in test case " << test_case_name << ", you tried\n" + << "to define a test using a fixture class different from the one\n" + << "used earlier. This can happen if the two fixture classes are\n" + << "from different namespaces and have the same name. You should\n" + << "probably rename one of the classes to put the tests into different\n" + << "test cases."; + + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors.GetString().c_str()); +} +#endif // GTEST_HAS_PARAM_TEST + +} // namespace internal + +namespace { + +// A predicate that checks the test name of a TestInfo against a known +// value. +// +// This is used for implementation of the TestCase class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestNameIs is copyable. + +//Commenting out this class since its not used and wherefor produces warnings +// class TestNameIs { +// public: +// // Constructor. +// // +// // TestNameIs has NO default constructor. +// explicit TestNameIs(const char* name) +// : name_(name) {} +// +// // Returns true iff the test name of test_info matches name_. +// bool operator()(const TestInfo * test_info) const { +// return test_info && test_info->name() == name_; +// } +// +// private: +// std::string name_; +//}; + +} // namespace + +namespace internal { + +// This method expands all parameterized tests registered with macros TEST_P +// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. +// This will be done just once during the program runtime. +void UnitTestImpl::RegisterParameterizedTests() { +#if GTEST_HAS_PARAM_TEST + if (!parameterized_tests_registered_) { + parameterized_test_registry_.RegisterTests(); + parameterized_tests_registered_ = true; + } +#endif +} + +} // namespace internal + +// Creates the test object, runs it, records its result, and then +// deletes it. +void TestInfo::Run() { + if (!should_run_) return; + + // Tells UnitTest where to store test result. + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_info(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + // Notifies the unit test event listeners that a test is about to start. + repeater->OnTestStart(*this); + + const TimeInMillis start = internal::GetTimeInMillis(); + + impl->os_stack_trace_getter()->UponLeavingGTest(); + + // Creates the test object. + Test* const test = internal::HandleExceptionsInMethodIfSupported( + factory_, &internal::TestFactoryBase::CreateTest, + "the test fixture's constructor"); + + // Runs the test only if the test object was created and its + // constructor didn't generate a fatal failure. + if ((test != NULL) && !Test::HasFatalFailure()) { + // This doesn't throw as all user code that can throw are wrapped into + // exception handling code. + test->Run(); + } + + // Deletes the test object. + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + test, &Test::DeleteSelf_, "the test fixture's destructor"); + + result_.set_elapsed_time(internal::GetTimeInMillis() - start); + + // Notifies the unit test event listener that a test has just finished. + repeater->OnTestEnd(*this); + + // Tells UnitTest to stop associating assertion results to this + // test. + impl->set_current_test_info(NULL); +} + +// class TestCase + +// Gets the number of successful tests in this test case. +int TestCase::successful_test_count() const { + return CountIf(test_info_list_, TestPassed); +} + +// Gets the number of failed tests in this test case. +int TestCase::failed_test_count() const { + return CountIf(test_info_list_, TestFailed); +} + +// Gets the number of disabled tests that will be reported in the XML report. +int TestCase::reportable_disabled_test_count() const { + return CountIf(test_info_list_, TestReportableDisabled); +} + +// Gets the number of disabled tests in this test case. +int TestCase::disabled_test_count() const { + return CountIf(test_info_list_, TestDisabled); +} + +// Gets the number of tests to be printed in the XML report. +int TestCase::reportable_test_count() const { + return CountIf(test_info_list_, TestReportable); +} + +// Get the number of tests in this test case that should run. +int TestCase::test_to_run_count() const { + return CountIf(test_info_list_, ShouldRunTest); +} + +// Gets the number of all tests. +int TestCase::total_test_count() const { + return static_cast(test_info_list_.size()); +} + +// Creates a TestCase with the given name. +// +// Arguments: +// +// name: name of the test case +// a_type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase::TestCase(const char* a_name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) + : name_(a_name), + type_param_(a_type_param ? new std::string(a_type_param) : NULL), + set_up_tc_(set_up_tc), + tear_down_tc_(tear_down_tc), + should_run_(false), + elapsed_time_(0) { +} + +// Destructor of TestCase. +TestCase::~TestCase() { + // Deletes every Test in the collection. + ForEach(test_info_list_, internal::Delete); +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +const TestInfo* TestCase::GetTestInfo(int i) const { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Returns the i-th test among all the tests. i can range from 0 to +// total_test_count() - 1. If i is not in that range, returns NULL. +TestInfo* TestCase::GetMutableTestInfo(int i) { + const int index = GetElementOr(test_indices_, i, -1); + return index < 0 ? NULL : test_info_list_[index]; +} + +// Adds a test to this test case. Will delete the test upon +// destruction of the TestCase object. +void TestCase::AddTestInfo(TestInfo * test_info) { + test_info_list_.push_back(test_info); + test_indices_.push_back(static_cast(test_indices_.size())); +} + +// Runs every test in this TestCase. +void TestCase::Run() { + if (!should_run_) return; + + internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); + impl->set_current_test_case(this); + + TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); + + repeater->OnTestCaseStart(*this); + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); + + const internal::TimeInMillis start = internal::GetTimeInMillis(); + for (int i = 0; i < total_test_count(); i++) { + GetMutableTestInfo(i)->Run(); + } + elapsed_time_ = internal::GetTimeInMillis() - start; + + impl->os_stack_trace_getter()->UponLeavingGTest(); + internal::HandleExceptionsInMethodIfSupported( + this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); + + repeater->OnTestCaseEnd(*this); + impl->set_current_test_case(NULL); +} + +// Clears the results of all tests in this test case. +void TestCase::ClearResult() { + ad_hoc_test_result_.Clear(); + ForEach(test_info_list_, TestInfo::ClearTestResult); +} + +// Shuffles the tests in this test case. +void TestCase::ShuffleTests(internal::Random* random) { + Shuffle(random, &test_indices_); +} + +// Restores the test order to before the first shuffle. +void TestCase::UnshuffleTests() { + for (size_t i = 0; i < test_indices_.size(); i++) { + test_indices_[i] = static_cast(i); + } +} + +// Formats a countable noun. Depending on its quantity, either the +// singular form or the plural form is used. e.g. +// +// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". +// FormatCountableNoun(5, "book", "books") returns "5 books". +static std::string FormatCountableNoun(int count, + const char * singular_form, + const char * plural_form) { + return internal::StreamableToString(count) + " " + + (count == 1 ? singular_form : plural_form); +} + +// Formats the count of tests. +static std::string FormatTestCount(int test_count) { + return FormatCountableNoun(test_count, "test", "tests"); +} + +// Formats the count of test cases. +static std::string FormatTestCaseCount(int test_case_count) { + return FormatCountableNoun(test_case_count, "test case", "test cases"); +} + +// Converts a TestPartResult::Type enum to human-friendly string +// representation. Both kNonFatalFailure and kFatalFailure are translated +// to "Failure", as the user usually doesn't care about the difference +// between the two when viewing the test result. +static const char * TestPartResultTypeToString(TestPartResult::Type type) { + switch (type) { + case TestPartResult::kSuccess: + return "Success"; + + case TestPartResult::kNonFatalFailure: + case TestPartResult::kFatalFailure: +#ifdef _MSC_VER + return "error: "; +#else + return "Failure\n"; +#endif + default: + return "Unknown result type"; + } +} + +namespace internal { + +// Prints a TestPartResult to an std::string. +static std::string PrintTestPartResultToString( + const TestPartResult& test_part_result) { + return (Message() + << internal::FormatFileLocation(test_part_result.file_name(), + test_part_result.line_number()) + << " " << TestPartResultTypeToString(test_part_result.type()) + << test_part_result.message()).GetString(); +} + +// Prints a TestPartResult. +static void PrintTestPartResult(const TestPartResult& test_part_result) { + const std::string& result = + PrintTestPartResultToString(test_part_result); + printf("%s\n", result.c_str()); + fflush(stdout); + // If the test program runs in Visual Studio or a debugger, the + // following statements add the test part result message to the Output + // window such that the user can double-click on it to jump to the + // corresponding source code location; otherwise they do nothing. +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + // We don't call OutputDebugString*() on Windows Mobile, as printing + // to stdout is done by OutputDebugString() there already - we don't + // want the same message printed twice. + ::OutputDebugStringA(result.c_str()); + ::OutputDebugStringA("\n"); +#endif +} + +// class PrettyUnitTestResultPrinter + +enum GTestColor { + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns the character attribute for the given color. +WORD GetColorAttribute(GTestColor color) { + switch (color) { + case COLOR_RED: return FOREGROUND_RED; + case COLOR_GREEN: return FOREGROUND_GREEN; + case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; + default: return 0; + } +} + +#else + +// Returns the ANSI color code for the given color. COLOR_DEFAULT is +// an invalid input. +const char* GetAnsiColorCode(GTestColor color) { + switch (color) { + case COLOR_RED: return "1"; + case COLOR_GREEN: return "2"; + case COLOR_YELLOW: return "3"; + default: return NULL; + }; +} + +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + +// Returns true iff Google Test should use colors in the output. +bool ShouldUseColor(bool stdout_is_tty) { + const char* const gtest_color = GTEST_FLAG(color).c_str(); + + if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { +#if GTEST_OS_WINDOWS + // On Windows the TERM variable is usually not set, but the + // console there does support colors. + return stdout_is_tty; +#else + // On non-Windows platforms, we rely on the TERM variable. + const char* const term = posix::GetEnv("TERM"); + const bool term_supports_color = + String::CStringEquals(term, "xterm") || + String::CStringEquals(term, "xterm-color") || + String::CStringEquals(term, "xterm-256color") || + String::CStringEquals(term, "screen") || + String::CStringEquals(term, "screen-256color") || + String::CStringEquals(term, "linux") || + String::CStringEquals(term, "cygwin"); + return stdout_is_tty && term_supports_color; +#endif // GTEST_OS_WINDOWS + } + + return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || + String::CaseInsensitiveCStringEquals(gtest_color, "true") || + String::CaseInsensitiveCStringEquals(gtest_color, "t") || + String::CStringEquals(gtest_color, "1"); + // We take "yes", "true", "t", and "1" as meaning "yes". If the + // value is neither one of these nor "auto", we treat it as "no" to + // be conservative. +} + +// Helpers for printing colored strings to stdout. Note that on Windows, we +// cannot simply emit special characters and have the terminal change colors. +// This routine must actually emit the characters rather than return a string +// that would be colored when printed, as can be done on Linux. +void ColoredPrintf(GTestColor color, const char* fmt, ...) { + va_list args; + va_start(args, fmt); + +#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS + const bool use_color = false; +#else + static const bool in_color_mode = + ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); + const bool use_color = in_color_mode && (color != COLOR_DEFAULT); +#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS + // The '!= 0' comparison is necessary to satisfy MSVC 7.1. + + if (!use_color) { + vprintf(fmt, args); + va_end(args); + return; + } + +#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); + + // Gets the current text color. + CONSOLE_SCREEN_BUFFER_INFO buffer_info; + GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); + const WORD old_color_attrs = buffer_info.wAttributes; + + // We need to flush the stream buffers into the console before each + // SetConsoleTextAttribute call lest it affect the text that is already + // printed but has not yet reached the console. + fflush(stdout); + SetConsoleTextAttribute(stdout_handle, + GetColorAttribute(color) | FOREGROUND_INTENSITY); + vprintf(fmt, args); + + fflush(stdout); + // Restores the text color. + SetConsoleTextAttribute(stdout_handle, old_color_attrs); +#else + printf("\033[0;3%sm", GetAnsiColorCode(color)); + vprintf(fmt, args); + printf("\033[m"); // Resets the terminal to default. +#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE + va_end(args); +} + +// Text printed in Google Test's text output and --gunit_list_tests +// output to label the type parameter and value parameter for a test. +static const char kTypeParamLabel[] = "TypeParam"; +static const char kValueParamLabel[] = "GetParam()"; + +void PrintFullTestCommentIfPresent(const TestInfo& test_info) { + const char* const type_param = test_info.type_param(); + const char* const value_param = test_info.value_param(); + + if (type_param != NULL || value_param != NULL) { + printf(", where "); + if (type_param != NULL) { + printf("%s = %s", kTypeParamLabel, type_param); + if (value_param != NULL) + printf(" and "); + } + if (value_param != NULL) { + printf("%s = %s", kValueParamLabel, value_param); + } + } +} + +// This class implements the TestEventListener interface. +// +// Class PrettyUnitTestResultPrinter is copyable. +class PrettyUnitTestResultPrinter : public TestEventListener { + public: + PrettyUnitTestResultPrinter() {} + static void PrintTestName(const char * test_case, const char * test) { + printf("%s.%s", test_case, test); + } + + // The following methods override what's in the TestEventListener class. + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} + + private: + static void PrintFailedTests(const UnitTest& unit_test); +}; + + // Fired before each iteration of tests starts. +void PrettyUnitTestResultPrinter::OnTestIterationStart( + const UnitTest& unit_test, int iteration) { + if (GTEST_FLAG(repeat) != 1) + printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); + + const char* const filter = GTEST_FLAG(filter).c_str(); + + // Prints the filter if it's not *. This reminds the user that some + // tests may be skipped. + if (!String::CStringEquals(filter, kUniversalFilter)) { + ColoredPrintf(COLOR_YELLOW, + "Note: %s filter = %s\n", GTEST_NAME_, filter); + } + + if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { + const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); + ColoredPrintf(COLOR_YELLOW, + "Note: This is test shard %d of %s.\n", + static_cast(shard_index) + 1, + internal::posix::GetEnv(kTestTotalShards)); + } + + if (GTEST_FLAG(shuffle)) { + ColoredPrintf(COLOR_YELLOW, + "Note: Randomizing tests' orders with a seed of %d .\n", + unit_test.random_seed()); + } + + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("Running %s from %s.\n", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment set-up.\n"); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s", counts.c_str(), test_case.name()); + if (test_case.type_param() == NULL) { + printf("\n"); + } else { + printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { + ColoredPrintf(COLOR_GREEN, "[ RUN ] "); + PrintTestName(test_info.test_case_name(), test_info.name()); + printf("\n"); + fflush(stdout); +} + +// Called after an assertion failure. +void PrettyUnitTestResultPrinter::OnTestPartResult( + const TestPartResult& result) { + // If the test part succeeded, we don't need to do anything. + if (result.type() == TestPartResult::kSuccess) + return; + + // Print failure message from the assertion (e.g. expected this and got that). + PrintTestPartResult(result); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { + if (test_info.result()->Passed()) { + ColoredPrintf(COLOR_GREEN, "[ OK ] "); + } else { + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + } + PrintTestName(test_info.test_case_name(), test_info.name()); + if (test_info.result()->Failed()) + PrintFullTestCommentIfPresent(test_info); + + if (GTEST_FLAG(print_time)) { + printf(" (%s ms)\n", internal::StreamableToString( + test_info.result()->elapsed_time()).c_str()); + } else { + printf("\n"); + } + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { + if (!GTEST_FLAG(print_time)) return; + + const std::string counts = + FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("%s from %s (%s ms total)\n\n", + counts.c_str(), test_case.name(), + internal::StreamableToString(test_case.elapsed_time()).c_str()); + fflush(stdout); +} + +void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( + const UnitTest& /*unit_test*/) { + ColoredPrintf(COLOR_GREEN, "[----------] "); + printf("Global test environment tear-down\n"); + fflush(stdout); +} + +// Internal helper for printing the list of failed tests. +void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { + const int failed_test_count = unit_test.failed_test_count(); + if (failed_test_count == 0) { + return; + } + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + const TestCase& test_case = *unit_test.GetTestCase(i); + if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { + continue; + } + for (int j = 0; j < test_case.total_test_count(); ++j) { + const TestInfo& test_info = *test_case.GetTestInfo(j); + if (!test_info.should_run() || test_info.result()->Passed()) { + continue; + } + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s.%s", test_case.name(), test_info.name()); + PrintFullTestCommentIfPresent(test_info); + printf("\n"); + } + } +} + +void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + ColoredPrintf(COLOR_GREEN, "[==========] "); + printf("%s from %s ran.", + FormatTestCount(unit_test.test_to_run_count()).c_str(), + FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); + if (GTEST_FLAG(print_time)) { + printf(" (%s ms total)", + internal::StreamableToString(unit_test.elapsed_time()).c_str()); + } + printf("\n"); + ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); + printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); + + int num_failures = unit_test.failed_test_count(); + if (!unit_test.Passed()) { + const int failed_test_count = unit_test.failed_test_count(); + ColoredPrintf(COLOR_RED, "[ FAILED ] "); + printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); + PrintFailedTests(unit_test); + printf("\n%2d FAILED %s\n", num_failures, + num_failures == 1 ? "TEST" : "TESTS"); + } + + int num_disabled = unit_test.reportable_disabled_test_count(); + if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { + if (!num_failures) { + printf("\n"); // Add a spacer if no FAILURE banner is displayed. + } + ColoredPrintf(COLOR_YELLOW, + " YOU HAVE %d DISABLED %s\n\n", + num_disabled, + num_disabled == 1 ? "TEST" : "TESTS"); + } + // Ensure that Google Test output is printed before, e.g., heapchecker output. + fflush(stdout); +} + +// End PrettyUnitTestResultPrinter + +// class TestEventRepeater +// +// This class forwards events to other event listeners. +class TestEventRepeater : public TestEventListener { + public: + TestEventRepeater() : forwarding_enabled_(true) {} + virtual ~TestEventRepeater(); + void Append(TestEventListener *listener); + TestEventListener* Release(TestEventListener* listener); + + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled() const { return forwarding_enabled_; } + void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } + + virtual void OnTestProgramStart(const UnitTest& unit_test); + virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); + virtual void OnTestCaseStart(const TestCase& test_case); + virtual void OnTestStart(const TestInfo& test_info); + virtual void OnTestPartResult(const TestPartResult& result); + virtual void OnTestEnd(const TestInfo& test_info); + virtual void OnTestCaseEnd(const TestCase& test_case); + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + virtual void OnTestProgramEnd(const UnitTest& unit_test); + + private: + // Controls whether events will be forwarded to listeners_. Set to false + // in death test child processes. + bool forwarding_enabled_; + // The list of listeners that receive events. + std::vector listeners_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); +}; + +TestEventRepeater::~TestEventRepeater() { + ForEach(listeners_, Delete); +} + +void TestEventRepeater::Append(TestEventListener *listener) { + listeners_.push_back(listener); +} + +// TODO(vladl@google.com): Factor the search functionality into Vector::Find. +TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { + for (size_t i = 0; i < listeners_.size(); ++i) { + if (listeners_[i] == listener) { + listeners_.erase(listeners_.begin() + i); + return listener; + } + } + + return NULL; +} + +// Since most methods are very similar, use macros to reduce boilerplate. +// This defines a member that forwards the call to all listeners. +#define GTEST_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (size_t i = 0; i < listeners_.size(); i++) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} +// This defines a member that forwards the call to all listeners in reverse +// order. +#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ +void TestEventRepeater::Name(const Type& parameter) { \ + if (forwarding_enabled_) { \ + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ + listeners_[i]->Name(parameter); \ + } \ + } \ +} + +GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) +GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) +GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) +GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) +GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) +GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) +GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) +GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) +GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) + +#undef GTEST_REPEATER_METHOD_ +#undef GTEST_REVERSE_REPEATER_METHOD_ + +void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (size_t i = 0; i < listeners_.size(); i++) { + listeners_[i]->OnTestIterationStart(unit_test, iteration); + } + } +} + +void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, + int iteration) { + if (forwarding_enabled_) { + for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { + listeners_[i]->OnTestIterationEnd(unit_test, iteration); + } + } +} + +// End TestEventRepeater + +// This class generates an XML output file. +class XmlUnitTestResultPrinter : public EmptyTestEventListener { + public: + explicit XmlUnitTestResultPrinter(const char* output_file); + + virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); + + private: + // Is c a whitespace character that is normalized to a space character + // when it appears in an XML attribute value? + static bool IsNormalizableWhitespace(char c) { + return c == 0x9 || c == 0xA || c == 0xD; + } + + // May c appear in a well-formed XML document? + static bool IsValidXmlCharacter(char c) { + return IsNormalizableWhitespace(c) || c >= 0x20; + } + + // Returns an XML-escaped copy of the input string str. If + // is_attribute is true, the text is meant to appear as an attribute + // value, and normalizable whitespace is preserved by replacing it + // with character references. + static std::string EscapeXml(const std::string& str, bool is_attribute); + + // Returns the given string with all characters invalid in XML removed. + static std::string RemoveInvalidXmlCharacters(const std::string& str); + + // Convenience wrapper around EscapeXml when str is an attribute value. + static std::string EscapeXmlAttribute(const std::string& str) { + return EscapeXml(str, true); + } + + // Convenience wrapper around EscapeXml when str is not an attribute value. + static std::string EscapeXmlText(const char* str) { + return EscapeXml(str, false); + } + + // Verifies that the given attribute belongs to the given element and + // streams the attribute as XML. + static void OutputXmlAttribute(std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value); + + // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. + static void OutputXmlCDataSection(::std::ostream* stream, const char* data); + + // Streams an XML representation of a TestInfo object. + static void OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info); + + // Prints an XML representation of a TestCase object + static void PrintXmlTestCase(::std::ostream* stream, + const TestCase& test_case); + + // Prints an XML summary of unit_test to output stream out. + static void PrintXmlUnitTest(::std::ostream* stream, + const UnitTest& unit_test); + + // Produces a string representing the test properties in a result as space + // delimited XML attributes based on the property key="value" pairs. + // When the std::string is not empty, it includes a space at the beginning, + // to delimit this attribute from prior attributes. + static std::string TestPropertiesAsXmlAttributes(const TestResult& result); + + // The output file. + const std::string output_file_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); +}; + +// Creates a new XmlUnitTestResultPrinter. +XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) + : output_file_(output_file) { + if (output_file_.c_str() == NULL || output_file_.empty()) { + fprintf(stderr, "XML output file may not be null\n"); + fflush(stderr); + exit(EXIT_FAILURE); + } +} + +// Called after the unit test ends. +void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, + int /*iteration*/) { + FILE* xmlout = NULL; + FilePath output_file(output_file_); + FilePath output_dir(output_file.RemoveFileName()); + + if (output_dir.CreateDirectoriesRecursively()) { + xmlout = posix::FOpen(output_file_.c_str(), "w"); + } + if (xmlout == NULL) { + // TODO(wan): report the reason of the failure. + // + // We don't do it for now as: + // + // 1. There is no urgent need for it. + // 2. It's a bit involved to make the errno variable thread-safe on + // all three operating systems (Linux, Windows, and Mac OS). + // 3. To interpret the meaning of errno in a thread-safe way, + // we need the strerror_r() function, which is not available on + // Windows. + fprintf(stderr, + "Unable to open file \"%s\"\n", + output_file_.c_str()); + fflush(stderr); + exit(EXIT_FAILURE); + } + std::stringstream stream; + PrintXmlUnitTest(&stream, unit_test); + fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); + fclose(xmlout); +} + +// Returns an XML-escaped copy of the input string str. If is_attribute +// is true, the text is meant to appear as an attribute value, and +// normalizable whitespace is preserved by replacing it with character +// references. +// +// Invalid XML characters in str, if any, are stripped from the output. +// It is expected that most, if not all, of the text processed by this +// module will consist of ordinary English text. +// If this module is ever modified to produce version 1.1 XML output, +// most invalid characters can be retained using character references. +// TODO(wan): It might be nice to have a minimally invasive, human-readable +// escaping scheme for invalid characters, rather than dropping them. +std::string XmlUnitTestResultPrinter::EscapeXml( + const std::string& str, bool is_attribute) { + Message m; + + for (size_t i = 0; i < str.size(); ++i) { + const char ch = str[i]; + switch (ch) { + case '<': + m << "<"; + break; + case '>': + m << ">"; + break; + case '&': + m << "&"; + break; + case '\'': + if (is_attribute) + m << "'"; + else + m << '\''; + break; + case '"': + if (is_attribute) + m << """; + else + m << '"'; + break; + default: + if (IsValidXmlCharacter(ch)) { + if (is_attribute && IsNormalizableWhitespace(ch)) + m << "&#x" << String::FormatByte(static_cast(ch)) + << ";"; + else + m << ch; + } + break; + } + } + + return m.GetString(); +} + +// Returns the given string with all characters invalid in XML removed. +// Currently invalid characters are dropped from the string. An +// alternative is to replace them with certain characters such as . or ?. +std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( + const std::string& str) { + std::string output; + output.reserve(str.size()); + for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) + if (IsValidXmlCharacter(*it)) + output.push_back(*it); + + return output; +} + +// The following routines generate an XML representation of a UnitTest +// object. +// +// This is how Google Test concepts map to the DTD: +// +// <-- corresponds to a UnitTest object +// <-- corresponds to a TestCase object +// <-- corresponds to a TestInfo object +// ... +// ... +// ... +// <-- individual assertion failures +// +// +// + +// Formats the given time in milliseconds as seconds. +std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { + ::std::stringstream ss; + ss << ms/1000.0; + return ss.str(); +} + +// Converts the given epoch time in milliseconds to a date string in the ISO +// 8601 format, without the timezone information. +std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { + // Using non-reentrant version as localtime_r is not portable. + time_t seconds = static_cast(ms / 1000); +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4996) // Temporarily disables warning 4996 + // (function or variable may be unsafe). + const struct tm* const time_struct = localtime(&seconds); // NOLINT +# pragma warning(pop) // Restores the warning state again. +#else + const struct tm* const time_struct = localtime(&seconds); // NOLINT +#endif + if (time_struct == NULL) + return ""; // Invalid ms value + + // YYYY-MM-DDThh:mm:ss + return StreamableToString(time_struct->tm_year + 1900) + "-" + + String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + + String::FormatIntWidth2(time_struct->tm_mday) + "T" + + String::FormatIntWidth2(time_struct->tm_hour) + ":" + + String::FormatIntWidth2(time_struct->tm_min) + ":" + + String::FormatIntWidth2(time_struct->tm_sec); +} + +// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. +void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, + const char* data) { + const char* segment = data; + *stream << ""); + if (next_segment != NULL) { + stream->write( + segment, static_cast(next_segment - segment)); + *stream << "]]>]]>"); + } else { + *stream << segment; + break; + } + } + *stream << "]]>"; +} + +void XmlUnitTestResultPrinter::OutputXmlAttribute( + std::ostream* stream, + const std::string& element_name, + const std::string& name, + const std::string& value) { + const std::vector& allowed_names = + GetReservedAttributesForElement(element_name); + + GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != + allowed_names.end()) + << "Attribute " << name << " is not allowed for element <" << element_name + << ">."; + + *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; +} + +// Prints an XML representation of a TestInfo object. +// TODO(wan): There is also value in printing properties with the plain printer. +void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, + const char* test_case_name, + const TestInfo& test_info) { + const TestResult& result = *test_info.result(); + const std::string kTestcase = "testcase"; + + *stream << " \n"; + } + const string location = internal::FormatCompilerIndependentFileLocation( + part.file_name(), part.line_number()); + const string summary = location + "\n" + part.summary(); + *stream << " "; + const string detail = location + "\n" + part.message(); + OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); + *stream << "\n"; + } + } + + if (failures == 0) + *stream << " />\n"; + else + *stream << " \n"; +} + +// Prints an XML representation of a TestCase object +void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, + const TestCase& test_case) { + const std::string kTestsuite = "testsuite"; + *stream << " <" << kTestsuite; + OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); + OutputXmlAttribute(stream, kTestsuite, "tests", + StreamableToString(test_case.reportable_test_count())); + OutputXmlAttribute(stream, kTestsuite, "failures", + StreamableToString(test_case.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuite, "disabled", + StreamableToString(test_case.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuite, "errors", "0"); + OutputXmlAttribute(stream, kTestsuite, "time", + FormatTimeInMillisAsSeconds(test_case.elapsed_time())); + *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) + << ">\n"; + + for (int i = 0; i < test_case.total_test_count(); ++i) { + if (test_case.GetTestInfo(i)->is_reportable()) + OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); + } + *stream << " \n"; +} + +// Prints an XML summary of unit_test to output stream out. +void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, + const UnitTest& unit_test) { + const std::string kTestsuites = "testsuites"; + + *stream << "\n"; + *stream << "<" << kTestsuites; + + OutputXmlAttribute(stream, kTestsuites, "tests", + StreamableToString(unit_test.reportable_test_count())); + OutputXmlAttribute(stream, kTestsuites, "failures", + StreamableToString(unit_test.failed_test_count())); + OutputXmlAttribute( + stream, kTestsuites, "disabled", + StreamableToString(unit_test.reportable_disabled_test_count())); + OutputXmlAttribute(stream, kTestsuites, "errors", "0"); + OutputXmlAttribute( + stream, kTestsuites, "timestamp", + FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); + OutputXmlAttribute(stream, kTestsuites, "time", + FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); + + if (GTEST_FLAG(shuffle)) { + OutputXmlAttribute(stream, kTestsuites, "random_seed", + StreamableToString(unit_test.random_seed())); + } + + *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); + + OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); + *stream << ">\n"; + + for (int i = 0; i < unit_test.total_test_case_count(); ++i) { + if (unit_test.GetTestCase(i)->reportable_test_count() > 0) + PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); + } + *stream << "\n"; +} + +// Produces a string representing the test properties in a result as space +// delimited XML attributes based on the property key="value" pairs. +std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( + const TestResult& result) { + Message attributes; + for (int i = 0; i < result.test_property_count(); ++i) { + const TestProperty& property = result.GetTestProperty(i); + attributes << " " << property.key() << "=" + << "\"" << EscapeXmlAttribute(property.value()) << "\""; + } + return attributes.GetString(); +} + +// End XmlUnitTestResultPrinter + +#if GTEST_CAN_STREAM_RESULTS_ + +// Checks if str contains '=', '&', '%' or '\n' characters. If yes, +// replaces them by "%xx" where xx is their hexadecimal value. For +// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) +// in both time and space -- important as the input str may contain an +// arbitrarily long test failure message and stack trace. +string StreamingListener::UrlEncode(const char* str) { + string result; + result.reserve(strlen(str) + 1); + for (char ch = *str; ch != '\0'; ch = *++str) { + switch (ch) { + case '%': + case '=': + case '&': + case '\n': + result.append("%" + String::FormatByte(static_cast(ch))); + break; + default: + result.push_back(ch); + break; + } + } + return result; +} + +void StreamingListener::SocketWriter::MakeConnection() { + GTEST_CHECK_(sockfd_ == -1) + << "MakeConnection() can't be called when there is already a connection."; + + addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. + hints.ai_socktype = SOCK_STREAM; + addrinfo* servinfo = NULL; + + // Use the getaddrinfo() to get a linked list of IP addresses for + // the given host name. + const int error_num = getaddrinfo( + host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); + if (error_num != 0) { + GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " + << gai_strerror(error_num); + } + + // Loop through all the results and connect to the first we can. + for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; + cur_addr = cur_addr->ai_next) { + sockfd_ = socket( + cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); + if (sockfd_ != -1) { + // Connect the client socket to the server socket. + if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { + close(sockfd_); + sockfd_ = -1; + } + } + } + + freeaddrinfo(servinfo); // all done with this structure + + if (sockfd_ == -1) { + GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " + << host_name_ << ":" << port_num_; + } +} + +// End of class Streaming Listener +#endif // GTEST_CAN_STREAM_RESULTS__ + +// Class ScopedTrace + +// Pushes the given source file location and message onto a per-thread +// trace stack maintained by Google Test. +ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + TraceInfo trace; + trace.file = file; + trace.line = line; + trace.message = message.GetString(); + + UnitTest::GetInstance()->PushGTestTrace(trace); +} + +// Pops the info pushed by the c'tor. +ScopedTrace::~ScopedTrace() + GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { + UnitTest::GetInstance()->PopGTestTrace(); +} + + +// class OsStackTraceGetter + +// Returns the current OS stack trace as an std::string. Parameters: +// +// max_depth - the maximum number of stack frames to be included +// in the trace. +// skip_count - the number of top frames to be skipped; doesn't count +// against max_depth. +// +string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, + int /* skip_count */) + GTEST_LOCK_EXCLUDED_(mutex_) { + return ""; +} + +void OsStackTraceGetter::UponLeavingGTest() + GTEST_LOCK_EXCLUDED_(mutex_) { +} + +const char* const +OsStackTraceGetter::kElidedFramesMarker = + "... " GTEST_NAME_ " internal frames ..."; + +// A helper class that creates the premature-exit file in its +// constructor and deletes the file in its destructor. +class ScopedPrematureExitFile { + public: + explicit ScopedPrematureExitFile(const char* premature_exit_filepath) + : premature_exit_filepath_(premature_exit_filepath) { + // If a path to the premature-exit file is specified... + if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { + // create the file with a single "0" character in it. I/O + // errors are ignored as there's nothing better we can do and we + // don't want to fail the test because of this. + FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); + fwrite("0", 1, 1, pfile); + fclose(pfile); + } + } + + ~ScopedPrematureExitFile() { + if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { + remove(premature_exit_filepath_); + } + } + + private: + const char* const premature_exit_filepath_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); +}; + +} // namespace internal + +// class TestEventListeners + +TestEventListeners::TestEventListeners() + : repeater_(new internal::TestEventRepeater()), + default_result_printer_(NULL), + default_xml_generator_(NULL) { +} + +TestEventListeners::~TestEventListeners() { delete repeater_; } + +// Returns the standard listener responsible for the default console +// output. Can be removed from the listeners list to shut down default +// console output. Note that removing this object from the listener list +// with Release transfers its ownership to the user. +void TestEventListeners::Append(TestEventListener* listener) { + repeater_->Append(listener); +} + +// Removes the given event listener from the list and returns it. It then +// becomes the caller's responsibility to delete the listener. Returns +// NULL if the listener is not found in the list. +TestEventListener* TestEventListeners::Release(TestEventListener* listener) { + if (listener == default_result_printer_) + default_result_printer_ = NULL; + else if (listener == default_xml_generator_) + default_xml_generator_ = NULL; + return repeater_->Release(listener); +} + +// Returns repeater that broadcasts the TestEventListener events to all +// subscribers. +TestEventListener* TestEventListeners::repeater() { return repeater_; } + +// Sets the default_result_printer attribute to the provided listener. +// The listener is also added to the listener list and previous +// default_result_printer is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { + if (default_result_printer_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_result_printer_); + default_result_printer_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Sets the default_xml_generator attribute to the provided listener. The +// listener is also added to the listener list and previous +// default_xml_generator is removed from it and deleted. The listener can +// also be NULL in which case it will not be added to the list. Does +// nothing if the previous and the current listener objects are the same. +void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { + if (default_xml_generator_ != listener) { + // It is an error to pass this method a listener that is already in the + // list. + delete Release(default_xml_generator_); + default_xml_generator_ = listener; + if (listener != NULL) + Append(listener); + } +} + +// Controls whether events will be forwarded by the repeater to the +// listeners in the list. +bool TestEventListeners::EventForwardingEnabled() const { + return repeater_->forwarding_enabled(); +} + +void TestEventListeners::SuppressEventForwarding() { + repeater_->set_forwarding_enabled(false); +} + +// class UnitTest + +// Gets the singleton UnitTest object. The first time this method is +// called, a UnitTest object is constructed and returned. Consecutive +// calls will return the same object. +// +// We don't protect this under mutex_ as a user is not supposed to +// call this before main() starts, from which point on the return +// value will never change. +UnitTest* UnitTest::GetInstance() { + // When compiled with MSVC 7.1 in optimized mode, destroying the + // UnitTest object upon exiting the program messes up the exit code, + // causing successful tests to appear failed. We have to use a + // different implementation in this case to bypass the compiler bug. + // This implementation makes the compiler happy, at the cost of + // leaking the UnitTest object. + + // CodeGear C++Builder insists on a public destructor for the + // default implementation. Use this implementation to keep good OO + // design with private destructor. + +#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) + static UnitTest* const instance = new UnitTest; + return instance; +#else + static UnitTest instance; + return &instance; +#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) +} + +// Gets the number of successful test cases. +int UnitTest::successful_test_case_count() const { + return impl()->successful_test_case_count(); +} + +// Gets the number of failed test cases. +int UnitTest::failed_test_case_count() const { + return impl()->failed_test_case_count(); +} + +// Gets the number of all test cases. +int UnitTest::total_test_case_count() const { + return impl()->total_test_case_count(); +} + +// Gets the number of all test cases that contain at least one test +// that should run. +int UnitTest::test_case_to_run_count() const { + return impl()->test_case_to_run_count(); +} + +// Gets the number of successful tests. +int UnitTest::successful_test_count() const { + return impl()->successful_test_count(); +} + +// Gets the number of failed tests. +int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } + +// Gets the number of disabled tests that will be reported in the XML report. +int UnitTest::reportable_disabled_test_count() const { + return impl()->reportable_disabled_test_count(); +} + +// Gets the number of disabled tests. +int UnitTest::disabled_test_count() const { + return impl()->disabled_test_count(); +} + +// Gets the number of tests to be printed in the XML report. +int UnitTest::reportable_test_count() const { + return impl()->reportable_test_count(); +} + +// Gets the number of all tests. +int UnitTest::total_test_count() const { return impl()->total_test_count(); } + +// Gets the number of tests that should run. +int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } + +// Gets the time of the test program start, in ms from the start of the +// UNIX epoch. +internal::TimeInMillis UnitTest::start_timestamp() const { + return impl()->start_timestamp(); +} + +// Gets the elapsed time, in milliseconds. +internal::TimeInMillis UnitTest::elapsed_time() const { + return impl()->elapsed_time(); +} + +// Returns true iff the unit test passed (i.e. all test cases passed). +bool UnitTest::Passed() const { return impl()->Passed(); } + +// Returns true iff the unit test failed (i.e. some test case failed +// or something outside of all tests failed). +bool UnitTest::Failed() const { return impl()->Failed(); } + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +const TestCase* UnitTest::GetTestCase(int i) const { + return impl()->GetTestCase(i); +} + +// Returns the TestResult containing information on test failures and +// properties logged outside of individual test cases. +const TestResult& UnitTest::ad_hoc_test_result() const { + return *impl()->ad_hoc_test_result(); +} + +// Gets the i-th test case among all the test cases. i can range from 0 to +// total_test_case_count() - 1. If i is not in that range, returns NULL. +TestCase* UnitTest::GetMutableTestCase(int i) { + return impl()->GetMutableTestCase(i); +} + +// Returns the list of event listeners that can be used to track events +// inside Google Test. +TestEventListeners& UnitTest::listeners() { + return *impl()->listeners(); +} + +// Registers and returns a global test environment. When a test +// program is run, all global test environments will be set-up in the +// order they were registered. After all tests in the program have +// finished, all global test environments will be torn-down in the +// *reverse* order they were registered. +// +// The UnitTest object takes ownership of the given environment. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +Environment* UnitTest::AddEnvironment(Environment* env) { + if (env == NULL) { + return NULL; + } + + impl_->environments().push_back(env); + return env; +} + +// Adds a TestPartResult to the current TestResult object. All Google Test +// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call +// this to report their results. The user code should use the +// assertion macros instead of calling this directly. +void UnitTest::AddTestPartResult( + TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { + Message msg; + msg << message; + + internal::MutexLock lock(&mutex_); + if (impl_->gtest_trace_stack().size() > 0) { + msg << "\n" << GTEST_NAME_ << " trace:"; + + for (int i = static_cast(impl_->gtest_trace_stack().size()); + i > 0; --i) { + const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; + msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) + << " " << trace.message; + } + } + + if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { + msg << internal::kStackTraceMarker << os_stack_trace; + } + + const TestPartResult result = + TestPartResult(result_type, file_name, line_number, + msg.GetString().c_str()); + impl_->GetTestPartResultReporterForCurrentThread()-> + ReportTestPartResult(result); + + if (result_type != TestPartResult::kSuccess) { + // gtest_break_on_failure takes precedence over + // gtest_throw_on_failure. This allows a user to set the latter + // in the code (perhaps in order to use Google Test assertions + // with another testing framework) and specify the former on the + // command line for debugging. + if (GTEST_FLAG(break_on_failure)) { +#if GTEST_OS_WINDOWS + // Using DebugBreak on Windows allows gtest to still break into a debugger + // when a failure happens and both the --gtest_break_on_failure and + // the --gtest_catch_exceptions flags are specified. + DebugBreak(); +#else + // Dereference NULL through a volatile pointer to prevent the compiler + // from removing. We use this rather than abort() or __builtin_trap() for + // portability: Symbian doesn't implement abort() well, and some debuggers + // don't correctly trap abort(). + *static_cast(NULL) = 1; +#endif // GTEST_OS_WINDOWS + } else if (GTEST_FLAG(throw_on_failure)) { +#if GTEST_HAS_EXCEPTIONS + throw internal::GoogleTestFailureException(result); +#else + // We cannot call abort() as it generates a pop-up in debug mode + // that cannot be suppressed in VC 7.1 or below. + exit(1); +#endif + } + } +} + +// Adds a TestProperty to the current TestResult object when invoked from +// inside a test, to current TestCase's ad_hoc_test_result_ when invoked +// from SetUpTestCase or TearDownTestCase, or to the global property set +// when invoked elsewhere. If the result already contains a property with +// the same key, the value will be updated. +void UnitTest::RecordProperty(const std::string& key, + const std::string& value) { + impl_->RecordProperty(TestProperty(key, value)); +} + +// Runs all tests in this UnitTest object and prints the result. +// Returns 0 if successful, or 1 otherwise. +// +// We don't protect this under mutex_, as we only support calling it +// from the main thread. +int UnitTest::Run() { + const bool in_death_test_child_process = + internal::GTEST_FLAG(internal_run_death_test).length() > 0; + + // Google Test implements this protocol for catching that a test + // program exits before returning control to Google Test: + // + // 1. Upon start, Google Test creates a file whose absolute path + // is specified by the environment variable + // TEST_PREMATURE_EXIT_FILE. + // 2. When Google Test has finished its work, it deletes the file. + // + // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before + // running a Google-Test-based test program and check the existence + // of the file at the end of the test execution to see if it has + // exited prematurely. + + // If we are in the child process of a death test, don't + // create/delete the premature exit file, as doing so is unnecessary + // and will confuse the parent process. Otherwise, create/delete + // the file upon entering/leaving this function. If the program + // somehow exits before this function has a chance to return, the + // premature-exit file will be left undeleted, causing a test runner + // that understands the premature-exit-file protocol to report the + // test as having failed. + const internal::ScopedPrematureExitFile premature_exit_file( + in_death_test_child_process ? + NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); + + // Captures the value of GTEST_FLAG(catch_exceptions). This value will be + // used for the duration of the program. + impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); + +#if GTEST_HAS_SEH + // Either the user wants Google Test to catch exceptions thrown by the + // tests or this is executing in the context of death test child + // process. In either case the user does not want to see pop-up dialogs + // about crashes - they are expected. + if (impl()->catch_exceptions() || in_death_test_child_process) { +# if !GTEST_OS_WINDOWS_MOBILE + // SetErrorMode doesn't exist on CE. + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | + SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); +# endif // !GTEST_OS_WINDOWS_MOBILE + +# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE + // Death test children can be terminated with _abort(). On Windows, + // _abort() can show a dialog with a warning message. This forces the + // abort message to go to stderr instead. + _set_error_mode(_OUT_TO_STDERR); +# endif + +# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE + // In the debug version, Visual Studio pops up a separate dialog + // offering a choice to debug the aborted program. We need to suppress + // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement + // executed. Google Test will notify the user of any unexpected + // failure via stderr. + // + // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. + // Users of prior VC versions shall suffer the agony and pain of + // clicking through the countless debug dialogs. + // TODO(vladl@google.com): find a way to suppress the abort dialog() in the + // debug mode when compiled with VC 7.1 or lower. + if (!GTEST_FLAG(break_on_failure)) + _set_abort_behavior( + 0x0, // Clear the following flags: + _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. +# endif + } +#endif // GTEST_HAS_SEH + + return internal::HandleExceptionsInMethodIfSupported( + impl(), + &internal::UnitTestImpl::RunAllTests, + "auxiliary test code (environments or event listeners)") ? 0 : 1; +} + +// Returns the working directory when the first TEST() or TEST_F() was +// executed. +const char* UnitTest::original_working_dir() const { + return impl_->original_working_dir_.c_str(); +} + +// Returns the TestCase object for the test that's currently running, +// or NULL if no test is running. +const TestCase* UnitTest::current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_case(); +} + +// Returns the TestInfo object for the test that's currently running, +// or NULL if no test is running. +const TestInfo* UnitTest::current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + return impl_->current_test_info(); +} + +// Returns the random seed used at the start of the current test run. +int UnitTest::random_seed() const { return impl_->random_seed(); } + +#if GTEST_HAS_PARAM_TEST +// Returns ParameterizedTestCaseRegistry object used to keep track of +// value-parameterized tests and instantiate and register them. +internal::ParameterizedTestCaseRegistry& + UnitTest::parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_) { + return impl_->parameterized_test_registry(); +} +#endif // GTEST_HAS_PARAM_TEST + +// Creates an empty UnitTest. +UnitTest::UnitTest() { + impl_ = new internal::UnitTestImpl(this); +} + +// Destructor of UnitTest. +UnitTest::~UnitTest() { + delete impl_; +} + +// Pushes a trace defined by SCOPED_TRACE() on to the per-thread +// Google Test trace stack. +void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().push_back(trace); +} + +// Pops a trace from the per-thread Google Test trace stack. +void UnitTest::PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_) { + internal::MutexLock lock(&mutex_); + impl_->gtest_trace_stack().pop_back(); +} + +namespace internal { + +UnitTestImpl::UnitTestImpl(UnitTest* parent) + : parent_(parent), +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4355) // Temporarily disables warning 4355 + // (using this in initializer). + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +# pragma warning(pop) // Restores the warning state again. +#else + default_global_test_part_result_reporter_(this), + default_per_thread_test_part_result_reporter_(this), +#endif // _MSC_VER + global_test_part_result_repoter_( + &default_global_test_part_result_reporter_), + per_thread_test_part_result_reporter_( + &default_per_thread_test_part_result_reporter_), +#if GTEST_HAS_PARAM_TEST + parameterized_test_registry_(), + parameterized_tests_registered_(false), +#endif // GTEST_HAS_PARAM_TEST + last_death_test_case_(-1), + current_test_case_(NULL), + current_test_info_(NULL), + ad_hoc_test_result_(), + os_stack_trace_getter_(NULL), + post_flag_parse_init_performed_(false), + random_seed_(0), // Will be overridden by the flag before first use. + random_(0), // Will be reseeded before first use. + start_timestamp_(0), + elapsed_time_(0), +#if GTEST_HAS_DEATH_TEST + death_test_factory_(new DefaultDeathTestFactory), +#endif + // Will be overridden by the flag before first use. + catch_exceptions_(false) { + listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); +} + +UnitTestImpl::~UnitTestImpl() { + // Deletes every TestCase. + ForEach(test_cases_, internal::Delete); + + // Deletes every Environment. + ForEach(environments_, internal::Delete); + + delete os_stack_trace_getter_; +} + +// Adds a TestProperty to the current TestResult object when invoked in a +// context of a test, to current test case's ad_hoc_test_result when invoke +// from SetUpTestCase/TearDownTestCase, or to the global property set +// otherwise. If the result already contains a property with the same key, +// the value will be updated. +void UnitTestImpl::RecordProperty(const TestProperty& test_property) { + std::string xml_element; + TestResult* test_result; // TestResult appropriate for property recording. + + if (current_test_info_ != NULL) { + xml_element = "testcase"; + test_result = &(current_test_info_->result_); + } else if (current_test_case_ != NULL) { + xml_element = "testsuite"; + test_result = &(current_test_case_->ad_hoc_test_result_); + } else { + xml_element = "testsuites"; + test_result = &ad_hoc_test_result_; + } + test_result->RecordProperty(xml_element, test_property); +} + +#if GTEST_HAS_DEATH_TEST +// Disables event forwarding if the control is currently in a death test +// subprocess. Must not be called before InitGoogleTest. +void UnitTestImpl::SuppressTestEventsIfInSubprocess() { + if (internal_run_death_test_flag_.get() != NULL) + listeners()->SuppressEventForwarding(); +} +#endif // GTEST_HAS_DEATH_TEST + +// Initializes event listeners performing XML output as specified by +// UnitTestOptions. Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureXmlOutput() { + const std::string& output_format = UnitTestOptions::GetOutputFormat(); + if (output_format == "xml") { + listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( + UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); + } else if (output_format != "") { + printf("WARNING: unrecognized output format \"%s\" ignored.\n", + output_format.c_str()); + fflush(stdout); + } +} + +#if GTEST_CAN_STREAM_RESULTS_ +// Initializes event listeners for streaming test results in string form. +// Must not be called before InitGoogleTest. +void UnitTestImpl::ConfigureStreamingOutput() { + const std::string& target = GTEST_FLAG(stream_result_to); + if (!target.empty()) { + const size_t pos = target.find(':'); + if (pos != std::string::npos) { + listeners()->Append(new StreamingListener(target.substr(0, pos), + target.substr(pos+1))); + } else { + printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", + target.c_str()); + fflush(stdout); + } + } +} +#endif // GTEST_CAN_STREAM_RESULTS_ + +// Performs initialization dependent upon flag values obtained in +// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to +// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest +// this function is also called from RunAllTests. Since this function can be +// called more than once, it has to be idempotent. +void UnitTestImpl::PostFlagParsingInit() { + // Ensures that this function does not execute more than once. + if (!post_flag_parse_init_performed_) { + post_flag_parse_init_performed_ = true; + +#if GTEST_HAS_DEATH_TEST + InitDeathTestSubprocessControlInfo(); + SuppressTestEventsIfInSubprocess(); +#endif // GTEST_HAS_DEATH_TEST + + // Registers parameterized tests. This makes parameterized tests + // available to the UnitTest reflection API without running + // RUN_ALL_TESTS. + RegisterParameterizedTests(); + + // Configures listeners for XML output. This makes it possible for users + // to shut down the default XML output before invoking RUN_ALL_TESTS. + ConfigureXmlOutput(); + +#if GTEST_CAN_STREAM_RESULTS_ + // Configures listeners for streaming test results to the specified server. + ConfigureStreamingOutput(); +#endif // GTEST_CAN_STREAM_RESULTS_ + } +} + +// A predicate that checks the name of a TestCase against a known +// value. +// +// This is used for implementation of the UnitTest class only. We put +// it in the anonymous namespace to prevent polluting the outer +// namespace. +// +// TestCaseNameIs is copyable. +class TestCaseNameIs { + public: + // Constructor. + explicit TestCaseNameIs(const std::string& name) + : name_(name) {} + + // Returns true iff the name of test_case matches name_. + bool operator()(const TestCase* test_case) const { + return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; + } + + private: + std::string name_; +}; + +// Finds and returns a TestCase with the given name. If one doesn't +// exist, creates one and returns it. It's the CALLER'S +// RESPONSIBILITY to ensure that this function is only called WHEN THE +// TESTS ARE NOT SHUFFLED. +// +// Arguments: +// +// test_case_name: name of the test case +// type_param: the name of the test case's type parameter, or NULL if +// this is not a typed or a type-parameterized test case. +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, + const char* type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc) { + // Can we find a TestCase with the given name? + const std::vector::const_iterator test_case = + std::find_if(test_cases_.begin(), test_cases_.end(), + TestCaseNameIs(test_case_name)); + + if (test_case != test_cases_.end()) + return *test_case; + + // No. Let's create one. + TestCase* const new_test_case = + new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); + + // Is this a death test case? + if (internal::UnitTestOptions::MatchesFilter(test_case_name, + kDeathTestCaseFilter)) { + // Yes. Inserts the test case after the last death test case + // defined so far. This only works when the test cases haven't + // been shuffled. Otherwise we may end up running a death test + // after a non-death test. + ++last_death_test_case_; + test_cases_.insert(test_cases_.begin() + last_death_test_case_, + new_test_case); + } else { + // No. Appends to the end of the list. + test_cases_.push_back(new_test_case); + } + + test_case_indices_.push_back(static_cast(test_case_indices_.size())); + return new_test_case; +} + +// Helpers for setting up / tearing down the given environment. They +// are for use in the ForEach() function. +static void SetUpEnvironment(Environment* env) { env->SetUp(); } +static void TearDownEnvironment(Environment* env) { env->TearDown(); } + +// Runs all tests in this UnitTest object, prints the result, and +// returns true if all tests are successful. If any exception is +// thrown during a test, the test is considered to be failed, but the +// rest of the tests will still be run. +// +// When parameterized tests are enabled, it expands and registers +// parameterized tests first in RegisterParameterizedTests(). +// All other functions called from RunAllTests() may safely assume that +// parameterized tests are ready to be counted and run. +bool UnitTestImpl::RunAllTests() { + // Makes sure InitGoogleTest() was called. + if (!GTestIsInitialized()) { + printf("%s", + "\nThis test program did NOT call ::testing::InitGoogleTest " + "before calling RUN_ALL_TESTS(). Please fix it.\n"); + return false; + } + + // Do not run any test if the --help flag was specified. + if (g_help_flag) + return true; + + // Repeats the call to the post-flag parsing initialization in case the + // user didn't call InitGoogleTest. + PostFlagParsingInit(); + + // Even if sharding is not on, test runners may want to use the + // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding + // protocol. + internal::WriteToShardStatusFileIfNeeded(); + + // True iff we are in a subprocess for running a thread-safe-style + // death test. + bool in_subprocess_for_death_test = false; + +#if GTEST_HAS_DEATH_TEST + in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); +#endif // GTEST_HAS_DEATH_TEST + + const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, + in_subprocess_for_death_test); + + // Compares the full test names with the filter to decide which + // tests to run. + const bool has_tests_to_run = FilterTests(should_shard + ? HONOR_SHARDING_PROTOCOL + : IGNORE_SHARDING_PROTOCOL) > 0; + + // Lists the tests and exits if the --gtest_list_tests flag was specified. + if (GTEST_FLAG(list_tests)) { + // This must be called *after* FilterTests() has been called. + ListTestsMatchingFilter(); + return true; + } + + random_seed_ = GTEST_FLAG(shuffle) ? + GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; + + // True iff at least one test has failed. + bool failed = false; + + TestEventListener* repeater = listeners()->repeater(); + + start_timestamp_ = GetTimeInMillis(); + repeater->OnTestProgramStart(*parent_); + + // How many times to repeat the tests? We don't want to repeat them + // when we are inside the subprocess of a death test. + const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); + // Repeats forever if the repeat count is negative. + const bool forever = repeat < 0; + for (int i = 0; forever || i != repeat; i++) { + // We want to preserve failures generated by ad-hoc test + // assertions executed before RUN_ALL_TESTS(). + ClearNonAdHocTestResult(); + + const TimeInMillis start = GetTimeInMillis(); + + // Shuffles test cases and tests if requested. + if (has_tests_to_run && GTEST_FLAG(shuffle)) { + random()->Reseed(random_seed_); + // This should be done before calling OnTestIterationStart(), + // such that a test event listener can see the actual test order + // in the event. + ShuffleTests(); + } + + // Tells the unit test event listeners that the tests are about to start. + repeater->OnTestIterationStart(*parent_, i); + + // Runs each test case if there is at least one test to run. + if (has_tests_to_run) { + // Sets up all environments beforehand. + repeater->OnEnvironmentsSetUpStart(*parent_); + ForEach(environments_, SetUpEnvironment); + repeater->OnEnvironmentsSetUpEnd(*parent_); + + // Runs the tests only if there was no fatal failure during global + // set-up. + if (!Test::HasFatalFailure()) { + for (int test_index = 0; test_index < total_test_case_count(); + test_index++) { + GetMutableTestCase(test_index)->Run(); + } + } + + // Tears down all environments in reverse order afterwards. + repeater->OnEnvironmentsTearDownStart(*parent_); + std::for_each(environments_.rbegin(), environments_.rend(), + TearDownEnvironment); + repeater->OnEnvironmentsTearDownEnd(*parent_); + } + + elapsed_time_ = GetTimeInMillis() - start; + + // Tells the unit test event listener that the tests have just finished. + repeater->OnTestIterationEnd(*parent_, i); + + // Gets the result and clears it. + if (!Passed()) { + failed = true; + } + + // Restores the original test order after the iteration. This + // allows the user to quickly repro a failure that happens in the + // N-th iteration without repeating the first (N - 1) iterations. + // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in + // case the user somehow changes the value of the flag somewhere + // (it's always safe to unshuffle the tests). + UnshuffleTests(); + + if (GTEST_FLAG(shuffle)) { + // Picks a new random seed for each iteration. + random_seed_ = GetNextRandomSeed(random_seed_); + } + } + + repeater->OnTestProgramEnd(*parent_); + + return !failed; +} + +// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file +// if the variable is present. If a file already exists at this location, this +// function will write over it. If the variable is present, but the file cannot +// be created, prints an error and exits. +void WriteToShardStatusFileIfNeeded() { + const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); + if (test_shard_file != NULL) { + FILE* const file = posix::FOpen(test_shard_file, "w"); + if (file == NULL) { + ColoredPrintf(COLOR_RED, + "Could not write to the test shard status file \"%s\" " + "specified by the %s environment variable.\n", + test_shard_file, kTestShardStatusFile); + fflush(stdout); + exit(EXIT_FAILURE); + } + fclose(file); + } +} + +// Checks whether sharding is enabled by examining the relevant +// environment variable values. If the variables are present, +// but inconsistent (i.e., shard_index >= total_shards), prints +// an error and exits. If in_subprocess_for_death_test, sharding is +// disabled because it must only be applied to the original test +// process. Otherwise, we could filter out death tests we intended to execute. +bool ShouldShard(const char* total_shards_env, + const char* shard_index_env, + bool in_subprocess_for_death_test) { + if (in_subprocess_for_death_test) { + return false; + } + + const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); + const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); + + if (total_shards == -1 && shard_index == -1) { + return false; + } else if (total_shards == -1 && shard_index != -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestShardIndex << " = " << shard_index + << ", but have left " << kTestTotalShards << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (total_shards != -1 && shard_index == -1) { + const Message msg = Message() + << "Invalid environment variables: you have " + << kTestTotalShards << " = " << total_shards + << ", but have left " << kTestShardIndex << " unset.\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } else if (shard_index < 0 || shard_index >= total_shards) { + const Message msg = Message() + << "Invalid environment variables: we require 0 <= " + << kTestShardIndex << " < " << kTestTotalShards + << ", but you have " << kTestShardIndex << "=" << shard_index + << ", " << kTestTotalShards << "=" << total_shards << ".\n"; + ColoredPrintf(COLOR_RED, msg.GetString().c_str()); + fflush(stdout); + exit(EXIT_FAILURE); + } + + return total_shards > 1; +} + +// Parses the environment variable var as an Int32. If it is unset, +// returns default_val. If it is not an Int32, prints an error +// and aborts. +Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { + const char* str_val = posix::GetEnv(var); + if (str_val == NULL) { + return default_val; + } + + Int32 result; + if (!ParseInt32(Message() << "The value of environment variable " << var, + str_val, &result)) { + exit(EXIT_FAILURE); + } + return result; +} + +// Given the total number of shards, the shard index, and the test id, +// returns true iff the test should be run on this shard. The test id is +// some arbitrary but unique non-negative integer assigned to each test +// method. Assumes that 0 <= shard_index < total_shards. +bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { + return (test_id % total_shards) == shard_index; +} + +// Compares the name of each test with the user-specified filter to +// decide whether the test should be run, then records the result in +// each TestCase and TestInfo object. +// If shard_tests == true, further filters tests based on sharding +// variables in the environment - see +// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. +// Returns the number of tests that should run. +int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { + const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestTotalShards, -1) : -1; + const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? + Int32FromEnvOrDie(kTestShardIndex, -1) : -1; + + // num_runnable_tests are the number of tests that will + // run across all shards (i.e., match filter and are not disabled). + // num_selected_tests are the number of tests to be run on + // this shard. + int num_runnable_tests = 0; + int num_selected_tests = 0; + for (size_t i = 0; i < test_cases_.size(); i++) { + TestCase* const test_case = test_cases_[i]; + const std::string &test_case_name = test_case->name(); + test_case->set_should_run(false); + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + TestInfo* const test_info = test_case->test_info_list()[j]; + const std::string test_name(test_info->name()); + // A test is disabled if test case name or test name matches + // kDisableTestFilter. + const bool is_disabled = + internal::UnitTestOptions::MatchesFilter(test_case_name, + kDisableTestFilter) || + internal::UnitTestOptions::MatchesFilter(test_name, + kDisableTestFilter); + test_info->is_disabled_ = is_disabled; + + const bool matches_filter = + internal::UnitTestOptions::FilterMatchesTest(test_case_name, + test_name); + test_info->matches_filter_ = matches_filter; + + const bool is_runnable = + (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && + matches_filter; + + const bool is_selected = is_runnable && + (shard_tests == IGNORE_SHARDING_PROTOCOL || + ShouldRunTestOnShard(total_shards, shard_index, + num_runnable_tests)); + + num_runnable_tests += is_runnable; + num_selected_tests += is_selected; + + test_info->should_run_ = is_selected; + test_case->set_should_run(test_case->should_run() || is_selected); + } + } + return num_selected_tests; +} + +// Prints the given C-string on a single line by replacing all '\n' +// characters with string "\\n". If the output takes more than +// max_length characters, only prints the first max_length characters +// and "...". +static void PrintOnOneLine(const char* str, int max_length) { + if (str != NULL) { + for (int i = 0; *str != '\0'; ++str) { + if (i >= max_length) { + printf("..."); + break; + } + if (*str == '\n') { + printf("\\n"); + i += 2; + } else { + printf("%c", *str); + ++i; + } + } + } +} + +// Prints the names of the tests matching the user-specified filter flag. +void UnitTestImpl::ListTestsMatchingFilter() { + // Print at most this many characters for each type/value parameter. + const int kMaxParamLength = 250; + + for (size_t i = 0; i < test_cases_.size(); i++) { + const TestCase* const test_case = test_cases_[i]; + bool printed_test_case_name = false; + + for (size_t j = 0; j < test_case->test_info_list().size(); j++) { + const TestInfo* const test_info = + test_case->test_info_list()[j]; + if (test_info->matches_filter_) { + if (!printed_test_case_name) { + printed_test_case_name = true; + printf("%s.", test_case->name()); + if (test_case->type_param() != NULL) { + printf(" # %s = ", kTypeParamLabel); + // We print the type parameter on a single line to make + // the output easy to parse by a program. + PrintOnOneLine(test_case->type_param(), kMaxParamLength); + } + printf("\n"); + } + printf(" %s", test_info->name()); + if (test_info->value_param() != NULL) { + printf(" # %s = ", kValueParamLabel); + // We print the value parameter on a single line to make the + // output easy to parse by a program. + PrintOnOneLine(test_info->value_param(), kMaxParamLength); + } + printf("\n"); + } + } + } + fflush(stdout); +} + +// Sets the OS stack trace getter. +// +// Does nothing if the input and the current OS stack trace getter are +// the same; otherwise, deletes the old getter and makes the input the +// current getter. +void UnitTestImpl::set_os_stack_trace_getter( + OsStackTraceGetterInterface* getter) { + if (os_stack_trace_getter_ != getter) { + delete os_stack_trace_getter_; + os_stack_trace_getter_ = getter; + } +} + +// Returns the current OS stack trace getter if it is not NULL; +// otherwise, creates an OsStackTraceGetter, makes it the current +// getter, and returns it. +OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { + if (os_stack_trace_getter_ == NULL) { + os_stack_trace_getter_ = new OsStackTraceGetter; + } + + return os_stack_trace_getter_; +} + +// Returns the TestResult for the test that's currently running, or +// the TestResult for the ad hoc test if no test is running. +TestResult* UnitTestImpl::current_test_result() { + return current_test_info_ ? + &(current_test_info_->result_) : &ad_hoc_test_result_; +} + +// Shuffles all test cases, and the tests within each test case, +// making sure that death tests are still run first. +void UnitTestImpl::ShuffleTests() { + // Shuffles the death test cases. + ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); + + // Shuffles the non-death test cases. + ShuffleRange(random(), last_death_test_case_ + 1, + static_cast(test_cases_.size()), &test_case_indices_); + + // Shuffles the tests inside each test case. + for (size_t i = 0; i < test_cases_.size(); i++) { + test_cases_[i]->ShuffleTests(random()); + } +} + +// Restores the test cases and tests to their order before the first shuffle. +void UnitTestImpl::UnshuffleTests() { + for (size_t i = 0; i < test_cases_.size(); i++) { + // Unshuffles the tests in each test case. + test_cases_[i]->UnshuffleTests(); + // Resets the index of each test case. + test_case_indices_[i] = static_cast(i); + } +} + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, + int skip_count) { + // We pass skip_count + 1 to skip this wrapper function in addition + // to what the user really wants to skip. + return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); +} + +// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to +// suppress unreachable code warnings. +namespace { +class ClassUniqueToAlwaysTrue {}; +} + +bool IsTrue(bool condition) { return condition; } + +bool AlwaysTrue() { +#if GTEST_HAS_EXCEPTIONS + // This condition is always false so AlwaysTrue() never actually throws, + // but it makes the compiler think that it may throw. + if (IsTrue(false)) + throw ClassUniqueToAlwaysTrue(); +#endif // GTEST_HAS_EXCEPTIONS + return true; +} + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +bool SkipPrefix(const char* prefix, const char** pstr) { + const size_t prefix_len = strlen(prefix); + if (strncmp(*pstr, prefix, prefix_len) == 0) { + *pstr += prefix_len; + return true; + } + return false; +} + +// Parses a string as a command line flag. The string should have +// the format "--flag=value". When def_optional is true, the "=value" +// part can be omitted. +// +// Returns the value of the flag, or NULL if the parsing failed. +const char* ParseFlagValue(const char* str, + const char* flag, + bool def_optional) { + // str and flag must not be NULL. + if (str == NULL || flag == NULL) return NULL; + + // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. + const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; + const size_t flag_len = flag_str.length(); + if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; + + // Skips the flag name. + const char* flag_end = str + flag_len; + + // When def_optional is true, it's OK to not have a "=value" part. + if (def_optional && (flag_end[0] == '\0')) { + return flag_end; + } + + // If def_optional is true and there are more characters after the + // flag name, or if def_optional is false, there must be a '=' after + // the flag name. + if (flag_end[0] != '=') return NULL; + + // Returns the string after "=". + return flag_end + 1; +} + +// Parses a string for a bool flag, in the form of either +// "--flag=value" or "--flag". +// +// In the former case, the value is taken as true as long as it does +// not start with '0', 'f', or 'F'. +// +// In the latter case, the value is taken as true. +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseBoolFlag(const char* str, const char* flag, bool* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, true); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Converts the string value to a bool. + *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); + return true; +} + +// Parses a string for an Int32 flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + return ParseInt32(Message() << "The value of flag --" << flag, + value_str, value); +} + +// Parses a string for a string flag, in the form of +// "--flag=value". +// +// On success, stores the value of the flag in *value, and returns +// true. On failure, returns false without changing *value. +bool ParseStringFlag(const char* str, const char* flag, std::string* value) { + // Gets the value of the flag as a string. + const char* const value_str = ParseFlagValue(str, flag, false); + + // Aborts if the parsing failed. + if (value_str == NULL) return false; + + // Sets *value to the value of the flag. + *value = value_str; + return true; +} + +// Determines whether a string has a prefix that Google Test uses for its +// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. +// If Google Test detects that a command line flag has its prefix but is not +// recognized, it will print its help message. Flags starting with +// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test +// internal flags and do not trigger the help message. +static bool HasGoogleTestFlagPrefix(const char* str) { + return (SkipPrefix("--", &str) || + SkipPrefix("-", &str) || + SkipPrefix("/", &str)) && + !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && + (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || + SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); +} + +// Prints a string containing code-encoded text. The following escape +// sequences can be used in the string to control the text color: +// +// @@ prints a single '@' character. +// @R changes the color to red. +// @G changes the color to green. +// @Y changes the color to yellow. +// @D changes to the default terminal text color. +// +// TODO(wan@google.com): Write tests for this once we add stdout +// capturing to Google Test. +static void PrintColorEncoded(const char* str) { + GTestColor color = COLOR_DEFAULT; // The current color. + + // Conceptually, we split the string into segments divided by escape + // sequences. Then we print one segment at a time. At the end of + // each iteration, the str pointer advances to the beginning of the + // next segment. + for (;;) { + const char* p = strchr(str, '@'); + if (p == NULL) { + ColoredPrintf(color, "%s", str); + return; + } + + ColoredPrintf(color, "%s", std::string(str, p).c_str()); + + const char ch = p[1]; + str = p + 2; + if (ch == '@') { + ColoredPrintf(color, "@"); + } else if (ch == 'D') { + color = COLOR_DEFAULT; + } else if (ch == 'R') { + color = COLOR_RED; + } else if (ch == 'G') { + color = COLOR_GREEN; + } else if (ch == 'Y') { + color = COLOR_YELLOW; + } else { + --str; + } + } +} + +static const char kColorEncodedHelpMessage[] = +"This program contains tests written using " GTEST_NAME_ ". You can use the\n" +"following command line flags to control its behavior:\n" +"\n" +"Test Selection:\n" +" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" +" List the names of all tests instead of running them. The name of\n" +" TEST(Foo, Bar) is \"Foo.Bar\".\n" +" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" + "[@G-@YNEGATIVE_PATTERNS]@D\n" +" Run only the tests whose name matches one of the positive patterns but\n" +" none of the negative patterns. '?' matches any single character; '*'\n" +" matches any substring; ':' separates two patterns.\n" +" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" +" Run all disabled tests too.\n" +"\n" +"Test Execution:\n" +" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" +" Run the tests repeatedly; use a negative count to repeat forever.\n" +" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" +" Randomize tests' orders on every iteration.\n" +" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" +" Random number seed to use for shuffling test orders (between 1 and\n" +" 99999, or 0 to use a seed based on the current time).\n" +"\n" +"Test Output:\n" +" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" +" Enable/disable colored output. The default is @Gauto@D.\n" +" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" +" Don't print the elapsed time of each test.\n" +" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" + GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" +" Generate an XML report in the given directory or with the given file\n" +" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" +#if GTEST_CAN_STREAM_RESULTS_ +" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" +" Stream test results to the given server.\n" +#endif // GTEST_CAN_STREAM_RESULTS_ +"\n" +"Assertion Behavior:\n" +#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" +" Set the default death test style.\n" +#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS +" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" +" Turn assertion failures into debugger break-points.\n" +" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" +" Turn assertion failures into C++ exceptions.\n" +" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" +" Do not report exceptions as test failures. Instead, allow them\n" +" to crash the program or throw a pop-up (on Windows).\n" +"\n" +"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " + "the corresponding\n" +"environment variable of a flag (all letters in upper-case). For example, to\n" +"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ + "color=no@D or set\n" +"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" +"\n" +"For more information, please read the " GTEST_NAME_ " documentation at\n" +"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" +"(not one in your own code or tests), please report it to\n" +"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. The type parameter CharType can be +// instantiated to either char or wchar_t. +template +void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { + for (int i = 1; i < *argc; i++) { + const std::string arg_string = StreamableToString(argv[i]); + const char* const arg = arg_string.c_str(); + + using internal::ParseBoolFlag; + using internal::ParseInt32Flag; + using internal::ParseStringFlag; + + // Do we see a Google Test flag? + if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, + >EST_FLAG(also_run_disabled_tests)) || + ParseBoolFlag(arg, kBreakOnFailureFlag, + >EST_FLAG(break_on_failure)) || + ParseBoolFlag(arg, kCatchExceptionsFlag, + >EST_FLAG(catch_exceptions)) || + ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || + ParseStringFlag(arg, kDeathTestStyleFlag, + >EST_FLAG(death_test_style)) || + ParseBoolFlag(arg, kDeathTestUseFork, + >EST_FLAG(death_test_use_fork)) || + ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || + ParseStringFlag(arg, kInternalRunDeathTestFlag, + >EST_FLAG(internal_run_death_test)) || + ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || + ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || + ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || + ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || + ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || + ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || + ParseInt32Flag(arg, kStackTraceDepthFlag, + >EST_FLAG(stack_trace_depth)) || + ParseStringFlag(arg, kStreamResultToFlag, + >EST_FLAG(stream_result_to)) || + ParseBoolFlag(arg, kThrowOnFailureFlag, + >EST_FLAG(throw_on_failure)) + ) { + // Yes. Shift the remainder of the argv list left by one. Note + // that argv has (*argc + 1) elements, the last one always being + // NULL. The following loop moves the trailing NULL element as + // well. + for (int j = i; j != *argc; j++) { + argv[j] = argv[j + 1]; + } + + // Decrements the argument count. + (*argc)--; + + // We also need to decrement the iterator as we just removed + // an element. + i--; + } else if (arg_string == "--help" || arg_string == "-h" || + arg_string == "-?" || arg_string == "/?" || + HasGoogleTestFlagPrefix(arg)) { + // Both help flag and unrecognized Google Test flags (excluding + // internal ones) trigger help display. + g_help_flag = true; + } + } + + if (g_help_flag) { + // We print the help here instead of in RUN_ALL_TESTS(), as the + // latter may not be called at all if the user is using Google + // Test with another testing framework. + PrintColorEncoded(kColorEncodedHelpMessage); + } +} + +// Parses the command line for Google Test flags, without initializing +// other parts of Google Test. +void ParseGoogleTestFlagsOnly(int* argc, char** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} +void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { + ParseGoogleTestFlagsOnlyImpl(argc, argv); +} + +// The internal implementation of InitGoogleTest(). +// +// The type parameter CharType can be instantiated to either char or +// wchar_t. +template +void InitGoogleTestImpl(int* argc, CharType** argv) { + g_init_gtest_count++; + + // We don't want to run the initialization code twice. + if (g_init_gtest_count != 1) return; + + if (*argc <= 0) return; + + internal::g_executable_path = internal::StreamableToString(argv[0]); + +#if GTEST_HAS_DEATH_TEST + + g_argvs.clear(); + for (int i = 0; i != *argc; i++) { + g_argvs.push_back(StreamableToString(argv[i])); + } + +#endif // GTEST_HAS_DEATH_TEST + + ParseGoogleTestFlagsOnly(argc, argv); + GetUnitTestImpl()->PostFlagParsingInit(); +} + +} // namespace internal + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +void InitGoogleTest(int* argc, char** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +void InitGoogleTest(int* argc, wchar_t** argv) { + internal::InitGoogleTestImpl(argc, argv); +} + +} // namespace testing +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) +// +// This file implements death tests. + + +#if GTEST_HAS_DEATH_TEST + +# if GTEST_OS_MAC +# include +# endif // GTEST_OS_MAC + +# include +# include +# include + +# if GTEST_OS_LINUX +# include +# endif // GTEST_OS_LINUX + +# include + +# if GTEST_OS_WINDOWS +# include +# else +# include +# include +# endif // GTEST_OS_WINDOWS + +# if GTEST_OS_QNX +# include +# endif // GTEST_OS_QNX + +#endif // GTEST_HAS_DEATH_TEST + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +// Constants. + +// The default death test style. +static const char kDefaultDeathTestStyle[] = "fast"; + +GTEST_DEFINE_string_( + death_test_style, + internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), + "Indicates how to run a death test in a forked child process: " + "\"threadsafe\" (child process re-executes the test binary " + "from the beginning, running only the specific death test) or " + "\"fast\" (child process runs the death test immediately " + "after forking)."); + +GTEST_DEFINE_bool_( + death_test_use_fork, + internal::BoolFromGTestEnv("death_test_use_fork", false), + "Instructs to use fork()/_exit() instead of clone() in death tests. " + "Ignored and always uses fork() on POSIX systems where clone() is not " + "implemented. Useful when running under valgrind or similar tools if " + "those do not support clone(). Valgrind 3.3.1 will just fail if " + "it sees an unsupported combination of clone() flags. " + "It is not recommended to use this flag w/o valgrind though it will " + "work in 99% of the cases. Once valgrind is fixed, this flag will " + "most likely be removed."); + +namespace internal { +GTEST_DEFINE_string_( + internal_run_death_test, "", + "Indicates the file, line number, temporal index of " + "the single death test to run, and a file descriptor to " + "which a success code may be sent, all separated by " + "the '|' characters. This flag is specified if and only if the current " + "process is a sub-process launched for running a thread-safe " + "death test. FOR INTERNAL USE ONLY."); +} // namespace internal + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Valid only for fast death tests. Indicates the code is running in the +// child process of a fast style death test. +static bool g_in_fast_death_test_child = false; + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +bool InDeathTestChild() { +# if GTEST_OS_WINDOWS + + // On Windows, death tests are thread-safe regardless of the value of the + // death_test_style flag. + return !GTEST_FLAG(internal_run_death_test).empty(); + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") + return !GTEST_FLAG(internal_run_death_test).empty(); + else + return g_in_fast_death_test_child; +#endif +} + +} // namespace internal + +// ExitedWithCode constructor. +ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { +} + +// ExitedWithCode function-call operator. +bool ExitedWithCode::operator()(int exit_status) const { +# if GTEST_OS_WINDOWS + + return exit_status == exit_code_; + +# else + + return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; + +# endif // GTEST_OS_WINDOWS +} + +# if !GTEST_OS_WINDOWS +// KilledBySignal constructor. +KilledBySignal::KilledBySignal(int signum) : signum_(signum) { +} + +// KilledBySignal function-call operator. +bool KilledBySignal::operator()(int exit_status) const { + return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; +} +# endif // !GTEST_OS_WINDOWS + +namespace internal { + +// Utilities needed for death tests. + +// Generates a textual description of a given exit code, in the format +// specified by wait(2). +static std::string ExitSummary(int exit_code) { + Message m; + +# if GTEST_OS_WINDOWS + + m << "Exited with exit status " << exit_code; + +# else + + if (WIFEXITED(exit_code)) { + m << "Exited with exit status " << WEXITSTATUS(exit_code); + } else if (WIFSIGNALED(exit_code)) { + m << "Terminated by signal " << WTERMSIG(exit_code); + } +# ifdef WCOREDUMP + if (WCOREDUMP(exit_code)) { + m << " (core dumped)"; + } +# endif +# endif // GTEST_OS_WINDOWS + + return m.GetString(); +} + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +bool ExitedUnsuccessfully(int exit_status) { + return !ExitedWithCode(0)(exit_status); +} + +# if !GTEST_OS_WINDOWS +// Generates a textual failure message when a death test finds more than +// one thread running, or cannot determine the number of threads, prior +// to executing the given statement. It is the responsibility of the +// caller not to pass a thread_count of 1. +static std::string DeathTestThreadWarning(size_t thread_count) { + Message msg; + msg << "Death tests use fork(), which is unsafe particularly" + << " in a threaded context. For this test, " << GTEST_NAME_ << " "; + if (thread_count == 0) + msg << "couldn't detect the number of threads."; + else + msg << "detected " << thread_count << " threads."; + return msg.GetString(); +} +# endif // !GTEST_OS_WINDOWS + +// Flag characters for reporting a death test that did not die. +static const char kDeathTestLived = 'L'; +static const char kDeathTestReturned = 'R'; +static const char kDeathTestThrew = 'T'; +static const char kDeathTestInternalError = 'I'; + +// An enumeration describing all of the possible ways that a death test can +// conclude. DIED means that the process died while executing the test +// code; LIVED means that process lived beyond the end of the test code; +// RETURNED means that the test statement attempted to execute a return +// statement, which is not allowed; THREW means that the test statement +// returned control by throwing an exception. IN_PROGRESS means the test +// has not yet concluded. +// TODO(vladl@google.com): Unify names and possibly values for +// AbortReason, DeathTestOutcome, and flag characters above. +enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; + +// Routine for aborting the program which is safe to call from an +// exec-style death test child process, in which case the error +// message is propagated back to the parent process. Otherwise, the +// message is simply printed to stderr. In either case, the program +// then exits with status 1. +void DeathTestAbort(const std::string& message) { + // On a POSIX system, this function may be called from a threadsafe-style + // death test child process, which operates on a very small stack. Use + // the heap for any additional non-minuscule memory requirements. + const InternalRunDeathTestFlag* const flag = + GetUnitTestImpl()->internal_run_death_test_flag(); + if (flag != NULL) { + FILE* parent = posix::FDOpen(flag->write_fd(), "w"); + fputc(kDeathTestInternalError, parent); + fprintf(parent, "%s", message.c_str()); + fflush(parent); + _exit(1); + } else { + fprintf(stderr, "%s", message.c_str()); + fflush(stderr); + posix::Abort(); + } +} + +// A replacement for CHECK that calls DeathTestAbort if the assertion +// fails. +# define GTEST_DEATH_TEST_CHECK_(expression) \ + do { \ + if (!::testing::internal::IsTrue(expression)) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for +// evaluating any system call that fulfills two conditions: it must return +// -1 on failure, and set errno to EINTR when it is interrupted and +// should be tried again. The macro expands to a loop that repeatedly +// evaluates the expression as long as it evaluates to -1 and sets +// errno to EINTR. If the expression evaluates to -1 but errno is +// something other than EINTR, DeathTestAbort is called. +# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ + do { \ + int gtest_retval; \ + do { \ + gtest_retval = (expression); \ + } while (gtest_retval == -1 && errno == EINTR); \ + if (gtest_retval == -1) { \ + DeathTestAbort( \ + ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + + ::testing::internal::StreamableToString(__LINE__) + ": " \ + + #expression + " != -1"); \ + } \ + } while (::testing::internal::AlwaysFalse()) + +// Returns the message describing the last system error in errno. +std::string GetLastErrnoDescription() { + return errno == 0 ? "" : posix::StrError(errno); +} + +// This is called from a death test parent process to read a failure +// message from the death test child process and log it with the FATAL +// severity. On Windows, the message is read from a pipe handle. On other +// platforms, it is read from a file descriptor. +static void FailFromInternalError(int fd) { + Message error; + char buffer[256]; + int num_read; + + do { + while ((num_read = posix::Read(fd, buffer, 255)) > 0) { + buffer[num_read] = '\0'; + error << buffer; + } + } while (num_read == -1 && errno == EINTR); + + if (num_read == 0) { + GTEST_LOG_(FATAL) << error.GetString(); + } else { + const int last_error = errno; + GTEST_LOG_(FATAL) << "Error while reading death test internal: " + << GetLastErrnoDescription() << " [" << last_error << "]"; + } +} + +// Death test constructor. Increments the running death test count +// for the current test. +DeathTest::DeathTest() { + TestInfo* const info = GetUnitTestImpl()->current_test_info(); + if (info == NULL) { + DeathTestAbort("Cannot run a death test outside of a TEST or " + "TEST_F construct"); + } +} + +// Creates and returns a death test by dispatching to the current +// death test factory. +bool DeathTest::Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) { + return GetUnitTestImpl()->death_test_factory()->Create( + statement, regex, file, line, test); +} + +const char* DeathTest::LastMessage() { + return last_death_test_message_.c_str(); +} + +void DeathTest::set_last_death_test_message(const std::string& message) { + last_death_test_message_ = message; +} + +std::string DeathTest::last_death_test_message_; + +// Provides cross platform implementation for some death functionality. +class DeathTestImpl : public DeathTest { + protected: + DeathTestImpl(const char* a_statement, const RE* a_regex) + : statement_(a_statement), + regex_(a_regex), + spawned_(false), + status_(-1), + outcome_(IN_PROGRESS), + read_fd_(-1), + write_fd_(-1) {} + + // read_fd_ is expected to be closed and cleared by a derived class. + ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } + + void Abort(AbortReason reason); + virtual bool Passed(bool status_ok); + + const char* statement() const { return statement_; } + const RE* regex() const { return regex_; } + bool spawned() const { return spawned_; } + void set_spawned(bool is_spawned) { spawned_ = is_spawned; } + int status() const { return status_; } + void set_status(int a_status) { status_ = a_status; } + DeathTestOutcome outcome() const { return outcome_; } + void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } + int read_fd() const { return read_fd_; } + void set_read_fd(int fd) { read_fd_ = fd; } + int write_fd() const { return write_fd_; } + void set_write_fd(int fd) { write_fd_ = fd; } + + // Called in the parent process only. Reads the result code of the death + // test child process via a pipe, interprets it to set the outcome_ + // member, and closes read_fd_. Outputs diagnostics and terminates in + // case of unexpected codes. + void ReadAndInterpretStatusByte(); + + private: + // The textual content of the code this object is testing. This class + // doesn't own this string and should not attempt to delete it. + const char* const statement_; + // The regular expression which test output must match. DeathTestImpl + // doesn't own this object and should not attempt to delete it. + const RE* const regex_; + // True if the death test child process has been successfully spawned. + bool spawned_; + // The exit status of the child process. + int status_; + // How the death test concluded. + DeathTestOutcome outcome_; + // Descriptor to the read end of the pipe to the child process. It is + // always -1 in the child process. The child keeps its write end of the + // pipe in write_fd_. + int read_fd_; + // Descriptor to the child's write end of the pipe to the parent process. + // It is always -1 in the parent process. The parent keeps its end of the + // pipe in read_fd_. + int write_fd_; +}; + +// Called in the parent process only. Reads the result code of the death +// test child process via a pipe, interprets it to set the outcome_ +// member, and closes read_fd_. Outputs diagnostics and terminates in +// case of unexpected codes. +void DeathTestImpl::ReadAndInterpretStatusByte() { + char flag; + int bytes_read; + + // The read() here blocks until data is available (signifying the + // failure of the death test) or until the pipe is closed (signifying + // its success), so it's okay to call this in the parent before + // the child process has exited. + do { + bytes_read = posix::Read(read_fd(), &flag, 1); + } while (bytes_read == -1 && errno == EINTR); + + if (bytes_read == 0) { + set_outcome(DIED); + } else if (bytes_read == 1) { + switch (flag) { + case kDeathTestReturned: + set_outcome(RETURNED); + break; + case kDeathTestThrew: + set_outcome(THREW); + break; + case kDeathTestLived: + set_outcome(LIVED); + break; + case kDeathTestInternalError: + FailFromInternalError(read_fd()); // Does not return. + break; + default: + GTEST_LOG_(FATAL) << "Death test child process reported " + << "unexpected status byte (" + << static_cast(flag) << ")"; + } + } else { + GTEST_LOG_(FATAL) << "Read from death test child process failed: " + << GetLastErrnoDescription(); + } + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); + set_read_fd(-1); +} + +// Signals that the death test code which should have exited, didn't. +// Should be called only in a death test child process. +// Writes a status byte to the child's status file descriptor, then +// calls _exit(1). +void DeathTestImpl::Abort(AbortReason reason) { + // The parent process considers the death test to be a failure if + // it finds any data in our pipe. So, here we write a single flag byte + // to the pipe, then exit. + const char status_ch = + reason == TEST_DID_NOT_DIE ? kDeathTestLived : + reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; + + GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); + // We are leaking the descriptor here because on some platforms (i.e., + // when built as Windows DLL), destructors of global objects will still + // run after calling _exit(). On such systems, write_fd_ will be + // indirectly closed from the destructor of UnitTestImpl, causing double + // close if it is also closed here. On debug configurations, double close + // may assert. As there are no in-process buffers to flush here, we are + // relying on the OS to close the descriptor after the process terminates + // when the destructors are not run. + _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) +} + +// Returns an indented copy of stderr output for a death test. +// This makes distinguishing death test output lines from regular log lines +// much easier. +static ::std::string FormatDeathTestOutput(const ::std::string& output) { + ::std::string ret; + for (size_t at = 0; ; ) { + const size_t line_end = output.find('\n', at); + ret += "[ DEATH ] "; + if (line_end == ::std::string::npos) { + ret += output.substr(at); + break; + } + ret += output.substr(at, line_end + 1 - at); + at = line_end + 1; + } + return ret; +} + +// Assesses the success or failure of a death test, using both private +// members which have previously been set, and one argument: +// +// Private data members: +// outcome: An enumeration describing how the death test +// concluded: DIED, LIVED, THREW, or RETURNED. The death test +// fails in the latter three cases. +// status: The exit status of the child process. On *nix, it is in the +// in the format specified by wait(2). On Windows, this is the +// value supplied to the ExitProcess() API or a numeric code +// of the exception that terminated the program. +// regex: A regular expression object to be applied to +// the test's captured standard error output; the death test +// fails if it does not match. +// +// Argument: +// status_ok: true if exit_status is acceptable in the context of +// this particular death test, which fails if it is false +// +// Returns true iff all of the above conditions are met. Otherwise, the +// first failing condition, in the order given above, is the one that is +// reported. Also sets the last death test message string. +bool DeathTestImpl::Passed(bool status_ok) { + if (!spawned()) + return false; + + const std::string error_message = GetCapturedStderr(); + + bool success = false; + Message buffer; + + buffer << "Death test: " << statement() << "\n"; + switch (outcome()) { + case LIVED: + buffer << " Result: failed to die.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case THREW: + buffer << " Result: threw an exception.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case RETURNED: + buffer << " Result: illegal return in test statement.\n" + << " Error msg:\n" << FormatDeathTestOutput(error_message); + break; + case DIED: + if (status_ok) { + const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); + if (matched) { + success = true; + } else { + buffer << " Result: died but not with expected error.\n" + << " Expected: " << regex()->pattern() << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + } else { + buffer << " Result: died but not with expected exit code:\n" + << " " << ExitSummary(status()) << "\n" + << "Actual msg:\n" << FormatDeathTestOutput(error_message); + } + break; + case IN_PROGRESS: + default: + GTEST_LOG_(FATAL) + << "DeathTest::Passed somehow called before conclusion of test"; + } + + DeathTest::set_last_death_test_message(buffer.GetString()); + return success; +} + +# if GTEST_OS_WINDOWS +// WindowsDeathTest implements death tests on Windows. Due to the +// specifics of starting new processes on Windows, death tests there are +// always threadsafe, and Google Test considers the +// --gtest_death_test_style=fast setting to be equivalent to +// --gtest_death_test_style=threadsafe there. +// +// A few implementation notes: Like the Linux version, the Windows +// implementation uses pipes for child-to-parent communication. But due to +// the specifics of pipes on Windows, some extra steps are required: +// +// 1. The parent creates a communication pipe and stores handles to both +// ends of it. +// 2. The parent starts the child and provides it with the information +// necessary to acquire the handle to the write end of the pipe. +// 3. The child acquires the write end of the pipe and signals the parent +// using a Windows event. +// 4. Now the parent can release the write end of the pipe on its side. If +// this is done before step 3, the object's reference count goes down to +// 0 and it is destroyed, preventing the child from acquiring it. The +// parent now has to release it, or read operations on the read end of +// the pipe will not return when the child terminates. +// 5. The parent reads child's output through the pipe (outcome code and +// any possible error messages) from the pipe, and its stderr and then +// determines whether to fail the test. +// +// Note: to distinguish Win32 API calls from the local method and function +// calls, the former are explicitly resolved in the global namespace. +// +class WindowsDeathTest : public DeathTestImpl { + public: + WindowsDeathTest(const char* a_statement, + const RE* a_regex, + const char* file, + int line) + : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + virtual TestRole AssumeRole(); + + private: + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; + // Handle to the write end of the pipe to the child process. + AutoHandle write_handle_; + // Child process handle. + AutoHandle child_handle_; + // Event the child process uses to signal the parent that it has + // acquired the handle to the write end of the pipe. After seeing this + // event the parent can release its own handles to make sure its + // ReadFile() calls return when the child terminates. + AutoHandle event_handle_; +}; + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int WindowsDeathTest::Wait() { + if (!spawned()) + return 0; + + // Wait until the child either signals that it has acquired the write end + // of the pipe or it dies. + const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; + switch (::WaitForMultipleObjects(2, + wait_handles, + FALSE, // Waits for any of the handles. + INFINITE)) { + case WAIT_OBJECT_0: + case WAIT_OBJECT_0 + 1: + break; + default: + GTEST_DEATH_TEST_CHECK_(false); // Should not get here. + } + + // The child has acquired the write end of the pipe or exited. + // We release the handle on our side and continue. + write_handle_.Reset(); + event_handle_.Reset(); + + ReadAndInterpretStatusByte(); + + // Waits for the child process to exit if it haven't already. This + // returns immediately if the child has already exited, regardless of + // whether previous calls to WaitForMultipleObjects synchronized on this + // handle or not. + GTEST_DEATH_TEST_CHECK_( + WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), + INFINITE)); + DWORD status_code; + GTEST_DEATH_TEST_CHECK_( + ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); + child_handle_.Reset(); + set_status(static_cast(status_code)); + return status(); +} + +// The AssumeRole process for a Windows death test. It creates a child +// process with the same executable as the current process to run the +// death test. The child process is given the --gtest_filter and +// --gtest_internal_run_death_test flags such that it knows to run the +// current death test only. +DeathTest::TestRole WindowsDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + // ParseInternalRunDeathTestFlag() has performed all the necessary + // processing. + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + // WindowsDeathTest uses an anonymous pipe to communicate results of + // a death test. + SECURITY_ATTRIBUTES handles_are_inheritable = { + sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + HANDLE read_handle, write_handle; + GTEST_DEATH_TEST_CHECK_( + ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, + 0) // Default buffer size. + != FALSE); + set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), + O_RDONLY)); + write_handle_.Reset(write_handle); + event_handle_.Reset(::CreateEvent( + &handles_are_inheritable, + TRUE, // The event will automatically reset to non-signaled state. + FALSE, // The initial state is non-signalled. + NULL)); // The even is unnamed. + GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + + "=" + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(static_cast(::GetCurrentProcessId())) + + // size_t has the same width as pointers on both 32-bit and 64-bit + // Windows platforms. + // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. + "|" + StreamableToString(reinterpret_cast(write_handle)) + + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); + + char executable_path[_MAX_PATH + 1]; // NOLINT + GTEST_DEATH_TEST_CHECK_( + _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, + executable_path, + _MAX_PATH)); + + std::string command_line = + std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + + internal_flag + "\""; + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // Flush the log buffers since the log streams are shared with the child. + FlushInfoLog(); + + // The child process will share the standard handles with the parent. + STARTUPINFOA startup_info; + memset(&startup_info, 0, sizeof(STARTUPINFO)); + startup_info.dwFlags = STARTF_USESTDHANDLES; + startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); + startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); + startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); + + PROCESS_INFORMATION process_info; + GTEST_DEATH_TEST_CHECK_(::CreateProcessA( + executable_path, + const_cast(command_line.c_str()), + NULL, // Retuned process handle is not inheritable. + NULL, // Retuned thread handle is not inheritable. + TRUE, // Child inherits all inheritable handles (for write_handle_). + 0x0, // Default creation flags. + NULL, // Inherit the parent's environment. + UnitTest::GetInstance()->original_working_dir(), + &startup_info, + &process_info) != FALSE); + child_handle_.Reset(process_info.hProcess); + ::CloseHandle(process_info.hThread); + set_spawned(true); + return OVERSEE_TEST; +} +# else // We are not on Windows. + +// ForkingDeathTest provides implementations for most of the abstract +// methods of the DeathTest interface. Only the AssumeRole method is +// left undefined. +class ForkingDeathTest : public DeathTestImpl { + public: + ForkingDeathTest(const char* statement, const RE* regex); + + // All of these virtual functions are inherited from DeathTest. + virtual int Wait(); + + protected: + void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } + + private: + // PID of child process during death test; 0 in the child process itself. + pid_t child_pid_; +}; + +// Constructs a ForkingDeathTest. +ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) + : DeathTestImpl(a_statement, a_regex), + child_pid_(-1) {} + +// Waits for the child in a death test to exit, returning its exit +// status, or 0 if no child process exists. As a side effect, sets the +// outcome data member. +int ForkingDeathTest::Wait() { + if (!spawned()) + return 0; + + ReadAndInterpretStatusByte(); + + int status_value; + GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); + set_status(status_value); + return status_value; +} + +// A concrete death test class that forks, then immediately runs the test +// in the child process. +class NoExecDeathTest : public ForkingDeathTest { + public: + NoExecDeathTest(const char* a_statement, const RE* a_regex) : + ForkingDeathTest(a_statement, a_regex) { } + virtual TestRole AssumeRole(); +}; + +// The AssumeRole process for a fork-and-run death test. It implements a +// straightforward fork, with a simple pipe to transmit the status byte. +DeathTest::TestRole NoExecDeathTest::AssumeRole() { + const size_t thread_count = GetThreadCount(); + if (thread_count != 1) { + GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + + DeathTest::set_last_death_test_message(""); + CaptureStderr(); + // When we fork the process below, the log file buffers are copied, but the + // file descriptors are shared. We flush all log files here so that closing + // the file descriptors in the child process doesn't throw off the + // synchronization between descriptors and buffers in the parent process. + // This is as close to the fork as possible to avoid a race condition in case + // there are multiple threads running before the death test, and another + // thread writes to the log file. + FlushInfoLog(); + + const pid_t child_pid = fork(); + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + set_child_pid(child_pid); + if (child_pid == 0) { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); + set_write_fd(pipe_fd[1]); + // Redirects all logging to stderr in the child process to prevent + // concurrent writes to the log files. We capture stderr in the parent + // process and append the child process' output to a log. + LogToStderr(); + // Event forwarding to the listeners of event listener API mush be shut + // down in death test subprocesses. + GetUnitTestImpl()->listeners()->SuppressEventForwarding(); + g_in_fast_death_test_child = true; + return EXECUTE_TEST; + } else { + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; + } +} + +// A concrete death test class that forks and re-executes the main +// program from the beginning, with command-line flags set that cause +// only this specific death test to be run. +class ExecDeathTest : public ForkingDeathTest { + public: + ExecDeathTest(const char* a_statement, const RE* a_regex, + const char* file, int line) : + ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } + virtual TestRole AssumeRole(); + private: + static ::std::vector + GetArgvsForDeathTestChildProcess() { + ::std::vector args = GetInjectableArgvs(); + return args; + } + // The name of the file in which the death test is located. + const char* const file_; + // The line number on which the death test is located. + const int line_; +}; + +// Utility class for accumulating command-line arguments. +class Arguments { + public: + Arguments() { + args_.push_back(NULL); + } + + ~Arguments() { + for (std::vector::iterator i = args_.begin(); i != args_.end(); + ++i) { + free(*i); + } + } + void AddArgument(const char* argument) { + args_.insert(args_.end() - 1, posix::StrDup(argument)); + } + + template + void AddArguments(const ::std::vector& arguments) { + for (typename ::std::vector::const_iterator i = arguments.begin(); + i != arguments.end(); + ++i) { + args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); + } + } + char* const* Argv() { + return &args_[0]; + } + + private: + std::vector args_; +}; + +// A struct that encompasses the arguments to the child process of a +// threadsafe-style death test process. +struct ExecDeathTestArgs { + char* const* argv; // Command-line arguments for the child's call to exec + int close_fd; // File descriptor to close; the read end of a pipe +}; + +# if GTEST_OS_MAC +inline char** GetEnviron() { + // When Google Test is built as a framework on MacOS X, the environ variable + // is unavailable. Apple's documentation (man environ) recommends using + // _NSGetEnviron() instead. + return *_NSGetEnviron(); +} +# else +// Some POSIX platforms expect you to declare environ. extern "C" makes +// it reside in the global namespace. +extern "C" char** environ; +inline char** GetEnviron() { return environ; } +# endif // GTEST_OS_MAC + +# if !GTEST_OS_QNX +// The main function for a threadsafe-style death test child process. +// This function is called in a clone()-ed process and thus must avoid +// any potentially unsafe operations like malloc or libc functions. +static int ExecDeathTestChildMain(void* child_arg) { + ExecDeathTestArgs* const args = static_cast(child_arg); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); + + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + // We can safely call execve() as it's a direct system call. We + // cannot use execvp() as it's a libc function and thus potentially + // unsafe. Since execve() doesn't search the PATH, the user must + // invoke the test program via a valid path that contains at least + // one path separator. + execve(args->argv[0], args->argv, GetEnviron()); + DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + + original_dir + " failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; +} +# endif // !GTEST_OS_QNX + +// Two utility routines that together determine the direction the stack +// grows. +// This could be accomplished more elegantly by a single recursive +// function, but we want to guard against the unlikely possibility of +// a smart compiler optimizing the recursion away. +// +// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining +// StackLowerThanAddress into StackGrowsDown, which then doesn't give +// correct answer. +void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; +void StackLowerThanAddress(const void* ptr, bool* result) { + int dummy; + *result = (&dummy < ptr); +} + +bool StackGrowsDown() { + int dummy; + bool result; + StackLowerThanAddress(&dummy, &result); + return result; +} + +// Spawns a child process with the same executable as the current process in +// a thread-safe manner and instructs it to run the death test. The +// implementation uses fork(2) + exec. On systems where clone(2) is +// available, it is used instead, being slightly more thread-safe. On QNX, +// fork supports only single-threaded environments, so this function uses +// spawn(2) there instead. The function dies with an error message if +// anything goes wrong. +static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { + ExecDeathTestArgs args = { argv, close_fd }; + pid_t child_pid = -1; + +# if GTEST_OS_QNX + // Obtains the current directory and sets it to be closed in the child + // process. + const int cwd_fd = open(".", O_RDONLY); + GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); + // We need to execute the test program in the same environment where + // it was originally invoked. Therefore we change to the original + // working directory first. + const char* const original_dir = + UnitTest::GetInstance()->original_working_dir(); + // We can safely call chdir() as it's a direct system call. + if (chdir(original_dir) != 0) { + DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + + GetLastErrnoDescription()); + return EXIT_FAILURE; + } + + int fd_flags; + // Set close_fd to be closed after spawn. + GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); + GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, + fd_flags | FD_CLOEXEC)); + struct inheritance inherit = {0}; + // spawn is a system call. + child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); + // Restores the current working directory. + GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); + +# else // GTEST_OS_QNX +# if GTEST_OS_LINUX + // When a SIGPROF signal is received while fork() or clone() are executing, + // the process may hang. To avoid this, we ignore SIGPROF here and re-enable + // it after the call to fork()/clone() is complete. + struct sigaction saved_sigprof_action; + struct sigaction ignore_sigprof_action; + memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); + sigemptyset(&ignore_sigprof_action.sa_mask); + ignore_sigprof_action.sa_handler = SIG_IGN; + GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( + SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); +# endif // GTEST_OS_LINUX + +# if GTEST_HAS_CLONE + const bool use_fork = GTEST_FLAG(death_test_use_fork); + + if (!use_fork) { + static const bool stack_grows_down = StackGrowsDown(); + const size_t stack_size = getpagesize(); + // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. + void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); + + // Maximum stack alignment in bytes: For a downward-growing stack, this + // amount is subtracted from size of the stack space to get an address + // that is within the stack space and is aligned on all systems we care + // about. As far as I know there is no ABI with stack alignment greater + // than 64. We assume stack and stack_size already have alignment of + // kMaxStackAlignment. + const size_t kMaxStackAlignment = 64; + void* const stack_top = + static_cast(stack) + + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); + GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && + reinterpret_cast(stack_top) % kMaxStackAlignment == 0); + + child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); + + GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); + } +# else + const bool use_fork = true; +# endif // GTEST_HAS_CLONE + + if (use_fork && (child_pid = fork()) == 0) { + ExecDeathTestChildMain(&args); + _exit(0); + } +# endif // GTEST_OS_QNX +# if GTEST_OS_LINUX + GTEST_DEATH_TEST_CHECK_SYSCALL_( + sigaction(SIGPROF, &saved_sigprof_action, NULL)); +# endif // GTEST_OS_LINUX + + GTEST_DEATH_TEST_CHECK_(child_pid != -1); + return child_pid; +} + +// The AssumeRole process for a fork-and-exec death test. It re-executes the +// main program from the beginning, setting the --gtest_filter +// and --gtest_internal_run_death_test flags to cause only the current +// death test to be re-run. +DeathTest::TestRole ExecDeathTest::AssumeRole() { + const UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const TestInfo* const info = impl->current_test_info(); + const int death_test_index = info->result()->death_test_count(); + + if (flag != NULL) { + set_write_fd(flag->write_fd()); + return EXECUTE_TEST; + } + + int pipe_fd[2]; + GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); + // Clear the close-on-exec flag on the write end of the pipe, lest + // it be closed when the child process does an exec: + GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); + + const std::string filter_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + + info->test_case_name() + "." + info->name(); + const std::string internal_flag = + std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + + file_ + "|" + StreamableToString(line_) + "|" + + StreamableToString(death_test_index) + "|" + + StreamableToString(pipe_fd[1]); + Arguments args; + args.AddArguments(GetArgvsForDeathTestChildProcess()); + args.AddArgument(filter_flag.c_str()); + args.AddArgument(internal_flag.c_str()); + + DeathTest::set_last_death_test_message(""); + + CaptureStderr(); + // See the comment in NoExecDeathTest::AssumeRole for why the next line + // is necessary. + FlushInfoLog(); + + const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); + GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); + set_child_pid(child_pid); + set_read_fd(pipe_fd[0]); + set_spawned(true); + return OVERSEE_TEST; +} + +# endif // !GTEST_OS_WINDOWS + +// Creates a concrete DeathTest-derived class that depends on the +// --gtest_death_test_style flag, and sets the pointer pointed to +// by the "test" argument to its address. If the test should be +// skipped, sets that pointer to NULL. Returns true, unless the +// flag is set to an invalid value. +bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, + const char* file, int line, + DeathTest** test) { + UnitTestImpl* const impl = GetUnitTestImpl(); + const InternalRunDeathTestFlag* const flag = + impl->internal_run_death_test_flag(); + const int death_test_index = impl->current_test_info() + ->increment_death_test_count(); + + if (flag != NULL) { + if (death_test_index > flag->index()) { + DeathTest::set_last_death_test_message( + "Death test count (" + StreamableToString(death_test_index) + + ") somehow exceeded expected maximum (" + + StreamableToString(flag->index()) + ")"); + return false; + } + + if (!(flag->file() == file && flag->line() == line && + flag->index() == death_test_index)) { + *test = NULL; + return true; + } + } + +# if GTEST_OS_WINDOWS + + if (GTEST_FLAG(death_test_style) == "threadsafe" || + GTEST_FLAG(death_test_style) == "fast") { + *test = new WindowsDeathTest(statement, regex, file, line); + } + +# else + + if (GTEST_FLAG(death_test_style) == "threadsafe") { + *test = new ExecDeathTest(statement, regex, file, line); + } else if (GTEST_FLAG(death_test_style) == "fast") { + *test = new NoExecDeathTest(statement, regex); + } + +# endif // GTEST_OS_WINDOWS + + else { // NOLINT - this is more readable than unbalanced brackets inside #if. + DeathTest::set_last_death_test_message( + "Unknown death test style \"" + GTEST_FLAG(death_test_style) + + "\" encountered"); + return false; + } + + return true; +} + +// Splits a given string on a given delimiter, populating a given +// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have +// ::std::string, so we can use it here. +static void SplitString(const ::std::string& str, char delimiter, + ::std::vector< ::std::string>* dest) { + ::std::vector< ::std::string> parsed; + ::std::string::size_type pos = 0; + while (::testing::internal::AlwaysTrue()) { + const ::std::string::size_type colon = str.find(delimiter, pos); + if (colon == ::std::string::npos) { + parsed.push_back(str.substr(pos)); + break; + } else { + parsed.push_back(str.substr(pos, colon - pos)); + pos = colon + 1; + } + } + dest->swap(parsed); +} + +# if GTEST_OS_WINDOWS +// Recreates the pipe and event handles from the provided parameters, +// signals the event, and returns a file descriptor wrapped around the pipe +// handle. This function is called in the child process only. +int GetStatusFileDescriptor(unsigned int parent_process_id, + size_t write_handle_as_size_t, + size_t event_handle_as_size_t) { + AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, + FALSE, // Non-inheritable. + parent_process_id)); + if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { + DeathTestAbort("Unable to open parent process " + + StreamableToString(parent_process_id)); + } + + // TODO(vladl@google.com): Replace the following check with a + // compile-time assertion when available. + GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); + + const HANDLE write_handle = + reinterpret_cast(write_handle_as_size_t); + HANDLE dup_write_handle; + + // The newly initialized handle is accessible only in in the parent + // process. To obtain one accessible within the child, we need to use + // DuplicateHandle. + if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, + ::GetCurrentProcess(), &dup_write_handle, + 0x0, // Requested privileges ignored since + // DUPLICATE_SAME_ACCESS is used. + FALSE, // Request non-inheritable handler. + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the pipe handle " + + StreamableToString(write_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); + HANDLE dup_event_handle; + + if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, + ::GetCurrentProcess(), &dup_event_handle, + 0x0, + FALSE, + DUPLICATE_SAME_ACCESS)) { + DeathTestAbort("Unable to duplicate the event handle " + + StreamableToString(event_handle_as_size_t) + + " from the parent process " + + StreamableToString(parent_process_id)); + } + + const int write_fd = + ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); + if (write_fd == -1) { + DeathTestAbort("Unable to convert pipe handle " + + StreamableToString(write_handle_as_size_t) + + " to a file descriptor"); + } + + // Signals the parent that the write end of the pipe has been acquired + // so the parent can release its own write end. + ::SetEvent(dup_event_handle); + + return write_fd; +} +# endif // GTEST_OS_WINDOWS + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { + if (GTEST_FLAG(internal_run_death_test) == "") return NULL; + + // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we + // can use it here. + int line = -1; + int index = -1; + ::std::vector< ::std::string> fields; + SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); + int write_fd = -1; + +# if GTEST_OS_WINDOWS + + unsigned int parent_process_id = 0; + size_t write_handle_as_size_t = 0; + size_t event_handle_as_size_t = 0; + + if (fields.size() != 6 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &parent_process_id) + || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) + || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + write_fd = GetStatusFileDescriptor(parent_process_id, + write_handle_as_size_t, + event_handle_as_size_t); +# else + + if (fields.size() != 4 + || !ParseNaturalNumber(fields[1], &line) + || !ParseNaturalNumber(fields[2], &index) + || !ParseNaturalNumber(fields[3], &write_fd)) { + DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + + GTEST_FLAG(internal_run_death_test)); + } + +# endif // GTEST_OS_WINDOWS + + return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); +} + +} // namespace internal + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: keith.ray@gmail.com (Keith Ray) + + +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include +#elif GTEST_OS_WINDOWS +# include +# include +#elif GTEST_OS_SYMBIAN +// Symbian OpenC has PATH_MAX in sys/syslimits.h +# include +#else +# include +# include // Some Linux distributions define PATH_MAX here. +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_MAX_ _MAX_PATH +#elif defined(PATH_MAX) +# define GTEST_PATH_MAX_ PATH_MAX +#elif defined(_XOPEN_PATH_MAX) +# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX +#else +# define GTEST_PATH_MAX_ _POSIX_PATH_MAX +#endif // GTEST_OS_WINDOWS + + +namespace testing { +namespace internal { + +#if GTEST_OS_WINDOWS +// On Windows, '\\' is the standard path separator, but many tools and the +// Windows API also accept '/' as an alternate path separator. Unless otherwise +// noted, a file path can contain either kind of path separators, or a mixture +// of them. +const char kPathSeparator = '\\'; +const char kAlternatePathSeparator = '/'; +//const char kPathSeparatorString[] = "\\"; +const char kAlternatePathSeparatorString[] = "/"; +# if GTEST_OS_WINDOWS_MOBILE +// Windows CE doesn't have a current directory. You should not use +// the current directory in tests on Windows CE, but this at least +// provides a reasonable fallback. +const char kCurrentDirectoryString[] = "\\"; +// Windows CE doesn't define INVALID_FILE_ATTRIBUTES +const DWORD kInvalidFileAttributes = 0xffffffff; +# else +const char kCurrentDirectoryString[] = ".\\"; +# endif // GTEST_OS_WINDOWS_MOBILE +#else +const char kPathSeparator = '/'; +//const char kPathSeparatorString[] = "/"; +const char kCurrentDirectoryString[] = "./"; +#endif // GTEST_OS_WINDOWS + +// Returns whether the given character is a valid path separator. +static bool IsPathSeparator(char c) { +#if GTEST_HAS_ALT_PATH_SEP_ + return (c == kPathSeparator) || (c == kAlternatePathSeparator); +#else + return c == kPathSeparator; +#endif +} + +// Returns the current working directory, or "" if unsuccessful. +FilePath FilePath::GetCurrentDir() { +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE doesn't have a current directory, so we just return + // something reasonable. + return FilePath(kCurrentDirectoryString); +#elif GTEST_OS_WINDOWS + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#else + char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; + return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns a copy of the FilePath with the case-insensitive extension removed. +// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns +// FilePath("dir/file"). If a case-insensitive extension is not +// found, returns a copy of the original FilePath. +FilePath FilePath::RemoveExtension(const char* extension) const { + const std::string dot_extension = std::string(".") + extension; + if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { + return FilePath(pathname_.substr( + 0, pathname_.length() - dot_extension.length())); + } + return *this; +} + +// Returns a pointer to the last occurence of a valid path separator in +// the FilePath. On Windows, for example, both '/' and '\' are valid path +// separators. Returns NULL if no path separator was found. +const char* FilePath::FindLastPathSeparator() const { + const char* const last_sep = strrchr(c_str(), kPathSeparator); +#if GTEST_HAS_ALT_PATH_SEP_ + const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); + // Comparing two pointers of which only one is NULL is undefined. + if (last_alt_sep != NULL && + (last_sep == NULL || last_alt_sep > last_sep)) { + return last_alt_sep; + } +#endif + return last_sep; +} + +// Returns a copy of the FilePath with the directory part removed. +// Example: FilePath("path/to/file").RemoveDirectoryName() returns +// FilePath("file"). If there is no directory part ("just_a_file"), it returns +// the FilePath unmodified. If there is no file part ("just_a_dir/") it +// returns an empty FilePath (""). +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveDirectoryName() const { + const char* const last_sep = FindLastPathSeparator(); + return last_sep ? FilePath(last_sep + 1) : *this; +} + +// RemoveFileName returns the directory path with the filename removed. +// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". +// If the FilePath is "a_file" or "/a_file", RemoveFileName returns +// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does +// not have a file, like "just/a/dir/", it returns the FilePath unmodified. +// On Windows platform, '\' is the path separator, otherwise it is '/'. +FilePath FilePath::RemoveFileName() const { + const char* const last_sep = FindLastPathSeparator(); + std::string dir; + if (last_sep) { + dir = std::string(c_str(), last_sep + 1 - c_str()); + } else { + dir = kCurrentDirectoryString; + } + return FilePath(dir); +} + +// Helper functions for naming files in a directory for xml output. + +// Given directory = "dir", base_name = "test", number = 0, +// extension = "xml", returns "dir/test.xml". If number is greater +// than zero (e.g., 12), returns "dir/test_12.xml". +// On Windows platform, uses \ as the separator rather than /. +FilePath FilePath::MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension) { + std::string file; + if (number == 0) { + file = base_name.string() + "." + extension; + } else { + file = base_name.string() + "_" + StreamableToString(number) + + "." + extension; + } + return ConcatPaths(directory, FilePath(file)); +} + +// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". +// On Windows, uses \ as the separator rather than /. +FilePath FilePath::ConcatPaths(const FilePath& directory, + const FilePath& relative_path) { + if (directory.IsEmpty()) + return relative_path; + const FilePath dir(directory.RemoveTrailingPathSeparator()); + return FilePath(dir.string() + kPathSeparator + relative_path.string()); +} + +// Returns true if pathname describes something findable in the file-system, +// either a file, directory, or whatever. +bool FilePath::FileOrDirectoryExists() const { +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + return attributes != kInvalidFileAttributes; +#else + posix::StatStruct file_stat; + return posix::Stat(pathname_.c_str(), &file_stat) == 0; +#endif // GTEST_OS_WINDOWS_MOBILE +} + +// Returns true if pathname describes a directory in the file-system +// that exists. +bool FilePath::DirectoryExists() const { + bool result = false; +#if GTEST_OS_WINDOWS + // Don't strip off trailing separator if path is a root directory on + // Windows (like "C:\\"). + const FilePath& path(IsRootDirectory() ? *this : + RemoveTrailingPathSeparator()); +#else + const FilePath& path(*this); +#endif + +#if GTEST_OS_WINDOWS_MOBILE + LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); + const DWORD attributes = GetFileAttributes(unicode); + delete [] unicode; + if ((attributes != kInvalidFileAttributes) && + (attributes & FILE_ATTRIBUTE_DIRECTORY)) { + result = true; + } +#else + posix::StatStruct file_stat; + result = posix::Stat(path.c_str(), &file_stat) == 0 && + posix::IsDir(file_stat); +#endif // GTEST_OS_WINDOWS_MOBILE + + return result; +} + +// Returns true if pathname describes a root directory. (Windows has one +// root directory per disk drive.) +bool FilePath::IsRootDirectory() const { +#if GTEST_OS_WINDOWS + // TODO(wan@google.com): on Windows a network share like + // \\server\share can be a root directory, although it cannot be the + // current directory. Handle this properly. + return pathname_.length() == 3 && IsAbsolutePath(); +#else + return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); +#endif +} + +// Returns true if pathname describes an absolute path. +bool FilePath::IsAbsolutePath() const { + const char* const name = pathname_.c_str(); +#if GTEST_OS_WINDOWS + return pathname_.length() >= 3 && + ((name[0] >= 'a' && name[0] <= 'z') || + (name[0] >= 'A' && name[0] <= 'Z')) && + name[1] == ':' && + IsPathSeparator(name[2]); +#else + return IsPathSeparator(name[0]); +#endif +} + +// Returns a pathname for a file that does not currently exist. The pathname +// will be directory/base_name.extension or +// directory/base_name_.extension if directory/base_name.extension +// already exists. The number will be incremented until a pathname is found +// that does not already exist. +// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. +// There could be a race condition if two or more processes are calling this +// function at the same time -- they could both pick the same filename. +FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension) { + FilePath full_pathname; + int number = 0; + do { + full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); + } while (full_pathname.FileOrDirectoryExists()); + return full_pathname; +} + +// Returns true if FilePath ends with a path separator, which indicates that +// it is intended to represent a directory. Returns false otherwise. +// This does NOT check that a directory (or file) actually exists. +bool FilePath::IsDirectory() const { + return !pathname_.empty() && + IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); +} + +// Create directories so that path exists. Returns true if successful or if +// the directories already exist; returns false if unable to create directories +// for any reason. +bool FilePath::CreateDirectoriesRecursively() const { + if (!this->IsDirectory()) { + return false; + } + + if (pathname_.length() == 0 || this->DirectoryExists()) { + return true; + } + + const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); + return parent.CreateDirectoriesRecursively() && this->CreateFolder(); +} + +// Create the directory so that path exists. Returns true if successful or +// if the directory already exists; returns false if unable to create the +// directory for any reason, including if the parent directory does not +// exist. Not named "CreateDirectory" because that's a macro on Windows. +bool FilePath::CreateFolder() const { +#if GTEST_OS_WINDOWS_MOBILE + FilePath removed_sep(this->RemoveTrailingPathSeparator()); + LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); + int result = CreateDirectory(unicode, NULL) ? 0 : -1; + delete [] unicode; +#elif GTEST_OS_WINDOWS + int result = _mkdir(pathname_.c_str()); +#else + int result = mkdir(pathname_.c_str(), 0777); +#endif // GTEST_OS_WINDOWS_MOBILE + + if (result == -1) { + return this->DirectoryExists(); // An error is OK if the directory exists. + } + return true; // No error. +} + +// If input name has a trailing separator character, remove it and return the +// name, otherwise return the name string unmodified. +// On Windows platform, uses \ as the separator, other platforms use /. +FilePath FilePath::RemoveTrailingPathSeparator() const { + return IsDirectory() + ? FilePath(pathname_.substr(0, pathname_.length() - 1)) + : *this; +} + +// Removes any redundant separators that might be in the pathname. +// For example, "bar///foo" becomes "bar/foo". Does not eliminate other +// redundancies that might be in a pathname involving "." or "..". +// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). +void FilePath::Normalize() { + if (pathname_.c_str() == NULL) { + pathname_ = ""; + return; + } + const char* src = pathname_.c_str(); + char* const dest = new char[pathname_.length() + 1]; + char* dest_ptr = dest; + memset(dest_ptr, 0, pathname_.length() + 1); + + while (*src != '\0') { + *dest_ptr = *src; + if (!IsPathSeparator(*src)) { + src++; + } else { +#if GTEST_HAS_ALT_PATH_SEP_ + if (*dest_ptr == kAlternatePathSeparator) { + *dest_ptr = kPathSeparator; + } +#endif + while (IsPathSeparator(*src)) + src++; + } + dest_ptr++; + } + *dest_ptr = '\0'; + pathname_ = dest; + delete[] dest; +} + +} // namespace internal +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + + +#include +#include +#include +#include + +#if GTEST_OS_WINDOWS_MOBILE +# include // For TerminateProcess() +#elif GTEST_OS_WINDOWS +# include +# include +#else +# include +#endif // GTEST_OS_WINDOWS_MOBILE + +#if GTEST_OS_MAC +# include +# include +# include +#endif // GTEST_OS_MAC + +#if GTEST_OS_QNX +# include +# include +#endif // GTEST_OS_QNX + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { +namespace internal { + +#if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC and C++Builder do not provide a definition of STDERR_FILENO. +const int kStdOutFileno = 1; +const int kStdErrFileno = 2; +#else +const int kStdOutFileno = STDOUT_FILENO; +const int kStdErrFileno = STDERR_FILENO; +#endif // _MSC_VER + +#if GTEST_OS_MAC + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const task_t task = mach_task_self(); + mach_msg_type_number_t thread_count; + thread_act_array_t thread_list; + const kern_return_t status = task_threads(task, &thread_list, &thread_count); + if (status == KERN_SUCCESS) { + // task_threads allocates resources in thread_list and we need to free them + // to avoid leaks. + vm_deallocate(task, + reinterpret_cast(thread_list), + sizeof(thread_t) * thread_count); + return static_cast(thread_count); + } else { + return 0; + } +} + +#elif GTEST_OS_QNX + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +size_t GetThreadCount() { + const int fd = open("/proc/self/as", O_RDONLY); + if (fd < 0) { + return 0; + } + procfs_info process_info; + const int status = + devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); + close(fd); + if (status == EOK) { + return static_cast(process_info.num_threads); + } else { + return 0; + } +} + +#else + +size_t GetThreadCount() { + // There's no portable way to detect the number of threads, so we just + // return 0 to indicate that we cannot detect it. + return 0; +} + +#endif // GTEST_OS_MAC + +#if GTEST_USES_POSIX_RE + +// Implements RE. Currently only needed for death tests. + +RE::~RE() { + if (is_valid_) { + // regfree'ing an invalid regex might crash because the content + // of the regex is undefined. Since the regex's are essentially + // the same, one cannot be valid (or invalid) without the other + // being so too. + regfree(&partial_regex_); + regfree(&full_regex_); + } + free(const_cast(pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.full_regex_, str, 1, &match, 0) == 0; +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + if (!re.is_valid_) return false; + + regmatch_t match; + return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = posix::StrDup(regex); + + // Reserves enough bytes to hold the regular expression used for a + // full match. + const size_t full_regex_len = strlen(regex) + 10; + char* const full_pattern = new char[full_regex_len]; + + snprintf(full_pattern, full_regex_len, "^(%s)$", regex); + is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; + // We want to call regcomp(&partial_regex_, ...) even if the + // previous expression returns false. Otherwise partial_regex_ may + // not be properly initialized can may cause trouble when it's + // freed. + // + // Some implementation of POSIX regex (e.g. on at least some + // versions of Cygwin) doesn't accept the empty string as a valid + // regex. We change it to an equivalent form "()" to be safe. + if (is_valid_) { + const char* const partial_regex = (*regex == '\0') ? "()" : regex; + is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; + } + EXPECT_TRUE(is_valid_) + << "Regular expression \"" << regex + << "\" is not a valid POSIX Extended regular expression."; + + delete[] full_pattern; +} + +#elif GTEST_USES_SIMPLE_RE + +// Returns true iff ch appears anywhere in str (excluding the +// terminating '\0' character). +bool IsInSet(char ch, const char* str) { + return ch != '\0' && strchr(str, ch) != NULL; +} + +// Returns true iff ch belongs to the given classification. Unlike +// similar functions in , these aren't affected by the +// current locale. +bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } +bool IsAsciiPunct(char ch) { + return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); +} +bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } +bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } +bool IsAsciiWordChar(char ch) { + return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || + ('0' <= ch && ch <= '9') || ch == '_'; +} + +// Returns true iff "\\c" is a supported escape sequence. +bool IsValidEscape(char c) { + return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); +} + +// Returns true iff the given atom (specified by escaped and pattern) +// matches ch. The result is undefined if the atom is invalid. +bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { + if (escaped) { // "\\p" where p is pattern_char. + switch (pattern_char) { + case 'd': return IsAsciiDigit(ch); + case 'D': return !IsAsciiDigit(ch); + case 'f': return ch == '\f'; + case 'n': return ch == '\n'; + case 'r': return ch == '\r'; + case 's': return IsAsciiWhiteSpace(ch); + case 'S': return !IsAsciiWhiteSpace(ch); + case 't': return ch == '\t'; + case 'v': return ch == '\v'; + case 'w': return IsAsciiWordChar(ch); + case 'W': return !IsAsciiWordChar(ch); + } + return IsAsciiPunct(pattern_char) && pattern_char == ch; + } + + return (pattern_char == '.' && ch != '\n') || pattern_char == ch; +} + +// Helper function used by ValidateRegex() to format error messages. +std::string FormatRegexSyntaxError(const char* regex, int index) { + return (Message() << "Syntax error at index " << index + << " in simple regular expression \"" << regex << "\": ").GetString(); +} + +// Generates non-fatal failures and returns false if regex is invalid; +// otherwise returns true. +bool ValidateRegex(const char* regex) { + if (regex == NULL) { + // TODO(wan@google.com): fix the source file location in the + // assertion failures to match where the regex is used in user + // code. + ADD_FAILURE() << "NULL is not a valid simple regular expression."; + return false; + } + + bool is_valid = true; + + // True iff ?, *, or + can follow the previous atom. + bool prev_repeatable = false; + for (int i = 0; regex[i]; i++) { + if (regex[i] == '\\') { // An escape sequence + i++; + if (regex[i] == '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "'\\' cannot appear at the end."; + return false; + } + + if (!IsValidEscape(regex[i])) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) + << "invalid escape sequence \"\\" << regex[i] << "\"."; + is_valid = false; + } + prev_repeatable = true; + } else { // Not an escape sequence. + const char ch = regex[i]; + + if (ch == '^' && i > 0) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'^' can only appear at the beginning."; + is_valid = false; + } else if (ch == '$' && regex[i + 1] != '\0') { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'$' can only appear at the end."; + is_valid = false; + } else if (IsInSet(ch, "()[]{}|")) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' is unsupported."; + is_valid = false; + } else if (IsRepeat(ch) && !prev_repeatable) { + ADD_FAILURE() << FormatRegexSyntaxError(regex, i) + << "'" << ch << "' can only follow a repeatable token."; + is_valid = false; + } + + prev_repeatable = !IsInSet(ch, "^$?*+"); + } + } + + return is_valid; +} + +// Matches a repeated regex atom followed by a valid simple regular +// expression. The regex atom is defined as c if escaped is false, +// or \c otherwise. repeat is the repetition meta character (?, *, +// or +). The behavior is undefined if str contains too many +// characters to be indexable by size_t, in which case the test will +// probably time out anyway. We are fine with this limitation as +// std::string has it too. +bool MatchRepetitionAndRegexAtHead( + bool escaped, char c, char repeat, const char* regex, + const char* str) { + const size_t min_count = (repeat == '+') ? 1 : 0; + const size_t max_count = (repeat == '?') ? 1 : + static_cast(-1) - 1; + // We cannot call numeric_limits::max() as it conflicts with the + // max() macro on Windows. + + for (size_t i = 0; i <= max_count; ++i) { + // We know that the atom matches each of the first i characters in str. + if (i >= min_count && MatchRegexAtHead(regex, str + i)) { + // We have enough matches at the head, and the tail matches too. + // Since we only care about *whether* the pattern matches str + // (as opposed to *how* it matches), there is no need to find a + // greedy match. + return true; + } + if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) + return false; + } + return false; +} + +// Returns true iff regex matches a prefix of str. regex must be a +// valid simple regular expression and not start with "^", or the +// result is undefined. +bool MatchRegexAtHead(const char* regex, const char* str) { + if (*regex == '\0') // An empty regex matches a prefix of anything. + return true; + + // "$" only matches the end of a string. Note that regex being + // valid guarantees that there's nothing after "$" in it. + if (*regex == '$') + return *str == '\0'; + + // Is the first thing in regex an escape sequence? + const bool escaped = *regex == '\\'; + if (escaped) + ++regex; + if (IsRepeat(regex[1])) { + // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so + // here's an indirect recursion. It terminates as the regex gets + // shorter in each recursion. + return MatchRepetitionAndRegexAtHead( + escaped, regex[0], regex[1], regex + 2, str); + } else { + // regex isn't empty, isn't "$", and doesn't start with a + // repetition. We match the first atom of regex with the first + // character of str and recurse. + return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && + MatchRegexAtHead(regex + 1, str + 1); + } +} + +// Returns true iff regex matches any substring of str. regex must be +// a valid simple regular expression, or the result is undefined. +// +// The algorithm is recursive, but the recursion depth doesn't exceed +// the regex length, so we won't need to worry about running out of +// stack space normally. In rare cases the time complexity can be +// exponential with respect to the regex length + the string length, +// but usually it's must faster (often close to linear). +bool MatchRegexAnywhere(const char* regex, const char* str) { + if (regex == NULL || str == NULL) + return false; + + if (*regex == '^') + return MatchRegexAtHead(regex + 1, str); + + // A successful match can be anywhere in str. + do { + if (MatchRegexAtHead(regex, str)) + return true; + } while (*str++ != '\0'); + return false; +} + +// Implements the RE class. + +RE::~RE() { + free(const_cast(pattern_)); + free(const_cast(full_pattern_)); +} + +// Returns true iff regular expression re matches the entire str. +bool RE::FullMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); +} + +// Returns true iff regular expression re matches a substring of str +// (including str itself). +bool RE::PartialMatch(const char* str, const RE& re) { + return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); +} + +// Initializes an RE from its string representation. +void RE::Init(const char* regex) { + pattern_ = full_pattern_ = NULL; + if (regex != NULL) { + pattern_ = posix::StrDup(regex); + } + + is_valid_ = ValidateRegex(regex); + if (!is_valid_) { + // No need to calculate the full pattern when the regex is invalid. + return; + } + + const size_t len = strlen(regex); + // Reserves enough bytes to hold the regular expression used for a + // full match: we need space to prepend a '^', append a '$', and + // terminate the string with '\0'. + char* buffer = static_cast(malloc(len + 3)); + full_pattern_ = buffer; + + if (*regex != '^') + *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. + + // We don't use snprintf or strncpy, as they trigger a warning when + // compiled with VC++ 8.0. + memcpy(buffer, regex, len); + buffer += len; + + if (len == 0 || regex[len - 1] != '$') + *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. + + *buffer = '\0'; +} + +#endif // GTEST_USES_POSIX_RE + +const char kUnknownFile[] = "unknown file"; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { + const std::string file_name(file == NULL ? kUnknownFile : file); + + if (line < 0) { + return file_name + ":"; + } +#ifdef _MSC_VER + return file_name + "(" + StreamableToString(line) + "):"; +#else + return file_name + ":" + StreamableToString(line) + ":"; +#endif // _MSC_VER +} + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +// Note that FormatCompilerIndependentFileLocation() does NOT append colon +// to the file location it produces, unlike FormatFileLocation(). +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( + const char* file, int line) { + const std::string file_name(file == NULL ? kUnknownFile : file); + + if (line < 0) + return file_name; + else + return file_name + ":" + StreamableToString(line); +} + + +GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) + : severity_(severity) { + const char* const marker = + severity == GTEST_INFO ? "[ INFO ]" : + severity == GTEST_WARNING ? "[WARNING]" : + severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; + GetStream() << ::std::endl << marker << " " + << FormatFileLocation(file, line).c_str() << ": "; +} + +// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. +GTestLog::~GTestLog() { + GetStream() << ::std::endl; + if (severity_ == GTEST_FATAL) { + fflush(stderr); + posix::Abort(); + } +} +// Disable Microsoft deprecation warnings for POSIX functions called from +// this class (creat, dup, dup2, and close) +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable: 4996) +#endif // _MSC_VER + +#if GTEST_HAS_STREAM_REDIRECTION + +// Object that captures an output stream (stdout/stderr). +class CapturedStream { + public: + // The ctor redirects the stream to a temporary file. + explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { +# if GTEST_OS_WINDOWS + char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT + char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT + + ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); + const UINT success = ::GetTempFileNameA(temp_dir_path, + "gtest_redir", + 0, // Generate unique file name. + temp_file_path); + GTEST_CHECK_(success != 0) + << "Unable to create a temporary file in " << temp_dir_path; + const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); + GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " + << temp_file_path; + filename_ = temp_file_path; +# else + // There's no guarantee that a test has write access to the current + // directory, so we create the temporary file in the /tmp directory + // instead. We use /tmp on most systems, and /sdcard on Android. + // That's because Android doesn't have /tmp. +# if GTEST_OS_LINUX_ANDROID + // Note: Android applications are expected to call the framework's + // Context.getExternalStorageDirectory() method through JNI to get + // the location of the world-writable SD Card directory. However, + // this requires a Context handle, which cannot be retrieved + // globally from native code. Doing so also precludes running the + // code as part of a regular standalone executable, which doesn't + // run in a Dalvik process (e.g. when running it through 'adb shell'). + // + // The location /sdcard is directly accessible from native code + // and is the only location (unofficially) supported by the Android + // team. It's generally a symlink to the real SD Card mount point + // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or + // other OEM-customized locations. Never rely on these, and always + // use /sdcard. + char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; +# else + char name_template[] = "/tmp/captured_stream.XXXXXX"; +# endif // GTEST_OS_LINUX_ANDROID + const int captured_fd = mkstemp(name_template); + filename_ = name_template; +# endif // GTEST_OS_WINDOWS + fflush(NULL); + dup2(captured_fd, fd_); + close(captured_fd); + } + + ~CapturedStream() { + remove(filename_.c_str()); + } + + std::string GetCapturedString() { + if (uncaptured_fd_ != -1) { + // Restores the original stream. + fflush(NULL); + dup2(uncaptured_fd_, fd_); + close(uncaptured_fd_); + uncaptured_fd_ = -1; + } + + FILE* const file = posix::FOpen(filename_.c_str(), "r"); + const std::string content = ReadEntireFile(file); + posix::FClose(file); + return content; + } + + private: + // Reads the entire content of a file as an std::string. + static std::string ReadEntireFile(FILE* file); + + // Returns the size (in bytes) of a file. + static size_t GetFileSize(FILE* file); + + const int fd_; // A stream to capture. + int uncaptured_fd_; + // Name of the temporary file holding the stderr output. + ::std::string filename_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); +}; + +// Returns the size (in bytes) of a file. +size_t CapturedStream::GetFileSize(FILE* file) { + fseek(file, 0, SEEK_END); + return static_cast(ftell(file)); +} + +// Reads the entire content of a file as a string. +std::string CapturedStream::ReadEntireFile(FILE* file) { + const size_t file_size = GetFileSize(file); + char* const buffer = new char[file_size]; + + size_t bytes_last_read = 0; // # of bytes read in the last fread() + size_t bytes_read = 0; // # of bytes read so far + + fseek(file, 0, SEEK_SET); + + // Keeps reading the file until we cannot read further or the + // pre-determined file size is reached. + do { + bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); + bytes_read += bytes_last_read; + } while (bytes_last_read > 0 && bytes_read < file_size); + + const std::string content(buffer, bytes_read); + delete[] buffer; + + return content; +} + +# ifdef _MSC_VER +# pragma warning(pop) +# endif // _MSC_VER + +static CapturedStream* g_captured_stderr = NULL; +static CapturedStream* g_captured_stdout = NULL; + +// Starts capturing an output stream (stdout/stderr). +void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { + if (*stream != NULL) { + GTEST_LOG_(FATAL) << "Only one " << stream_name + << " capturer can exist at a time."; + } + *stream = new CapturedStream(fd); +} + +// Stops capturing the output stream and returns the captured string. +std::string GetCapturedStream(CapturedStream** captured_stream) { + const std::string content = (*captured_stream)->GetCapturedString(); + + delete *captured_stream; + *captured_stream = NULL; + + return content; +} + +// Starts capturing stdout. +void CaptureStdout() { + CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); +} + +// Starts capturing stderr. +void CaptureStderr() { + CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); +} + +// Stops capturing stdout and returns the captured string. +std::string GetCapturedStdout() { + return GetCapturedStream(&g_captured_stdout); +} + +// Stops capturing stderr and returns the captured string. +std::string GetCapturedStderr() { + return GetCapturedStream(&g_captured_stderr); +} + +#endif // GTEST_HAS_STREAM_REDIRECTION + +#if GTEST_HAS_DEATH_TEST + +// A copy of all command line arguments. Set by InitGoogleTest(). +::std::vector g_argvs; + +static const ::std::vector* g_injected_test_argvs = + NULL; // Owned. + +void SetInjectableArgvs(const ::std::vector* argvs) { + if (g_injected_test_argvs != argvs) + delete g_injected_test_argvs; + g_injected_test_argvs = argvs; +} + +const ::std::vector& GetInjectableArgvs() { + if (g_injected_test_argvs != NULL) { + return *g_injected_test_argvs; + } + return g_argvs; +} +#endif // GTEST_HAS_DEATH_TEST + +#if GTEST_OS_WINDOWS_MOBILE +namespace posix { +void Abort() { + DebugBreak(); + TerminateProcess(GetCurrentProcess(), 1); +} +} // namespace posix +#endif // GTEST_OS_WINDOWS_MOBILE + +// Returns the name of the environment variable corresponding to the +// given flag. For example, FlagToEnvVar("foo") will return +// "GTEST_FOO" in the open-source version. +static std::string FlagToEnvVar(const char* flag) { + const std::string full_flag = + (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); + + Message env_var; + for (size_t i = 0; i != full_flag.length(); i++) { + env_var << ToUpper(full_flag.c_str()[i]); + } + + return env_var.GetString(); +} + +// Parses 'str' for a 32-bit signed integer. If successful, writes +// the result to *value and returns true; otherwise leaves *value +// unchanged and returns false. +bool ParseInt32(const Message& src_text, const char* str, Int32* value) { + // Parses the environment variable as a decimal integer. + char* end = NULL; + const long long_value = strtol(str, &end, 10); // NOLINT + + // Has strtol() consumed all characters in the string? + if (*end != '\0') { + // No - an invalid character was encountered. + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value \"" << str << "\".\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + // Is the parsed value in the range of an Int32? + const Int32 result = static_cast(long_value); + if (long_value == LONG_MAX || long_value == LONG_MIN || + // The parsed value overflows as a long. (strtol() returns + // LONG_MAX or LONG_MIN when the input overflows.) + result != long_value + // The parsed value overflows as an Int32. + ) { + Message msg; + msg << "WARNING: " << src_text + << " is expected to be a 32-bit integer, but actually" + << " has value " << str << ", which overflows.\n"; + printf("%s", msg.GetString().c_str()); + fflush(stdout); + return false; + } + + *value = result; + return true; +} + +// Reads and returns the Boolean environment variable corresponding to +// the given flag; if it's not set, returns default_value. +// +// The value is considered true iff it's not "0". +bool BoolFromGTestEnv(const char* flag, bool default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + return string_value == NULL ? + default_value : strcmp(string_value, "0") != 0; +} + +// Reads and returns a 32-bit integer stored in the environment +// variable corresponding to the given flag; if it isn't set or +// doesn't represent a valid 32-bit integer, returns default_value. +Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const string_value = posix::GetEnv(env_var.c_str()); + if (string_value == NULL) { + // The environment variable is not set. + return default_value; + } + + Int32 result = default_value; + if (!ParseInt32(Message() << "Environment variable " << env_var, + string_value, &result)) { + printf("The default value %s is used.\n", + (Message() << default_value).GetString().c_str()); + fflush(stdout); + return default_value; + } + + return result; +} + +// Reads and returns the string environment variable corresponding to +// the given flag; if it's not set, returns default_value. +const char* StringFromGTestEnv(const char* flag, const char* default_value) { + const std::string env_var = FlagToEnvVar(flag); + const char* const value = posix::GetEnv(env_var.c_str()); + return value == NULL ? default_value : value; +} + +} // namespace internal +} // namespace testing +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// It uses the << operator when possible, and prints the bytes in the +// object otherwise. A user can override its behavior for a class +// type Foo by defining either operator<<(::std::ostream&, const Foo&) +// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that +// defines Foo. + +#include +#include +#include // NOLINT +#include + +namespace testing { + +namespace { + +using ::std::ostream; + +// Prints a segment of bytes in the given object. +void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, + size_t count, ostream* os) { + char text[5] = ""; + for (size_t i = 0; i != count; i++) { + const size_t j = start + i; + if (i != 0) { + // Organizes the bytes into groups of 2 for easy parsing by + // human. + if ((j % 2) == 0) + *os << ' '; + else + *os << '-'; + } + GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); + *os << text; + } +} + +// Prints the bytes in the given value to the given ostream. +void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, + ostream* os) { + // Tells the user how big the object is. + *os << count << "-byte object <"; + + const size_t kThreshold = 132; + const size_t kChunkSize = 64; + // If the object size is bigger than kThreshold, we'll have to omit + // some details by printing only the first and the last kChunkSize + // bytes. + // TODO(wan): let the user control the threshold using a flag. + if (count < kThreshold) { + PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); + } else { + PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); + *os << " ... "; + // Rounds up to 2-byte boundary. + const size_t resume_pos = (count - kChunkSize + 1)/2*2; + PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); + } + *os << ">"; +} + +} // namespace + +namespace internal2 { + +// Delegates to PrintBytesInObjectToImpl() to print the bytes in the +// given object. The delegation simplifies the implementation, which +// uses the << operator and thus is easier done outside of the +// ::testing::internal namespace, which contains a << operator that +// sometimes conflicts with the one in STL. +void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, + ostream* os) { + PrintBytesInObjectToImpl(obj_bytes, count, os); +} + +} // namespace internal2 + +namespace internal { + +// Depending on the value of a char (or wchar_t), we print it in one +// of three formats: +// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), +// - as a hexidecimal escape sequence (e.g. '\x7F'), or +// - as a special escape sequence (e.g. '\r', '\n'). +enum CharFormat { + kAsIs, + kHexEscape, + kSpecialEscape +}; + +// Returns true if c is a printable ASCII character. We test the +// value of c directly instead of calling isprint(), which is buggy on +// Windows Mobile. +inline bool IsPrintableAscii(wchar_t c) { + return 0x20 <= c && c <= 0x7E; +} + +// Prints a wide or narrow char c as a character literal without the +// quotes, escaping it when necessary; returns how c was formatted. +// The template argument UnsignedChar is the unsigned version of Char, +// which is the type of c. +template +static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { + switch (static_cast(c)) { + case L'\0': + *os << "\\0"; + break; + case L'\'': + *os << "\\'"; + break; + case L'\\': + *os << "\\\\"; + break; + case L'\a': + *os << "\\a"; + break; + case L'\b': + *os << "\\b"; + break; + case L'\f': + *os << "\\f"; + break; + case L'\n': + *os << "\\n"; + break; + case L'\r': + *os << "\\r"; + break; + case L'\t': + *os << "\\t"; + break; + case L'\v': + *os << "\\v"; + break; + default: + if (IsPrintableAscii(c)) { + *os << static_cast(c); + return kAsIs; + } else { + *os << "\\x" + String::FormatHexInt(static_cast(c)); + return kHexEscape; + } + } + return kSpecialEscape; +} + +// Prints a wchar_t c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { + switch (c) { + case L'\'': + *os << "'"; + return kAsIs; + case L'"': + *os << "\\\""; + return kSpecialEscape; + default: + return PrintAsCharLiteralTo(c, os); + } +} + +// Prints a char c as if it's part of a string literal, escaping it when +// necessary; returns how c was formatted. +static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { + return PrintAsStringLiteralTo( + static_cast(static_cast(c)), os); +} + +// Prints a wide or narrow character c and its code. '\0' is printed +// as "'\\0'", other unprintable characters are also properly escaped +// using the standard C++ escape sequence. The template argument +// UnsignedChar is the unsigned version of Char, which is the type of c. +template +void PrintCharAndCodeTo(Char c, ostream* os) { + // First, print c as a literal in the most readable form we can find. + *os << ((sizeof(c) > 1) ? "L'" : "'"); + const CharFormat format = PrintAsCharLiteralTo(c, os); + *os << "'"; + + // To aid user debugging, we also print c's code in decimal, unless + // it's 0 (in which case c was printed as '\\0', making the code + // obvious). + if (c == 0) + return; + *os << " (" << static_cast(c); + + // For more convenience, we print c's code again in hexidecimal, + // unless c was already printed in the form '\x##' or the code is in + // [1, 9]. + if (format == kHexEscape || (1 <= c && c <= 9)) { + // Do nothing. + } else { + *os << ", 0x" << String::FormatHexInt(static_cast(c)); + } + *os << ")"; +} + +void PrintTo(unsigned char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} +void PrintTo(signed char c, ::std::ostream* os) { + PrintCharAndCodeTo(c, os); +} + +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its code. L'\0' is printed as "L'\\0'". +void PrintTo(wchar_t wc, ostream* os) { + PrintCharAndCodeTo(wc, os); +} + +// Prints the given array of characters to the ostream. CharType must be either +// char or wchar_t. +// The array starts at begin, the length is len, it may include '\0' characters +// and may not be NUL-terminated. +template +static void PrintCharsAsStringTo( + const CharType* begin, size_t len, ostream* os) { + const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; + *os << kQuoteBegin; + bool is_previous_hex = false; + for (size_t index = 0; index < len; ++index) { + const CharType cur = begin[index]; + if (is_previous_hex && IsXDigit(cur)) { + // Previous character is of '\x..' form and this character can be + // interpreted as another hexadecimal digit in its number. Break string to + // disambiguate. + *os << "\" " << kQuoteBegin; + } + is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; + } + *os << "\""; +} + +// Prints a (const) char/wchar_t array of 'len' elements, starting at address +// 'begin'. CharType must be either char or wchar_t. +template +static void UniversalPrintCharArray( + const CharType* begin, size_t len, ostream* os) { + // The code + // const char kFoo[] = "foo"; + // generates an array of 4, not 3, elements, with the last one being '\0'. + // + // Therefore when printing a char array, we don't print the last element if + // it's '\0', such that the output matches the string literal as it's + // written in the source code. + if (len > 0 && begin[len - 1] == '\0') { + PrintCharsAsStringTo(begin, len - 1, os); + return; + } + + // If, however, the last element in the array is not '\0', e.g. + // const char kFoo[] = { 'f', 'o', 'o' }; + // we must print the entire array. We also print a message to indicate + // that the array is not NUL-terminated. + PrintCharsAsStringTo(begin, len, os); + *os << " (no terminating NUL)"; +} + +// Prints a (const) char array of 'len' elements, starting at address 'begin'. +void UniversalPrintArray(const char* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints a (const) wchar_t array of 'len' elements, starting at address +// 'begin'. +void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { + UniversalPrintCharArray(begin, len, os); +} + +// Prints the given C string to the ostream. +void PrintTo(const char* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, strlen(s), os); + } +} + +// MSVC compiler can be configured to define whar_t as a typedef +// of unsigned short. Defining an overload for const wchar_t* in that case +// would cause pointers to unsigned shorts be printed as wide strings, +// possibly accessing more memory than intended and causing invalid +// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when +// wchar_t is implemented as a native type. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Prints the given wide C string to the ostream. +void PrintTo(const wchar_t* s, ostream* os) { + if (s == NULL) { + *os << "NULL"; + } else { + *os << ImplicitCast_(s) << " pointing to "; + PrintCharsAsStringTo(s, wcslen(s), os); + } +} +#endif // wchar_t is native + +// Prints a ::string object. +#if GTEST_HAS_GLOBAL_STRING +void PrintStringTo(const ::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +void PrintStringTo(const ::std::string& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} + +// Prints a ::wstring object. +#if GTEST_HAS_GLOBAL_WSTRING +void PrintWideStringTo(const ::wstring& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +void PrintWideStringTo(const ::std::wstring& s, ostream* os) { + PrintCharsAsStringTo(s.data(), s.size(), os); +} +#endif // GTEST_HAS_STD_WSTRING + +} // namespace internal + +} // namespace testing +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: mheule@google.com (Markus Heule) +// +// The Google C++ Testing Framework (Google Test) + + +// Indicates that this translation unit is part of Google Test's +// implementation. It must come before gtest-internal-inl.h is +// included, or there will be a compiler error. This trick is to +// prevent a user from accidentally including gtest-internal-inl.h in +// his code. +#define GTEST_IMPLEMENTATION_ 1 +#undef GTEST_IMPLEMENTATION_ + +namespace testing { + +using internal::GetUnitTestImpl; + +// Gets the summary of the failure message by omitting the stack trace +// in it. +std::string TestPartResult::ExtractSummary(const char* message) { + const char* const stack_trace = strstr(message, internal::kStackTraceMarker); + return stack_trace == NULL ? message : + std::string(message, stack_trace); +} + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { + return os + << result.file_name() << ":" << result.line_number() << ": " + << (result.type() == TestPartResult::kSuccess ? "Success" : + result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : + "Non-fatal failure") << ":\n" + << result.message() << std::endl; +} + +// Appends a TestPartResult to the array. +void TestPartResultArray::Append(const TestPartResult& result) { + array_.push_back(result); +} + +// Returns the TestPartResult at the given index (0-based). +const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { + if (index < 0 || index >= size()) { + printf("\nInvalid index (%d) into TestPartResultArray.\n", index); + internal::posix::Abort(); + } + + return array_[index]; +} + +// Returns the number of TestPartResult objects in the array. +int TestPartResultArray::size() const { + return static_cast(array_.size()); +} + +namespace internal { + +HasNewFatalFailureHelper::HasNewFatalFailureHelper() + : has_new_fatal_failure_(false), + original_reporter_(GetUnitTestImpl()-> + GetTestPartResultReporterForCurrentThread()) { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); +} + +HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { + GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( + original_reporter_); +} + +void HasNewFatalFailureHelper::ReportTestPartResult( + const TestPartResult& result) { + if (result.fatally_failed()) + has_new_fatal_failure_ = true; + original_reporter_->ReportTestPartResult(result); +} + +} // namespace internal + +} // namespace testing +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + + +namespace testing { +namespace internal { + +#if GTEST_HAS_TYPED_TEST_P + +// Skips to the first non-space char in str. Returns an empty string if str +// contains only whitespace characters. +static const char* SkipSpaces(const char* str) { + while (IsSpace(*str)) + str++; + return str; +} + +// Verifies that registered_tests match the test names in +// defined_test_names_; returns registered_tests if successful, or +// aborts the program otherwise. +const char* TypedTestCasePState::VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests) { + typedef ::std::set::const_iterator DefinedTestIter; + registered_ = true; + + // Skip initial whitespace in registered_tests since some + // preprocessors prefix stringizied literals with whitespace. + registered_tests = SkipSpaces(registered_tests); + + Message errors; + ::std::set tests; + for (const char* names = registered_tests; names != NULL; + names = SkipComma(names)) { + const std::string name = GetPrefixUntilComma(names); + if (tests.count(name) != 0) { + errors << "Test " << name << " is listed more than once.\n"; + continue; + } + + bool found = false; + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (name == *it) { + found = true; + break; + } + } + + if (found) { + tests.insert(name); + } else { + errors << "No test named " << name + << " can be found in this test case.\n"; + } + } + + for (DefinedTestIter it = defined_test_names_.begin(); + it != defined_test_names_.end(); + ++it) { + if (tests.count(*it) == 0) { + errors << "You forgot to list test " << *it << ".\n"; + } + } + + const std::string& errors_str = errors.GetString(); + if (errors_str != "") { + fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), + errors_str.c_str()); + fflush(stderr); + posix::Abort(); + } + + return registered_tests; +} + +#endif // GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing diff --git a/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h b/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h new file mode 120000 index 0000000000..48d39090f1 --- /dev/null +++ b/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h @@ -0,0 +1 @@ +gtest.h \ No newline at end of file diff --git a/lib/kokkos/tpls/gtest/gtest/gtest.h b/lib/kokkos/tpls/gtest/gtest/gtest.h new file mode 100644 index 0000000000..c74d098fa9 --- /dev/null +++ b/lib/kokkos/tpls/gtest/gtest/gtest.h @@ -0,0 +1,20065 @@ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for Google Test. It should be +// included by any test program that uses Google Test. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! +// +// Acknowledgment: Google Test borrowed the idea of automatic test +// registration from Barthelemy Dagenais' (barthelemy@prologique.com) +// easyUnit framework. + +#ifdef __GNUC__ +#pragma GCC system_header +#endif + +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_H_ + +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares functions and macros used internally by +// Google Test. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: wan@google.com (Zhanyong Wan) +// +// Low-level types and utilities for porting Google Test to various +// platforms. They are subject to change without notice. DO NOT USE +// THEM IN USER CODE. +// +// This file is fundamental to Google Test. All other Google Test source +// files are expected to #include this. Therefore, it cannot #include +// any other Google Test header. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +// The user can define the following macros in the build script to +// control Google Test's behavior. If the user doesn't define a macro +// in this list, Google Test will define it. +// +// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) +// is/isn't available. +// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions +// are enabled. +// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::string, which is different to std::string). +// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string +// is/isn't available (some systems define +// ::wstring, which is different to std::wstring). +// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular +// expressions are/aren't available. +// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that +// is/isn't available. +// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't +// enabled. +// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that +// std::wstring does/doesn't work (Google Test can +// be used where std::wstring is unavailable). +// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple +// is/isn't available. +// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the +// compiler supports Microsoft's "Structured +// Exception Handling". +// GTEST_HAS_STREAM_REDIRECTION +// - Define it to 1/0 to indicate whether the +// platform supports I/O stream redirection using +// dup() and dup2(). +// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google +// Test's own tr1 tuple implementation should be +// used. Unused when the user sets +// GTEST_HAS_TR1_TUPLE to 0. +// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test +// is building in C++11/C++98 mode. +// GTEST_LINKED_AS_SHARED_LIBRARY +// - Define to 1 when compiling tests that use +// Google Test as a shared library (known as +// DLL on Windows). +// GTEST_CREATE_SHARED_LIBRARY +// - Define to 1 when compiling Google Test itself +// as a shared library. + +// This header defines the following utilities: +// +// Macros indicating the current platform (defined to 1 if compiled on +// the given platform; otherwise undefined): +// GTEST_OS_AIX - IBM AIX +// GTEST_OS_CYGWIN - Cygwin +// GTEST_OS_HPUX - HP-UX +// GTEST_OS_LINUX - Linux +// GTEST_OS_LINUX_ANDROID - Google Android +// GTEST_OS_MAC - Mac OS X +// GTEST_OS_IOS - iOS +// GTEST_OS_IOS_SIMULATOR - iOS simulator +// GTEST_OS_NACL - Google Native Client (NaCl) +// GTEST_OS_OPENBSD - OpenBSD +// GTEST_OS_QNX - QNX +// GTEST_OS_SOLARIS - Sun Solaris +// GTEST_OS_SYMBIAN - Symbian +// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) +// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop +// GTEST_OS_WINDOWS_MINGW - MinGW +// GTEST_OS_WINDOWS_MOBILE - Windows Mobile +// GTEST_OS_ZOS - z/OS +// +// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the +// most stable support. Since core members of the Google Test project +// don't have access to other platforms, support for them may be less +// stable. If you notice any problems on your platform, please notify +// googletestframework@googlegroups.com (patches for fixing them are +// even more welcome!). +// +// Note that it is possible that none of the GTEST_OS_* macros are defined. +// +// Macros indicating available Google Test features (defined to 1 if +// the corresponding feature is supported; otherwise undefined): +// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized +// tests) +// GTEST_HAS_DEATH_TEST - death tests +// GTEST_HAS_PARAM_TEST - value-parameterized tests +// GTEST_HAS_TYPED_TEST - typed tests +// GTEST_HAS_TYPED_TEST_P - type-parameterized tests +// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with +// GTEST_HAS_POSIX_RE (see above) which users can +// define themselves. +// GTEST_USES_SIMPLE_RE - our own simple regex is used; +// the above two are mutually exclusive. +// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). +// +// Macros for basic C++ coding: +// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. +// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a +// variable don't have to be used. +// GTEST_DISALLOW_ASSIGN_ - disables operator=. +// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. +// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. +// +// Synchronization: +// Mutex, MutexLock, ThreadLocal, GetThreadCount() +// - synchronization primitives. +// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above +// synchronization primitives have real implementations +// and Google Test is thread-safe; or 0 otherwise. +// +// Template meta programming: +// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. +// IteratorTraits - partial implementation of std::iterator_traits, which +// is not available in libCstd when compiled with Sun C++. +// +// Smart pointers: +// scoped_ptr - as in TR2. +// +// Regular expressions: +// RE - a simple regular expression class using the POSIX +// Extended Regular Expression syntax on UNIX-like +// platforms, or a reduced regular exception syntax on +// other platforms, including Windows. +// +// Logging: +// GTEST_LOG_() - logs messages at the specified severity level. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. +// +// Stdout and stderr capturing: +// CaptureStdout() - starts capturing stdout. +// GetCapturedStdout() - stops capturing stdout and returns the captured +// string. +// CaptureStderr() - starts capturing stderr. +// GetCapturedStderr() - stops capturing stderr and returns the captured +// string. +// +// Integer types: +// TypeWithSize - maps an integer to a int type. +// Int32, UInt32, Int64, UInt64, TimeInMillis +// - integers of known sizes. +// BiggestInt - the biggest signed integer type. +// +// Command-line utilities: +// GTEST_FLAG() - references a flag. +// GTEST_DECLARE_*() - declares a flag. +// GTEST_DEFINE_*() - defines a flag. +// GetInjectableArgvs() - returns the command line as a vector of strings. +// +// Environment variable utilities: +// GetEnv() - gets the value of an environment variable. +// BoolFromGTestEnv() - parses a bool environment variable. +// Int32FromGTestEnv() - parses an Int32 environment variable. +// StringFromGTestEnv() - parses a string environment variable. + +#include // for isspace, etc +#include // for ptrdiff_t +#include +#include +#include +#ifndef _WIN32_WCE +# include +# include +#endif // !_WIN32_WCE + +#if defined __APPLE__ +# include +# include +#endif + +#include // NOLINT +#include // NOLINT +#include // NOLINT + +#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" +#define GTEST_FLAG_PREFIX_ "gtest_" +#define GTEST_FLAG_PREFIX_DASH_ "gtest-" +#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" +#define GTEST_NAME_ "Google Test" +#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" + +// Determines the version of gcc that is used to compile this. +#ifdef __GNUC__ +// 40302 means version 4.3.2. +# define GTEST_GCC_VER_ \ + (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) +#endif // __GNUC__ + +// Determines the platform on which Google Test is compiled. +#ifdef __CYGWIN__ +# define GTEST_OS_CYGWIN 1 +#elif defined __SYMBIAN32__ +# define GTEST_OS_SYMBIAN 1 +#elif defined _WIN32 +# define GTEST_OS_WINDOWS 1 +# ifdef _WIN32_WCE +# define GTEST_OS_WINDOWS_MOBILE 1 +# elif defined(__MINGW__) || defined(__MINGW32__) +# define GTEST_OS_WINDOWS_MINGW 1 +# else +# define GTEST_OS_WINDOWS_DESKTOP 1 +# endif // _WIN32_WCE +#elif defined __APPLE__ +# define GTEST_OS_MAC 1 +# if TARGET_OS_IPHONE +# define GTEST_OS_IOS 1 +# if TARGET_IPHONE_SIMULATOR +# define GTEST_OS_IOS_SIMULATOR 1 +# endif +# endif +#elif defined __linux__ +# define GTEST_OS_LINUX 1 +# if defined __ANDROID__ +# define GTEST_OS_LINUX_ANDROID 1 +# endif +#elif defined __MVS__ +# define GTEST_OS_ZOS 1 +#elif defined(__sun) && defined(__SVR4) +# define GTEST_OS_SOLARIS 1 +#elif defined(_AIX) +# define GTEST_OS_AIX 1 +#elif defined(__hpux) +# define GTEST_OS_HPUX 1 +#elif defined __native_client__ +# define GTEST_OS_NACL 1 +#elif defined __OpenBSD__ +# define GTEST_OS_OPENBSD 1 +#elif defined __QNX__ +# define GTEST_OS_QNX 1 +#endif // __CYGWIN__ + +#ifndef GTEST_LANG_CXX11 +// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when +// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a +// value for __cplusplus, and recent versions of clang, gcc, and +// probably other compilers set that too in C++11 mode. +# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L +// Compiling in at least C++11 mode. +# define GTEST_LANG_CXX11 1 +# else +# define GTEST_LANG_CXX11 0 +# endif +#endif + +// Brings in definitions for functions used in the testing::internal::posix +// namespace (read, write, close, chdir, isatty, stat). We do not currently +// use them on Windows Mobile. +#if !GTEST_OS_WINDOWS +// This assumes that non-Windows OSes provide unistd.h. For OSes where this +// is not the case, we need to include headers that provide the functions +// mentioned above. +# include +# include +#elif !GTEST_OS_WINDOWS_MOBILE +# include +# include +#endif + +#if GTEST_OS_LINUX_ANDROID +// Used to define __ANDROID_API__ matching the target NDK API level. +# include // NOLINT +#endif + +// Defines this to true iff Google Test can use POSIX regular expressions. +#ifndef GTEST_HAS_POSIX_RE +# if GTEST_OS_LINUX_ANDROID +// On Android, is only available starting with Gingerbread. +# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) +# else +# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) +# endif +#endif + +#if GTEST_HAS_POSIX_RE + +// On some platforms, needs someone to define size_t, and +// won't compile otherwise. We can #include it here as we already +// included , which is guaranteed to define size_t through +// . +# include // NOLINT + +# define GTEST_USES_POSIX_RE 1 + +#elif GTEST_OS_WINDOWS + +// is not available on Windows. Use our own simple regex +// implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#else + +// may not be available on this platform. Use our own +// simple regex implementation instead. +# define GTEST_USES_SIMPLE_RE 1 + +#endif // GTEST_HAS_POSIX_RE + +#ifndef GTEST_HAS_EXCEPTIONS +// The user didn't tell us whether exceptions are enabled, so we need +// to figure it out. +# if defined(_MSC_VER) || defined(__BORLANDC__) +// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS +// macro to enable exceptions, so we'll do the same. +// Assumes that exceptions are enabled by default. +# ifndef _HAS_EXCEPTIONS +# define _HAS_EXCEPTIONS 1 +# endif // _HAS_EXCEPTIONS +# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS +# elif defined(__GNUC__) && __EXCEPTIONS +// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__SUNPRO_CC) +// Sun Pro CC supports exceptions. However, there is no compile-time way of +// detecting whether they are enabled or not. Therefore, we assume that +// they are enabled unless the user tells us otherwise. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__IBMCPP__) && __EXCEPTIONS +// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. +# define GTEST_HAS_EXCEPTIONS 1 +# elif defined(__HP_aCC) +// Exception handling is in effect by default in HP aCC compiler. It has to +// be turned of by +noeh compiler option if desired. +# define GTEST_HAS_EXCEPTIONS 1 +# else +// For other compilers, we assume exceptions are disabled to be +// conservative. +# define GTEST_HAS_EXCEPTIONS 0 +# endif // defined(_MSC_VER) || defined(__BORLANDC__) +#endif // GTEST_HAS_EXCEPTIONS + +#if !defined(GTEST_HAS_STD_STRING) +// Even though we don't use this macro any longer, we keep it in case +// some clients still depend on it. +# define GTEST_HAS_STD_STRING 1 +#elif !GTEST_HAS_STD_STRING +// The user told us that ::std::string isn't available. +# error "Google Test cannot be used where ::std::string isn't available." +#endif // !defined(GTEST_HAS_STD_STRING) + +#ifndef GTEST_HAS_GLOBAL_STRING +// The user didn't tell us whether ::string is available, so we need +// to figure it out. + +# define GTEST_HAS_GLOBAL_STRING 0 + +#endif // GTEST_HAS_GLOBAL_STRING + +#ifndef GTEST_HAS_STD_WSTRING +// The user didn't tell us whether ::std::wstring is available, so we need +// to figure it out. +// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring +// is available. + +// Cygwin 1.7 and below doesn't support ::std::wstring. +// Solaris' libc++ doesn't support it either. Android has +// no support for it at least as recent as Froyo (2.2). +# define GTEST_HAS_STD_WSTRING \ + (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) + +#endif // GTEST_HAS_STD_WSTRING + +#ifndef GTEST_HAS_GLOBAL_WSTRING +// The user didn't tell us whether ::wstring is available, so we need +// to figure it out. +# define GTEST_HAS_GLOBAL_WSTRING \ + (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) +#endif // GTEST_HAS_GLOBAL_WSTRING + +// Determines whether RTTI is available. +#ifndef GTEST_HAS_RTTI +// The user didn't tell us whether RTTI is enabled, so we need to +// figure it out. + +# ifdef _MSC_VER + +# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) + +# ifdef __GXX_RTTI +// When building against STLport with the Android NDK and with +// -frtti -fno-exceptions, the build fails at link time with undefined +// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, +// so disable RTTI when detected. +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ + !defined(__EXCEPTIONS) +# define GTEST_HAS_RTTI 0 +# else +# define GTEST_HAS_RTTI 1 +# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS +# else +# define GTEST_HAS_RTTI 0 +# endif // __GXX_RTTI + +// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends +// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the +// first version with C++ support. +# elif defined(__clang__) + +# define GTEST_HAS_RTTI __has_feature(cxx_rtti) + +// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if +// both the typeid and dynamic_cast features are present. +# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) + +# ifdef __RTTI_ALL__ +# define GTEST_HAS_RTTI 1 +# else +# define GTEST_HAS_RTTI 0 +# endif + +# else + +// For all other compilers, we assume RTTI is enabled. +# define GTEST_HAS_RTTI 1 + +# endif // _MSC_VER + +#endif // GTEST_HAS_RTTI + +// It's this header's responsibility to #include when RTTI +// is enabled. +#if GTEST_HAS_RTTI +# include +#endif + +// Determines whether Google Test can use the pthreads library. +#ifndef GTEST_HAS_PTHREAD +// The user didn't tell us explicitly, so we assume pthreads support is +// available on Linux and Mac. +// +// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 +// to your compiler flags. +# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ + || GTEST_OS_QNX) +#endif // GTEST_HAS_PTHREAD + +#if GTEST_HAS_PTHREAD +// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is +// true. +# include // NOLINT + +// For timespec and nanosleep, used below. +# include // NOLINT +#endif + +// Determines whether Google Test can use tr1/tuple. You can define +// this macro to 0 to prevent Google Test from using tuple (any +// feature depending on tuple with be disabled in this mode). +#ifndef GTEST_HAS_TR1_TUPLE +# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) +// STLport, provided with the Android NDK, has neither or . +# define GTEST_HAS_TR1_TUPLE 0 +# else +// The user didn't tell us not to do it, so we assume it's OK. +# define GTEST_HAS_TR1_TUPLE 1 +# endif +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether Google Test's own tr1 tuple implementation +// should be used. +#ifndef GTEST_USE_OWN_TR1_TUPLE +// The user didn't tell us, so we need to figure it out. + +// We use our own TR1 tuple if we aren't sure the user has an +// implementation of it already. At this time, libstdc++ 4.0.0+ and +// MSVC 2010 are the only mainstream standard libraries that come +// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler +// pretends to be GCC by defining __GNUC__ and friends, but cannot +// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 +// tuple in a 323 MB Feature Pack download, which we cannot assume the +// user has. QNX's QCC compiler is a modified GCC but it doesn't +// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, +// and it can be used with some compilers that define __GNUC__. +# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ + && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 +# define GTEST_ENV_HAS_TR1_TUPLE_ 1 +# endif + +// C++11 specifies that provides std::tuple. Use that if gtest is used +// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 +// can build with clang but need to use gcc4.2's libstdc++). +# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) +# define GTEST_ENV_HAS_STD_TUPLE_ 1 +# endif + +# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ +# define GTEST_USE_OWN_TR1_TUPLE 0 +# else +# define GTEST_USE_OWN_TR1_TUPLE 1 +# endif + +#endif // GTEST_USE_OWN_TR1_TUPLE + +// To avoid conditional compilation everywhere, we make it +// gtest-port.h's responsibility to #include the header implementing +// tr1/tuple. +#if GTEST_HAS_TR1_TUPLE + +# if GTEST_USE_OWN_TR1_TUPLE +// This file was GENERATED by command: +// pump.py gtest-tuple.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2009 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Implements a subset of TR1 tuple needed by Google Test and Google Mock. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ + +#include // For ::std::pair. + +// The compiler used in Symbian has a bug that prevents us from declaring the +// tuple template as a friend (it complains that tuple is redefined). This +// hack bypasses the bug by declaring the members that should otherwise be +// private as public. +// Sun Studio versions < 12 also have the above bug. +#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: +#else +# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ + template friend class tuple; \ + private: +#endif + +// GTEST_n_TUPLE_(T) is the type of an n-tuple. +#define GTEST_0_TUPLE_(T) tuple<> +#define GTEST_1_TUPLE_(T) tuple +#define GTEST_2_TUPLE_(T) tuple +#define GTEST_3_TUPLE_(T) tuple +#define GTEST_4_TUPLE_(T) tuple +#define GTEST_5_TUPLE_(T) tuple +#define GTEST_6_TUPLE_(T) tuple +#define GTEST_7_TUPLE_(T) tuple +#define GTEST_8_TUPLE_(T) tuple +#define GTEST_9_TUPLE_(T) tuple +#define GTEST_10_TUPLE_(T) tuple + +// GTEST_n_TYPENAMES_(T) declares a list of n typenames. +#define GTEST_0_TYPENAMES_(T) +#define GTEST_1_TYPENAMES_(T) typename T##0 +#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 +#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 +#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3 +#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4 +#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5 +#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6 +#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 +#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8 +#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ + typename T##3, typename T##4, typename T##5, typename T##6, \ + typename T##7, typename T##8, typename T##9 + +// In theory, defining stuff in the ::std namespace is undefined +// behavior. We can do this as we are playing the role of a standard +// library vendor. +namespace std { +namespace tr1 { + +template +class tuple; + +// Anything in namespace gtest_internal is Google Test's INTERNAL +// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. +namespace gtest_internal { + +// ByRef::type is T if T is a reference; otherwise it's const T&. +template +struct ByRef { typedef const T& type; }; // NOLINT +template +struct ByRef { typedef T& type; }; // NOLINT + +// A handy wrapper for ByRef. +#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type + +// AddRef::type is T if T is a reference; otherwise it's T&. This +// is the same as tr1::add_reference::type. +template +struct AddRef { typedef T& type; }; // NOLINT +template +struct AddRef { typedef T& type; }; // NOLINT + +// A handy wrapper for AddRef. +#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type + +// A helper for implementing get(). +template class Get; + +// A helper for implementing tuple_element. kIndexValid is true +// iff k < the number of fields in tuple type T. +template +struct TupleElement; + +template +struct TupleElement { + typedef T0 type; +}; + +template +struct TupleElement { + typedef T1 type; +}; + +template +struct TupleElement { + typedef T2 type; +}; + +template +struct TupleElement { + typedef T3 type; +}; + +template +struct TupleElement { + typedef T4 type; +}; + +template +struct TupleElement { + typedef T5 type; +}; + +template +struct TupleElement { + typedef T6 type; +}; + +template +struct TupleElement { + typedef T7 type; +}; + +template +struct TupleElement { + typedef T8 type; +}; + +template +struct TupleElement { + typedef T9 type; +}; + +} // namespace gtest_internal + +template <> +class tuple<> { + public: + tuple() {} + tuple(const tuple& /* t */) {} + tuple& operator=(const tuple& /* t */) { return *this; } +}; + +template +class GTEST_1_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} + + tuple(const tuple& t) : f0_(t.f0_) {} + + template + tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_1_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { + f0_ = t.f0_; + return *this; + } + + T0 f0_; +}; + +template +class GTEST_2_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), + f1_(f1) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} + + template + tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} + template + tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_2_TUPLE_(U)& t) { + return CopyFrom(t); + } + template + tuple& operator=(const ::std::pair& p) { + f0_ = p.first; + f1_ = p.second; + return *this; + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + return *this; + } + + T0 f0_; + T1 f1_; +}; + +template +class GTEST_3_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + template + tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_3_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; +}; + +template +class GTEST_4_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} + + template + tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_4_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; +}; + +template +class GTEST_5_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, + GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_) {} + + template + tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_5_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; +}; + +template +class GTEST_6_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_) {} + + template + tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_6_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; +}; + +template +class GTEST_7_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + template + tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_7_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; +}; + +template +class GTEST_8_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, + GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + template + tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_8_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; +}; + +template +class GTEST_9_TUPLE_(T) { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), + f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + template + tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_9_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; +}; + +template +class tuple { + public: + template friend class gtest_internal::Get; + + tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), + f9_() {} + + explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, + GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, + GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, + GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), + f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} + + tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), + f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} + + template + tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), + f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), + f9_(t.f9_) {} + + tuple& operator=(const tuple& t) { return CopyFrom(t); } + + template + tuple& operator=(const GTEST_10_TUPLE_(U)& t) { + return CopyFrom(t); + } + + GTEST_DECLARE_TUPLE_AS_FRIEND_ + + template + tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { + f0_ = t.f0_; + f1_ = t.f1_; + f2_ = t.f2_; + f3_ = t.f3_; + f4_ = t.f4_; + f5_ = t.f5_; + f6_ = t.f6_; + f7_ = t.f7_; + f8_ = t.f8_; + f9_ = t.f9_; + return *this; + } + + T0 f0_; + T1 f1_; + T2 f2_; + T3 f3_; + T4 f4_; + T5 f5_; + T6 f6_; + T7 f7_; + T8 f8_; + T9 f9_; +}; + +// 6.1.3.2 Tuple creation functions. + +// Known limitations: we don't support passing an +// std::tr1::reference_wrapper to make_tuple(). And we don't +// implement tie(). + +inline tuple<> make_tuple() { return tuple<>(); } + +template +inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { + return GTEST_1_TUPLE_(T)(f0); +} + +template +inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { + return GTEST_2_TUPLE_(T)(f0, f1); +} + +template +inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { + return GTEST_3_TUPLE_(T)(f0, f1, f2); +} + +template +inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3) { + return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); +} + +template +inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4) { + return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); +} + +template +inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5) { + return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); +} + +template +inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6) { + return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); +} + +template +inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { + return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); +} + +template +inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8) { + return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); +} + +template +inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, + const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, + const T8& f8, const T9& f9) { + return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); +} + +// 6.1.3.3 Tuple helper classes. + +template struct tuple_size; + +template +struct tuple_size { + static const int value = 0; +}; + +template +struct tuple_size { + static const int value = 1; +}; + +template +struct tuple_size { + static const int value = 2; +}; + +template +struct tuple_size { + static const int value = 3; +}; + +template +struct tuple_size { + static const int value = 4; +}; + +template +struct tuple_size { + static const int value = 5; +}; + +template +struct tuple_size { + static const int value = 6; +}; + +template +struct tuple_size { + static const int value = 7; +}; + +template +struct tuple_size { + static const int value = 8; +}; + +template +struct tuple_size { + static const int value = 9; +}; + +template +struct tuple_size { + static const int value = 10; +}; + +template +struct tuple_element { + typedef typename gtest_internal::TupleElement< + k < (tuple_size::value), k, Tuple>::type type; +}; + +#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type + +// 6.1.3.4 Element access. + +namespace gtest_internal { + +template <> +class Get<0> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + Field(Tuple& t) { return t.f0_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) + ConstField(const Tuple& t) { return t.f0_; } +}; + +template <> +class Get<1> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + Field(Tuple& t) { return t.f1_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) + ConstField(const Tuple& t) { return t.f1_; } +}; + +template <> +class Get<2> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + Field(Tuple& t) { return t.f2_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) + ConstField(const Tuple& t) { return t.f2_; } +}; + +template <> +class Get<3> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + Field(Tuple& t) { return t.f3_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) + ConstField(const Tuple& t) { return t.f3_; } +}; + +template <> +class Get<4> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + Field(Tuple& t) { return t.f4_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) + ConstField(const Tuple& t) { return t.f4_; } +}; + +template <> +class Get<5> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + Field(Tuple& t) { return t.f5_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) + ConstField(const Tuple& t) { return t.f5_; } +}; + +template <> +class Get<6> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + Field(Tuple& t) { return t.f6_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) + ConstField(const Tuple& t) { return t.f6_; } +}; + +template <> +class Get<7> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + Field(Tuple& t) { return t.f7_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) + ConstField(const Tuple& t) { return t.f7_; } +}; + +template <> +class Get<8> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + Field(Tuple& t) { return t.f8_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) + ConstField(const Tuple& t) { return t.f8_; } +}; + +template <> +class Get<9> { + public: + template + static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + Field(Tuple& t) { return t.f9_; } // NOLINT + + template + static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) + ConstField(const Tuple& t) { return t.f9_; } +}; + +} // namespace gtest_internal + +template +GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::Field(t); +} + +template +GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) +get(const GTEST_10_TUPLE_(T)& t) { + return gtest_internal::Get::ConstField(t); +} + +// 6.1.3.5 Relational operators + +// We only implement == and !=, as we don't have a need for the rest yet. + +namespace gtest_internal { + +// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the +// first k fields of t1 equals the first k fields of t2. +// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if +// k1 != k2. +template +struct SameSizeTuplePrefixComparator; + +template <> +struct SameSizeTuplePrefixComparator<0, 0> { + template + static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { + return true; + } +}; + +template +struct SameSizeTuplePrefixComparator { + template + static bool Eq(const Tuple1& t1, const Tuple2& t2) { + return SameSizeTuplePrefixComparator::Eq(t1, t2) && + ::std::tr1::get(t1) == ::std::tr1::get(t2); + } +}; + +} // namespace gtest_internal + +template +inline bool operator==(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { + return gtest_internal::SameSizeTuplePrefixComparator< + tuple_size::value, + tuple_size::value>::Eq(t, u); +} + +template +inline bool operator!=(const GTEST_10_TUPLE_(T)& t, + const GTEST_10_TUPLE_(U)& u) { return !(t == u); } + +// 6.1.4 Pairs. +// Unimplemented. + +} // namespace tr1 +} // namespace std + +#undef GTEST_0_TUPLE_ +#undef GTEST_1_TUPLE_ +#undef GTEST_2_TUPLE_ +#undef GTEST_3_TUPLE_ +#undef GTEST_4_TUPLE_ +#undef GTEST_5_TUPLE_ +#undef GTEST_6_TUPLE_ +#undef GTEST_7_TUPLE_ +#undef GTEST_8_TUPLE_ +#undef GTEST_9_TUPLE_ +#undef GTEST_10_TUPLE_ + +#undef GTEST_0_TYPENAMES_ +#undef GTEST_1_TYPENAMES_ +#undef GTEST_2_TYPENAMES_ +#undef GTEST_3_TYPENAMES_ +#undef GTEST_4_TYPENAMES_ +#undef GTEST_5_TYPENAMES_ +#undef GTEST_6_TYPENAMES_ +#undef GTEST_7_TYPENAMES_ +#undef GTEST_8_TYPENAMES_ +#undef GTEST_9_TYPENAMES_ +#undef GTEST_10_TYPENAMES_ + +#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ +#undef GTEST_BY_REF_ +#undef GTEST_ADD_REF_ +#undef GTEST_TUPLE_ELEMENT_ + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ +# elif GTEST_ENV_HAS_STD_TUPLE_ +# include +// C++11 puts its tuple into the ::std namespace rather than +// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. +// This causes undefined behavior, but supported compilers react in +// the way we intend. +namespace std { +namespace tr1 { +using ::std::get; +using ::std::make_tuple; +using ::std::tuple; +using ::std::tuple_element; +using ::std::tuple_size; +} +} + +# elif GTEST_OS_SYMBIAN + +// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to +// use STLport's tuple implementation, which unfortunately doesn't +// work as the copy of STLport distributed with Symbian is incomplete. +// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to +// use its own tuple implementation. +# ifdef BOOST_HAS_TR1_TUPLE +# undef BOOST_HAS_TR1_TUPLE +# endif // BOOST_HAS_TR1_TUPLE + +// This prevents , which defines +// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . +# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED +# include + +# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) +// GCC 4.0+ implements tr1/tuple in the header. This does +// not conform to the TR1 spec, which requires the header to be . + +# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 +// Until version 4.3.2, gcc has a bug that causes , +// which is #included by , to not compile when RTTI is +// disabled. _TR1_FUNCTIONAL is the header guard for +// . Hence the following #define is a hack to prevent +// from being included. +# define _TR1_FUNCTIONAL 1 +# include +# undef _TR1_FUNCTIONAL // Allows the user to #include + // if he chooses to. +# else +# include // NOLINT +# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 + +# else +// If the compiler is not GCC 4.0+, we assume the user is using a +// spec-conforming TR1 implementation. +# include // NOLINT +# endif // GTEST_USE_OWN_TR1_TUPLE + +#endif // GTEST_HAS_TR1_TUPLE + +// Determines whether clone(2) is supported. +// Usually it will only be available on Linux, excluding +// Linux on the Itanium architecture. +// Also see http://linux.die.net/man/2/clone. +#ifndef GTEST_HAS_CLONE +// The user didn't tell us, so we need to figure it out. + +# if GTEST_OS_LINUX && !defined(__ia64__) +# if GTEST_OS_LINUX_ANDROID +// On Android, clone() is only available on ARM starting with Gingerbread. +# if defined(__arm__) && __ANDROID_API__ >= 9 +# define GTEST_HAS_CLONE 1 +# else +# define GTEST_HAS_CLONE 0 +# endif +# else +# define GTEST_HAS_CLONE 1 +# endif +# else +# define GTEST_HAS_CLONE 0 +# endif // GTEST_OS_LINUX && !defined(__ia64__) + +#endif // GTEST_HAS_CLONE + +// Determines whether to support stream redirection. This is used to test +// output correctness and to implement death tests. +#ifndef GTEST_HAS_STREAM_REDIRECTION +// By default, we assume that stream redirection is supported on all +// platforms except known mobile ones. +# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN +# define GTEST_HAS_STREAM_REDIRECTION 0 +# else +# define GTEST_HAS_STREAM_REDIRECTION 1 +# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN +#endif // GTEST_HAS_STREAM_REDIRECTION + +// Determines whether to support death tests. +// Google Test does not support death tests for VC 7.1 and earlier as +// abort() in a VC 7.1 application compiled as GUI in debug config +// pops up a dialog window that cannot be suppressed programmatically. +#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ + (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ + (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ + GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ + GTEST_OS_OPENBSD || GTEST_OS_QNX) +# define GTEST_HAS_DEATH_TEST 1 +# include // NOLINT +#endif + +// We don't support MSVC 7.1 with exceptions disabled now. Therefore +// all the compilers we care about are adequate for supporting +// value-parameterized tests. +#define GTEST_HAS_PARAM_TEST 1 + +// Determines whether to support type-driven tests. + +// Typed tests need and variadic macros, which GCC, VC++ 8.0, +// Sun Pro CC, IBM Visual Age, and HP aCC support. +#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ + defined(__IBMCPP__) || defined(__HP_aCC) +# define GTEST_HAS_TYPED_TEST 1 +# define GTEST_HAS_TYPED_TEST_P 1 +#endif + +// Determines whether to support Combine(). This only makes sense when +// value-parameterized tests are enabled. The implementation doesn't +// work on Sun Studio since it doesn't understand templated conversion +// operators. +#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) +# define GTEST_HAS_COMBINE 1 +#endif + +// Determines whether the system compiler uses UTF-16 for encoding wide strings. +#define GTEST_WIDE_STRING_USES_UTF16_ \ + (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) + +// Determines whether test results can be streamed to a socket. +#if GTEST_OS_LINUX +# define GTEST_CAN_STREAM_RESULTS_ 1 +#endif + +// Defines some utility macros. + +// The GNU compiler emits a warning if nested "if" statements are followed by +// an "else" statement and braces are not used to explicitly disambiguate the +// "else" binding. This leads to problems with code like: +// +// if (gate) +// ASSERT_*(condition) << "Some message"; +// +// The "switch (0) case 0:" idiom is used to suppress this. +#ifdef __INTEL_COMPILER +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ +#else +# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT +#endif + +// Use this annotation at the end of a struct/class definition to +// prevent the compiler from optimizing away instances that are never +// used. This is useful when all interesting logic happens inside the +// c'tor and / or d'tor. Example: +// +// struct Foo { +// Foo() { ... } +// } GTEST_ATTRIBUTE_UNUSED_; +// +// Also use it after a variable or parameter declaration to tell the +// compiler the variable/parameter does not have to be used. +#if defined(__GNUC__) && !defined(COMPILER_ICC) +# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) +#else +# define GTEST_ATTRIBUTE_UNUSED_ +#endif + +// A macro to disallow operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_ASSIGN_(type)\ + void operator=(type const &) + +// A macro to disallow copy constructor and operator= +// This should be used in the private: declarations for a class. +#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ + type(type const &);\ + GTEST_DISALLOW_ASSIGN_(type) + +// Tell the compiler to warn about unused return values for functions declared +// with this macro. The macro should be used on function declarations +// following the argument list: +// +// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; +#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) +# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) +#else +# define GTEST_MUST_USE_RESULT_ +#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC + +// Determine whether the compiler supports Microsoft's Structured Exception +// Handling. This is supported by several Windows compilers but generally +// does not exist on any other system. +#ifndef GTEST_HAS_SEH +// The user didn't tell us, so we need to figure it out. + +# if defined(_MSC_VER) || defined(__BORLANDC__) +// These two compilers are known to support SEH. +# define GTEST_HAS_SEH 1 +# else +// Assume no SEH. +# define GTEST_HAS_SEH 0 +# endif + +#endif // GTEST_HAS_SEH + +#ifdef _MSC_VER + +# if GTEST_LINKED_AS_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllimport) +# elif GTEST_CREATE_SHARED_LIBRARY +# define GTEST_API_ __declspec(dllexport) +# endif + +#endif // _MSC_VER + +#ifndef GTEST_API_ +# define GTEST_API_ +#endif + +#ifdef __GNUC__ +// Ask the compiler to never inline a given function. +# define GTEST_NO_INLINE_ __attribute__((noinline)) +#else +# define GTEST_NO_INLINE_ +#endif + +// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. +#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) +# define GTEST_HAS_CXXABI_H_ 1 +#else +# define GTEST_HAS_CXXABI_H_ 0 +#endif + +namespace testing { + +class Message; + +namespace internal { + +// A secret type that Google Test users don't know about. It has no +// definition on purpose. Therefore it's impossible to create a +// Secret object, which is what we want. +class Secret; + +// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time +// expression is true. For example, you could use it to verify the +// size of a static array: +// +// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, +// content_type_names_incorrect_size); +// +// or to make sure a struct is smaller than a certain size: +// +// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); +// +// The second argument to the macro is the name of the variable. If +// the expression is false, most compilers will issue a warning/error +// containing the name of the variable. + +template +struct CompileAssert { +}; + +#define GTEST_COMPILE_ASSERT_(expr, msg) \ + typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ + msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ + +// Implementation details of GTEST_COMPILE_ASSERT_: +// +// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 +// elements (and thus is invalid) when the expression is false. +// +// - The simpler definition +// +// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] +// +// does not work, as gcc supports variable-length arrays whose sizes +// are determined at run-time (this is gcc's extension and not part +// of the C++ standard). As a result, gcc fails to reject the +// following code with the simple definition: +// +// int foo; +// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is +// // not a compile-time constant. +// +// - By using the type CompileAssert<(bool(expr))>, we ensures that +// expr is a compile-time constant. (Template arguments must be +// determined at compile-time.) +// +// - The outter parentheses in CompileAssert<(bool(expr))> are necessary +// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written +// +// CompileAssert +// +// instead, these compilers will refuse to compile +// +// GTEST_COMPILE_ASSERT_(5 > 0, some_message); +// +// (They seem to think the ">" in "5 > 0" marks the end of the +// template argument list.) +// +// - The array size is (bool(expr) ? 1 : -1), instead of simply +// +// ((expr) ? 1 : -1). +// +// This is to avoid running into a bug in MS VC 7.1, which +// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. + +// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. +// +// This template is declared, but intentionally undefined. +template +struct StaticAssertTypeEqHelper; + +template +struct StaticAssertTypeEqHelper {}; + +#if GTEST_HAS_GLOBAL_STRING +typedef ::string string; +#else +typedef ::std::string string; +#endif // GTEST_HAS_GLOBAL_STRING + +#if GTEST_HAS_GLOBAL_WSTRING +typedef ::wstring wstring; +#elif GTEST_HAS_STD_WSTRING +typedef ::std::wstring wstring; +#endif // GTEST_HAS_GLOBAL_WSTRING + +// A helper for suppressing warnings on constant condition. It just +// returns 'condition'. +GTEST_API_ bool IsTrue(bool condition); + +// Defines scoped_ptr. + +// This implementation of scoped_ptr is PARTIAL - it only contains +// enough stuff to satisfy Google Test's need. +template +class scoped_ptr { + public: + typedef T element_type; + + explicit scoped_ptr(T* p = NULL) : ptr_(p) {} + ~scoped_ptr() { reset(); } + + T& operator*() const { return *ptr_; } + T* operator->() const { return ptr_; } + T* get() const { return ptr_; } + + T* release() { + T* const ptr = ptr_; + ptr_ = NULL; + return ptr; + } + + void reset(T* p = NULL) { + if (p != ptr_) { + if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. + delete ptr_; + } + ptr_ = p; + } + } + + private: + T* ptr_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); +}; + +// Defines RE. + +// A simple C++ wrapper for . It uses the POSIX Extended +// Regular Expression syntax. +class GTEST_API_ RE { + public: + // A copy constructor is required by the Standard to initialize object + // references from r-values. + RE(const RE& other) { Init(other.pattern()); } + + // Constructs an RE from a string. + RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT + +#if GTEST_HAS_GLOBAL_STRING + + RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT + +#endif // GTEST_HAS_GLOBAL_STRING + + RE(const char* regex) { Init(regex); } // NOLINT + ~RE(); + + // Returns the string representation of the regex. + const char* pattern() const { return pattern_; } + + // FullMatch(str, re) returns true iff regular expression re matches + // the entire str. + // PartialMatch(str, re) returns true iff regular expression re + // matches a substring of str (including str itself). + // + // TODO(wan@google.com): make FullMatch() and PartialMatch() work + // when str contains NUL characters. + static bool FullMatch(const ::std::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::std::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#if GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const ::string& str, const RE& re) { + return FullMatch(str.c_str(), re); + } + static bool PartialMatch(const ::string& str, const RE& re) { + return PartialMatch(str.c_str(), re); + } + +#endif // GTEST_HAS_GLOBAL_STRING + + static bool FullMatch(const char* str, const RE& re); + static bool PartialMatch(const char* str, const RE& re); + + private: + void Init(const char* regex); + + // We use a const char* instead of an std::string, as Google Test used to be + // used where std::string is not available. TODO(wan@google.com): change to + // std::string. + const char* pattern_; + bool is_valid_; + +#if GTEST_USES_POSIX_RE + + regex_t full_regex_; // For FullMatch(). + regex_t partial_regex_; // For PartialMatch(). + +#else // GTEST_USES_SIMPLE_RE + + const char* full_pattern_; // For FullMatch(); + +#endif + + GTEST_DISALLOW_ASSIGN_(RE); +}; + +// Formats a source file path and a line number as they would appear +// in an error message from the compiler used to compile this code. +GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); + +// Formats a file location for compiler-independent XML output. +// Although this function is not platform dependent, we put it next to +// FormatFileLocation in order to contrast the two functions. +GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, + int line); + +// Defines logging utilities: +// GTEST_LOG_(severity) - logs messages at the specified severity level. The +// message itself is streamed into the macro. +// LogToStderr() - directs all log messages to stderr. +// FlushInfoLog() - flushes informational log messages. + +enum GTestLogSeverity { + GTEST_INFO, + GTEST_WARNING, + GTEST_ERROR, + GTEST_FATAL +}; + +// Formats log entry severity, provides a stream object for streaming the +// log message, and terminates the message with a newline when going out of +// scope. +class GTEST_API_ GTestLog { + public: + GTestLog(GTestLogSeverity severity, const char* file, int line); + + // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. + ~GTestLog(); + + ::std::ostream& GetStream() { return ::std::cerr; } + + private: + const GTestLogSeverity severity_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); +}; + +#define GTEST_LOG_(severity) \ + ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ + __FILE__, __LINE__).GetStream() + +inline void LogToStderr() {} +inline void FlushInfoLog() { fflush(NULL); } + +// INTERNAL IMPLEMENTATION - DO NOT USE. +// +// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition +// is not satisfied. +// Synopsys: +// GTEST_CHECK_(boolean_condition); +// or +// GTEST_CHECK_(boolean_condition) << "Additional message"; +// +// This checks the condition and if the condition is not satisfied +// it prints message about the condition violation, including the +// condition itself, plus additional message streamed into it, if any, +// and then it aborts the program. It aborts the program irrespective of +// whether it is built in the debug mode or not. +#define GTEST_CHECK_(condition) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::IsTrue(condition)) \ + ; \ + else \ + GTEST_LOG_(FATAL) << "Condition " #condition " failed. " + +// An all-mode assert to verify that the given POSIX-style function +// call returns 0 (indicating success). Known limitation: this +// doesn't expand to a balanced 'if' statement, so enclose the macro +// in {} if you need to use it as the only statement in an 'if' +// branch. +#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ + if (const int gtest_error = (posix_call)) \ + GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ + << gtest_error + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Use ImplicitCast_ as a safe version of static_cast for upcasting in +// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a +// const Foo*). When you use ImplicitCast_, the compiler checks that +// the cast is safe. Such explicit ImplicitCast_s are necessary in +// surprisingly many situations where C++ demands an exact type match +// instead of an argument type convertable to a target type. +// +// The syntax for using ImplicitCast_ is the same as for static_cast: +// +// ImplicitCast_(expr) +// +// ImplicitCast_ would have been part of the C++ standard library, +// but the proposal was submitted too late. It will probably make +// its way into the language in the future. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., implicit_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template +inline To ImplicitCast_(To x) { return x; } + +// When you upcast (that is, cast a pointer from type Foo to type +// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts +// always succeed. When you downcast (that is, cast a pointer from +// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because +// how do you know the pointer is really of type SubclassOfFoo? It +// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, +// when you downcast, you should use this macro. In debug mode, we +// use dynamic_cast<> to double-check the downcast is legal (we die +// if it's not). In normal mode, we do the efficient static_cast<> +// instead. Thus, it's important to test in debug mode to make sure +// the cast is legal! +// This is the only place in the code we should use dynamic_cast<>. +// In particular, you SHOULDN'T be using dynamic_cast<> in order to +// do RTTI (eg code like this: +// if (dynamic_cast(foo)) HandleASubclass1Object(foo); +// if (dynamic_cast(foo)) HandleASubclass2Object(foo); +// You should design the code some other way not to need this. +// +// This relatively ugly name is intentional. It prevents clashes with +// similar functions users may have (e.g., down_cast). The internal +// namespace alone is not enough because the function can be found by ADL. +template // use like this: DownCast_(foo); +inline To DownCast_(From* f) { // so we only accept pointers + // Ensures that To is a sub-type of From *. This test is here only + // for compile-time type checking, and has no overhead in an + // optimized build at run-time, as it will be optimized away + // completely. + if (false) { + const To to = NULL; + ::testing::internal::ImplicitCast_(to); + } + +#if GTEST_HAS_RTTI + // RTTI: debug mode only! + GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); +#endif + return static_cast(f); +} + +// Downcasts the pointer of type Base to Derived. +// Derived must be a subclass of Base. The parameter MUST +// point to a class of type Derived, not any subclass of it. +// When RTTI is available, the function performs a runtime +// check to enforce this. +template +Derived* CheckedDowncastToActualType(Base* base) { +#if GTEST_HAS_RTTI + GTEST_CHECK_(typeid(*base) == typeid(Derived)); + return dynamic_cast(base); // NOLINT +#else + return static_cast(base); // Poor man's downcast. +#endif +} + +#if GTEST_HAS_STREAM_REDIRECTION + +// Defines the stderr capturer: +// CaptureStdout - starts capturing stdout. +// GetCapturedStdout - stops capturing stdout and returns the captured string. +// CaptureStderr - starts capturing stderr. +// GetCapturedStderr - stops capturing stderr and returns the captured string. +// +GTEST_API_ void CaptureStdout(); +GTEST_API_ std::string GetCapturedStdout(); +GTEST_API_ void CaptureStderr(); +GTEST_API_ std::string GetCapturedStderr(); + +#endif // GTEST_HAS_STREAM_REDIRECTION + + +#if GTEST_HAS_DEATH_TEST + +const ::std::vector& GetInjectableArgvs(); +void SetInjectableArgvs(const ::std::vector* + new_argvs); + +// A copy of all command line arguments. Set by InitGoogleTest(). +extern ::std::vector g_argvs; + +#endif // GTEST_HAS_DEATH_TEST + +// Defines synchronization primitives. + +#if GTEST_HAS_PTHREAD + +// Sleeps for (roughly) n milli-seconds. This function is only for +// testing Google Test's own constructs. Don't use it in user tests, +// either directly or indirectly. +inline void SleepMilliseconds(int n) { + const timespec time = { + 0, // 0 seconds. + n * 1000L * 1000L, // And n ms. + }; + nanosleep(&time, NULL); +} + +// Allows a controller thread to pause execution of newly created +// threads until notified. Instances of this class must be created +// and destroyed in the controller thread. +// +// This class is only for testing Google Test's own constructs. Do not +// use it in user tests, either directly or indirectly. +class Notification { + public: + Notification() : notified_(false) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + } + ~Notification() { + pthread_mutex_destroy(&mutex_); + } + + // Notifies all threads created with this notification to start. Must + // be called from the controller thread. + void Notify() { + pthread_mutex_lock(&mutex_); + notified_ = true; + pthread_mutex_unlock(&mutex_); + } + + // Blocks until the controller thread notifies. Must be called from a test + // thread. + void WaitForNotification() { + for (;;) { + pthread_mutex_lock(&mutex_); + const bool notified = notified_; + pthread_mutex_unlock(&mutex_); + if (notified) + break; + SleepMilliseconds(10); + } + } + + private: + pthread_mutex_t mutex_; + bool notified_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); +}; + +// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. +// Consequently, it cannot select a correct instantiation of ThreadWithParam +// in order to call its Run(). Introducing ThreadWithParamBase as a +// non-templated base class for ThreadWithParam allows us to bypass this +// problem. +class ThreadWithParamBase { + public: + virtual ~ThreadWithParamBase() {} + virtual void Run() = 0; +}; + +// pthread_create() accepts a pointer to a function type with the C linkage. +// According to the Standard (7.5/1), function types with different linkages +// are different even if they are otherwise identical. Some compilers (for +// example, SunStudio) treat them as different types. Since class methods +// cannot be defined with C-linkage we need to define a free C-function to +// pass into pthread_create(). +extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { + static_cast(thread)->Run(); + return NULL; +} + +// Helper class for testing Google Test's multi-threading constructs. +// To use it, write: +// +// void ThreadFunc(int param) { /* Do things with param */ } +// Notification thread_can_start; +// ... +// // The thread_can_start parameter is optional; you can supply NULL. +// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); +// thread_can_start.Notify(); +// +// These classes are only for testing Google Test's own constructs. Do +// not use them in user tests, either directly or indirectly. +template +class ThreadWithParam : public ThreadWithParamBase { + public: + typedef void (*UserThreadFunc)(T); + + ThreadWithParam( + UserThreadFunc func, T param, Notification* thread_can_start) + : func_(func), + param_(param), + thread_can_start_(thread_can_start), + finished_(false) { + ThreadWithParamBase* const base = this; + // The thread can be created only after all fields except thread_ + // have been initialized. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); + } + ~ThreadWithParam() { Join(); } + + void Join() { + if (!finished_) { + GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); + finished_ = true; + } + } + + virtual void Run() { + if (thread_can_start_ != NULL) + thread_can_start_->WaitForNotification(); + func_(param_); + } + + private: + const UserThreadFunc func_; // User-supplied thread function. + const T param_; // User-supplied parameter to the thread function. + // When non-NULL, used to block execution until the controller thread + // notifies. + Notification* const thread_can_start_; + bool finished_; // true iff we know that the thread function has finished. + pthread_t thread_; // The native thread object. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); +}; + +// MutexBase and Mutex implement mutex on pthreads-based platforms. They +// are used in conjunction with class MutexLock: +// +// Mutex mutex; +// ... +// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end +// // of the current scope. +// +// MutexBase implements behavior for both statically and dynamically +// allocated mutexes. Do not use MutexBase directly. Instead, write +// the following to define a static mutex: +// +// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); +// +// You can forward declare a static mutex like this: +// +// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); +// +// To create a dynamic mutex, just define an object of type Mutex. +class MutexBase { + public: + // Acquires this mutex. + void Lock() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); + owner_ = pthread_self(); + has_owner_ = true; + } + + // Releases this mutex. + void Unlock() { + // Since the lock is being released the owner_ field should no longer be + // considered valid. We don't protect writing to has_owner_ here, as it's + // the caller's responsibility to ensure that the current thread holds the + // mutex when this is called. + has_owner_ = false; + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); + } + + // Does nothing if the current thread holds the mutex. Otherwise, crashes + // with high probability. + void AssertHeld() const { + GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) + << "The current thread is not holding the mutex @" << this; + } + + // A static mutex may be used before main() is entered. It may even + // be used before the dynamic initialization stage. Therefore we + // must be able to initialize a static mutex object at link time. + // This means MutexBase has to be a POD and its member variables + // have to be public. + public: + pthread_mutex_t mutex_; // The underlying pthread mutex. + // has_owner_ indicates whether the owner_ field below contains a valid thread + // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All + // accesses to the owner_ field should be protected by a check of this field. + // An alternative might be to memset() owner_ to all zeros, but there's no + // guarantee that a zero'd pthread_t is necessarily invalid or even different + // from pthread_self(). + bool has_owner_; + pthread_t owner_; // The thread holding the mutex. +}; + +// Forward-declares a static mutex. +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::MutexBase mutex + +// Defines and statically (i.e. at link time) initializes a static mutex. +// The initialization list here does not explicitly initialize each field, +// instead relying on default initialization for the unspecified fields. In +// particular, the owner_ field (a pthread_t) is not explicitly initialized. +// This allows initialization to work whether pthread_t is a scalar or struct. +// The flag -Wmissing-field-initializers must not be specified for this to work. +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ + ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } + +// The Mutex class can only be used for mutexes created at runtime. It +// shares its API with MutexBase otherwise. +class Mutex : public MutexBase { + public: + Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); + has_owner_ = false; + } + ~Mutex() { + GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); +}; + +// We cannot name this class MutexLock as the ctor declaration would +// conflict with a macro named MutexLock, which is defined on some +// platforms. Hence the typedef trick below. +class GTestMutexLock { + public: + explicit GTestMutexLock(MutexBase* mutex) + : mutex_(mutex) { mutex_->Lock(); } + + ~GTestMutexLock() { mutex_->Unlock(); } + + private: + MutexBase* const mutex_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); +}; + +typedef GTestMutexLock MutexLock; + +// Helpers for ThreadLocal. + +// pthread_key_create() requires DeleteThreadLocalValue() to have +// C-linkage. Therefore it cannot be templatized to access +// ThreadLocal. Hence the need for class +// ThreadLocalValueHolderBase. +class ThreadLocalValueHolderBase { + public: + virtual ~ThreadLocalValueHolderBase() {} +}; + +// Called by pthread to delete thread-local data stored by +// pthread_setspecific(). +extern "C" inline void DeleteThreadLocalValue(void* value_holder) { + delete static_cast(value_holder); +} + +// Implements thread-local storage on pthreads-based systems. +// +// // Thread 1 +// ThreadLocal tl(100); // 100 is the default value for each thread. +// +// // Thread 2 +// tl.set(150); // Changes the value for thread 2 only. +// EXPECT_EQ(150, tl.get()); +// +// // Thread 1 +// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. +// tl.set(200); +// EXPECT_EQ(200, tl.get()); +// +// The template type argument T must have a public copy constructor. +// In addition, the default ThreadLocal constructor requires T to have +// a public default constructor. +// +// An object managed for a thread by a ThreadLocal instance is deleted +// when the thread exits. Or, if the ThreadLocal instance dies in +// that thread, when the ThreadLocal dies. It's the user's +// responsibility to ensure that all other threads using a ThreadLocal +// have exited when it dies, or the per-thread objects for those +// threads will not be deleted. +// +// Google Test only uses global ThreadLocal objects. That means they +// will die after main() has returned. Therefore, no per-thread +// object managed by Google Test will be leaked as long as all threads +// using Google Test have exited when main() returns. +template +class ThreadLocal { + public: + ThreadLocal() : key_(CreateKey()), + default_() {} + explicit ThreadLocal(const T& value) : key_(CreateKey()), + default_(value) {} + + ~ThreadLocal() { + // Destroys the managed object for the current thread, if any. + DeleteThreadLocalValue(pthread_getspecific(key_)); + + // Releases resources associated with the key. This will *not* + // delete managed objects for other threads. + GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); + } + + T* pointer() { return GetOrCreateValue(); } + const T* pointer() const { return GetOrCreateValue(); } + const T& get() const { return *pointer(); } + void set(const T& value) { *pointer() = value; } + + private: + // Holds a value of type T. + class ValueHolder : public ThreadLocalValueHolderBase { + public: + explicit ValueHolder(const T& value) : value_(value) {} + + T* pointer() { return &value_; } + + private: + T value_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); + }; + + static pthread_key_t CreateKey() { + pthread_key_t key; + // When a thread exits, DeleteThreadLocalValue() will be called on + // the object managed for that thread. + GTEST_CHECK_POSIX_SUCCESS_( + pthread_key_create(&key, &DeleteThreadLocalValue)); + return key; + } + + T* GetOrCreateValue() const { + ThreadLocalValueHolderBase* const holder = + static_cast(pthread_getspecific(key_)); + if (holder != NULL) { + return CheckedDowncastToActualType(holder)->pointer(); + } + + ValueHolder* const new_holder = new ValueHolder(default_); + ThreadLocalValueHolderBase* const holder_base = new_holder; + GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); + return new_holder->pointer(); + } + + // A key pthreads uses for looking up per-thread values. + const pthread_key_t key_; + const T default_; // The default value for each thread. + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); +}; + +# define GTEST_IS_THREADSAFE 1 + +#else // GTEST_HAS_PTHREAD + +// A dummy implementation of synchronization primitives (mutex, lock, +// and thread-local variable). Necessary for compiling Google Test where +// mutex is not supported - using Google Test in multiple threads is not +// supported on such platforms. + +class Mutex { + public: + Mutex() {} + void Lock() {} + void Unlock() {} + void AssertHeld() const {} +}; + +# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ + extern ::testing::internal::Mutex mutex + +# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex + +class GTestMutexLock { + public: + explicit GTestMutexLock(Mutex*) {} // NOLINT +}; + +typedef GTestMutexLock MutexLock; + +template +class ThreadLocal { + public: + ThreadLocal() : value_() {} + explicit ThreadLocal(const T& value) : value_(value) {} + T* pointer() { return &value_; } + const T* pointer() const { return &value_; } + const T& get() const { return value_; } + void set(const T& value) { value_ = value; } + private: + T value_; +}; + +// The above synchronization primitives have dummy implementations. +// Therefore Google Test is not thread-safe. +# define GTEST_IS_THREADSAFE 0 + +#endif // GTEST_HAS_PTHREAD + +// Returns the number of threads running in the process, or 0 to indicate that +// we cannot detect it. +GTEST_API_ size_t GetThreadCount(); + +// Passing non-POD classes through ellipsis (...) crashes the ARM +// compiler and generates a warning in Sun Studio. The Nokia Symbian +// and the IBM XL C/C++ compiler try to instantiate a copy constructor +// for objects passed through ellipsis (...), failing for uncopyable +// objects. We define this to ensure that only POD is passed through +// ellipsis on these systems. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_ELLIPSIS_NEEDS_POD_ 1 +#else +# define GTEST_CAN_COMPARE_NULL 1 +#endif + +// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between +// const T& and const T* in a function template. These compilers +// _can_ decide between class template specializations for T and T*, +// so a tr1::type_traits-like is_pointer works. +#if defined(__SYMBIAN32__) || defined(__IBMCPP__) +# define GTEST_NEEDS_IS_POINTER_ 1 +#endif + +template +struct bool_constant { + typedef bool_constant type; + static const bool value = bool_value; +}; +template const bool bool_constant::value; + +typedef bool_constant false_type; +typedef bool_constant true_type; + +template +struct is_pointer : public false_type {}; + +template +struct is_pointer : public true_type {}; + +template +struct IteratorTraits { + typedef typename Iterator::value_type value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +template +struct IteratorTraits { + typedef T value_type; +}; + +#if GTEST_OS_WINDOWS +# define GTEST_PATH_SEP_ "\\" +# define GTEST_HAS_ALT_PATH_SEP_ 1 +// The biggest signed integer type the compiler supports. +typedef __int64 BiggestInt; +#else +# define GTEST_PATH_SEP_ "/" +# define GTEST_HAS_ALT_PATH_SEP_ 0 +typedef long long BiggestInt; // NOLINT +#endif // GTEST_OS_WINDOWS + +// Utilities for char. + +// isspace(int ch) and friends accept an unsigned char or EOF. char +// may be signed, depending on the compiler (or compiler flags). +// Therefore we need to cast a char to unsigned char before calling +// isspace(), etc. + +inline bool IsAlpha(char ch) { + return isalpha(static_cast(ch)) != 0; +} +inline bool IsAlNum(char ch) { + return isalnum(static_cast(ch)) != 0; +} +inline bool IsDigit(char ch) { + return isdigit(static_cast(ch)) != 0; +} +inline bool IsLower(char ch) { + return islower(static_cast(ch)) != 0; +} +inline bool IsSpace(char ch) { + return isspace(static_cast(ch)) != 0; +} +inline bool IsUpper(char ch) { + return isupper(static_cast(ch)) != 0; +} +inline bool IsXDigit(char ch) { + return isxdigit(static_cast(ch)) != 0; +} +inline bool IsXDigit(wchar_t ch) { + const unsigned char low_byte = static_cast(ch); + return ch == low_byte && isxdigit(low_byte) != 0; +} + +inline char ToLower(char ch) { + return static_cast(tolower(static_cast(ch))); +} +inline char ToUpper(char ch) { + return static_cast(toupper(static_cast(ch))); +} + +// The testing::internal::posix namespace holds wrappers for common +// POSIX functions. These wrappers hide the differences between +// Windows/MSVC and POSIX systems. Since some compilers define these +// standard functions as macros, the wrapper cannot have the same name +// as the wrapped function. + +namespace posix { + +// Functions with a different name on Windows. + +#if GTEST_OS_WINDOWS + +typedef struct _stat StatStruct; + +# ifdef __BORLANDC__ +inline int IsATTY(int fd) { return isatty(fd); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +# else // !__BORLANDC__ +# if GTEST_OS_WINDOWS_MOBILE +inline int IsATTY(int /* fd */) { return 0; } +# else +inline int IsATTY(int fd) { return _isatty(fd); } +# endif // GTEST_OS_WINDOWS_MOBILE +inline int StrCaseCmp(const char* s1, const char* s2) { + return _stricmp(s1, s2); +} +inline char* StrDup(const char* src) { return _strdup(src); } +# endif // __BORLANDC__ + +# if GTEST_OS_WINDOWS_MOBILE +inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } +// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this +// time and thus not defined there. +# else +inline int FileNo(FILE* file) { return _fileno(file); } +inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } +inline int RmDir(const char* dir) { return _rmdir(dir); } +inline bool IsDir(const StatStruct& st) { + return (_S_IFDIR & st.st_mode) != 0; +} +# endif // GTEST_OS_WINDOWS_MOBILE + +#else + +typedef struct stat StatStruct; + +inline int FileNo(FILE* file) { return fileno(file); } +inline int IsATTY(int fd) { return isatty(fd); } +inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } +inline int StrCaseCmp(const char* s1, const char* s2) { + return strcasecmp(s1, s2); +} +inline char* StrDup(const char* src) { return strdup(src); } +inline int RmDir(const char* dir) { return rmdir(dir); } +inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } + +#endif // GTEST_OS_WINDOWS + +// Functions deprecated by MSVC 8.0. + +#ifdef _MSC_VER +// Temporarily disable warning 4996 (deprecated function). +# pragma warning(push) +# pragma warning(disable:4996) +#endif + +inline const char* StrNCpy(char* dest, const char* src, size_t n) { + return strncpy(dest, src, n); +} + +// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and +// StrError() aren't needed on Windows CE at this time and thus not +// defined there. + +#if !GTEST_OS_WINDOWS_MOBILE +inline int ChDir(const char* dir) { return chdir(dir); } +#endif +inline FILE* FOpen(const char* path, const char* mode) { + return fopen(path, mode); +} +#if !GTEST_OS_WINDOWS_MOBILE +inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { + return freopen(path, mode, stream); +} +inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } +#endif +inline int FClose(FILE* fp) { return fclose(fp); } +#if !GTEST_OS_WINDOWS_MOBILE +inline int Read(int fd, void* buf, unsigned int count) { + return static_cast(read(fd, buf, count)); +} +inline int Write(int fd, const void* buf, unsigned int count) { + return static_cast(write(fd, buf, count)); +} +inline int Close(int fd) { return close(fd); } +inline const char* StrError(int errnum) { return strerror(errnum); } +#endif +inline const char* GetEnv(const char* name) { +#if GTEST_OS_WINDOWS_MOBILE + // We are on Windows CE, which has no environment variables. + return NULL; +#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) + // Environment variables which we programmatically clear will be set to the + // empty string rather than unset (NULL). Handle that case. + const char* const env = getenv(name); + return (env != NULL && env[0] != '\0') ? env : NULL; +#else + return getenv(name); +#endif +} + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + +#if GTEST_OS_WINDOWS_MOBILE +// Windows CE has no C library. The abort() function is used in +// several places in Google Test. This implementation provides a reasonable +// imitation of standard behaviour. +void Abort(); +#else +inline void Abort() { abort(); } +#endif // GTEST_OS_WINDOWS_MOBILE + +} // namespace posix + +// MSVC "deprecates" snprintf and issues warnings wherever it is used. In +// order to avoid these warnings, we need to use _snprintf or _snprintf_s on +// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate +// function in order to achieve that. We use macro definition here because +// snprintf is a variadic function. +#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE +// MSVC 2005 and above support variadic macros. +# define GTEST_SNPRINTF_(buffer, size, format, ...) \ + _snprintf_s(buffer, size, size, format, __VA_ARGS__) +#elif defined(_MSC_VER) +// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't +// complain about _snprintf. +# define GTEST_SNPRINTF_ _snprintf +#else +# define GTEST_SNPRINTF_ snprintf +#endif + +// The maximum number a BiggestInt can represent. This definition +// works no matter BiggestInt is represented in one's complement or +// two's complement. +// +// We cannot rely on numeric_limits in STL, as __int64 and long long +// are not part of standard C++ and numeric_limits doesn't need to be +// defined for them. +const BiggestInt kMaxBiggestInt = + ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); + +// This template class serves as a compile-time function from size to +// type. It maps a size in bytes to a primitive type with that +// size. e.g. +// +// TypeWithSize<4>::UInt +// +// is typedef-ed to be unsigned int (unsigned integer made up of 4 +// bytes). +// +// Such functionality should belong to STL, but I cannot find it +// there. +// +// Google Test uses this class in the implementation of floating-point +// comparison. +// +// For now it only handles UInt (unsigned int) as that's all Google Test +// needs. Other types can be easily added in the future if need +// arises. +template +class TypeWithSize { + public: + // This prevents the user from using TypeWithSize with incorrect + // values of N. + typedef void UInt; +}; + +// The specialization for size 4. +template <> +class TypeWithSize<4> { + public: + // unsigned int has size 4 in both gcc and MSVC. + // + // As base/basictypes.h doesn't compile on Windows, we cannot use + // uint32, uint64, and etc here. + typedef int Int; + typedef unsigned int UInt; +}; + +// The specialization for size 8. +template <> +class TypeWithSize<8> { + public: +#if GTEST_OS_WINDOWS + typedef __int64 Int; + typedef unsigned __int64 UInt; +#else + typedef long long Int; // NOLINT + typedef unsigned long long UInt; // NOLINT +#endif // GTEST_OS_WINDOWS +}; + +// Integer types of known sizes. +typedef TypeWithSize<4>::Int Int32; +typedef TypeWithSize<4>::UInt UInt32; +typedef TypeWithSize<8>::Int Int64; +typedef TypeWithSize<8>::UInt UInt64; +typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. + +// Utilities for command line flags and environment variables. + +// Macro for referencing flags. +#define GTEST_FLAG(name) FLAGS_gtest_##name + +// Macros for declaring flags. +#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) +#define GTEST_DECLARE_int32_(name) \ + GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) +#define GTEST_DECLARE_string_(name) \ + GTEST_API_ extern ::std::string GTEST_FLAG(name) + +// Macros for defining flags. +#define GTEST_DEFINE_bool_(name, default_val, doc) \ + GTEST_API_ bool GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_int32_(name, default_val, doc) \ + GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) +#define GTEST_DEFINE_string_(name, default_val, doc) \ + GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) + +// Thread annotations +#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) +#define GTEST_LOCK_EXCLUDED_(locks) + +// Parses 'str' for a 32-bit signed integer. If successful, writes the result +// to *value and returns true; otherwise leaves *value unchanged and returns +// false. +// TODO(chandlerc): Find a better way to refactor flag and environment parsing +// out of both gtest-port.cc and gtest.cc to avoid exporting this utility +// function. +bool ParseInt32(const Message& src_text, const char* str, Int32* value); + +// Parses a bool/Int32/string from the environment variable +// corresponding to the given Google Test flag. +bool BoolFromGTestEnv(const char* flag, bool default_val); +GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); +const char* StringFromGTestEnv(const char* flag, const char* default_val); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ + +#if GTEST_OS_LINUX +# include +# include +# include +# include +#endif // GTEST_OS_LINUX + +#if GTEST_HAS_EXCEPTIONS +# include +#endif + +#include +#include +#include +#include +#include +#include + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the Message class. +// +// IMPORTANT NOTE: Due to limitation of the C++ language, we have to +// leave some internal implementation details in this header file. +// They are clearly marked by comments like this: +// +// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +// +// Such code is NOT meant to be used by a user directly, and is subject +// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user +// program! + +#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ + +#include + + +// Ensures that there is at least one operator<< in the global namespace. +// See Message& operator<<(...) below for why. +void operator<<(const testing::internal::Secret&, int); + +namespace testing { + +// The Message class works like an ostream repeater. +// +// Typical usage: +// +// 1. You stream a bunch of values to a Message object. +// It will remember the text in a stringstream. +// 2. Then you stream the Message object to an ostream. +// This causes the text in the Message to be streamed +// to the ostream. +// +// For example; +// +// testing::Message foo; +// foo << 1 << " != " << 2; +// std::cout << foo; +// +// will print "1 != 2". +// +// Message is not intended to be inherited from. In particular, its +// destructor is not virtual. +// +// Note that stringstream behaves differently in gcc and in MSVC. You +// can stream a NULL char pointer to it in the former, but not in the +// latter (it causes an access violation if you do). The Message +// class hides this difference by treating a NULL char pointer as +// "(null)". +class GTEST_API_ Message { + private: + // The type of basic IO manipulators (endl, ends, and flush) for + // narrow streams. + typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); + + public: + // Constructs an empty Message. + Message(); + + // Copy constructor. + Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT + *ss_ << msg.GetString(); + } + + // Constructs a Message from a C-string. + explicit Message(const char* str) : ss_(new ::std::stringstream) { + *ss_ << str; + } + +#if GTEST_OS_SYMBIAN + // Streams a value (either a pointer or not) to this object. + template + inline Message& operator <<(const T& value) { + StreamHelper(typename internal::is_pointer::type(), value); + return *this; + } +#else + // Streams a non-pointer value to this object. + template + inline Message& operator <<(const T& val) { + // Some libraries overload << for STL containers. These + // overloads are defined in the global namespace instead of ::std. + // + // C++'s symbol lookup rule (i.e. Koenig lookup) says that these + // overloads are visible in either the std namespace or the global + // namespace, but not other namespaces, including the testing + // namespace which Google Test's Message class is in. + // + // To allow STL containers (and other types that has a << operator + // defined in the global namespace) to be used in Google Test + // assertions, testing::Message must access the custom << operator + // from the global namespace. With this using declaration, + // overloads of << defined in the global namespace and those + // visible via Koenig lookup are both exposed in this function. + using ::operator <<; + *ss_ << val; + return *this; + } + + // Streams a pointer value to this object. + // + // This function is an overload of the previous one. When you + // stream a pointer to a Message, this definition will be used as it + // is more specialized. (The C++ Standard, section + // [temp.func.order].) If you stream a non-pointer, then the + // previous definition will be used. + // + // The reason for this overload is that streaming a NULL pointer to + // ostream is undefined behavior. Depending on the compiler, you + // may get "0", "(nil)", "(null)", or an access violation. To + // ensure consistent result across compilers, we always treat NULL + // as "(null)". + template + inline Message& operator <<(T* const& pointer) { // NOLINT + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + return *this; + } +#endif // GTEST_OS_SYMBIAN + + // Since the basic IO manipulators are overloaded for both narrow + // and wide streams, we have to provide this specialized definition + // of operator <<, even though its body is the same as the + // templatized version above. Without this definition, streaming + // endl or other basic IO manipulators to Message will confuse the + // compiler. + Message& operator <<(BasicNarrowIoManip val) { + *ss_ << val; + return *this; + } + + // Instead of 1/0, we want to see true/false for bool values. + Message& operator <<(bool b) { + return *this << (b ? "true" : "false"); + } + + // These two overloads allow streaming a wide C string to a Message + // using the UTF-8 encoding. + Message& operator <<(const wchar_t* wide_c_str); + Message& operator <<(wchar_t* wide_c_str); + +#if GTEST_HAS_STD_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::std::wstring& wstr); +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_GLOBAL_WSTRING + // Converts the given wide string to a narrow string using the UTF-8 + // encoding, and streams the result to this Message object. + Message& operator <<(const ::wstring& wstr); +#endif // GTEST_HAS_GLOBAL_WSTRING + + // Gets the text streamed to this object so far as an std::string. + // Each '\0' character in the buffer is replaced with "\\0". + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + std::string GetString() const; + + private: + +#if GTEST_OS_SYMBIAN + // These are needed as the Nokia Symbian Compiler cannot decide between + // const T& and const T* in a function template. The Nokia compiler _can_ + // decide between class template specializations for T and T*, so a + // tr1::type_traits-like is_pointer works, and we can overload on that. + template + inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { + if (pointer == NULL) { + *ss_ << "(null)"; + } else { + *ss_ << pointer; + } + } + template + inline void StreamHelper(internal::false_type /*is_pointer*/, + const T& value) { + // See the comments in Message& operator <<(const T&) above for why + // we need this using statement. + using ::operator <<; + *ss_ << value; + } +#endif // GTEST_OS_SYMBIAN + + // We'll hold the text streamed to this object here. + const internal::scoped_ptr< ::std::stringstream> ss_; + + // We declare (but don't implement) this to prevent the compiler + // from implementing the assignment operator. + void operator=(const Message&); +}; + +// Streams a Message to an ostream. +inline std::ostream& operator <<(std::ostream& os, const Message& sb) { + return os << sb.GetString(); +} + +namespace internal { + +// Converts a streamable value to an std::string. A NULL pointer is +// converted to "(null)". When the input value is a ::string, +// ::std::string, ::wstring, or ::std::wstring object, each NUL +// character in it is replaced with "\\0". +template +std::string StreamableToString(const T& streamable) { + return (Message() << streamable).GetString(); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file declares the String class and functions used internally by +// Google Test. They are subject to change without notice. They should not used +// by code external to Google Test. +// +// This header file is #included by . +// It should not be #included by other files. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ + +#ifdef __BORLANDC__ +// string.h is not guaranteed to provide strcpy on C++ Builder. +# include +#endif + +#include +#include + + +namespace testing { +namespace internal { + +// String - an abstract class holding static string utilities. +class GTEST_API_ String { + public: + // Static utility methods + + // Clones a 0-terminated C string, allocating memory using new. The + // caller is responsible for deleting the return value using + // delete[]. Returns the cloned string, or NULL if the input is + // NULL. + // + // This is different from strdup() in string.h, which allocates + // memory using malloc(). + static const char* CloneCString(const char* c_str); + +#if GTEST_OS_WINDOWS_MOBILE + // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be + // able to pass strings to Win32 APIs on CE we need to convert them + // to 'Unicode', UTF-16. + + // Creates a UTF-16 wide string from the given ANSI string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the wide string, or NULL if the + // input is NULL. + // + // The wide string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static LPCWSTR AnsiToUtf16(const char* c_str); + + // Creates an ANSI string from the given wide string, allocating + // memory using new. The caller is responsible for deleting the return + // value using delete[]. Returns the ANSI string, or NULL if the + // input is NULL. + // + // The returned string is created using the ANSI codepage (CP_ACP) to + // match the behaviour of the ANSI versions of Win32 calls and the + // C runtime. + static const char* Utf16ToAnsi(LPCWSTR utf16_str); +#endif + + // Compares two C strings. Returns true iff they have the same content. + // + // Unlike strcmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CStringEquals(const char* lhs, const char* rhs); + + // Converts a wide C string to a String using the UTF-8 encoding. + // NULL will be converted to "(null)". If an error occurred during + // the conversion, "(failed to convert from wide string)" is + // returned. + static std::string ShowWideCString(const wchar_t* wide_c_str); + + // Compares two wide C strings. Returns true iff they have the same + // content. + // + // Unlike wcscmp(), this function can handle NULL argument(s). A + // NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); + + // Compares two C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike strcasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL C string, + // including the empty string. + static bool CaseInsensitiveCStringEquals(const char* lhs, + const char* rhs); + + // Compares two wide C strings, ignoring case. Returns true iff they + // have the same content. + // + // Unlike wcscasecmp(), this function can handle NULL argument(s). + // A NULL C string is considered different to any non-NULL wide C string, + // including the empty string. + // NB: The implementations on different platforms slightly differ. + // On windows, this method uses _wcsicmp which compares according to LC_CTYPE + // environment variable. On GNU platform this method uses wcscasecmp + // which compares according to LC_CTYPE category of the current locale. + // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the + // current locale. + static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, + const wchar_t* rhs); + + // Returns true iff the given string ends with the given suffix, ignoring + // case. Any string is considered to end with an empty suffix. + static bool EndsWithCaseInsensitive( + const std::string& str, const std::string& suffix); + + // Formats an int value as "%02d". + static std::string FormatIntWidth2(int value); // "%02d" for width == 2 + + // Formats an int value as "%X". + static std::string FormatHexInt(int value); + + // Formats a byte as "%02X". + static std::string FormatByte(unsigned char value); + + private: + String(); // Not meant to be instantiated. +}; // class String + +// Gets the content of the stringstream's buffer as an std::string. Each '\0' +// character in the buffer is replaced with "\\0". +GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: keith.ray@gmail.com (Keith Ray) +// +// Google Test filepath utilities +// +// This header file declares classes and functions used internally by +// Google Test. They are subject to change without notice. +// +// This file is #included in . +// Do not include this header file separately! + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ + + +namespace testing { +namespace internal { + +// FilePath - a class for file and directory pathname manipulation which +// handles platform-specific conventions (like the pathname separator). +// Used for helper functions for naming files in a directory for xml output. +// Except for Set methods, all methods are const or static, which provides an +// "immutable value object" -- useful for peace of mind. +// A FilePath with a value ending in a path separator ("like/this/") represents +// a directory, otherwise it is assumed to represent a file. In either case, +// it may or may not represent an actual file or directory in the file system. +// Names are NOT checked for syntax correctness -- no checking for illegal +// characters, malformed paths, etc. + +class GTEST_API_ FilePath { + public: + FilePath() : pathname_("") { } + FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } + + explicit FilePath(const std::string& pathname) : pathname_(pathname) { + Normalize(); + } + + FilePath& operator=(const FilePath& rhs) { + Set(rhs); + return *this; + } + + void Set(const FilePath& rhs) { + pathname_ = rhs.pathname_; + } + + const std::string& string() const { return pathname_; } + const char* c_str() const { return pathname_.c_str(); } + + // Returns the current working directory, or "" if unsuccessful. + static FilePath GetCurrentDir(); + + // Given directory = "dir", base_name = "test", number = 0, + // extension = "xml", returns "dir/test.xml". If number is greater + // than zero (e.g., 12), returns "dir/test_12.xml". + // On Windows platform, uses \ as the separator rather than /. + static FilePath MakeFileName(const FilePath& directory, + const FilePath& base_name, + int number, + const char* extension); + + // Given directory = "dir", relative_path = "test.xml", + // returns "dir/test.xml". + // On Windows, uses \ as the separator rather than /. + static FilePath ConcatPaths(const FilePath& directory, + const FilePath& relative_path); + + // Returns a pathname for a file that does not currently exist. The pathname + // will be directory/base_name.extension or + // directory/base_name_.extension if directory/base_name.extension + // already exists. The number will be incremented until a pathname is found + // that does not already exist. + // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. + // There could be a race condition if two or more processes are calling this + // function at the same time -- they could both pick the same filename. + static FilePath GenerateUniqueFileName(const FilePath& directory, + const FilePath& base_name, + const char* extension); + + // Returns true iff the path is "". + bool IsEmpty() const { return pathname_.empty(); } + + // If input name has a trailing separator character, removes it and returns + // the name, otherwise return the name string unmodified. + // On Windows platform, uses \ as the separator, other platforms use /. + FilePath RemoveTrailingPathSeparator() const; + + // Returns a copy of the FilePath with the directory part removed. + // Example: FilePath("path/to/file").RemoveDirectoryName() returns + // FilePath("file"). If there is no directory part ("just_a_file"), it returns + // the FilePath unmodified. If there is no file part ("just_a_dir/") it + // returns an empty FilePath (""). + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveDirectoryName() const; + + // RemoveFileName returns the directory path with the filename removed. + // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". + // If the FilePath is "a_file" or "/a_file", RemoveFileName returns + // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does + // not have a file, like "just/a/dir/", it returns the FilePath unmodified. + // On Windows platform, '\' is the path separator, otherwise it is '/'. + FilePath RemoveFileName() const; + + // Returns a copy of the FilePath with the case-insensitive extension removed. + // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns + // FilePath("dir/file"). If a case-insensitive extension is not + // found, returns a copy of the original FilePath. + FilePath RemoveExtension(const char* extension) const; + + // Creates directories so that path exists. Returns true if successful or if + // the directories already exist; returns false if unable to create + // directories for any reason. Will also return false if the FilePath does + // not represent a directory (that is, it doesn't end with a path separator). + bool CreateDirectoriesRecursively() const; + + // Create the directory so that path exists. Returns true if successful or + // if the directory already exists; returns false if unable to create the + // directory for any reason, including if the parent directory does not + // exist. Not named "CreateDirectory" because that's a macro on Windows. + bool CreateFolder() const; + + // Returns true if FilePath describes something in the file-system, + // either a file, directory, or whatever, and that something exists. + bool FileOrDirectoryExists() const; + + // Returns true if pathname describes a directory in the file-system + // that exists. + bool DirectoryExists() const; + + // Returns true if FilePath ends with a path separator, which indicates that + // it is intended to represent a directory. Returns false otherwise. + // This does NOT check that a directory (or file) actually exists. + bool IsDirectory() const; + + // Returns true if pathname describes a root directory. (Windows has one + // root directory per disk drive.) + bool IsRootDirectory() const; + + // Returns true if pathname describes an absolute path. + bool IsAbsolutePath() const; + + private: + // Replaces multiple consecutive separators with a single separator. + // For example, "bar///foo" becomes "bar/foo". Does not eliminate other + // redundancies that might be in a pathname involving "." or "..". + // + // A pathname with multiple consecutive separators may occur either through + // user error or as a result of some scripts or APIs that generate a pathname + // with a trailing separator. On other platforms the same API or script + // may NOT generate a pathname with a trailing "/". Then elsewhere that + // pathname may have another "/" and pathname components added to it, + // without checking for the separator already being there. + // The script language and operating system may allow paths like "foo//bar" + // but some of the functions in FilePath will not handle that correctly. In + // particular, RemoveTrailingPathSeparator() only removes one separator, and + // it is called in CreateDirectoriesRecursively() assuming that it will change + // a pathname from directory syntax (trailing separator) to filename syntax. + // + // On Windows this method also replaces the alternate path separator '/' with + // the primary path separator '\\', so that for example "bar\\/\\foo" becomes + // "bar\\foo". + + void Normalize(); + + // Returns a pointer to the last occurence of a valid path separator in + // the FilePath. On Windows, for example, both '/' and '\' are valid path + // separators. Returns NULL if no path separator was found. + const char* FindLastPathSeparator() const; + + std::string pathname_; +}; // class FilePath + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ +// This file was GENERATED by command: +// pump.py gtest-type-util.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Type utilities needed for implementing typed and type-parameterized +// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently we support at most 50 types in a list, and at most 50 +// type-parameterized tests in one type-parameterized test case. +// Please contact googletestframework@googlegroups.com if you need +// more. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + + +// #ifdef __GNUC__ is too general here. It is possible to use gcc without using +// libstdc++ (which is where cxxabi.h comes from). +# if GTEST_HAS_CXXABI_H_ +# include +# elif defined(__HP_aCC) +# include +# endif // GTEST_HASH_CXXABI_H_ + +namespace testing { +namespace internal { + +// GetTypeName() returns a human-readable name of type T. +// NB: This function is also used in Google Mock, so don't move it inside of +// the typed-test-only section below. +template +std::string GetTypeName() { +# if GTEST_HAS_RTTI + + const char* const name = typeid(T).name(); +# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) + int status = 0; + // gcc's implementation of typeid(T).name() mangles the type name, + // so we have to demangle it. +# if GTEST_HAS_CXXABI_H_ + using abi::__cxa_demangle; +# endif // GTEST_HAS_CXXABI_H_ + char* const readable_name = __cxa_demangle(name, 0, 0, &status); + const std::string name_str(status == 0 ? readable_name : name); + free(readable_name); + return name_str; +# else + return name; +# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC + +# else + + return ""; + +# endif // GTEST_HAS_RTTI +} + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// AssertyTypeEq::type is defined iff T1 and T2 are the same +// type. This can be used as a compile-time assertion to ensure that +// two types are equal. + +template +struct AssertTypeEq; + +template +struct AssertTypeEq { + typedef bool type; +}; + +// A unique type used as the default value for the arguments of class +// template Types. This allows us to simulate variadic templates +// (e.g. Types, Type, and etc), which C++ doesn't +// support directly. +struct None {}; + +// The following family of struct and struct templates are used to +// represent type lists. In particular, TypesN +// represents a type list with N types (T1, T2, ..., and TN) in it. +// Except for Types0, every struct in the family has two member types: +// Head for the first type in the list, and Tail for the rest of the +// list. + +// The empty type list. +struct Types0 {}; + +// Type lists of length 1, 2, 3, and so on. + +template +struct Types1 { + typedef T1 Head; + typedef Types0 Tail; +}; +template +struct Types2 { + typedef T1 Head; + typedef Types1 Tail; +}; + +template +struct Types3 { + typedef T1 Head; + typedef Types2 Tail; +}; + +template +struct Types4 { + typedef T1 Head; + typedef Types3 Tail; +}; + +template +struct Types5 { + typedef T1 Head; + typedef Types4 Tail; +}; + +template +struct Types6 { + typedef T1 Head; + typedef Types5 Tail; +}; + +template +struct Types7 { + typedef T1 Head; + typedef Types6 Tail; +}; + +template +struct Types8 { + typedef T1 Head; + typedef Types7 Tail; +}; + +template +struct Types9 { + typedef T1 Head; + typedef Types8 Tail; +}; + +template +struct Types10 { + typedef T1 Head; + typedef Types9 Tail; +}; + +template +struct Types11 { + typedef T1 Head; + typedef Types10 Tail; +}; + +template +struct Types12 { + typedef T1 Head; + typedef Types11 Tail; +}; + +template +struct Types13 { + typedef T1 Head; + typedef Types12 Tail; +}; + +template +struct Types14 { + typedef T1 Head; + typedef Types13 Tail; +}; + +template +struct Types15 { + typedef T1 Head; + typedef Types14 Tail; +}; + +template +struct Types16 { + typedef T1 Head; + typedef Types15 Tail; +}; + +template +struct Types17 { + typedef T1 Head; + typedef Types16 Tail; +}; + +template +struct Types18 { + typedef T1 Head; + typedef Types17 Tail; +}; + +template +struct Types19 { + typedef T1 Head; + typedef Types18 Tail; +}; + +template +struct Types20 { + typedef T1 Head; + typedef Types19 Tail; +}; + +template +struct Types21 { + typedef T1 Head; + typedef Types20 Tail; +}; + +template +struct Types22 { + typedef T1 Head; + typedef Types21 Tail; +}; + +template +struct Types23 { + typedef T1 Head; + typedef Types22 Tail; +}; + +template +struct Types24 { + typedef T1 Head; + typedef Types23 Tail; +}; + +template +struct Types25 { + typedef T1 Head; + typedef Types24 Tail; +}; + +template +struct Types26 { + typedef T1 Head; + typedef Types25 Tail; +}; + +template +struct Types27 { + typedef T1 Head; + typedef Types26 Tail; +}; + +template +struct Types28 { + typedef T1 Head; + typedef Types27 Tail; +}; + +template +struct Types29 { + typedef T1 Head; + typedef Types28 Tail; +}; + +template +struct Types30 { + typedef T1 Head; + typedef Types29 Tail; +}; + +template +struct Types31 { + typedef T1 Head; + typedef Types30 Tail; +}; + +template +struct Types32 { + typedef T1 Head; + typedef Types31 Tail; +}; + +template +struct Types33 { + typedef T1 Head; + typedef Types32 Tail; +}; + +template +struct Types34 { + typedef T1 Head; + typedef Types33 Tail; +}; + +template +struct Types35 { + typedef T1 Head; + typedef Types34 Tail; +}; + +template +struct Types36 { + typedef T1 Head; + typedef Types35 Tail; +}; + +template +struct Types37 { + typedef T1 Head; + typedef Types36 Tail; +}; + +template +struct Types38 { + typedef T1 Head; + typedef Types37 Tail; +}; + +template +struct Types39 { + typedef T1 Head; + typedef Types38 Tail; +}; + +template +struct Types40 { + typedef T1 Head; + typedef Types39 Tail; +}; + +template +struct Types41 { + typedef T1 Head; + typedef Types40 Tail; +}; + +template +struct Types42 { + typedef T1 Head; + typedef Types41 Tail; +}; + +template +struct Types43 { + typedef T1 Head; + typedef Types42 Tail; +}; + +template +struct Types44 { + typedef T1 Head; + typedef Types43 Tail; +}; + +template +struct Types45 { + typedef T1 Head; + typedef Types44 Tail; +}; + +template +struct Types46 { + typedef T1 Head; + typedef Types45 Tail; +}; + +template +struct Types47 { + typedef T1 Head; + typedef Types46 Tail; +}; + +template +struct Types48 { + typedef T1 Head; + typedef Types47 Tail; +}; + +template +struct Types49 { + typedef T1 Head; + typedef Types48 Tail; +}; + +template +struct Types50 { + typedef T1 Head; + typedef Types49 Tail; +}; + + +} // namespace internal + +// We don't want to require the users to write TypesN<...> directly, +// as that would require them to count the length. Types<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Types +// will appear as Types in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Types, and Google Test will translate +// that to TypesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Types template. +template +struct Types { + typedef internal::Types50 type; +}; + +template <> +struct Types { + typedef internal::Types0 type; +}; +template +struct Types { + typedef internal::Types1 type; +}; +template +struct Types { + typedef internal::Types2 type; +}; +template +struct Types { + typedef internal::Types3 type; +}; +template +struct Types { + typedef internal::Types4 type; +}; +template +struct Types { + typedef internal::Types5 type; +}; +template +struct Types { + typedef internal::Types6 type; +}; +template +struct Types { + typedef internal::Types7 type; +}; +template +struct Types { + typedef internal::Types8 type; +}; +template +struct Types { + typedef internal::Types9 type; +}; +template +struct Types { + typedef internal::Types10 type; +}; +template +struct Types { + typedef internal::Types11 type; +}; +template +struct Types { + typedef internal::Types12 type; +}; +template +struct Types { + typedef internal::Types13 type; +}; +template +struct Types { + typedef internal::Types14 type; +}; +template +struct Types { + typedef internal::Types15 type; +}; +template +struct Types { + typedef internal::Types16 type; +}; +template +struct Types { + typedef internal::Types17 type; +}; +template +struct Types { + typedef internal::Types18 type; +}; +template +struct Types { + typedef internal::Types19 type; +}; +template +struct Types { + typedef internal::Types20 type; +}; +template +struct Types { + typedef internal::Types21 type; +}; +template +struct Types { + typedef internal::Types22 type; +}; +template +struct Types { + typedef internal::Types23 type; +}; +template +struct Types { + typedef internal::Types24 type; +}; +template +struct Types { + typedef internal::Types25 type; +}; +template +struct Types { + typedef internal::Types26 type; +}; +template +struct Types { + typedef internal::Types27 type; +}; +template +struct Types { + typedef internal::Types28 type; +}; +template +struct Types { + typedef internal::Types29 type; +}; +template +struct Types { + typedef internal::Types30 type; +}; +template +struct Types { + typedef internal::Types31 type; +}; +template +struct Types { + typedef internal::Types32 type; +}; +template +struct Types { + typedef internal::Types33 type; +}; +template +struct Types { + typedef internal::Types34 type; +}; +template +struct Types { + typedef internal::Types35 type; +}; +template +struct Types { + typedef internal::Types36 type; +}; +template +struct Types { + typedef internal::Types37 type; +}; +template +struct Types { + typedef internal::Types38 type; +}; +template +struct Types { + typedef internal::Types39 type; +}; +template +struct Types { + typedef internal::Types40 type; +}; +template +struct Types { + typedef internal::Types41 type; +}; +template +struct Types { + typedef internal::Types42 type; +}; +template +struct Types { + typedef internal::Types43 type; +}; +template +struct Types { + typedef internal::Types44 type; +}; +template +struct Types { + typedef internal::Types45 type; +}; +template +struct Types { + typedef internal::Types46 type; +}; +template +struct Types { + typedef internal::Types47 type; +}; +template +struct Types { + typedef internal::Types48 type; +}; +template +struct Types { + typedef internal::Types49 type; +}; + +namespace internal { + +# define GTEST_TEMPLATE_ template class + +// The template "selector" struct TemplateSel is used to +// represent Tmpl, which must be a class template with one type +// parameter, as a type. TemplateSel::Bind::type is defined +// as the type Tmpl. This allows us to actually instantiate the +// template "selected" by TemplateSel. +// +// This trick is necessary for simulating typedef for class templates, +// which C++ doesn't support directly. +template +struct TemplateSel { + template + struct Bind { + typedef Tmpl type; + }; +}; + +# define GTEST_BIND_(TmplSel, T) \ + TmplSel::template Bind::type + +// A unique struct template used as the default value for the +// arguments of class template Templates. This allows us to simulate +// variadic templates (e.g. Templates, Templates, +// and etc), which C++ doesn't support directly. +template +struct NoneT {}; + +// The following family of struct and struct templates are used to +// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except +// for Templates0, every struct in the family has two member types: +// Head for the selector of the first template in the list, and Tail +// for the rest of the list. + +// The empty template list. +struct Templates0 {}; + +// Template lists of length 1, 2, 3, and so on. + +template +struct Templates1 { + typedef TemplateSel Head; + typedef Templates0 Tail; +}; +template +struct Templates2 { + typedef TemplateSel Head; + typedef Templates1 Tail; +}; + +template +struct Templates3 { + typedef TemplateSel Head; + typedef Templates2 Tail; +}; + +template +struct Templates4 { + typedef TemplateSel Head; + typedef Templates3 Tail; +}; + +template +struct Templates5 { + typedef TemplateSel Head; + typedef Templates4 Tail; +}; + +template +struct Templates6 { + typedef TemplateSel Head; + typedef Templates5 Tail; +}; + +template +struct Templates7 { + typedef TemplateSel Head; + typedef Templates6 Tail; +}; + +template +struct Templates8 { + typedef TemplateSel Head; + typedef Templates7 Tail; +}; + +template +struct Templates9 { + typedef TemplateSel Head; + typedef Templates8 Tail; +}; + +template +struct Templates10 { + typedef TemplateSel Head; + typedef Templates9 Tail; +}; + +template +struct Templates11 { + typedef TemplateSel Head; + typedef Templates10 Tail; +}; + +template +struct Templates12 { + typedef TemplateSel Head; + typedef Templates11 Tail; +}; + +template +struct Templates13 { + typedef TemplateSel Head; + typedef Templates12 Tail; +}; + +template +struct Templates14 { + typedef TemplateSel Head; + typedef Templates13 Tail; +}; + +template +struct Templates15 { + typedef TemplateSel Head; + typedef Templates14 Tail; +}; + +template +struct Templates16 { + typedef TemplateSel Head; + typedef Templates15 Tail; +}; + +template +struct Templates17 { + typedef TemplateSel Head; + typedef Templates16 Tail; +}; + +template +struct Templates18 { + typedef TemplateSel Head; + typedef Templates17 Tail; +}; + +template +struct Templates19 { + typedef TemplateSel Head; + typedef Templates18 Tail; +}; + +template +struct Templates20 { + typedef TemplateSel Head; + typedef Templates19 Tail; +}; + +template +struct Templates21 { + typedef TemplateSel Head; + typedef Templates20 Tail; +}; + +template +struct Templates22 { + typedef TemplateSel Head; + typedef Templates21 Tail; +}; + +template +struct Templates23 { + typedef TemplateSel Head; + typedef Templates22 Tail; +}; + +template +struct Templates24 { + typedef TemplateSel Head; + typedef Templates23 Tail; +}; + +template +struct Templates25 { + typedef TemplateSel Head; + typedef Templates24 Tail; +}; + +template +struct Templates26 { + typedef TemplateSel Head; + typedef Templates25 Tail; +}; + +template +struct Templates27 { + typedef TemplateSel Head; + typedef Templates26 Tail; +}; + +template +struct Templates28 { + typedef TemplateSel Head; + typedef Templates27 Tail; +}; + +template +struct Templates29 { + typedef TemplateSel Head; + typedef Templates28 Tail; +}; + +template +struct Templates30 { + typedef TemplateSel Head; + typedef Templates29 Tail; +}; + +template +struct Templates31 { + typedef TemplateSel Head; + typedef Templates30 Tail; +}; + +template +struct Templates32 { + typedef TemplateSel Head; + typedef Templates31 Tail; +}; + +template +struct Templates33 { + typedef TemplateSel Head; + typedef Templates32 Tail; +}; + +template +struct Templates34 { + typedef TemplateSel Head; + typedef Templates33 Tail; +}; + +template +struct Templates35 { + typedef TemplateSel Head; + typedef Templates34 Tail; +}; + +template +struct Templates36 { + typedef TemplateSel Head; + typedef Templates35 Tail; +}; + +template +struct Templates37 { + typedef TemplateSel Head; + typedef Templates36 Tail; +}; + +template +struct Templates38 { + typedef TemplateSel Head; + typedef Templates37 Tail; +}; + +template +struct Templates39 { + typedef TemplateSel Head; + typedef Templates38 Tail; +}; + +template +struct Templates40 { + typedef TemplateSel Head; + typedef Templates39 Tail; +}; + +template +struct Templates41 { + typedef TemplateSel Head; + typedef Templates40 Tail; +}; + +template +struct Templates42 { + typedef TemplateSel Head; + typedef Templates41 Tail; +}; + +template +struct Templates43 { + typedef TemplateSel Head; + typedef Templates42 Tail; +}; + +template +struct Templates44 { + typedef TemplateSel Head; + typedef Templates43 Tail; +}; + +template +struct Templates45 { + typedef TemplateSel Head; + typedef Templates44 Tail; +}; + +template +struct Templates46 { + typedef TemplateSel Head; + typedef Templates45 Tail; +}; + +template +struct Templates47 { + typedef TemplateSel Head; + typedef Templates46 Tail; +}; + +template +struct Templates48 { + typedef TemplateSel Head; + typedef Templates47 Tail; +}; + +template +struct Templates49 { + typedef TemplateSel Head; + typedef Templates48 Tail; +}; + +template +struct Templates50 { + typedef TemplateSel Head; + typedef Templates49 Tail; +}; + + +// We don't want to require the users to write TemplatesN<...> directly, +// as that would require them to count the length. Templates<...> is much +// easier to write, but generates horrible messages when there is a +// compiler error, as gcc insists on printing out each template +// argument, even if it has the default value (this means Templates +// will appear as Templates in the compiler +// errors). +// +// Our solution is to combine the best part of the two approaches: a +// user would write Templates, and Google Test will translate +// that to TemplatesN internally to make error messages +// readable. The translation is done by the 'type' member of the +// Templates template. +template +struct Templates { + typedef Templates50 type; +}; + +template <> +struct Templates { + typedef Templates0 type; +}; +template +struct Templates { + typedef Templates1 type; +}; +template +struct Templates { + typedef Templates2 type; +}; +template +struct Templates { + typedef Templates3 type; +}; +template +struct Templates { + typedef Templates4 type; +}; +template +struct Templates { + typedef Templates5 type; +}; +template +struct Templates { + typedef Templates6 type; +}; +template +struct Templates { + typedef Templates7 type; +}; +template +struct Templates { + typedef Templates8 type; +}; +template +struct Templates { + typedef Templates9 type; +}; +template +struct Templates { + typedef Templates10 type; +}; +template +struct Templates { + typedef Templates11 type; +}; +template +struct Templates { + typedef Templates12 type; +}; +template +struct Templates { + typedef Templates13 type; +}; +template +struct Templates { + typedef Templates14 type; +}; +template +struct Templates { + typedef Templates15 type; +}; +template +struct Templates { + typedef Templates16 type; +}; +template +struct Templates { + typedef Templates17 type; +}; +template +struct Templates { + typedef Templates18 type; +}; +template +struct Templates { + typedef Templates19 type; +}; +template +struct Templates { + typedef Templates20 type; +}; +template +struct Templates { + typedef Templates21 type; +}; +template +struct Templates { + typedef Templates22 type; +}; +template +struct Templates { + typedef Templates23 type; +}; +template +struct Templates { + typedef Templates24 type; +}; +template +struct Templates { + typedef Templates25 type; +}; +template +struct Templates { + typedef Templates26 type; +}; +template +struct Templates { + typedef Templates27 type; +}; +template +struct Templates { + typedef Templates28 type; +}; +template +struct Templates { + typedef Templates29 type; +}; +template +struct Templates { + typedef Templates30 type; +}; +template +struct Templates { + typedef Templates31 type; +}; +template +struct Templates { + typedef Templates32 type; +}; +template +struct Templates { + typedef Templates33 type; +}; +template +struct Templates { + typedef Templates34 type; +}; +template +struct Templates { + typedef Templates35 type; +}; +template +struct Templates { + typedef Templates36 type; +}; +template +struct Templates { + typedef Templates37 type; +}; +template +struct Templates { + typedef Templates38 type; +}; +template +struct Templates { + typedef Templates39 type; +}; +template +struct Templates { + typedef Templates40 type; +}; +template +struct Templates { + typedef Templates41 type; +}; +template +struct Templates { + typedef Templates42 type; +}; +template +struct Templates { + typedef Templates43 type; +}; +template +struct Templates { + typedef Templates44 type; +}; +template +struct Templates { + typedef Templates45 type; +}; +template +struct Templates { + typedef Templates46 type; +}; +template +struct Templates { + typedef Templates47 type; +}; +template +struct Templates { + typedef Templates48 type; +}; +template +struct Templates { + typedef Templates49 type; +}; + +// The TypeList template makes it possible to use either a single type +// or a Types<...> list in TYPED_TEST_CASE() and +// INSTANTIATE_TYPED_TEST_CASE_P(). + +template +struct TypeList { + typedef Types1 type; +}; + +template +struct TypeList > { + typedef typename Types::type type; +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ + +// Due to C++ preprocessor weirdness, we need double indirection to +// concatenate two tokens when one of them is __LINE__. Writing +// +// foo ## __LINE__ +// +// will result in the token foo__LINE__, instead of foo followed by +// the current line number. For more details, see +// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 +#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) +#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar + +class ProtocolMessage; +namespace proto2 { class Message; } + +namespace testing { + +// Forward declarations. + +class AssertionResult; // Result of an assertion. +class Message; // Represents a failure message. +class Test; // Represents a test. +class TestInfo; // Information about a test. +class TestPartResult; // Result of a test part. +class UnitTest; // A collection of test cases. + +template +::std::string PrintToString(const T& value); + +namespace internal { + +struct TraceInfo; // Information about a trace point. +class ScopedTrace; // Implements scoped trace. +class TestInfoImpl; // Opaque implementation of TestInfo +class UnitTestImpl; // Opaque implementation of UnitTest + +// How many times InitGoogleTest() has been called. +GTEST_API_ extern int g_init_gtest_count; + +// The text used in failure messages to indicate the start of the +// stack trace. +GTEST_API_ extern const char kStackTraceMarker[]; + +// Two overloaded helpers for checking at compile time whether an +// expression is a null pointer literal (i.e. NULL or any 0-valued +// compile-time integral constant). Their return values have +// different sizes, so we can use sizeof() to test which version is +// picked by the compiler. These helpers have no implementations, as +// we only need their signatures. +// +// Given IsNullLiteralHelper(x), the compiler will pick the first +// version if x can be implicitly converted to Secret*, and pick the +// second version otherwise. Since Secret is a secret and incomplete +// type, the only expression a user can write that has type Secret* is +// a null pointer literal. Therefore, we know that x is a null +// pointer literal if and only if the first version is picked by the +// compiler. +char IsNullLiteralHelper(Secret* p); +char (&IsNullLiteralHelper(...))[2]; // NOLINT + +// A compile-time bool constant that is true if and only if x is a +// null pointer literal (i.e. NULL or any 0-valued compile-time +// integral constant). +#ifdef GTEST_ELLIPSIS_NEEDS_POD_ +// We lose support for NULL detection where the compiler doesn't like +// passing non-POD classes through ellipsis (...). +# define GTEST_IS_NULL_LITERAL_(x) false +#else +# define GTEST_IS_NULL_LITERAL_(x) \ + (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) +#endif // GTEST_ELLIPSIS_NEEDS_POD_ + +// Appends the user-supplied message to the Google-Test-generated message. +GTEST_API_ std::string AppendUserMessage( + const std::string& gtest_msg, const Message& user_msg); + +#if GTEST_HAS_EXCEPTIONS + +// This exception is thrown by (and only by) a failed Google Test +// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions +// are enabled). We derive it from std::runtime_error, which is for +// errors presumably detectable only at run time. Since +// std::runtime_error inherits from std::exception, many testing +// frameworks know how to extract and print the message inside it. +class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { + public: + explicit GoogleTestFailureException(const TestPartResult& failure); +}; + +#endif // GTEST_HAS_EXCEPTIONS + +// A helper class for creating scoped traces in user programs. +class GTEST_API_ ScopedTrace { + public: + // The c'tor pushes the given source file location and message onto + // a trace stack maintained by Google Test. + ScopedTrace(const char* file, int line, const Message& message); + + // The d'tor pops the info pushed by the c'tor. + // + // Note that the d'tor is not virtual in order to be efficient. + // Don't inherit from ScopedTrace! + ~ScopedTrace(); + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); +} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its + // c'tor and d'tor. Therefore it doesn't + // need to be used otherwise. + +// Constructs and returns the message for an equality assertion +// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. +// +// The first four parameters are the expressions used in the assertion +// and their values, as strings. For example, for ASSERT_EQ(foo, bar) +// where foo is 5 and bar is 6, we have: +// +// expected_expression: "foo" +// actual_expression: "bar" +// expected_value: "5" +// actual_value: "6" +// +// The ignoring_case parameter is true iff the assertion is a +// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will +// be inserted into the message. +GTEST_API_ AssertionResult EqFailure(const char* expected_expression, + const char* actual_expression, + const std::string& expected_value, + const std::string& actual_value, + bool ignoring_case); + +// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. +GTEST_API_ std::string GetBoolAssertionFailureMessage( + const AssertionResult& assertion_result, + const char* expression_text, + const char* actual_predicate_value, + const char* expected_predicate_value); + +// This template class represents an IEEE floating-point number +// (either single-precision or double-precision, depending on the +// template parameters). +// +// The purpose of this class is to do more sophisticated number +// comparison. (Due to round-off error, etc, it's very unlikely that +// two floating-points will be equal exactly. Hence a naive +// comparison by the == operation often doesn't work.) +// +// Format of IEEE floating-point: +// +// The most-significant bit being the leftmost, an IEEE +// floating-point looks like +// +// sign_bit exponent_bits fraction_bits +// +// Here, sign_bit is a single bit that designates the sign of the +// number. +// +// For float, there are 8 exponent bits and 23 fraction bits. +// +// For double, there are 11 exponent bits and 52 fraction bits. +// +// More details can be found at +// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +template +class FloatingPoint { + public: + // Defines the unsigned integer type that has the same size as the + // floating point number. + typedef typename TypeWithSize::UInt Bits; + + // Constants. + + // # of bits in a number. + static const size_t kBitCount = 8*sizeof(RawType); + + // # of fraction bits in a number. + static const size_t kFractionBitCount = + std::numeric_limits::digits - 1; + + // # of exponent bits in a number. + static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; + + // The mask for the sign bit. + static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); + + // The mask for the fraction bits. + static const Bits kFractionBitMask = + ~static_cast(0) >> (kExponentBitCount + 1); + + // The mask for the exponent bits. + static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); + + // How many ULP's (Units in the Last Place) we want to tolerate when + // comparing two numbers. The larger the value, the more error we + // allow. A 0 value means that two numbers must be exactly the same + // to be considered equal. + // + // The maximum error of a single floating-point operation is 0.5 + // units in the last place. On Intel CPU's, all floating-point + // calculations are done with 80-bit precision, while double has 64 + // bits. Therefore, 4 should be enough for ordinary use. + // + // See the following article for more details on ULP: + // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ + static const size_t kMaxUlps = 4; + + // Constructs a FloatingPoint from a raw floating-point number. + // + // On an Intel CPU, passing a non-normalized NAN (Not a Number) + // around may change its bits, although the new value is guaranteed + // to be also a NAN. Therefore, don't expect this constructor to + // preserve the bits in x when x is a NAN. + explicit FloatingPoint(const RawType& x) { u_.value_ = x; } + + // Static methods + + // Reinterprets a bit pattern as a floating-point number. + // + // This function is needed to test the AlmostEquals() method. + static RawType ReinterpretBits(const Bits bits) { + FloatingPoint fp(0); + fp.u_.bits_ = bits; + return fp.u_.value_; + } + + // Returns the floating-point number that represent positive infinity. + static RawType Infinity() { + return ReinterpretBits(kExponentBitMask); + } + + // Returns the maximum representable finite floating-point number. + static RawType Max(); + + // Non-static methods + + // Returns the bits that represents this number. + const Bits &bits() const { return u_.bits_; } + + // Returns the exponent bits of this number. + Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } + + // Returns the fraction bits of this number. + Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } + + // Returns the sign bit of this number. + Bits sign_bit() const { return kSignBitMask & u_.bits_; } + + // Returns true iff this is NAN (not a number). + bool is_nan() const { + // It's a NAN if the exponent bits are all ones and the fraction + // bits are not entirely zeros. + return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); + } + + // Returns true iff this number is at most kMaxUlps ULP's away from + // rhs. In particular, this function: + // + // - returns false if either number is (or both are) NAN. + // - treats really large numbers as almost equal to infinity. + // - thinks +0.0 and -0.0 are 0 DLP's apart. + bool AlmostEquals(const FloatingPoint& rhs) const { + // The IEEE standard says that any comparison operation involving + // a NAN must return false. + if (is_nan() || rhs.is_nan()) return false; + + return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) + <= kMaxUlps; + } + + private: + // The data type used to store the actual floating-point number. + union FloatingPointUnion { + RawType value_; // The raw floating-point number. + Bits bits_; // The bits that represent the number. + }; + + // Converts an integer from the sign-and-magnitude representation to + // the biased representation. More precisely, let N be 2 to the + // power of (kBitCount - 1), an integer x is represented by the + // unsigned number x + N. + // + // For instance, + // + // -N + 1 (the most negative number representable using + // sign-and-magnitude) is represented by 1; + // 0 is represented by N; and + // N - 1 (the biggest number representable using + // sign-and-magnitude) is represented by 2N - 1. + // + // Read http://en.wikipedia.org/wiki/Signed_number_representations + // for more details on signed number representations. + static Bits SignAndMagnitudeToBiased(const Bits &sam) { + if (kSignBitMask & sam) { + // sam represents a negative number. + return ~sam + 1; + } else { + // sam represents a positive number. + return kSignBitMask | sam; + } + } + + // Given two numbers in the sign-and-magnitude representation, + // returns the distance between them as an unsigned number. + static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, + const Bits &sam2) { + const Bits biased1 = SignAndMagnitudeToBiased(sam1); + const Bits biased2 = SignAndMagnitudeToBiased(sam2); + return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); + } + + FloatingPointUnion u_; +}; + +// We cannot use std::numeric_limits::max() as it clashes with the max() +// macro defined by . +template <> +inline float FloatingPoint::Max() { return FLT_MAX; } +template <> +inline double FloatingPoint::Max() { return DBL_MAX; } + +// Typedefs the instances of the FloatingPoint template class that we +// care to use. +typedef FloatingPoint Float; +typedef FloatingPoint Double; + +// In order to catch the mistake of putting tests that use different +// test fixture classes in the same test case, we need to assign +// unique IDs to fixture classes and compare them. The TypeId type is +// used to hold such IDs. The user should treat TypeId as an opaque +// type: the only operation allowed on TypeId values is to compare +// them for equality using the == operator. +typedef const void* TypeId; + +template +class TypeIdHelper { + public: + // dummy_ must not have a const type. Otherwise an overly eager + // compiler (e.g. MSVC 7.1 & 8.0) may try to merge + // TypeIdHelper::dummy_ for different Ts as an "optimization". + static bool dummy_; +}; + +template +bool TypeIdHelper::dummy_ = false; + +// GetTypeId() returns the ID of type T. Different values will be +// returned for different types. Calling the function twice with the +// same type argument is guaranteed to return the same ID. +template +TypeId GetTypeId() { + // The compiler is required to allocate a different + // TypeIdHelper::dummy_ variable for each T used to instantiate + // the template. Therefore, the address of dummy_ is guaranteed to + // be unique. + return &(TypeIdHelper::dummy_); +} + +// Returns the type ID of ::testing::Test. Always call this instead +// of GetTypeId< ::testing::Test>() to get the type ID of +// ::testing::Test, as the latter may give the wrong result due to a +// suspected linker bug when compiling Google Test as a Mac OS X +// framework. +GTEST_API_ TypeId GetTestTypeId(); + +// Defines the abstract factory interface that creates instances +// of a Test object. +class TestFactoryBase { + public: + virtual ~TestFactoryBase() {} + + // Creates a test instance to run. The instance is both created and destroyed + // within TestInfoImpl::Run() + virtual Test* CreateTest() = 0; + + protected: + TestFactoryBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); +}; + +// This class provides implementation of TeastFactoryBase interface. +// It is used in TEST and TEST_F macros. +template +class TestFactoryImpl : public TestFactoryBase { + public: + virtual Test* CreateTest() { return new TestClass; } +}; + +#if GTEST_OS_WINDOWS + +// Predicate-formatters for implementing the HRESULT checking macros +// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} +// We pass a long instead of HRESULT to avoid causing an +// include dependency for the HRESULT type. +GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, + long hr); // NOLINT +GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, + long hr); // NOLINT + +#endif // GTEST_OS_WINDOWS + +// Types of SetUpTestCase() and TearDownTestCase() functions. +typedef void (*SetUpTestCaseFunc)(); +typedef void (*TearDownTestCaseFunc)(); + +// Creates a new TestInfo object and registers it with Google Test; +// returns the created object. +// +// Arguments: +// +// test_case_name: name of the test case +// name: name of the test +// type_param the name of the test's type parameter, or NULL if +// this is not a typed or a type-parameterized test. +// value_param text representation of the test's value parameter, +// or NULL if this is not a type-parameterized test. +// fixture_class_id: ID of the test fixture class +// set_up_tc: pointer to the function that sets up the test case +// tear_down_tc: pointer to the function that tears down the test case +// factory: pointer to the factory that creates a test object. +// The newly created TestInfo instance will assume +// ownership of the factory object. +GTEST_API_ TestInfo* MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + TypeId fixture_class_id, + SetUpTestCaseFunc set_up_tc, + TearDownTestCaseFunc tear_down_tc, + TestFactoryBase* factory); + +// If *pstr starts with the given prefix, modifies *pstr to be right +// past the prefix and returns true; otherwise leaves *pstr unchanged +// and returns false. None of pstr, *pstr, and prefix can be NULL. +GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); + +#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// State of the definition of a type-parameterized test case. +class GTEST_API_ TypedTestCasePState { + public: + TypedTestCasePState() : registered_(false) {} + + // Adds the given test name to defined_test_names_ and return true + // if the test case hasn't been registered; otherwise aborts the + // program. + bool AddTestName(const char* file, int line, const char* case_name, + const char* test_name) { + if (registered_) { + fprintf(stderr, "%s Test %s must be defined before " + "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", + FormatFileLocation(file, line).c_str(), test_name, case_name); + fflush(stderr); + posix::Abort(); + } + defined_test_names_.insert(test_name); + return true; + } + + // Verifies that registered_tests match the test names in + // defined_test_names_; returns registered_tests if successful, or + // aborts the program otherwise. + const char* VerifyRegisteredTestNames( + const char* file, int line, const char* registered_tests); + + private: + bool registered_; + ::std::set defined_test_names_; +}; + +// Skips to the first non-space char after the first comma in 'str'; +// returns NULL if no comma is found in 'str'. +inline const char* SkipComma(const char* str) { + const char* comma = strchr(str, ','); + if (comma == NULL) { + return NULL; + } + while (IsSpace(*(++comma))) {} + return comma; +} + +// Returns the prefix of 'str' before the first comma in it; returns +// the entire string if it contains no comma. +inline std::string GetPrefixUntilComma(const char* str) { + const char* comma = strchr(str, ','); + return comma == NULL ? str : std::string(str, comma); +} + +// TypeParameterizedTest::Register() +// registers a list of type-parameterized tests with Google Test. The +// return value is insignificant - we just need to return something +// such that we can call this function in a namespace scope. +// +// Implementation note: The GTEST_TEMPLATE_ macro declares a template +// template parameter. It's defined in gtest-type-util.h. +template +class TypeParameterizedTest { + public: + // 'index' is the index of the test in the type list 'Types' + // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, + // Types). Valid values for 'index' are [0, N - 1] where N is the + // length of Types. + static bool Register(const char* prefix, const char* case_name, + const char* test_names, int index) { + typedef typename Types::Head Type; + typedef Fixture FixtureClass; + typedef typename GTEST_BIND_(TestSel, Type) TestClass; + + // First, registers the first type-parameterized test in the type + // list. + MakeAndRegisterTestInfo( + (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + + StreamableToString(index)).c_str(), + GetPrefixUntilComma(test_names).c_str(), + GetTypeName().c_str(), + NULL, // No value parameter. + GetTypeId(), + TestClass::SetUpTestCase, + TestClass::TearDownTestCase, + new TestFactoryImpl); + + // Next, recurses (at compile time) with the tail of the type list. + return TypeParameterizedTest + ::Register(prefix, case_name, test_names, index + 1); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTest { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/, int /*index*/) { + return true; + } +}; + +// TypeParameterizedTestCase::Register() +// registers *all combinations* of 'Tests' and 'Types' with Google +// Test. The return value is insignificant - we just need to return +// something such that we can call this function in a namespace scope. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* prefix, const char* case_name, + const char* test_names) { + typedef typename Tests::Head Head; + + // First, register the first test in 'Test' for each type in 'Types'. + TypeParameterizedTest::Register( + prefix, case_name, test_names, 0); + + // Next, recurses (at compile time) with the tail of the test list. + return TypeParameterizedTestCase + ::Register(prefix, case_name, SkipComma(test_names)); + } +}; + +// The base case for the compile time recursion. +template +class TypeParameterizedTestCase { + public: + static bool Register(const char* /*prefix*/, const char* /*case_name*/, + const char* /*test_names*/) { + return true; + } +}; + +#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P + +// Returns the current OS stack trace as an std::string. +// +// The maximum number of stack frames to be included is specified by +// the gtest_stack_trace_depth flag. The skip_count parameter +// specifies the number of top frames to be skipped, which doesn't +// count against the number of frames to be included. +// +// For example, if Foo() calls Bar(), which in turn calls +// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in +// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. +GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( + UnitTest* unit_test, int skip_count); + +// Helpers for suppressing warnings on unreachable code or constant +// condition. + +// Always returns true. +GTEST_API_ bool AlwaysTrue(); + +// Always returns false. +inline bool AlwaysFalse() { return !AlwaysTrue(); } + +// Helper for suppressing false warning from Clang on a const char* +// variable declared in a conditional expression always being NULL in +// the else branch. +struct GTEST_API_ ConstCharPtr { + ConstCharPtr(const char* str) : value(str) {} + operator bool() const { return true; } + const char* value; +}; + +// A simple Linear Congruential Generator for generating random +// numbers with a uniform distribution. Unlike rand() and srand(), it +// doesn't use global state (and therefore can't interfere with user +// code). Unlike rand_r(), it's portable. An LCG isn't very random, +// but it's good enough for our purposes. +class GTEST_API_ Random { + public: + static const UInt32 kMaxRange = 1u << 31; + + explicit Random(UInt32 seed) : state_(seed) {} + + void Reseed(UInt32 seed) { state_ = seed; } + + // Generates a random number from [0, range). Crashes if 'range' is + // 0 or greater than kMaxRange. + UInt32 Generate(UInt32 range); + + private: + UInt32 state_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); +}; + +// Defining a variable of type CompileAssertTypesEqual will cause a +// compiler error iff T1 and T2 are different types. +template +struct CompileAssertTypesEqual; + +template +struct CompileAssertTypesEqual { +}; + +// Removes the reference from a type if it is a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::remove_reference, which is not widely available yet. +template +struct RemoveReference { typedef T type; }; // NOLINT +template +struct RemoveReference { typedef T type; }; // NOLINT + +// A handy wrapper around RemoveReference that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_REFERENCE_(T) \ + typename ::testing::internal::RemoveReference::type + +// Removes const from a type if it is a const type, otherwise leaves +// it unchanged. This is the same as tr1::remove_const, which is not +// widely available yet. +template +struct RemoveConst { typedef T type; }; // NOLINT +template +struct RemoveConst { typedef T type; }; // NOLINT + +// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above +// definition to fail to remove the const in 'const int[3]' and 'const +// char[3][4]'. The following specialization works around the bug. +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; + +#if defined(_MSC_VER) && _MSC_VER < 1400 +// This is the only specialization that allows VC++ 7.1 to remove const in +// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC +// and thus needs to be conditionally compiled. +template +struct RemoveConst { + typedef typename RemoveConst::type type[N]; +}; +#endif + +// A handy wrapper around RemoveConst that works when the argument +// T depends on template parameters. +#define GTEST_REMOVE_CONST_(T) \ + typename ::testing::internal::RemoveConst::type + +// Turns const U&, U&, const U, and U all into U. +#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ + GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) + +// Adds reference to a type if it is not a reference type, +// otherwise leaves it unchanged. This is the same as +// tr1::add_reference, which is not widely available yet. +template +struct AddReference { typedef T& type; }; // NOLINT +template +struct AddReference { typedef T& type; }; // NOLINT + +// A handy wrapper around AddReference that works when the argument T +// depends on template parameters. +#define GTEST_ADD_REFERENCE_(T) \ + typename ::testing::internal::AddReference::type + +// Adds a reference to const on top of T as necessary. For example, +// it transforms +// +// char ==> const char& +// const char ==> const char& +// char& ==> const char& +// const char& ==> const char& +// +// The argument T must depend on some template parameters. +#define GTEST_REFERENCE_TO_CONST_(T) \ + GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) + +// ImplicitlyConvertible::value is a compile-time bool +// constant that's true iff type From can be implicitly converted to +// type To. +template +class ImplicitlyConvertible { + private: + // We need the following helper functions only for their types. + // They have no implementations. + + // MakeFrom() is an expression whose type is From. We cannot simply + // use From(), as the type From may not have a public default + // constructor. + static From MakeFrom(); + + // These two functions are overloaded. Given an expression + // Helper(x), the compiler will pick the first version if x can be + // implicitly converted to type To; otherwise it will pick the + // second version. + // + // The first version returns a value of size 1, and the second + // version returns a value of size 2. Therefore, by checking the + // size of Helper(x), which can be done at compile time, we can tell + // which version of Helper() is used, and hence whether x can be + // implicitly converted to type To. + static char Helper(To); + static char (&Helper(...))[2]; // NOLINT + + // We have to put the 'public' section after the 'private' section, + // or MSVC refuses to compile the code. + public: + // MSVC warns about implicitly converting from double to int for + // possible loss of data, so we need to temporarily disable the + // warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4244) // Temporarily disables warning 4244. + + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +# pragma warning(pop) // Restores the warning state. +#elif defined(__BORLANDC__) + // C++Builder cannot use member overload resolution during template + // instantiation. The simplest workaround is to use its C++0x type traits + // functions (C++Builder 2009 and above only). + static const bool value = __is_convertible(From, To); +#else + static const bool value = + sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; +#endif // _MSV_VER +}; +template +const bool ImplicitlyConvertible::value; + +// IsAProtocolMessage::value is a compile-time bool constant that's +// true iff T is type ProtocolMessage, proto2::Message, or a subclass +// of those. +template +struct IsAProtocolMessage + : public bool_constant< + ImplicitlyConvertible::value || + ImplicitlyConvertible::value> { +}; + +// When the compiler sees expression IsContainerTest(0), if C is an +// STL-style container class, the first overload of IsContainerTest +// will be viable (since both C::iterator* and C::const_iterator* are +// valid types and NULL can be implicitly converted to them). It will +// be picked over the second overload as 'int' is a perfect match for +// the type of argument 0. If C::iterator or C::const_iterator is not +// a valid type, the first overload is not viable, and the second +// overload will be picked. Therefore, we can determine whether C is +// a container class by checking the type of IsContainerTest(0). +// The value of the expression is insignificant. +// +// Note that we look for both C::iterator and C::const_iterator. The +// reason is that C++ injects the name of a class as a member of the +// class itself (e.g. you can refer to class iterator as either +// 'iterator' or 'iterator::iterator'). If we look for C::iterator +// only, for example, we would mistakenly think that a class named +// iterator is an STL container. +// +// Also note that the simpler approach of overloading +// IsContainerTest(typename C::const_iterator*) and +// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. +typedef int IsContainer; +template +IsContainer IsContainerTest(int /* dummy */, + typename C::iterator* /* it */ = NULL, + typename C::const_iterator* /* const_it */ = NULL) { + return 0; +} + +typedef char IsNotContainer; +template +IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } + +// EnableIf::type is void when 'Cond' is true, and +// undefined when 'Cond' is false. To use SFINAE to make a function +// overload only apply when a particular expression is true, add +// "typename EnableIf::type* = 0" as the last parameter. +template struct EnableIf; +template<> struct EnableIf { typedef void type; }; // NOLINT + +// Utilities for native arrays. + +// ArrayEq() compares two k-dimensional native arrays using the +// elements' operator==, where k can be any integer >= 0. When k is +// 0, ArrayEq() degenerates into comparing a single pair of values. + +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs); + +// This generic version is used when k is 0. +template +inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } + +// This overload is used when k >= 1. +template +inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { + return internal::ArrayEq(lhs, N, rhs); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous ArrayEq() function, arrays with different sizes would +// lead to different copies of the template code. +template +bool ArrayEq(const T* lhs, size_t size, const U* rhs) { + for (size_t i = 0; i != size; i++) { + if (!internal::ArrayEq(lhs[i], rhs[i])) + return false; + } + return true; +} + +// Finds the first element in the iterator range [begin, end) that +// equals elem. Element may be a native array type itself. +template +Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { + for (Iter it = begin; it != end; ++it) { + if (internal::ArrayEq(*it, elem)) + return it; + } + return end; +} + +// CopyArray() copies a k-dimensional native array using the elements' +// operator=, where k can be any integer >= 0. When k is 0, +// CopyArray() degenerates into copying a single value. + +template +void CopyArray(const T* from, size_t size, U* to); + +// This generic version is used when k is 0. +template +inline void CopyArray(const T& from, U* to) { *to = from; } + +// This overload is used when k >= 1. +template +inline void CopyArray(const T(&from)[N], U(*to)[N]) { + internal::CopyArray(from, N, *to); +} + +// This helper reduces code bloat. If we instead put its logic inside +// the previous CopyArray() function, arrays with different sizes +// would lead to different copies of the template code. +template +void CopyArray(const T* from, size_t size, U* to) { + for (size_t i = 0; i != size; i++) { + internal::CopyArray(from[i], to + i); + } +} + +// The relation between an NativeArray object (see below) and the +// native array it represents. +enum RelationToSource { + kReference, // The NativeArray references the native array. + kCopy // The NativeArray makes a copy of the native array and + // owns the copy. +}; + +// Adapts a native array to a read-only STL-style container. Instead +// of the complete STL container concept, this adaptor only implements +// members useful for Google Mock's container matchers. New members +// should be added as needed. To simplify the implementation, we only +// support Element being a raw type (i.e. having no top-level const or +// reference modifier). It's the client's responsibility to satisfy +// this requirement. Element can be an array type itself (hence +// multi-dimensional arrays are supported). +template +class NativeArray { + public: + // STL-style container typedefs. + typedef Element value_type; + typedef Element* iterator; + typedef const Element* const_iterator; + + // Constructs from a native array. + NativeArray(const Element* array, size_t count, RelationToSource relation) { + Init(array, count, relation); + } + + // Copy constructor. + NativeArray(const NativeArray& rhs) { + Init(rhs.array_, rhs.size_, rhs.relation_to_source_); + } + + ~NativeArray() { + // Ensures that the user doesn't instantiate NativeArray with a + // const or reference type. + static_cast(StaticAssertTypeEqHelper()); + if (relation_to_source_ == kCopy) + delete[] array_; + } + + // STL-style container methods. + size_t size() const { return size_; } + const_iterator begin() const { return array_; } + const_iterator end() const { return array_ + size_; } + bool operator==(const NativeArray& rhs) const { + return size() == rhs.size() && + ArrayEq(begin(), size(), rhs.begin()); + } + + private: + // Initializes this object; makes a copy of the input array if + // 'relation' is kCopy. + void Init(const Element* array, size_t a_size, RelationToSource relation) { + if (relation == kReference) { + array_ = array; + } else { + Element* const copy = new Element[a_size]; + CopyArray(array, a_size, copy); + array_ = copy; + } + size_ = a_size; + relation_to_source_ = relation; + } + + const Element* array_; + size_t size_; + RelationToSource relation_to_source_; + + GTEST_DISALLOW_ASSIGN_(NativeArray); +}; + +} // namespace internal +} // namespace testing + +#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ + ::testing::internal::AssertHelper(result_type, file, line, message) \ + = ::testing::Message() + +#define GTEST_MESSAGE_(message, result_type) \ + GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) + +#define GTEST_FATAL_FAILURE_(message) \ + return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) + +#define GTEST_NONFATAL_FAILURE_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) + +#define GTEST_SUCCESS_(message) \ + GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) + +// Suppresses MSVC warnings 4072 (unreachable code) for the code following +// statement if it returns or throws (or doesn't return or throw in some +// situations). +#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ + if (::testing::internal::AlwaysTrue()) { statement; } + +#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::ConstCharPtr gtest_msg = "") { \ + bool gtest_caught_expected = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (expected_exception const&) { \ + gtest_caught_expected = true; \ + } \ + catch (...) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws a different type."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + if (!gtest_caught_expected) { \ + gtest_msg.value = \ + "Expected: " #statement " throws an exception of type " \ + #expected_exception ".\n Actual: it throws nothing."; \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ + fail(gtest_msg.value) + +#define GTEST_TEST_NO_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ + fail("Expected: " #statement " doesn't throw an exception.\n" \ + " Actual: it throws.") + +#define GTEST_TEST_ANY_THROW_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + bool gtest_caught_any = false; \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } \ + catch (...) { \ + gtest_caught_any = true; \ + } \ + if (!gtest_caught_any) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ + fail("Expected: " #statement " throws an exception.\n" \ + " Actual: it doesn't.") + + +// Implements Boolean test assertions such as EXPECT_TRUE. expression can be +// either a boolean expression or an AssertionResult. text is a textual +// represenation of expression as it was passed into the EXPECT_TRUE. +#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar_ = \ + ::testing::AssertionResult(expression)) \ + ; \ + else \ + fail(::testing::internal::GetBoolAssertionFailureMessage(\ + gtest_ar_, text, #actual, #expected).c_str()) + +#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ + fail("Expected: " #statement " doesn't generate new fatal " \ + "failures in the current thread.\n" \ + " Actual: it does.") + +// Expands to the name of the class that implements the given test. +#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + test_case_name##_##test_name##_Test + +// Helper macro for defining tests. +#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ +class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ + public:\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ + private:\ + virtual void TestBody();\ + static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ +};\ +\ +::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ + ::test_info_ =\ + ::testing::internal::MakeAndRegisterTestInfo(\ + #test_case_name, #test_name, NULL, NULL, \ + (parent_id), \ + parent_class::SetUpTestCase, \ + parent_class::TearDownTestCase, \ + new ::testing::internal::TestFactoryImpl<\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ +void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines the public API for death tests. It is +// #included by gtest.h so a user doesn't need to include this +// directly. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ + +// Copyright 2005, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) +// +// The Google C++ Testing Framework (Google Test) +// +// This header file defines internal utilities needed for implementing +// death tests. They are subject to change without notice. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + + +#include + +namespace testing { +namespace internal { + +GTEST_DECLARE_string_(internal_run_death_test); + +// Names of the flags (needed for parsing Google Test flags). +const char kDeathTestStyleFlag[] = "death_test_style"; +const char kDeathTestUseFork[] = "death_test_use_fork"; +const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; + +#if GTEST_HAS_DEATH_TEST + +// DeathTest is a class that hides much of the complexity of the +// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method +// returns a concrete class that depends on the prevailing death test +// style, as defined by the --gtest_death_test_style and/or +// --gtest_internal_run_death_test flags. + +// In describing the results of death tests, these terms are used with +// the corresponding definitions: +// +// exit status: The integer exit information in the format specified +// by wait(2) +// exit code: The integer code passed to exit(3), _exit(2), or +// returned from main() +class GTEST_API_ DeathTest { + public: + // Create returns false if there was an error determining the + // appropriate action to take for the current death test; for example, + // if the gtest_death_test_style flag is set to an invalid value. + // The LastMessage method will return a more detailed message in that + // case. Otherwise, the DeathTest pointer pointed to by the "test" + // argument is set. If the death test should be skipped, the pointer + // is set to NULL; otherwise, it is set to the address of a new concrete + // DeathTest object that controls the execution of the current test. + static bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); + DeathTest(); + virtual ~DeathTest() { } + + // A helper class that aborts a death test when it's deleted. + class ReturnSentinel { + public: + explicit ReturnSentinel(DeathTest* test) : test_(test) { } + ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } + private: + DeathTest* const test_; + GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); + } GTEST_ATTRIBUTE_UNUSED_; + + // An enumeration of possible roles that may be taken when a death + // test is encountered. EXECUTE means that the death test logic should + // be executed immediately. OVERSEE means that the program should prepare + // the appropriate environment for a child process to execute the death + // test, then wait for it to complete. + enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; + + // An enumeration of the three reasons that a test might be aborted. + enum AbortReason { + TEST_ENCOUNTERED_RETURN_STATEMENT, + TEST_THREW_EXCEPTION, + TEST_DID_NOT_DIE + }; + + // Assumes one of the above roles. + virtual TestRole AssumeRole() = 0; + + // Waits for the death test to finish and returns its status. + virtual int Wait() = 0; + + // Returns true if the death test passed; that is, the test process + // exited during the test, its exit status matches a user-supplied + // predicate, and its stderr output matches a user-supplied regular + // expression. + // The user-supplied predicate may be a macro expression rather + // than a function pointer or functor, or else Wait and Passed could + // be combined. + virtual bool Passed(bool exit_status_ok) = 0; + + // Signals that the death test did not die as expected. + virtual void Abort(AbortReason reason) = 0; + + // Returns a human-readable outcome message regarding the outcome of + // the last death test. + static const char* LastMessage(); + + static void set_last_death_test_message(const std::string& message); + + private: + // A string containing a description of the outcome of the last death test. + static std::string last_death_test_message_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); +}; + +// Factory interface for death tests. May be mocked out for testing. +class DeathTestFactory { + public: + virtual ~DeathTestFactory() { } + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test) = 0; +}; + +// A concrete DeathTestFactory implementation for normal use. +class DefaultDeathTestFactory : public DeathTestFactory { + public: + virtual bool Create(const char* statement, const RE* regex, + const char* file, int line, DeathTest** test); +}; + +// Returns true if exit_status describes a process that was terminated +// by a signal, or exited normally with a nonzero exit code. +GTEST_API_ bool ExitedUnsuccessfully(int exit_status); + +// Traps C++ exceptions escaping statement and reports them as test +// failures. Note that trapping SEH exceptions is not implemented here. +# if GTEST_HAS_EXCEPTIONS +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + try { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } catch (const ::std::exception& gtest_exception) { \ + fprintf(\ + stderr, \ + "\n%s: Caught std::exception-derived exception escaping the " \ + "death test statement. Exception message: %s\n", \ + ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ + gtest_exception.what()); \ + fflush(stderr); \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } catch (...) { \ + death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ + } + +# else +# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) + +# endif + +// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, +// ASSERT_EXIT*, and EXPECT_EXIT*. +# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + const ::testing::internal::RE& gtest_regex = (regex); \ + ::testing::internal::DeathTest* gtest_dt; \ + if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ + __FILE__, __LINE__, >est_dt)) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + if (gtest_dt != NULL) { \ + ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ + gtest_dt_ptr(gtest_dt); \ + switch (gtest_dt->AssumeRole()) { \ + case ::testing::internal::DeathTest::OVERSEE_TEST: \ + if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ + goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ + } \ + break; \ + case ::testing::internal::DeathTest::EXECUTE_TEST: { \ + ::testing::internal::DeathTest::ReturnSentinel \ + gtest_sentinel(gtest_dt); \ + GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ + gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ + break; \ + } \ + default: \ + break; \ + } \ + } \ + } else \ + GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ + fail(::testing::internal::DeathTest::LastMessage()) +// The symbol "fail" here expands to something into which a message +// can be streamed. + +// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in +// NDEBUG mode. In this case we need the statements to be executed, the regex is +// ignored, and the macro must accept a streamed message even though the message +// is never printed. +# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + } else \ + ::testing::Message() + +// A class representing the parsed contents of the +// --gtest_internal_run_death_test flag, as it existed when +// RUN_ALL_TESTS was called. +class InternalRunDeathTestFlag { + public: + InternalRunDeathTestFlag(const std::string& a_file, + int a_line, + int an_index, + int a_write_fd) + : file_(a_file), line_(a_line), index_(an_index), + write_fd_(a_write_fd) {} + + ~InternalRunDeathTestFlag() { + if (write_fd_ >= 0) + posix::Close(write_fd_); + } + + const std::string& file() const { return file_; } + int line() const { return line_; } + int index() const { return index_; } + int write_fd() const { return write_fd_; } + + private: + std::string file_; + int line_; + int index_; + int write_fd_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); +}; + +// Returns a newly created InternalRunDeathTestFlag object with fields +// initialized from the GTEST_FLAG(internal_run_death_test) flag if +// the flag is specified; otherwise returns NULL. +InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); + +#else // GTEST_HAS_DEATH_TEST + +// This macro is used for implementing macros such as +// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where +// death tests are not supported. Those macros must compile on such systems +// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on +// systems that support death tests. This allows one to write such a macro +// on a system that does not support death tests and be sure that it will +// compile on a death-test supporting system. +// +// Parameters: +// statement - A statement that a macro such as EXPECT_DEATH would test +// for program termination. This macro has to make sure this +// statement is compiled but not executed, to ensure that +// EXPECT_DEATH_IF_SUPPORTED compiles with a certain +// parameter iff EXPECT_DEATH compiles with it. +// regex - A regex that a macro such as EXPECT_DEATH would use to test +// the output of statement. This parameter has to be +// compiled but not evaluated by this macro, to ensure that +// this macro only accepts expressions that a macro such as +// EXPECT_DEATH would accept. +// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED +// and a return statement for ASSERT_DEATH_IF_SUPPORTED. +// This ensures that ASSERT_DEATH_IF_SUPPORTED will not +// compile inside functions where ASSERT_DEATH doesn't +// compile. +// +// The branch that has an always false condition is used to ensure that +// statement and regex are compiled (and thus syntactically correct) but +// never executed. The unreachable code macro protects the terminator +// statement from generating an 'unreachable code' warning in case +// statement unconditionally returns or throws. The Message constructor at +// the end allows the syntax of streaming additional messages into the +// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. +# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (::testing::internal::AlwaysTrue()) { \ + GTEST_LOG_(WARNING) \ + << "Death tests are not supported on this platform.\n" \ + << "Statement '" #statement "' cannot be verified."; \ + } else if (::testing::internal::AlwaysFalse()) { \ + ::testing::internal::RE::PartialMatch(".*", (regex)); \ + GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ + terminator; \ + } else \ + ::testing::Message() + +#endif // GTEST_HAS_DEATH_TEST + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ + +namespace testing { + +// This flag controls the style of death tests. Valid values are "threadsafe", +// meaning that the death test child process will re-execute the test binary +// from the start, running only a single death test, or "fast", +// meaning that the child process will execute the test logic immediately +// after forking. +GTEST_DECLARE_string_(death_test_style); + +#if GTEST_HAS_DEATH_TEST + +namespace internal { + +// Returns a Boolean value indicating whether the caller is currently +// executing in the context of the death test child process. Tools such as +// Valgrind heap checkers may need this to modify their behavior in death +// tests. IMPORTANT: This is an internal utility. Using it may break the +// implementation of death tests. User code MUST NOT use it. +GTEST_API_ bool InDeathTestChild(); + +} // namespace internal + +// The following macros are useful for writing death tests. + +// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is +// executed: +// +// 1. It generates a warning if there is more than one active +// thread. This is because it's safe to fork() or clone() only +// when there is a single thread. +// +// 2. The parent process clone()s a sub-process and runs the death +// test in it; the sub-process exits with code 0 at the end of the +// death test, if it hasn't exited already. +// +// 3. The parent process waits for the sub-process to terminate. +// +// 4. The parent process checks the exit code and error message of +// the sub-process. +// +// Examples: +// +// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); +// for (int i = 0; i < 5; i++) { +// EXPECT_DEATH(server.ProcessRequest(i), +// "Invalid request .* in ProcessRequest()") +// << "Failed to die on request " << i; +// } +// +// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); +// +// bool KilledBySIGHUP(int exit_code) { +// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; +// } +// +// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); +// +// On the regular expressions used in death tests: +// +// On POSIX-compliant systems (*nix), we use the library, +// which uses the POSIX extended regex syntax. +// +// On other platforms (e.g. Windows), we only support a simple regex +// syntax implemented as part of Google Test. This limited +// implementation should be enough most of the time when writing +// death tests; though it lacks many features you can find in PCRE +// or POSIX extended regex syntax. For example, we don't support +// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and +// repetition count ("x{5,7}"), among others. +// +// Below is the syntax that we do support. We chose it to be a +// subset of both PCRE and POSIX extended regex, so it's easy to +// learn wherever you come from. In the following: 'A' denotes a +// literal character, period (.), or a single \\ escape sequence; +// 'x' and 'y' denote regular expressions; 'm' and 'n' are for +// natural numbers. +// +// c matches any literal character c +// \\d matches any decimal digit +// \\D matches any character that's not a decimal digit +// \\f matches \f +// \\n matches \n +// \\r matches \r +// \\s matches any ASCII whitespace, including \n +// \\S matches any character that's not a whitespace +// \\t matches \t +// \\v matches \v +// \\w matches any letter, _, or decimal digit +// \\W matches any character that \\w doesn't match +// \\c matches any literal character c, which must be a punctuation +// . matches any single character except \n +// A? matches 0 or 1 occurrences of A +// A* matches 0 or many occurrences of A +// A+ matches 1 or many occurrences of A +// ^ matches the beginning of a string (not that of each line) +// $ matches the end of a string (not that of each line) +// xy matches x followed by y +// +// If you accidentally use PCRE or POSIX extended regex features +// not implemented by us, you will get a run-time failure. In that +// case, please try to rewrite your regular expression within the +// above syntax. +// +// This implementation is *not* meant to be as highly tuned or robust +// as a compiled regex library, but should perform well enough for a +// death test, which already incurs significant overhead by launching +// a child process. +// +// Known caveats: +// +// A "threadsafe" style death test obtains the path to the test +// program from argv[0] and re-executes it in the sub-process. For +// simplicity, the current implementation doesn't search the PATH +// when launching the sub-process. This means that the user must +// invoke the test program via a path that contains at least one +// path separator (e.g. path/to/foo_test and +// /absolute/path/to/bar_test are fine, but foo_test is not). This +// is rarely a problem as people usually don't put the test binary +// directory in PATH. +// +// TODO(wan@google.com): make thread-safe death tests search the PATH. + +// Asserts that a given statement causes the program to exit, with an +// integer exit status that satisfies predicate, and emitting error output +// that matches regex. +# define ASSERT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) + +// Like ASSERT_EXIT, but continues on to successive tests in the +// test case, if any: +# define EXPECT_EXIT(statement, predicate, regex) \ + GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) + +// Asserts that a given statement causes the program to exit, either by +// explicitly exiting with a nonzero exit code or being killed by a +// signal, and emitting error output that matches regex. +# define ASSERT_DEATH(statement, regex) \ + ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Like ASSERT_DEATH, but continues on to successive tests in the +// test case, if any: +# define EXPECT_DEATH(statement, regex) \ + EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) + +// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: + +// Tests that an exit code describes a normal exit with a given exit code. +class GTEST_API_ ExitedWithCode { + public: + explicit ExitedWithCode(int exit_code); + bool operator()(int exit_status) const; + private: + // No implementation - assignment is unsupported. + void operator=(const ExitedWithCode& other); + + const int exit_code_; +}; + +# if !GTEST_OS_WINDOWS +// Tests that an exit code describes an exit due to termination by a +// given signal. +class GTEST_API_ KilledBySignal { + public: + explicit KilledBySignal(int signum); + bool operator()(int exit_status) const; + private: + const int signum_; +}; +# endif // !GTEST_OS_WINDOWS + +// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. +// The death testing framework causes this to have interesting semantics, +// since the sideeffects of the call are only visible in opt mode, and not +// in debug mode. +// +// In practice, this can be used to test functions that utilize the +// LOG(DFATAL) macro using the following style: +// +// int DieInDebugOr12(int* sideeffect) { +// if (sideeffect) { +// *sideeffect = 12; +// } +// LOG(DFATAL) << "death"; +// return 12; +// } +// +// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { +// int sideeffect = 0; +// // Only asserts in dbg. +// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); +// +// #ifdef NDEBUG +// // opt-mode has sideeffect visible. +// EXPECT_EQ(12, sideeffect); +// #else +// // dbg-mode no visible sideeffect. +// EXPECT_EQ(0, sideeffect); +// #endif +// } +// +// This will assert that DieInDebugReturn12InOpt() crashes in debug +// mode, usually due to a DCHECK or LOG(DFATAL), but returns the +// appropriate fallback value (12 in this case) in opt mode. If you +// need to test that a function has appropriate side-effects in opt +// mode, include assertions against the side-effects. A general +// pattern for this is: +// +// EXPECT_DEBUG_DEATH({ +// // Side-effects here will have an effect after this statement in +// // opt mode, but none in debug mode. +// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); +// }, "death"); +// +# ifdef NDEBUG + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + GTEST_EXECUTE_STATEMENT_(statement, regex) + +# else + +# define EXPECT_DEBUG_DEATH(statement, regex) \ + EXPECT_DEATH(statement, regex) + +# define ASSERT_DEBUG_DEATH(statement, regex) \ + ASSERT_DEATH(statement, regex) + +# endif // NDEBUG for EXPECT_DEBUG_DEATH +#endif // GTEST_HAS_DEATH_TEST + +// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and +// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if +// death tests are supported; otherwise they just issue a warning. This is +// useful when you are combining death test assertions with normal test +// assertions in one test. +#if GTEST_HAS_DEATH_TEST +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + EXPECT_DEATH(statement, regex) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + ASSERT_DEATH(statement, regex) +#else +# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) +# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ + GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) +#endif + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ +// This file was GENERATED by command: +// pump.py gtest-param-test.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: vladl@google.com (Vlad Losev) +// +// Macros and functions for implementing parameterized tests +// in Google C++ Testing Framework (Google Test) +// +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ + + +// Value-parameterized tests allow you to test your code with different +// parameters without writing multiple copies of the same test. +// +// Here is how you use value-parameterized tests: + +#if 0 + +// To write value-parameterized tests, first you should define a fixture +// class. It is usually derived from testing::TestWithParam (see below for +// another inheritance scheme that's sometimes useful in more complicated +// class hierarchies), where the type of your parameter values. +// TestWithParam is itself derived from testing::Test. T can be any +// copyable type. If it's a raw pointer, you are responsible for managing the +// lifespan of the pointed values. + +class FooTest : public ::testing::TestWithParam { + // You can implement all the usual class fixture members here. +}; + +// Then, use the TEST_P macro to define as many parameterized tests +// for this fixture as you want. The _P suffix is for "parameterized" +// or "pattern", whichever you prefer to think. + +TEST_P(FooTest, DoesBlah) { + // Inside a test, access the test parameter with the GetParam() method + // of the TestWithParam class: + EXPECT_TRUE(foo.Blah(GetParam())); + ... +} + +TEST_P(FooTest, HasBlahBlah) { + ... +} + +// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test +// case with any set of parameters you want. Google Test defines a number +// of functions for generating test parameters. They return what we call +// (surprise!) parameter generators. Here is a summary of them, which +// are all in the testing namespace: +// +// +// Range(begin, end [, step]) - Yields values {begin, begin+step, +// begin+step+step, ...}. The values do not +// include end. step defaults to 1. +// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. +// ValuesIn(container) - Yields values from a C-style array, an STL +// ValuesIn(begin,end) container, or an iterator range [begin, end). +// Bool() - Yields sequence {false, true}. +// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product +// for the math savvy) of the values generated +// by the N generators. +// +// For more details, see comments at the definitions of these functions below +// in this file. +// +// The following statement will instantiate tests from the FooTest test case +// each with parameter values "meeny", "miny", and "moe". + +INSTANTIATE_TEST_CASE_P(InstantiationName, + FooTest, + Values("meeny", "miny", "moe")); + +// To distinguish different instances of the pattern, (yes, you +// can instantiate it more then once) the first argument to the +// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the +// actual test case name. Remember to pick unique prefixes for different +// instantiations. The tests from the instantiation above will have +// these names: +// +// * InstantiationName/FooTest.DoesBlah/0 for "meeny" +// * InstantiationName/FooTest.DoesBlah/1 for "miny" +// * InstantiationName/FooTest.DoesBlah/2 for "moe" +// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" +// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" +// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" +// +// You can use these names in --gtest_filter. +// +// This statement will instantiate all tests from FooTest again, each +// with parameter values "cat" and "dog": + +const char* pets[] = {"cat", "dog"}; +INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); + +// The tests from the instantiation above will have these names: +// +// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" +// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" +// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" +// +// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests +// in the given test case, whether their definitions come before or +// AFTER the INSTANTIATE_TEST_CASE_P statement. +// +// Please also note that generator expressions (including parameters to the +// generators) are evaluated in InitGoogleTest(), after main() has started. +// This allows the user on one hand, to adjust generator parameters in order +// to dynamically determine a set of tests to run and on the other hand, +// give the user a chance to inspect the generated tests with Google Test +// reflection API before RUN_ALL_TESTS() is executed. +// +// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc +// for more examples. +// +// In the future, we plan to publish the API for defining new parameter +// generators. But for now this interface remains part of the internal +// implementation and is subject to change. +// +// +// A parameterized test fixture must be derived from testing::Test and from +// testing::WithParamInterface, where T is the type of the parameter +// values. Inheriting from TestWithParam satisfies that requirement because +// TestWithParam inherits from both Test and WithParamInterface. In more +// complicated hierarchies, however, it is occasionally useful to inherit +// separately from Test and WithParamInterface. For example: + +class BaseTest : public ::testing::Test { + // You can inherit all the usual members for a non-parameterized test + // fixture here. +}; + +class DerivedTest : public BaseTest, public ::testing::WithParamInterface { + // The usual test fixture members go here too. +}; + +TEST_F(BaseTest, HasFoo) { + // This is an ordinary non-parameterized test. +} + +TEST_P(DerivedTest, DoesBlah) { + // GetParam works just the same here as if you inherit from TestWithParam. + EXPECT_TRUE(foo.Blah(GetParam())); +} + +#endif // 0 + + +#if !GTEST_OS_SYMBIAN +# include +#endif + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ + +#include +#include +#include + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. +// Copyright 2003 Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Authors: Dan Egnor (egnor@google.com) +// +// A "smart" pointer type with reference tracking. Every pointer to a +// particular object is kept on a circular linked list. When the last pointer +// to an object is destroyed or reassigned, the object is deleted. +// +// Used properly, this deletes the object when the last reference goes away. +// There are several caveats: +// - Like all reference counting schemes, cycles lead to leaks. +// - Each smart pointer is actually two pointers (8 bytes instead of 4). +// - Every time a pointer is assigned, the entire list of pointers to that +// object is traversed. This class is therefore NOT SUITABLE when there +// will often be more than two or three pointers to a particular object. +// - References are only tracked as long as linked_ptr<> objects are copied. +// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS +// will happen (double deletion). +// +// A good use of this class is storing object references in STL containers. +// You can safely put linked_ptr<> in a vector<>. +// Other uses may not be as good. +// +// Note: If you use an incomplete type with linked_ptr<>, the class +// *containing* linked_ptr<> must have a constructor and destructor (even +// if they do nothing!). +// +// Bill Gibbons suggested we use something like this. +// +// Thread Safety: +// Unlike other linked_ptr implementations, in this implementation +// a linked_ptr object is thread-safe in the sense that: +// - it's safe to copy linked_ptr objects concurrently, +// - it's safe to copy *from* a linked_ptr and read its underlying +// raw pointer (e.g. via get()) concurrently, and +// - it's safe to write to two linked_ptrs that point to the same +// shared object concurrently. +// TODO(wan@google.com): rename this to safe_linked_ptr to avoid +// confusion with normal linked_ptr. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ + +#include +#include + + +namespace testing { +namespace internal { + +// Protects copying of all linked_ptr objects. +GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); + +// This is used internally by all instances of linked_ptr<>. It needs to be +// a non-template class because different types of linked_ptr<> can refer to +// the same object (linked_ptr(obj) vs linked_ptr(obj)). +// So, it needs to be possible for different types of linked_ptr to participate +// in the same circular linked list, so we need a single class type here. +// +// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. +class linked_ptr_internal { + public: + // Create a new circle that includes only this instance. + void join_new() { + next_ = this; + } + + // Many linked_ptr operations may change p.link_ for some linked_ptr + // variable p in the same circle as this object. Therefore we need + // to prevent two such operations from occurring concurrently. + // + // Note that different types of linked_ptr objects can coexist in a + // circle (e.g. linked_ptr, linked_ptr, and + // linked_ptr). Therefore we must use a single mutex to + // protect all linked_ptr objects. This can create serious + // contention in production code, but is acceptable in a testing + // framework. + + // Join an existing circle. + void join(linked_ptr_internal const* ptr) + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + linked_ptr_internal const* p = ptr; + while (p->next_ != ptr) p = p->next_; + p->next_ = this; + next_ = ptr; + } + + // Leave whatever circle we're part of. Returns true if we were the + // last member of the circle. Once this is done, you can join() another. + bool depart() + GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { + MutexLock lock(&g_linked_ptr_mutex); + + if (next_ == this) return true; + linked_ptr_internal const* p = next_; + while (p->next_ != this) p = p->next_; + p->next_ = next_; + return false; + } + + private: + mutable linked_ptr_internal const* next_; +}; + +template +class linked_ptr { + public: + typedef T element_type; + + // Take over ownership of a raw pointer. This should happen as soon as + // possible after the object is created. + explicit linked_ptr(T* ptr = NULL) { capture(ptr); } + ~linked_ptr() { depart(); } + + // Copy an existing linked_ptr<>, adding ourselves to the list of references. + template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } + linked_ptr(linked_ptr const& ptr) { // NOLINT + assert(&ptr != this); + copy(&ptr); + } + + // Assignment releases the old value and acquires the new. + template linked_ptr& operator=(linked_ptr const& ptr) { + depart(); + copy(&ptr); + return *this; + } + + linked_ptr& operator=(linked_ptr const& ptr) { + if (&ptr != this) { + depart(); + copy(&ptr); + } + return *this; + } + + // Smart pointer members. + void reset(T* ptr = NULL) { + depart(); + capture(ptr); + } + T* get() const { return value_; } + T* operator->() const { return value_; } + T& operator*() const { return *value_; } + + bool operator==(T* p) const { return value_ == p; } + bool operator!=(T* p) const { return value_ != p; } + template + bool operator==(linked_ptr const& ptr) const { + return value_ == ptr.get(); + } + template + bool operator!=(linked_ptr const& ptr) const { + return value_ != ptr.get(); + } + + private: + template + friend class linked_ptr; + + T* value_; + linked_ptr_internal link_; + + void depart() { + if (link_.depart()) delete value_; + } + + void capture(T* ptr) { + value_ = ptr; + link_.join_new(); + } + + template void copy(linked_ptr const* ptr) { + value_ = ptr->get(); + if (value_) + link_.join(&ptr->link_); + else + link_.join_new(); + } +}; + +template inline +bool operator==(T* ptr, const linked_ptr& x) { + return ptr == x.get(); +} + +template inline +bool operator!=(T* ptr, const linked_ptr& x) { + return ptr != x.get(); +} + +// A function to convert T* into linked_ptr +// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation +// for linked_ptr >(new FooBarBaz(arg)) +template +linked_ptr make_linked_ptr(T* ptr) { + return linked_ptr(ptr); +} + +} // namespace internal +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ +// Copyright 2007, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + +// Google Test - The Google C++ Testing Framework +// +// This file implements a universal value printer that can print a +// value of any type T: +// +// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); +// +// A user can teach this function how to print a class type T by +// defining either operator<<() or PrintTo() in the namespace that +// defines T. More specifically, the FIRST defined function in the +// following list will be used (assuming T is defined in namespace +// foo): +// +// 1. foo::PrintTo(const T&, ostream*) +// 2. operator<<(ostream&, const T&) defined in either foo or the +// global namespace. +// +// If none of the above is defined, it will print the debug string of +// the value if it is a protocol buffer, or print the raw bytes in the +// value otherwise. +// +// To aid debugging: when T is a reference type, the address of the +// value is also printed; when T is a (const) char pointer, both the +// pointer value and the NUL-terminated string it points to are +// printed. +// +// We also provide some convenient wrappers: +// +// // Prints a value to a string. For a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// std::string ::testing::PrintToString(const T& value); +// +// // Prints a value tersely: for a reference type, the referenced +// // value (but not the address) is printed; for a (const or not) char +// // pointer, the NUL-terminated string (but not the pointer) is +// // printed. +// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); +// +// // Prints value using the type inferred by the compiler. The difference +// // from UniversalTersePrint() is that this function prints both the +// // pointer and the NUL-terminated string for a (const or not) char pointer. +// void ::testing::internal::UniversalPrint(const T& value, ostream*); +// +// // Prints the fields of a tuple tersely to a string vector, one +// // element for each field. Tuple support must be enabled in +// // gtest-port.h. +// std::vector UniversalTersePrintTupleFieldsToStrings( +// const Tuple& value); +// +// Known limitation: +// +// The print primitives print the elements of an STL-style container +// using the compiler-inferred type of *iter where iter is a +// const_iterator of the container. When const_iterator is an input +// iterator but not a forward iterator, this inferred type may not +// match value_type, and the print output may be incorrect. In +// practice, this is rarely a problem as for most containers +// const_iterator is a forward iterator. We'll fix this if there's an +// actual need for it. Note that this fix cannot rely on value_type +// being defined as many user-defined container types don't have +// value_type. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#include // NOLINT +#include +#include +#include +#include + +namespace testing { + +// Definitions in the 'internal' and 'internal2' name spaces are +// subject to change without notice. DO NOT USE THEM IN USER CODE! +namespace internal2 { + +// Prints the given number of bytes in the given object to the given +// ostream. +GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, + size_t count, + ::std::ostream* os); + +// For selecting which printer to use when a given type has neither << +// nor PrintTo(). +enum TypeKind { + kProtobuf, // a protobuf type + kConvertibleToInteger, // a type implicitly convertible to BiggestInt + // (e.g. a named or unnamed enum type) + kOtherType // anything else +}; + +// TypeWithoutFormatter::PrintValue(value, os) is called +// by the universal printer to print a value of type T when neither +// operator<< nor PrintTo() is defined for T, where kTypeKind is the +// "kind" of T as defined by enum TypeKind. +template +class TypeWithoutFormatter { + public: + // This default version is called when kTypeKind is kOtherType. + static void PrintValue(const T& value, ::std::ostream* os) { + PrintBytesInObjectTo(reinterpret_cast(&value), + sizeof(value), os); + } +}; + +// We print a protobuf using its ShortDebugString() when the string +// doesn't exceed this many characters; otherwise we print it using +// DebugString() for better readability. +const size_t kProtobufOneLinerMaxLength = 50; + +template +class TypeWithoutFormatter { + public: + static void PrintValue(const T& value, ::std::ostream* os) { + const ::testing::internal::string short_str = value.ShortDebugString(); + const ::testing::internal::string pretty_str = + short_str.length() <= kProtobufOneLinerMaxLength ? + short_str : ("\n" + value.DebugString()); + *os << ("<" + pretty_str + ">"); + } +}; + +template +class TypeWithoutFormatter { + public: + // Since T has no << operator or PrintTo() but can be implicitly + // converted to BiggestInt, we print it as a BiggestInt. + // + // Most likely T is an enum type (either named or unnamed), in which + // case printing it as an integer is the desired behavior. In case + // T is not an enum, printing it as an integer is the best we can do + // given that it has no user-defined printer. + static void PrintValue(const T& value, ::std::ostream* os) { + const internal::BiggestInt kBigInt = value; + *os << kBigInt; + } +}; + +// Prints the given value to the given ostream. If the value is a +// protocol message, its debug string is printed; if it's an enum or +// of a type implicitly convertible to BiggestInt, it's printed as an +// integer; otherwise the bytes in the value are printed. This is +// what UniversalPrinter::Print() does when it knows nothing about +// type T and T has neither << operator nor PrintTo(). +// +// A user can override this behavior for a class type Foo by defining +// a << operator in the namespace where Foo is defined. +// +// We put this operator in namespace 'internal2' instead of 'internal' +// to simplify the implementation, as much code in 'internal' needs to +// use << in STL, which would conflict with our own << were it defined +// in 'internal'. +// +// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If +// we define it to take an std::ostream instead, we'll get an +// "ambiguous overloads" compiler error when trying to print a type +// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether +// operator<<(std::ostream&, const T&) or +// operator<<(std::basic_stream, const Foo&) is more +// specific. +template +::std::basic_ostream& operator<<( + ::std::basic_ostream& os, const T& x) { + TypeWithoutFormatter::value ? kProtobuf : + internal::ImplicitlyConvertible::value ? + kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); + return os; +} + +} // namespace internal2 +} // namespace testing + +// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up +// magic needed for implementing UniversalPrinter won't work. +namespace testing_internal { + +// Used to print a value that is not an STL-style container when the +// user doesn't define PrintTo() for it. +template +void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { + // With the following statement, during unqualified name lookup, + // testing::internal2::operator<< appears as if it was declared in + // the nearest enclosing namespace that contains both + // ::testing_internal and ::testing::internal2, i.e. the global + // namespace. For more details, refer to the C++ Standard section + // 7.3.4-1 [namespace.udir]. This allows us to fall back onto + // testing::internal2::operator<< in case T doesn't come with a << + // operator. + // + // We cannot write 'using ::testing::internal2::operator<<;', which + // gcc 3.3 fails to compile due to a compiler bug. + using namespace ::testing::internal2; // NOLINT + + // Assuming T is defined in namespace foo, in the next statement, + // the compiler will consider all of: + // + // 1. foo::operator<< (thanks to Koenig look-up), + // 2. ::operator<< (as the current namespace is enclosed in ::), + // 3. testing::internal2::operator<< (thanks to the using statement above). + // + // The operator<< whose type matches T best will be picked. + // + // We deliberately allow #2 to be a candidate, as sometimes it's + // impossible to define #1 (e.g. when foo is ::std, defining + // anything in it is undefined behavior unless you are a compiler + // vendor.). + *os << value; +} + +} // namespace testing_internal + +namespace testing { +namespace internal { + +// UniversalPrinter::Print(value, ostream_ptr) prints the given +// value to the given ostream. The caller must ensure that +// 'ostream_ptr' is not NULL, or the behavior is undefined. +// +// We define UniversalPrinter as a class template (as opposed to a +// function template), as we need to partially specialize it for +// reference types, which cannot be done with function templates. +template +class UniversalPrinter; + +template +void UniversalPrint(const T& value, ::std::ostream* os); + +// Used to print an STL-style container when the user doesn't define +// a PrintTo() for it. +template +void DefaultPrintTo(IsContainer /* dummy */, + false_type /* is not a pointer */, + const C& container, ::std::ostream* os) { + const size_t kMaxCount = 32; // The maximum number of elements to print. + *os << '{'; + size_t count = 0; + for (typename C::const_iterator it = container.begin(); + it != container.end(); ++it, ++count) { + if (count > 0) { + *os << ','; + if (count == kMaxCount) { // Enough has been printed. + *os << " ..."; + break; + } + } + *os << ' '; + // We cannot call PrintTo(*it, os) here as PrintTo() doesn't + // handle *it being a native array. + internal::UniversalPrint(*it, os); + } + + if (count > 0) { + *os << ' '; + } + *os << '}'; +} + +// Used to print a pointer that is neither a char pointer nor a member +// pointer, when the user doesn't define PrintTo() for it. (A member +// variable pointer or member function pointer doesn't really point to +// a location in the address space. Their representation is +// implementation-defined. Therefore they will be printed as raw +// bytes.) +template +void DefaultPrintTo(IsNotContainer /* dummy */, + true_type /* is a pointer */, + T* p, ::std::ostream* os) { + if (p == NULL) { + *os << "NULL"; + } else { + // C++ doesn't allow casting from a function pointer to any object + // pointer. + // + // IsTrue() silences warnings: "Condition is always true", + // "unreachable code". + if (IsTrue(ImplicitlyConvertible::value)) { + // T is not a function type. We just call << to print p, + // relying on ADL to pick up user-defined << for their pointer + // types, if any. + *os << p; + } else { + // T is a function type, so '*os << p' doesn't do what we want + // (it just prints p as bool). We want to print p as a const + // void*. However, we cannot cast it to const void* directly, + // even using reinterpret_cast, as earlier versions of gcc + // (e.g. 3.4.5) cannot compile the cast when p is a function + // pointer. Casting to UInt64 first solves the problem. + *os << reinterpret_cast( + reinterpret_cast(p)); + } + } +} + +// Used to print a non-container, non-pointer value when the user +// doesn't define PrintTo() for it. +template +void DefaultPrintTo(IsNotContainer /* dummy */, + false_type /* is not a pointer */, + const T& value, ::std::ostream* os) { + ::testing_internal::DefaultPrintNonContainerTo(value, os); +} + +// Prints the given value using the << operator if it has one; +// otherwise prints the bytes in it. This is what +// UniversalPrinter::Print() does when PrintTo() is not specialized +// or overloaded for type T. +// +// A user can override this behavior for a class type Foo by defining +// an overload of PrintTo() in the namespace where Foo is defined. We +// give the user this option as sometimes defining a << operator for +// Foo is not desirable (e.g. the coding style may prevent doing it, +// or there is already a << operator but it doesn't do what the user +// wants). +template +void PrintTo(const T& value, ::std::ostream* os) { + // DefaultPrintTo() is overloaded. The type of its first two + // arguments determine which version will be picked. If T is an + // STL-style container, the version for container will be called; if + // T is a pointer, the pointer version will be called; otherwise the + // generic version will be called. + // + // Note that we check for container types here, prior to we check + // for protocol message types in our operator<<. The rationale is: + // + // For protocol messages, we want to give people a chance to + // override Google Mock's format by defining a PrintTo() or + // operator<<. For STL containers, other formats can be + // incompatible with Google Mock's format for the container + // elements; therefore we check for container types here to ensure + // that our format is used. + // + // The second argument of DefaultPrintTo() is needed to bypass a bug + // in Symbian's C++ compiler that prevents it from picking the right + // overload between: + // + // PrintTo(const T& x, ...); + // PrintTo(T* x, ...); + DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); +} + +// The following list of PrintTo() overloads tells +// UniversalPrinter::Print() how to print standard types (built-in +// types, strings, plain arrays, and pointers). + +// Overloads for various char types. +GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); +GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); +inline void PrintTo(char c, ::std::ostream* os) { + // When printing a plain char, we always treat it as unsigned. This + // way, the output won't be affected by whether the compiler thinks + // char is signed or not. + PrintTo(static_cast(c), os); +} + +// Overloads for other simple built-in types. +inline void PrintTo(bool x, ::std::ostream* os) { + *os << (x ? "true" : "false"); +} + +// Overload for wchar_t type. +// Prints a wchar_t as a symbol if it is printable or as its internal +// code otherwise and also as its decimal code (except for L'\0'). +// The L'\0' char is printed as "L'\\0'". The decimal code is printed +// as signed integer when wchar_t is implemented by the compiler +// as a signed type and is printed as an unsigned integer when wchar_t +// is implemented as an unsigned type. +GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); + +// Overloads for C strings. +GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); +inline void PrintTo(char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// signed/unsigned char is often used for representing binary data, so +// we print pointers to it as void* to be safe. +inline void PrintTo(const signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(signed char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(const unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +inline void PrintTo(unsigned char* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} + +// MSVC can be configured to define wchar_t as a typedef of unsigned +// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native +// type. When wchar_t is a typedef, defining an overload for const +// wchar_t* would cause unsigned short* be printed as a wide string, +// possibly causing invalid memory accesses. +#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) +// Overloads for wide C strings +GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); +inline void PrintTo(wchar_t* s, ::std::ostream* os) { + PrintTo(ImplicitCast_(s), os); +} +#endif + +// Overload for C arrays. Multi-dimensional arrays are printed +// properly. + +// Prints the given number of elements in an array, without printing +// the curly braces. +template +void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { + UniversalPrint(a[0], os); + for (size_t i = 1; i != count; i++) { + *os << ", "; + UniversalPrint(a[i], os); + } +} + +// Overloads for ::string and ::std::string. +#if GTEST_HAS_GLOBAL_STRING +GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); +inline void PrintTo(const ::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_STRING + +GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); +inline void PrintTo(const ::std::string& s, ::std::ostream* os) { + PrintStringTo(s, os); +} + +// Overloads for ::wstring and ::std::wstring. +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_GLOBAL_WSTRING + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); +inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { + PrintWideStringTo(s, os); +} +#endif // GTEST_HAS_STD_WSTRING + +#if GTEST_HAS_TR1_TUPLE +// Overload for ::std::tr1::tuple. Needed for printing function arguments, +// which are packed as tuples. + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os); + +// Overloaded PrintTo() for tuples of various arities. We support +// tuples of up-to 10 fields. The following implementation works +// regardless of whether tr1::tuple is implemented using the +// non-standard variadic template feature or not. + +inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo(const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} + +template +void PrintTo( + const ::std::tr1::tuple& t, + ::std::ostream* os) { + PrintTupleTo(t, os); +} +#endif // GTEST_HAS_TR1_TUPLE + +// Overload for std::pair. +template +void PrintTo(const ::std::pair& value, ::std::ostream* os) { + *os << '('; + // We cannot use UniversalPrint(value.first, os) here, as T1 may be + // a reference type. The same for printing value.second. + UniversalPrinter::Print(value.first, os); + *os << ", "; + UniversalPrinter::Print(value.second, os); + *os << ')'; +} + +// Implements printing a non-reference type T by letting the compiler +// pick the right overload of PrintTo() for T. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + // Note: we deliberately don't call this PrintTo(), as that name + // conflicts with ::testing::internal::PrintTo in the body of the + // function. + static void Print(const T& value, ::std::ostream* os) { + // By default, ::testing::internal::PrintTo() is used for printing + // the value. + // + // Thanks to Koenig look-up, if T is a class and has its own + // PrintTo() function defined in its namespace, that function will + // be visible here. Since it is more specific than the generic ones + // in ::testing::internal, it will be picked by the compiler in the + // following statement - exactly what we want. + PrintTo(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// UniversalPrintArray(begin, len, os) prints an array of 'len' +// elements, starting at address 'begin'. +template +void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { + if (len == 0) { + *os << "{}"; + } else { + *os << "{ "; + const size_t kThreshold = 18; + const size_t kChunkSize = 8; + // If the array has more than kThreshold elements, we'll have to + // omit some details by printing only the first and the last + // kChunkSize elements. + // TODO(wan@google.com): let the user control the threshold using a flag. + if (len <= kThreshold) { + PrintRawArrayTo(begin, len, os); + } else { + PrintRawArrayTo(begin, kChunkSize, os); + *os << ", ..., "; + PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); + } + *os << " }"; + } +} +// This overload prints a (const) char array compactly. +GTEST_API_ void UniversalPrintArray( + const char* begin, size_t len, ::std::ostream* os); + +// This overload prints a (const) wchar_t array compactly. +GTEST_API_ void UniversalPrintArray( + const wchar_t* begin, size_t len, ::std::ostream* os); + +// Implements printing an array type T[N]. +template +class UniversalPrinter { + public: + // Prints the given array, omitting some elements when there are too + // many. + static void Print(const T (&a)[N], ::std::ostream* os) { + UniversalPrintArray(a, N, os); + } +}; + +// Implements printing a reference type T&. +template +class UniversalPrinter { + public: + // MSVC warns about adding const to a function type, so we want to + // disable the warning. +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4180) // Temporarily disables warning 4180. +#endif // _MSC_VER + + static void Print(const T& value, ::std::ostream* os) { + // Prints the address of the value. We use reinterpret_cast here + // as static_cast doesn't compile when T is a function type. + *os << "@" << reinterpret_cast(&value) << " "; + + // Then prints the value itself. + UniversalPrint(value, os); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif // _MSC_VER +}; + +// Prints a value tersely: for a reference type, the referenced value +// (but not the address) is printed; for a (const) char pointer, the +// NUL-terminated string (but not the pointer) is printed. + +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T& value, ::std::ostream* os) { + UniversalPrint(value, os); + } +}; +template +class UniversalTersePrinter { + public: + static void Print(const T (&value)[N], ::std::ostream* os) { + UniversalPrinter::Print(value, os); + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(const char* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(string(str), os); + } + } +}; +template <> +class UniversalTersePrinter { + public: + static void Print(char* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +#if GTEST_HAS_STD_WSTRING +template <> +class UniversalTersePrinter { + public: + static void Print(const wchar_t* str, ::std::ostream* os) { + if (str == NULL) { + *os << "NULL"; + } else { + UniversalPrint(::std::wstring(str), os); + } + } +}; +#endif + +template <> +class UniversalTersePrinter { + public: + static void Print(wchar_t* str, ::std::ostream* os) { + UniversalTersePrinter::Print(str, os); + } +}; + +template +void UniversalTersePrint(const T& value, ::std::ostream* os) { + UniversalTersePrinter::Print(value, os); +} + +// Prints a value using the type inferred by the compiler. The +// difference between this and UniversalTersePrint() is that for a +// (const) char pointer, this prints both the pointer and the +// NUL-terminated string. +template +void UniversalPrint(const T& value, ::std::ostream* os) { + // A workarond for the bug in VC++ 7.1 that prevents us from instantiating + // UniversalPrinter with T directly. + typedef T T1; + UniversalPrinter::Print(value, os); +} + +#if GTEST_HAS_TR1_TUPLE +typedef ::std::vector Strings; + +// This helper template allows PrintTo() for tuples and +// UniversalTersePrintTupleFieldsToStrings() to be defined by +// induction on the number of tuple fields. The idea is that +// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N +// fields in tuple t, and can be defined in terms of +// TuplePrefixPrinter. + +// The inductive case. +template +struct TuplePrefixPrinter { + // Prints the first N fields of a tuple. + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + TuplePrefixPrinter::PrintPrefixTo(t, os); + *os << ", "; + UniversalPrinter::type> + ::Print(::std::tr1::get(t), os); + } + + // Tersely prints the first N fields of a tuple to a string vector, + // one element for each field. + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Base cases. +template <> +struct TuplePrefixPrinter<0> { + template + static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} + + template + static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} +}; +// We have to specialize the entire TuplePrefixPrinter<> class +// template here, even though the definition of +// TersePrintPrefixToStrings() is the same as the generic version, as +// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't +// support specializing a method template of a class template. +template <> +struct TuplePrefixPrinter<1> { + template + static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { + UniversalPrinter::type>:: + Print(::std::tr1::get<0>(t), os); + } + + template + static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { + ::std::stringstream ss; + UniversalTersePrint(::std::tr1::get<0>(t), &ss); + strings->push_back(ss.str()); + } +}; + +// Helper function for printing a tuple. T must be instantiated with +// a tuple type. +template +void PrintTupleTo(const T& t, ::std::ostream* os) { + *os << "("; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + PrintPrefixTo(t, os); + *os << ")"; +} + +// Prints the fields of a tuple tersely to a string vector, one +// element for each field. See the comment before +// UniversalTersePrint() for how we define "tersely". +template +Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { + Strings result; + TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: + TersePrintPrefixToStrings(value, &result); + return result; +} +#endif // GTEST_HAS_TR1_TUPLE + +} // namespace internal + +template +::std::string PrintToString(const T& value) { + ::std::stringstream ss; + internal::UniversalTersePrinter::Print(value, &ss); + return ss.str(); +} + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { +namespace internal { + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Outputs a message explaining invalid registration of different +// fixture class for the same test case. This may happen when +// TEST_P macro is used to define two tests with the same name +// but in different namespaces. +GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, + const char* file, int line); + +template class ParamGeneratorInterface; +template class ParamGenerator; + +// Interface for iterating over elements provided by an implementation +// of ParamGeneratorInterface. +template +class ParamIteratorInterface { + public: + virtual ~ParamIteratorInterface() {} + // A pointer to the base generator instance. + // Used only for the purposes of iterator comparison + // to make sure that two iterators belong to the same generator. + virtual const ParamGeneratorInterface* BaseGenerator() const = 0; + // Advances iterator to point to the next element + // provided by the generator. The caller is responsible + // for not calling Advance() on an iterator equal to + // BaseGenerator()->End(). + virtual void Advance() = 0; + // Clones the iterator object. Used for implementing copy semantics + // of ParamIterator. + virtual ParamIteratorInterface* Clone() const = 0; + // Dereferences the current iterator and provides (read-only) access + // to the pointed value. It is the caller's responsibility not to call + // Current() on an iterator equal to BaseGenerator()->End(). + // Used for implementing ParamGenerator::operator*(). + virtual const T* Current() const = 0; + // Determines whether the given iterator and other point to the same + // element in the sequence generated by the generator. + // Used for implementing ParamGenerator::operator==(). + virtual bool Equals(const ParamIteratorInterface& other) const = 0; +}; + +// Class iterating over elements provided by an implementation of +// ParamGeneratorInterface. It wraps ParamIteratorInterface +// and implements the const forward iterator concept. +template +class ParamIterator { + public: + typedef T value_type; + typedef const T& reference; + typedef ptrdiff_t difference_type; + + // ParamIterator assumes ownership of the impl_ pointer. + ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} + ParamIterator& operator=(const ParamIterator& other) { + if (this != &other) + impl_.reset(other.impl_->Clone()); + return *this; + } + + const T& operator*() const { return *impl_->Current(); } + const T* operator->() const { return impl_->Current(); } + // Prefix version of operator++. + ParamIterator& operator++() { + impl_->Advance(); + return *this; + } + // Postfix version of operator++. + ParamIterator operator++(int /*unused*/) { + ParamIteratorInterface* clone = impl_->Clone(); + impl_->Advance(); + return ParamIterator(clone); + } + bool operator==(const ParamIterator& other) const { + return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); + } + bool operator!=(const ParamIterator& other) const { + return !(*this == other); + } + + private: + friend class ParamGenerator; + explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} + scoped_ptr > impl_; +}; + +// ParamGeneratorInterface is the binary interface to access generators +// defined in other translation units. +template +class ParamGeneratorInterface { + public: + typedef T ParamType; + + virtual ~ParamGeneratorInterface() {} + + // Generator interface definition + virtual ParamIteratorInterface* Begin() const = 0; + virtual ParamIteratorInterface* End() const = 0; +}; + +// Wraps ParamGeneratorInterface and provides general generator syntax +// compatible with the STL Container concept. +// This class implements copy initialization semantics and the contained +// ParamGeneratorInterface instance is shared among all copies +// of the original object. This is possible because that instance is immutable. +template +class ParamGenerator { + public: + typedef ParamIterator iterator; + + explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} + ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} + + ParamGenerator& operator=(const ParamGenerator& other) { + impl_ = other.impl_; + return *this; + } + + iterator begin() const { return iterator(impl_->Begin()); } + iterator end() const { return iterator(impl_->End()); } + + private: + linked_ptr > impl_; +}; + +// Generates values from a range of two comparable values. Can be used to +// generate sequences of user-defined types that implement operator+() and +// operator<(). +// This class is used in the Range() function. +template +class RangeGenerator : public ParamGeneratorInterface { + public: + RangeGenerator(T begin, T end, IncrementT step) + : begin_(begin), end_(end), + step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} + virtual ~RangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, begin_, 0, step_); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, end_, end_index_, step_); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, T value, int index, + IncrementT step) + : base_(base), value_(value), index_(index), step_(step) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + value_ = value_ + step_; + index_++; + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const T* Current() const { return &value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const int other_index = + CheckedDowncastToActualType(&other)->index_; + return index_ == other_index; + } + + private: + Iterator(const Iterator& other) + : ParamIteratorInterface(), + base_(other.base_), value_(other.value_), index_(other.index_), + step_(other.step_) {} + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + T value_; + int index_; + const IncrementT step_; + }; // class RangeGenerator::Iterator + + static int CalculateEndIndex(const T& begin, + const T& end, + const IncrementT& step) { + int end_index = 0; + for (T i = begin; i < end; i = i + step) + end_index++; + return end_index; + } + + // No implementation - assignment is unsupported. + void operator=(const RangeGenerator& other); + + const T begin_; + const T end_; + const IncrementT step_; + // The index for the end() iterator. All the elements in the generated + // sequence are indexed (0-based) to aid iterator comparison. + const int end_index_; +}; // class RangeGenerator + + +// Generates values from a pair of STL-style iterators. Used in the +// ValuesIn() function. The elements are copied from the source range +// since the source can be located on the stack, and the generator +// is likely to persist beyond that stack frame. +template +class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { + public: + template + ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) + : container_(begin, end) {} + virtual ~ValuesInIteratorRangeGenerator() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, container_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, container_.end()); + } + + private: + typedef typename ::std::vector ContainerType; + + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + typename ContainerType::const_iterator iterator) + : base_(base), iterator_(iterator) {} + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + virtual void Advance() { + ++iterator_; + value_.reset(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + // We need to use cached value referenced by iterator_ because *iterator_ + // can return a temporary object (and of type other then T), so just + // having "return &*iterator_;" doesn't work. + // value_ is updated here and not in Advance() because Advance() + // can advance iterator_ beyond the end of the range, and we cannot + // detect that fact. The client code, on the other hand, is + // responsible for not calling Current() on an out-of-range iterator. + virtual const T* Current() const { + if (value_.get() == NULL) + value_.reset(new T(*iterator_)); + return value_.get(); + } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + return iterator_ == + CheckedDowncastToActualType(&other)->iterator_; + } + + private: + Iterator(const Iterator& other) + // The explicit constructor call suppresses a false warning + // emitted by gcc when supplied with the -Wextra option. + : ParamIteratorInterface(), + base_(other.base_), + iterator_(other.iterator_) {} + + const ParamGeneratorInterface* const base_; + typename ContainerType::const_iterator iterator_; + // A cached value of *iterator_. We keep it here to allow access by + // pointer in the wrapping iterator's operator->(). + // value_ needs to be mutable to be accessed in Current(). + // Use of scoped_ptr helps manage cached value's lifetime, + // which is bound by the lifespan of the iterator itself. + mutable scoped_ptr value_; + }; // class ValuesInIteratorRangeGenerator::Iterator + + // No implementation - assignment is unsupported. + void operator=(const ValuesInIteratorRangeGenerator& other); + + const ContainerType container_; +}; // class ValuesInIteratorRangeGenerator + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Stores a parameter value and later creates tests parameterized with that +// value. +template +class ParameterizedTestFactory : public TestFactoryBase { + public: + typedef typename TestClass::ParamType ParamType; + explicit ParameterizedTestFactory(ParamType parameter) : + parameter_(parameter) {} + virtual Test* CreateTest() { + TestClass::SetParam(¶meter_); + return new TestClass(); + } + + private: + const ParamType parameter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactoryBase is a base class for meta-factories that create +// test factories for passing into MakeAndRegisterTestInfo function. +template +class TestMetaFactoryBase { + public: + virtual ~TestMetaFactoryBase() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// TestMetaFactory creates test factories for passing into +// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives +// ownership of test factory pointer, same factory object cannot be passed +// into that method twice. But ParameterizedTestCaseInfo is going to call +// it for each Test/Parameter value combination. Thus it needs meta factory +// creator class. +template +class TestMetaFactory + : public TestMetaFactoryBase { + public: + typedef typename TestCase::ParamType ParamType; + + TestMetaFactory() {} + + virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { + return new ParameterizedTestFactory(parameter); + } + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfoBase is a generic interface +// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase +// accumulates test information provided by TEST_P macro invocations +// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations +// and uses that information to register all resulting test instances +// in RegisterTests method. The ParameterizeTestCaseRegistry class holds +// a collection of pointers to the ParameterizedTestCaseInfo objects +// and calls RegisterTests() on each of them when asked. +class ParameterizedTestCaseInfoBase { + public: + virtual ~ParameterizedTestCaseInfoBase() {} + + // Base part of test case name for display purposes. + virtual const string& GetTestCaseName() const = 0; + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const = 0; + // UnitTest class invokes this method to register tests in this + // test case right before running them in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + virtual void RegisterTests() = 0; + + protected: + ParameterizedTestCaseInfoBase() {} + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); +}; + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P +// macro invocations for a particular test case and generators +// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that +// test case. It registers tests with all values generated by all +// generators when asked. +template +class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { + public: + // ParamType and GeneratorCreationFunc are private types but are required + // for declarations of public methods AddTestPattern() and + // AddTestCaseInstantiation(). + typedef typename TestCase::ParamType ParamType; + // A function that returns an instance of appropriate generator type. + typedef ParamGenerator(GeneratorCreationFunc)(); + + explicit ParameterizedTestCaseInfo(const char* name) + : test_case_name_(name) {} + + // Test case base name for display purposes. + virtual const string& GetTestCaseName() const { return test_case_name_; } + // Test case id to verify identity. + virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } + // TEST_P macro uses AddTestPattern() to record information + // about a single test in a LocalTestInfo structure. + // test_case_name is the base name of the test case (without invocation + // prefix). test_base_name is the name of an individual test without + // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is + // test case base name and DoBar is test base name. + void AddTestPattern(const char* test_case_name, + const char* test_base_name, + TestMetaFactoryBase* meta_factory) { + tests_.push_back(linked_ptr(new TestInfo(test_case_name, + test_base_name, + meta_factory))); + } + // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information + // about a generator. + int AddTestCaseInstantiation(const string& instantiation_name, + GeneratorCreationFunc* func, + const char* /* file */, + int /* line */) { + instantiations_.push_back(::std::make_pair(instantiation_name, func)); + return 0; // Return value used only to run this method in namespace scope. + } + // UnitTest class invokes this method to register tests in this test case + // test cases right before running tests in RUN_ALL_TESTS macro. + // This method should not be called more then once on any single + // instance of a ParameterizedTestCaseInfoBase derived class. + // UnitTest has a guard to prevent from calling this method more then once. + virtual void RegisterTests() { + for (typename TestInfoContainer::iterator test_it = tests_.begin(); + test_it != tests_.end(); ++test_it) { + linked_ptr test_info = *test_it; + for (typename InstantiationContainer::iterator gen_it = + instantiations_.begin(); gen_it != instantiations_.end(); + ++gen_it) { + const string& instantiation_name = gen_it->first; + ParamGenerator generator((*gen_it->second)()); + + string test_case_name; + if ( !instantiation_name.empty() ) + test_case_name = instantiation_name + "/"; + test_case_name += test_info->test_case_base_name; + + int i = 0; + for (typename ParamGenerator::iterator param_it = + generator.begin(); + param_it != generator.end(); ++param_it, ++i) { + Message test_name_stream; + test_name_stream << test_info->test_base_name << "/" << i; + MakeAndRegisterTestInfo( + test_case_name.c_str(), + test_name_stream.GetString().c_str(), + NULL, // No type parameter. + PrintToString(*param_it).c_str(), + GetTestCaseTypeId(), + TestCase::SetUpTestCase, + TestCase::TearDownTestCase, + test_info->test_meta_factory->CreateTestFactory(*param_it)); + } // for param_it + } // for gen_it + } // for test_it + } // RegisterTests + + private: + // LocalTestInfo structure keeps information about a single test registered + // with TEST_P macro. + struct TestInfo { + TestInfo(const char* a_test_case_base_name, + const char* a_test_base_name, + TestMetaFactoryBase* a_test_meta_factory) : + test_case_base_name(a_test_case_base_name), + test_base_name(a_test_base_name), + test_meta_factory(a_test_meta_factory) {} + + const string test_case_base_name; + const string test_base_name; + const scoped_ptr > test_meta_factory; + }; + typedef ::std::vector > TestInfoContainer; + // Keeps pairs of + // received from INSTANTIATE_TEST_CASE_P macros. + typedef ::std::vector > + InstantiationContainer; + + const string test_case_name_; + TestInfoContainer tests_; + InstantiationContainer instantiations_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); +}; // class ParameterizedTestCaseInfo + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase +// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P +// macros use it to locate their corresponding ParameterizedTestCaseInfo +// descriptors. +class ParameterizedTestCaseRegistry { + public: + ParameterizedTestCaseRegistry() {} + ~ParameterizedTestCaseRegistry() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + delete *it; + } + } + + // Looks up or creates and returns a structure containing information about + // tests and instantiations of a particular test case. + template + ParameterizedTestCaseInfo* GetTestCasePatternHolder( + const char* test_case_name, + const char* file, + int line) { + ParameterizedTestCaseInfo* typed_test_info = NULL; + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + if ((*it)->GetTestCaseName() == test_case_name) { + if ((*it)->GetTestCaseTypeId() != GetTypeId()) { + // Complain about incorrect usage of Google Test facilities + // and terminate the program since we cannot guaranty correct + // test case setup and tear-down in this case. + ReportInvalidTestCaseType(test_case_name, file, line); + posix::Abort(); + } else { + // At this point we are sure that the object we found is of the same + // type we are looking for, so we downcast it to that type + // without further checks. + typed_test_info = CheckedDowncastToActualType< + ParameterizedTestCaseInfo >(*it); + } + break; + } + } + if (typed_test_info == NULL) { + typed_test_info = new ParameterizedTestCaseInfo(test_case_name); + test_case_infos_.push_back(typed_test_info); + } + return typed_test_info; + } + void RegisterTests() { + for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); + it != test_case_infos_.end(); ++it) { + (*it)->RegisterTests(); + } + } + + private: + typedef ::std::vector TestCaseInfoContainer; + + TestCaseInfoContainer test_case_infos_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); +}; + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ +// This file was GENERATED by command: +// pump.py gtest-param-util-generated.h.pump +// DO NOT EDIT BY HAND!!! + +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: vladl@google.com (Vlad Losev) + +// Type and function utilities for implementing parameterized tests. +// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! +// +// Currently Google Test supports at most 50 arguments in Values, +// and at most 10 arguments in Combine. Please contact +// googletestframework@googlegroups.com if you need more. +// Please note that the number of arguments to Combine is limited +// by the maximum arity of the implementation of tr1::tuple which is +// currently set at 10. + +#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ +#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +// scripts/fuse_gtest.py depends on gtest's own header being #included +// *unconditionally*. Therefore these #includes cannot be moved +// inside #if GTEST_HAS_PARAM_TEST. + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Forward declarations of ValuesIn(), which is implemented in +// include/gtest/gtest-param-test.h. +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end); + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]); + +template +internal::ParamGenerator ValuesIn( + const Container& container); + +namespace internal { + +// Used in the Values() function to provide polymorphic capabilities. +template +class ValueArray1 { + public: + explicit ValueArray1(T1 v1) : v1_(v1) {} + + template + operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray1& other); + + const T1 v1_; +}; + +template +class ValueArray2 { + public: + ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray2& other); + + const T1 v1_; + const T2 v2_; +}; + +template +class ValueArray3 { + public: + ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray3& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; +}; + +template +class ValueArray4 { + public: + ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray4& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; +}; + +template +class ValueArray5 { + public: + ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray5& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; +}; + +template +class ValueArray6 { + public: + ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray6& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; +}; + +template +class ValueArray7 { + public: + ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray7& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; +}; + +template +class ValueArray8 { + public: + ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray8& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; +}; + +template +class ValueArray9 { + public: + ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray9& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; +}; + +template +class ValueArray10 { + public: + ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray10& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; +}; + +template +class ValueArray11 { + public: + ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray11& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; +}; + +template +class ValueArray12 { + public: + ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray12& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; +}; + +template +class ValueArray13 { + public: + ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray13& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; +}; + +template +class ValueArray14 { + public: + ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray14& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; +}; + +template +class ValueArray15 { + public: + ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray15& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; +}; + +template +class ValueArray16 { + public: + ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray16& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; +}; + +template +class ValueArray17 { + public: + ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray17& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; +}; + +template +class ValueArray18 { + public: + ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray18& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; +}; + +template +class ValueArray19 { + public: + ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray19& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; +}; + +template +class ValueArray20 { + public: + ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray20& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; +}; + +template +class ValueArray21 { + public: + ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray21& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; +}; + +template +class ValueArray22 { + public: + ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray22& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; +}; + +template +class ValueArray23 { + public: + ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray23& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; +}; + +template +class ValueArray24 { + public: + ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray24& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; +}; + +template +class ValueArray25 { + public: + ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray25& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; +}; + +template +class ValueArray26 { + public: + ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray26& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; +}; + +template +class ValueArray27 { + public: + ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray27& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; +}; + +template +class ValueArray28 { + public: + ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray28& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; +}; + +template +class ValueArray29 { + public: + ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray29& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; +}; + +template +class ValueArray30 { + public: + ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray30& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; +}; + +template +class ValueArray31 { + public: + ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray31& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; +}; + +template +class ValueArray32 { + public: + ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray32& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; +}; + +template +class ValueArray33 { + public: + ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray33& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; +}; + +template +class ValueArray34 { + public: + ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray34& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; +}; + +template +class ValueArray35 { + public: + ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray35& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; +}; + +template +class ValueArray36 { + public: + ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray36& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; +}; + +template +class ValueArray37 { + public: + ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray37& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; +}; + +template +class ValueArray38 { + public: + ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray38& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; +}; + +template +class ValueArray39 { + public: + ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray39& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; +}; + +template +class ValueArray40 { + public: + ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray40& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; +}; + +template +class ValueArray41 { + public: + ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray41& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; +}; + +template +class ValueArray42 { + public: + ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray42& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; +}; + +template +class ValueArray43 { + public: + ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), + v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), + v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), + v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), + v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), + v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), + v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray43& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; +}; + +template +class ValueArray44 { + public: + ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), + v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), + v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), + v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), + v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), + v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), + v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), + v43_(v43), v44_(v44) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray44& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; +}; + +template +class ValueArray45 { + public: + ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), + v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), + v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), + v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), + v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), + v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), + v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), + v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray45& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; +}; + +template +class ValueArray46 { + public: + ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), + v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray46& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; +}; + +template +class ValueArray47 { + public: + ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), + v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), + v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), + v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), + v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), + v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), + v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), + v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), + v47_(v47) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray47& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; +}; + +template +class ValueArray48 { + public: + ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), + v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), + v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), + v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), + v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), + v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), + v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), + v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), + v46_(v46), v47_(v47), v48_(v48) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray48& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; +}; + +template +class ValueArray49 { + public: + ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, + T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_), static_cast(v49_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray49& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; +}; + +template +class ValueArray50 { + public: + ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, + T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), + v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), + v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), + v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), + v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), + v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), + v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), + v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} + + template + operator ParamGenerator() const { + const T array[] = {static_cast(v1_), static_cast(v2_), + static_cast(v3_), static_cast(v4_), static_cast(v5_), + static_cast(v6_), static_cast(v7_), static_cast(v8_), + static_cast(v9_), static_cast(v10_), static_cast(v11_), + static_cast(v12_), static_cast(v13_), static_cast(v14_), + static_cast(v15_), static_cast(v16_), static_cast(v17_), + static_cast(v18_), static_cast(v19_), static_cast(v20_), + static_cast(v21_), static_cast(v22_), static_cast(v23_), + static_cast(v24_), static_cast(v25_), static_cast(v26_), + static_cast(v27_), static_cast(v28_), static_cast(v29_), + static_cast(v30_), static_cast(v31_), static_cast(v32_), + static_cast(v33_), static_cast(v34_), static_cast(v35_), + static_cast(v36_), static_cast(v37_), static_cast(v38_), + static_cast(v39_), static_cast(v40_), static_cast(v41_), + static_cast(v42_), static_cast(v43_), static_cast(v44_), + static_cast(v45_), static_cast(v46_), static_cast(v47_), + static_cast(v48_), static_cast(v49_), static_cast(v50_)}; + return ValuesIn(array); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const ValueArray50& other); + + const T1 v1_; + const T2 v2_; + const T3 v3_; + const T4 v4_; + const T5 v5_; + const T6 v6_; + const T7 v7_; + const T8 v8_; + const T9 v9_; + const T10 v10_; + const T11 v11_; + const T12 v12_; + const T13 v13_; + const T14 v14_; + const T15 v15_; + const T16 v16_; + const T17 v17_; + const T18 v18_; + const T19 v19_; + const T20 v20_; + const T21 v21_; + const T22 v22_; + const T23 v23_; + const T24 v24_; + const T25 v25_; + const T26 v26_; + const T27 v27_; + const T28 v28_; + const T29 v29_; + const T30 v30_; + const T31 v31_; + const T32 v32_; + const T33 v33_; + const T34 v34_; + const T35 v35_; + const T36 v36_; + const T37 v37_; + const T38 v38_; + const T39 v39_; + const T40 v40_; + const T41 v41_; + const T42 v42_; + const T43 v43_; + const T44 v44_; + const T45 v45_; + const T46 v46_; + const T47 v47_; + const T48 v48_; + const T49 v49_; + const T50 v50_; +}; + +# if GTEST_HAS_COMBINE +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Generates values from the Cartesian product of values produced +// by the argument generators. +// +template +class CartesianProductGenerator2 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator2(const ParamGenerator& g1, + const ParamGenerator& g2) + : g1_(g1), g2_(g2) {} + virtual ~CartesianProductGenerator2() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current2_; + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + ParamType current_value_; + }; // class CartesianProductGenerator2::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator2& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; +}; // class CartesianProductGenerator2 + + +template +class CartesianProductGenerator3 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator3(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + virtual ~CartesianProductGenerator3() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current3_; + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + ParamType current_value_; + }; // class CartesianProductGenerator3::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator3& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; +}; // class CartesianProductGenerator3 + + +template +class CartesianProductGenerator4 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator4(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + virtual ~CartesianProductGenerator4() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current4_; + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + ParamType current_value_; + }; // class CartesianProductGenerator4::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator4& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; +}; // class CartesianProductGenerator4 + + +template +class CartesianProductGenerator5 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator5(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + virtual ~CartesianProductGenerator5() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current5_; + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + ParamType current_value_; + }; // class CartesianProductGenerator5::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator5& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; +}; // class CartesianProductGenerator5 + + +template +class CartesianProductGenerator6 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator6(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + virtual ~CartesianProductGenerator6() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current6_; + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + ParamType current_value_; + }; // class CartesianProductGenerator6::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator6& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; +}; // class CartesianProductGenerator6 + + +template +class CartesianProductGenerator7 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator7(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + virtual ~CartesianProductGenerator7() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current7_; + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + ParamType current_value_; + }; // class CartesianProductGenerator7::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator7& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; +}; // class CartesianProductGenerator7 + + +template +class CartesianProductGenerator8 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator8(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + virtual ~CartesianProductGenerator8() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current8_; + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + ParamType current_value_; + }; // class CartesianProductGenerator8::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator8& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; +}; // class CartesianProductGenerator8 + + +template +class CartesianProductGenerator9 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator9(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + virtual ~CartesianProductGenerator9() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current9_; + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + ParamType current_value_; + }; // class CartesianProductGenerator9::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator9& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; +}; // class CartesianProductGenerator9 + + +template +class CartesianProductGenerator10 + : public ParamGeneratorInterface< ::std::tr1::tuple > { + public: + typedef ::std::tr1::tuple ParamType; + + CartesianProductGenerator10(const ParamGenerator& g1, + const ParamGenerator& g2, const ParamGenerator& g3, + const ParamGenerator& g4, const ParamGenerator& g5, + const ParamGenerator& g6, const ParamGenerator& g7, + const ParamGenerator& g8, const ParamGenerator& g9, + const ParamGenerator& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + virtual ~CartesianProductGenerator10() {} + + virtual ParamIteratorInterface* Begin() const { + return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, + g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, + g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); + } + virtual ParamIteratorInterface* End() const { + return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), + g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, + g8_.end(), g9_, g9_.end(), g10_, g10_.end()); + } + + private: + class Iterator : public ParamIteratorInterface { + public: + Iterator(const ParamGeneratorInterface* base, + const ParamGenerator& g1, + const typename ParamGenerator::iterator& current1, + const ParamGenerator& g2, + const typename ParamGenerator::iterator& current2, + const ParamGenerator& g3, + const typename ParamGenerator::iterator& current3, + const ParamGenerator& g4, + const typename ParamGenerator::iterator& current4, + const ParamGenerator& g5, + const typename ParamGenerator::iterator& current5, + const ParamGenerator& g6, + const typename ParamGenerator::iterator& current6, + const ParamGenerator& g7, + const typename ParamGenerator::iterator& current7, + const ParamGenerator& g8, + const typename ParamGenerator::iterator& current8, + const ParamGenerator& g9, + const typename ParamGenerator::iterator& current9, + const ParamGenerator& g10, + const typename ParamGenerator::iterator& current10) + : base_(base), + begin1_(g1.begin()), end1_(g1.end()), current1_(current1), + begin2_(g2.begin()), end2_(g2.end()), current2_(current2), + begin3_(g3.begin()), end3_(g3.end()), current3_(current3), + begin4_(g4.begin()), end4_(g4.end()), current4_(current4), + begin5_(g5.begin()), end5_(g5.end()), current5_(current5), + begin6_(g6.begin()), end6_(g6.end()), current6_(current6), + begin7_(g7.begin()), end7_(g7.end()), current7_(current7), + begin8_(g8.begin()), end8_(g8.end()), current8_(current8), + begin9_(g9.begin()), end9_(g9.end()), current9_(current9), + begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { + ComputeCurrentValue(); + } + virtual ~Iterator() {} + + virtual const ParamGeneratorInterface* BaseGenerator() const { + return base_; + } + // Advance should not be called on beyond-of-range iterators + // so no component iterators must be beyond end of range, either. + virtual void Advance() { + assert(!AtEnd()); + ++current10_; + if (current10_ == end10_) { + current10_ = begin10_; + ++current9_; + } + if (current9_ == end9_) { + current9_ = begin9_; + ++current8_; + } + if (current8_ == end8_) { + current8_ = begin8_; + ++current7_; + } + if (current7_ == end7_) { + current7_ = begin7_; + ++current6_; + } + if (current6_ == end6_) { + current6_ = begin6_; + ++current5_; + } + if (current5_ == end5_) { + current5_ = begin5_; + ++current4_; + } + if (current4_ == end4_) { + current4_ = begin4_; + ++current3_; + } + if (current3_ == end3_) { + current3_ = begin3_; + ++current2_; + } + if (current2_ == end2_) { + current2_ = begin2_; + ++current1_; + } + ComputeCurrentValue(); + } + virtual ParamIteratorInterface* Clone() const { + return new Iterator(*this); + } + virtual const ParamType* Current() const { return ¤t_value_; } + virtual bool Equals(const ParamIteratorInterface& other) const { + // Having the same base generator guarantees that the other + // iterator is of the same type and we can downcast. + GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) + << "The program attempted to compare iterators " + << "from different generators." << std::endl; + const Iterator* typed_other = + CheckedDowncastToActualType(&other); + // We must report iterators equal if they both point beyond their + // respective ranges. That can happen in a variety of fashions, + // so we have to consult AtEnd(). + return (AtEnd() && typed_other->AtEnd()) || + ( + current1_ == typed_other->current1_ && + current2_ == typed_other->current2_ && + current3_ == typed_other->current3_ && + current4_ == typed_other->current4_ && + current5_ == typed_other->current5_ && + current6_ == typed_other->current6_ && + current7_ == typed_other->current7_ && + current8_ == typed_other->current8_ && + current9_ == typed_other->current9_ && + current10_ == typed_other->current10_); + } + + private: + Iterator(const Iterator& other) + : base_(other.base_), + begin1_(other.begin1_), + end1_(other.end1_), + current1_(other.current1_), + begin2_(other.begin2_), + end2_(other.end2_), + current2_(other.current2_), + begin3_(other.begin3_), + end3_(other.end3_), + current3_(other.current3_), + begin4_(other.begin4_), + end4_(other.end4_), + current4_(other.current4_), + begin5_(other.begin5_), + end5_(other.end5_), + current5_(other.current5_), + begin6_(other.begin6_), + end6_(other.end6_), + current6_(other.current6_), + begin7_(other.begin7_), + end7_(other.end7_), + current7_(other.current7_), + begin8_(other.begin8_), + end8_(other.end8_), + current8_(other.current8_), + begin9_(other.begin9_), + end9_(other.end9_), + current9_(other.current9_), + begin10_(other.begin10_), + end10_(other.end10_), + current10_(other.current10_) { + ComputeCurrentValue(); + } + + void ComputeCurrentValue() { + if (!AtEnd()) + current_value_ = ParamType(*current1_, *current2_, *current3_, + *current4_, *current5_, *current6_, *current7_, *current8_, + *current9_, *current10_); + } + bool AtEnd() const { + // We must report iterator past the end of the range when either of the + // component iterators has reached the end of its range. + return + current1_ == end1_ || + current2_ == end2_ || + current3_ == end3_ || + current4_ == end4_ || + current5_ == end5_ || + current6_ == end6_ || + current7_ == end7_ || + current8_ == end8_ || + current9_ == end9_ || + current10_ == end10_; + } + + // No implementation - assignment is unsupported. + void operator=(const Iterator& other); + + const ParamGeneratorInterface* const base_; + // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. + // current[i]_ is the actual traversing iterator. + const typename ParamGenerator::iterator begin1_; + const typename ParamGenerator::iterator end1_; + typename ParamGenerator::iterator current1_; + const typename ParamGenerator::iterator begin2_; + const typename ParamGenerator::iterator end2_; + typename ParamGenerator::iterator current2_; + const typename ParamGenerator::iterator begin3_; + const typename ParamGenerator::iterator end3_; + typename ParamGenerator::iterator current3_; + const typename ParamGenerator::iterator begin4_; + const typename ParamGenerator::iterator end4_; + typename ParamGenerator::iterator current4_; + const typename ParamGenerator::iterator begin5_; + const typename ParamGenerator::iterator end5_; + typename ParamGenerator::iterator current5_; + const typename ParamGenerator::iterator begin6_; + const typename ParamGenerator::iterator end6_; + typename ParamGenerator::iterator current6_; + const typename ParamGenerator::iterator begin7_; + const typename ParamGenerator::iterator end7_; + typename ParamGenerator::iterator current7_; + const typename ParamGenerator::iterator begin8_; + const typename ParamGenerator::iterator end8_; + typename ParamGenerator::iterator current8_; + const typename ParamGenerator::iterator begin9_; + const typename ParamGenerator::iterator end9_; + typename ParamGenerator::iterator current9_; + const typename ParamGenerator::iterator begin10_; + const typename ParamGenerator::iterator end10_; + typename ParamGenerator::iterator current10_; + ParamType current_value_; + }; // class CartesianProductGenerator10::Iterator + + // No implementation - assignment is unsupported. + void operator=(const CartesianProductGenerator10& other); + + const ParamGenerator g1_; + const ParamGenerator g2_; + const ParamGenerator g3_; + const ParamGenerator g4_; + const ParamGenerator g5_; + const ParamGenerator g6_; + const ParamGenerator g7_; + const ParamGenerator g8_; + const ParamGenerator g9_; + const ParamGenerator g10_; +}; // class CartesianProductGenerator10 + + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Helper classes providing Combine() with polymorphic features. They allow +// casting CartesianProductGeneratorN to ParamGenerator if T is +// convertible to U. +// +template +class CartesianProductHolder2 { + public: +CartesianProductHolder2(const Generator1& g1, const Generator2& g2) + : g1_(g1), g2_(g2) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator2( + static_cast >(g1_), + static_cast >(g2_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder2& other); + + const Generator1 g1_; + const Generator2 g2_; +}; // class CartesianProductHolder2 + +template +class CartesianProductHolder3 { + public: +CartesianProductHolder3(const Generator1& g1, const Generator2& g2, + const Generator3& g3) + : g1_(g1), g2_(g2), g3_(g3) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator3( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder3& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; +}; // class CartesianProductHolder3 + +template +class CartesianProductHolder4 { + public: +CartesianProductHolder4(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator4( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder4& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; +}; // class CartesianProductHolder4 + +template +class CartesianProductHolder5 { + public: +CartesianProductHolder5(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator5( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder5& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; +}; // class CartesianProductHolder5 + +template +class CartesianProductHolder6 { + public: +CartesianProductHolder6(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator6( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder6& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; +}; // class CartesianProductHolder6 + +template +class CartesianProductHolder7 { + public: +CartesianProductHolder7(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator7( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder7& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; +}; // class CartesianProductHolder7 + +template +class CartesianProductHolder8 { + public: +CartesianProductHolder8(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), + g8_(g8) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator8( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder8& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; +}; // class CartesianProductHolder8 + +template +class CartesianProductHolder9 { + public: +CartesianProductHolder9(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator9( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder9& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; +}; // class CartesianProductHolder9 + +template +class CartesianProductHolder10 { + public: +CartesianProductHolder10(const Generator1& g1, const Generator2& g2, + const Generator3& g3, const Generator4& g4, const Generator5& g5, + const Generator6& g6, const Generator7& g7, const Generator8& g8, + const Generator9& g9, const Generator10& g10) + : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), + g9_(g9), g10_(g10) {} + template + operator ParamGenerator< ::std::tr1::tuple >() const { + return ParamGenerator< ::std::tr1::tuple >( + new CartesianProductGenerator10( + static_cast >(g1_), + static_cast >(g2_), + static_cast >(g3_), + static_cast >(g4_), + static_cast >(g5_), + static_cast >(g6_), + static_cast >(g7_), + static_cast >(g8_), + static_cast >(g9_), + static_cast >(g10_))); + } + + private: + // No implementation - assignment is unsupported. + void operator=(const CartesianProductHolder10& other); + + const Generator1 g1_; + const Generator2 g2_; + const Generator3 g3_; + const Generator4 g4_; + const Generator5 g5_; + const Generator6 g6_; + const Generator7 g7_; + const Generator8 g8_; + const Generator9 g9_; + const Generator10 g10_; +}; // class CartesianProductHolder10 + +# endif // GTEST_HAS_COMBINE + +} // namespace internal +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ + +#if GTEST_HAS_PARAM_TEST + +namespace testing { + +// Functions producing parameter generators. +// +// Google Test uses these generators to produce parameters for value- +// parameterized tests. When a parameterized test case is instantiated +// with a particular generator, Google Test creates and runs tests +// for each element in the sequence produced by the generator. +// +// In the following sample, tests from test case FooTest are instantiated +// each three times with parameter values 3, 5, and 8: +// +// class FooTest : public TestWithParam { ... }; +// +// TEST_P(FooTest, TestThis) { +// } +// TEST_P(FooTest, TestThat) { +// } +// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); +// + +// Range() returns generators providing sequences of values in a range. +// +// Synopsis: +// Range(start, end) +// - returns a generator producing a sequence of values {start, start+1, +// start+2, ..., }. +// Range(start, end, step) +// - returns a generator producing a sequence of values {start, start+step, +// start+step+step, ..., }. +// Notes: +// * The generated sequences never include end. For example, Range(1, 5) +// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) +// returns a generator producing {1, 3, 5, 7}. +// * start and end must have the same type. That type may be any integral or +// floating-point type or a user defined type satisfying these conditions: +// * It must be assignable (have operator=() defined). +// * It must have operator+() (operator+(int-compatible type) for +// two-operand version). +// * It must have operator<() defined. +// Elements in the resulting sequences will also have that type. +// * Condition start < end must be satisfied in order for resulting sequences +// to contain any elements. +// +template +internal::ParamGenerator Range(T start, T end, IncrementT step) { + return internal::ParamGenerator( + new internal::RangeGenerator(start, end, step)); +} + +template +internal::ParamGenerator Range(T start, T end) { + return Range(start, end, 1); +} + +// ValuesIn() function allows generation of tests with parameters coming from +// a container. +// +// Synopsis: +// ValuesIn(const T (&array)[N]) +// - returns a generator producing sequences with elements from +// a C-style array. +// ValuesIn(const Container& container) +// - returns a generator producing sequences with elements from +// an STL-style container. +// ValuesIn(Iterator begin, Iterator end) +// - returns a generator producing sequences with elements from +// a range [begin, end) defined by a pair of STL-style iterators. These +// iterators can also be plain C pointers. +// +// Please note that ValuesIn copies the values from the containers +// passed in and keeps them to generate tests in RUN_ALL_TESTS(). +// +// Examples: +// +// This instantiates tests from test case StringTest +// each with C-string values of "foo", "bar", and "baz": +// +// const char* strings[] = {"foo", "bar", "baz"}; +// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); +// +// This instantiates tests from test case StlStringTest +// each with STL strings with values "a" and "b": +// +// ::std::vector< ::std::string> GetParameterStrings() { +// ::std::vector< ::std::string> v; +// v.push_back("a"); +// v.push_back("b"); +// return v; +// } +// +// INSTANTIATE_TEST_CASE_P(CharSequence, +// StlStringTest, +// ValuesIn(GetParameterStrings())); +// +// +// This will also instantiate tests from CharTest +// each with parameter values 'a' and 'b': +// +// ::std::list GetParameterChars() { +// ::std::list list; +// list.push_back('a'); +// list.push_back('b'); +// return list; +// } +// ::std::list l = GetParameterChars(); +// INSTANTIATE_TEST_CASE_P(CharSequence2, +// CharTest, +// ValuesIn(l.begin(), l.end())); +// +template +internal::ParamGenerator< + typename ::testing::internal::IteratorTraits::value_type> +ValuesIn(ForwardIterator begin, ForwardIterator end) { + typedef typename ::testing::internal::IteratorTraits + ::value_type ParamType; + return internal::ParamGenerator( + new internal::ValuesInIteratorRangeGenerator(begin, end)); +} + +template +internal::ParamGenerator ValuesIn(const T (&array)[N]) { + return ValuesIn(array, array + N); +} + +template +internal::ParamGenerator ValuesIn( + const Container& container) { + return ValuesIn(container.begin(), container.end()); +} + +// Values() allows generating tests from explicitly specified list of +// parameters. +// +// Synopsis: +// Values(T v1, T v2, ..., T vN) +// - returns a generator producing sequences with elements v1, v2, ..., vN. +// +// For example, this instantiates tests from test case BarTest each +// with values "one", "two", and "three": +// +// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); +// +// This instantiates tests from test case BazTest each with values 1, 2, 3.5. +// The exact type of values will depend on the type of parameter in BazTest. +// +// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); +// +// Currently, Values() supports from 1 to 50 parameters. +// +template +internal::ValueArray1 Values(T1 v1) { + return internal::ValueArray1(v1); +} + +template +internal::ValueArray2 Values(T1 v1, T2 v2) { + return internal::ValueArray2(v1, v2); +} + +template +internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { + return internal::ValueArray3(v1, v2, v3); +} + +template +internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { + return internal::ValueArray4(v1, v2, v3, v4); +} + +template +internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5) { + return internal::ValueArray5(v1, v2, v3, v4, v5); +} + +template +internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6) { + return internal::ValueArray6(v1, v2, v3, v4, v5, v6); +} + +template +internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7) { + return internal::ValueArray7(v1, v2, v3, v4, v5, + v6, v7); +} + +template +internal::ValueArray8 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { + return internal::ValueArray8(v1, v2, v3, v4, + v5, v6, v7, v8); +} + +template +internal::ValueArray9 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { + return internal::ValueArray9(v1, v2, v3, + v4, v5, v6, v7, v8, v9); +} + +template +internal::ValueArray10 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { + return internal::ValueArray10(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10); +} + +template +internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11) { + return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); +} + +template +internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12) { + return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); +} + +template +internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13) { + return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); +} + +template +internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { + return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14); +} + +template +internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { + return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15); +} + +template +internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16) { + return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16); +} + +template +internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17) { + return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17); +} + +template +internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18) { + return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18); +} + +template +internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { + return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); +} + +template +internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { + return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); +} + +template +internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { + return internal::ValueArray21(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); +} + +template +internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22) { + return internal::ValueArray22(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22); +} + +template +internal::ValueArray23 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23) { + return internal::ValueArray23(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23); +} + +template +internal::ValueArray24 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24) { + return internal::ValueArray24(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24); +} + +template +internal::ValueArray25 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { + return internal::ValueArray25(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25); +} + +template +internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26) { + return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); +} + +template +internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27) { + return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); +} + +template +internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28) { + return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28); +} + +template +internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29) { + return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29); +} + +template +internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { + return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30); +} + +template +internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { + return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31); +} + +template +internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32) { + return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32); +} + +template +internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33) { + return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); +} + +template +internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34) { + return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); +} + +template +internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { + return internal::ValueArray35(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); +} + +template +internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { + return internal::ValueArray36(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36); +} + +template +internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, + T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37) { + return internal::ValueArray37(v1, v2, v3, + v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37); +} + +template +internal::ValueArray38 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38) { + return internal::ValueArray38(v1, v2, + v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, + v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, + v33, v34, v35, v36, v37, v38); +} + +template +internal::ValueArray39 Values(T1 v1, T2 v2, + T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, + T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, + T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, + T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, + T37 v37, T38 v38, T39 v39) { + return internal::ValueArray39(v1, + v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, + v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, + v32, v33, v34, v35, v36, v37, v38, v39); +} + +template +internal::ValueArray40 Values(T1 v1, + T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, + T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, + T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, + T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, + T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { + return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, + v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, + v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); +} + +template +internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { + return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, + v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, + v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); +} + +template +internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42) { + return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, + v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, + v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, + v42); +} + +template +internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43) { + return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, + v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, + v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, + v41, v42, v43); +} + +template +internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, + T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, + T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, + T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, + T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, + T42 v42, T43 v43, T44 v44) { + return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, + v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, + v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, + v40, v41, v42, v43, v44); +} + +template +internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, + T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, + T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, + T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, + T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, + T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { + return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, + v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, + v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, + v39, v40, v41, v42, v43, v44, v45); +} + +template +internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { + return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, + v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46); +} + +template +internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, + T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { + return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, + v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, + v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, + v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); +} + +template +internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, + T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, + T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, + T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, + T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, + T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, + T48 v48) { + return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, + v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, + v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, + v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); +} + +template +internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, + T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, + T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, + T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, + T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, + T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, + T47 v47, T48 v48, T49 v49) { + return internal::ValueArray49(v1, v2, v3, v4, v5, v6, + v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, + v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, + v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); +} + +template +internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, + T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, + T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, + T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, + T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, + T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, + T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { + return internal::ValueArray50(v1, v2, v3, v4, + v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, + v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, + v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, + v48, v49, v50); +} + +// Bool() allows generating tests with parameters in a set of (false, true). +// +// Synopsis: +// Bool() +// - returns a generator producing sequences with elements {false, true}. +// +// It is useful when testing code that depends on Boolean flags. Combinations +// of multiple flags can be tested when several Bool()'s are combined using +// Combine() function. +// +// In the following example all tests in the test case FlagDependentTest +// will be instantiated twice with parameters false and true. +// +// class FlagDependentTest : public testing::TestWithParam { +// virtual void SetUp() { +// external_flag = GetParam(); +// } +// } +// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); +// +inline internal::ParamGenerator Bool() { + return Values(false, true); +} + +# if GTEST_HAS_COMBINE +// Combine() allows the user to combine two or more sequences to produce +// values of a Cartesian product of those sequences' elements. +// +// Synopsis: +// Combine(gen1, gen2, ..., genN) +// - returns a generator producing sequences with elements coming from +// the Cartesian product of elements from the sequences generated by +// gen1, gen2, ..., genN. The sequence elements will have a type of +// tuple where T1, T2, ..., TN are the types +// of elements from sequences produces by gen1, gen2, ..., genN. +// +// Combine can have up to 10 arguments. This number is currently limited +// by the maximum number of elements in the tuple implementation used by Google +// Test. +// +// Example: +// +// This will instantiate tests in test case AnimalTest each one with +// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), +// tuple("dog", BLACK), and tuple("dog", WHITE): +// +// enum Color { BLACK, GRAY, WHITE }; +// class AnimalTest +// : public testing::TestWithParam > {...}; +// +// TEST_P(AnimalTest, AnimalLooksNice) {...} +// +// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, +// Combine(Values("cat", "dog"), +// Values(BLACK, WHITE))); +// +// This will instantiate tests in FlagDependentTest with all variations of two +// Boolean flags: +// +// class FlagDependentTest +// : public testing::TestWithParam > { +// virtual void SetUp() { +// // Assigns external_flag_1 and external_flag_2 values from the tuple. +// tie(external_flag_1, external_flag_2) = GetParam(); +// } +// }; +// +// TEST_P(FlagDependentTest, TestFeature1) { +// // Test your code using external_flag_1 and external_flag_2 here. +// } +// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, +// Combine(Bool(), Bool())); +// +template +internal::CartesianProductHolder2 Combine( + const Generator1& g1, const Generator2& g2) { + return internal::CartesianProductHolder2( + g1, g2); +} + +template +internal::CartesianProductHolder3 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3) { + return internal::CartesianProductHolder3( + g1, g2, g3); +} + +template +internal::CartesianProductHolder4 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4) { + return internal::CartesianProductHolder4( + g1, g2, g3, g4); +} + +template +internal::CartesianProductHolder5 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5) { + return internal::CartesianProductHolder5( + g1, g2, g3, g4, g5); +} + +template +internal::CartesianProductHolder6 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6) { + return internal::CartesianProductHolder6( + g1, g2, g3, g4, g5, g6); +} + +template +internal::CartesianProductHolder7 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7) { + return internal::CartesianProductHolder7( + g1, g2, g3, g4, g5, g6, g7); +} + +template +internal::CartesianProductHolder8 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8) { + return internal::CartesianProductHolder8( + g1, g2, g3, g4, g5, g6, g7, g8); +} + +template +internal::CartesianProductHolder9 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9) { + return internal::CartesianProductHolder9( + g1, g2, g3, g4, g5, g6, g7, g8, g9); +} + +template +internal::CartesianProductHolder10 Combine( + const Generator1& g1, const Generator2& g2, const Generator3& g3, + const Generator4& g4, const Generator5& g5, const Generator6& g6, + const Generator7& g7, const Generator8& g8, const Generator9& g9, + const Generator10& g10) { + return internal::CartesianProductHolder10( + g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); +} +# endif // GTEST_HAS_COMBINE + + + +# define TEST_P(test_case_name, test_name) \ + class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ + : public test_case_name { \ + public: \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ + virtual void TestBody(); \ + private: \ + static int AddToRegistry() { \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ + #test_case_name, \ + #test_name, \ + new ::testing::internal::TestMetaFactory< \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ + return 0; \ + } \ + static int gtest_registering_dummy_; \ + GTEST_DISALLOW_COPY_AND_ASSIGN_(\ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ + }; \ + int GTEST_TEST_CLASS_NAME_(test_case_name, \ + test_name)::gtest_registering_dummy_ = \ + GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ + void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() + +# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ + ::testing::internal::ParamGenerator \ + gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ + int gtest_##prefix##test_case_name##_dummy_ = \ + ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ + GetTestCasePatternHolder(\ + #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ + #prefix, \ + >est_##prefix##test_case_name##_EvalGenerator_, \ + __FILE__, __LINE__) + +} // namespace testing + +#endif // GTEST_HAS_PARAM_TEST + +#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) +// +// Google C++ Testing Framework definitions useful in production code. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ + +// When you need to test the private or protected members of a class, +// use the FRIEND_TEST macro to declare your tests as friends of the +// class. For example: +// +// class MyClass { +// private: +// void MyMethod(); +// FRIEND_TEST(MyClassTest, MyMethod); +// }; +// +// class MyClassTest : public testing::Test { +// // ... +// }; +// +// TEST_F(MyClassTest, MyMethod) { +// // Can call MyClass::MyMethod() here. +// } + +#define FRIEND_TEST(test_case_name, test_name)\ +friend class test_case_name##_##test_name##_Test + +#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: mheule@google.com (Markus Heule) +// + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ + +#include +#include + +namespace testing { + +// A copyable object representing the result of a test part (i.e. an +// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). +// +// Don't inherit from TestPartResult as its destructor is not virtual. +class GTEST_API_ TestPartResult { + public: + // The possible outcomes of a test part (i.e. an assertion or an + // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). + enum Type { + kSuccess, // Succeeded. + kNonFatalFailure, // Failed but the test can continue. + kFatalFailure // Failed and the test should be terminated. + }; + + // C'tor. TestPartResult does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestPartResult object. + TestPartResult(Type a_type, + const char* a_file_name, + int a_line_number, + const char* a_message) + : type_(a_type), + file_name_(a_file_name == NULL ? "" : a_file_name), + line_number_(a_line_number), + summary_(ExtractSummary(a_message)), + message_(a_message) { + } + + // Gets the outcome of the test part. + Type type() const { return type_; } + + // Gets the name of the source file where the test part took place, or + // NULL if it's unknown. + const char* file_name() const { + return file_name_.empty() ? NULL : file_name_.c_str(); + } + + // Gets the line in the source file where the test part took place, + // or -1 if it's unknown. + int line_number() const { return line_number_; } + + // Gets the summary of the failure message. + const char* summary() const { return summary_.c_str(); } + + // Gets the message associated with the test part. + const char* message() const { return message_.c_str(); } + + // Returns true iff the test part passed. + bool passed() const { return type_ == kSuccess; } + + // Returns true iff the test part failed. + bool failed() const { return type_ != kSuccess; } + + // Returns true iff the test part non-fatally failed. + bool nonfatally_failed() const { return type_ == kNonFatalFailure; } + + // Returns true iff the test part fatally failed. + bool fatally_failed() const { return type_ == kFatalFailure; } + + private: + Type type_; + + // Gets the summary of the failure message by omitting the stack + // trace in it. + static std::string ExtractSummary(const char* message); + + // The name of the source file where the test part took place, or + // "" if the source file is unknown. + std::string file_name_; + // The line in the source file where the test part took place, or -1 + // if the line number is unknown. + int line_number_; + std::string summary_; // The test failure summary. + std::string message_; // The test failure message. +}; + +// Prints a TestPartResult object. +std::ostream& operator<<(std::ostream& os, const TestPartResult& result); + +// An array of TestPartResult objects. +// +// Don't inherit from TestPartResultArray as its destructor is not +// virtual. +class GTEST_API_ TestPartResultArray { + public: + TestPartResultArray() {} + + // Appends the given TestPartResult to the array. + void Append(const TestPartResult& result); + + // Returns the TestPartResult at the given index (0-based). + const TestPartResult& GetTestPartResult(int index) const; + + // Returns the number of TestPartResult objects in the array. + int size() const; + + private: + std::vector array_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); +}; + +// This interface knows how to report a test part result. +class TestPartResultReporterInterface { + public: + virtual ~TestPartResultReporterInterface() {} + + virtual void ReportTestPartResult(const TestPartResult& result) = 0; +}; + +namespace internal { + +// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a +// statement generates new fatal failures. To do so it registers itself as the +// current test part result reporter. Besides checking if fatal failures were +// reported, it only delegates the reporting to the former result reporter. +// The original result reporter is restored in the destructor. +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +class GTEST_API_ HasNewFatalFailureHelper + : public TestPartResultReporterInterface { + public: + HasNewFatalFailureHelper(); + virtual ~HasNewFatalFailureHelper(); + virtual void ReportTestPartResult(const TestPartResult& result); + bool has_new_fatal_failure() const { return has_new_fatal_failure_; } + private: + bool has_new_fatal_failure_; + TestPartResultReporterInterface* original_reporter_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); +}; + +} // namespace internal + +} // namespace testing + +#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ +// Copyright 2008 Google Inc. +// All Rights Reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. +// +// Author: wan@google.com (Zhanyong Wan) + +#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ +#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// This header implements typed tests and type-parameterized tests. + +// Typed (aka type-driven) tests repeat the same test for types in a +// list. You must know which types you want to test with when writing +// typed tests. Here's how you do it: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + public: + ... + typedef std::list List; + static T shared_; + T value_; +}; + +// Next, associate a list of types with the test case, which will be +// repeated for each type in the list. The typedef is necessary for +// the macro to parse correctly. +typedef testing::Types MyTypes; +TYPED_TEST_CASE(FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// TYPED_TEST_CASE(FooTest, int); + +// Then, use TYPED_TEST() instead of TEST_F() to define as many typed +// tests for this test case as you want. +TYPED_TEST(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + // Since we are inside a derived class template, C++ requires use to + // visit the members of FooTest via 'this'. + TypeParam n = this->value_; + + // To visit static members of the fixture, add the TestFixture:: + // prefix. + n += TestFixture::shared_; + + // To refer to typedefs in the fixture, add the "typename + // TestFixture::" prefix. + typename TestFixture::List values; + values.push_back(n); + ... +} + +TYPED_TEST(FooTest, HasPropertyA) { ... } + +#endif // 0 + +// Type-parameterized tests are abstract test patterns parameterized +// by a type. Compared with typed tests, type-parameterized tests +// allow you to define the test pattern without knowing what the type +// parameters are. The defined pattern can be instantiated with +// different types any number of times, in any number of translation +// units. +// +// If you are designing an interface or concept, you can define a +// suite of type-parameterized tests to verify properties that any +// valid implementation of the interface/concept should have. Then, +// each implementation can easily instantiate the test suite to verify +// that it conforms to the requirements, without having to write +// similar tests repeatedly. Here's an example: + +#if 0 + +// First, define a fixture class template. It should be parameterized +// by a type. Remember to derive it from testing::Test. +template +class FooTest : public testing::Test { + ... +}; + +// Next, declare that you will define a type-parameterized test case +// (the _P suffix is for "parameterized" or "pattern", whichever you +// prefer): +TYPED_TEST_CASE_P(FooTest); + +// Then, use TYPED_TEST_P() to define as many type-parameterized tests +// for this type-parameterized test case as you want. +TYPED_TEST_P(FooTest, DoesBlah) { + // Inside a test, refer to TypeParam to get the type parameter. + TypeParam n = 0; + ... +} + +TYPED_TEST_P(FooTest, HasPropertyA) { ... } + +// Now the tricky part: you need to register all test patterns before +// you can instantiate them. The first argument of the macro is the +// test case name; the rest are the names of the tests in this test +// case. +REGISTER_TYPED_TEST_CASE_P(FooTest, + DoesBlah, HasPropertyA); + +// Finally, you are free to instantiate the pattern with the types you +// want. If you put the above code in a header file, you can #include +// it in multiple C++ source files and instantiate it multiple times. +// +// To distinguish different instances of the pattern, the first +// argument to the INSTANTIATE_* macro is a prefix that will be added +// to the actual test case name. Remember to pick unique prefixes for +// different instances. +typedef testing::Types MyTypes; +INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); + +// If the type list contains only one type, you can write that type +// directly without Types<...>: +// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); + +#endif // 0 + + +// Implements typed tests. + +#if GTEST_HAS_TYPED_TEST + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the typedef for the type parameters of the +// given test case. +# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define TYPED_TEST_CASE(CaseName, Types) \ + typedef ::testing::internal::TypeList< Types >::type \ + GTEST_TYPE_PARAMS_(CaseName) + +# define TYPED_TEST(CaseName, TestName) \ + template \ + class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ + : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTest< \ + CaseName, \ + ::testing::internal::TemplateSel< \ + GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ + GTEST_TYPE_PARAMS_(CaseName)>::Register(\ + "", #CaseName, #TestName, 0); \ + template \ + void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() + +#endif // GTEST_HAS_TYPED_TEST + +// Implements type-parameterized tests. + +#if GTEST_HAS_TYPED_TEST_P + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the namespace name that the type-parameterized tests for +// the given type-parameterized test case are defined in. The exact +// name of the namespace is subject to change without notice. +# define GTEST_CASE_NAMESPACE_(TestCaseName) \ + gtest_case_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// +// Expands to the name of the variable used to remember the names of +// the defined tests in the given test case. +# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ + gtest_typed_test_case_p_state_##TestCaseName##_ + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. +// +// Expands to the name of the variable used to remember the names of +// the registered tests in the given test case. +# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ + gtest_registered_test_names_##TestCaseName##_ + +// The variables defined in the type-parameterized test macros are +// static as typically these macros are used in a .h file that can be +// #included in multiple translation units linked together. +# define TYPED_TEST_CASE_P(CaseName) \ + static ::testing::internal::TypedTestCasePState \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) + +# define TYPED_TEST_P(CaseName, TestName) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + template \ + class TestName : public CaseName { \ + private: \ + typedef CaseName TestFixture; \ + typedef gtest_TypeParam_ TypeParam; \ + virtual void TestBody(); \ + }; \ + static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ + __FILE__, __LINE__, #CaseName, #TestName); \ + } \ + template \ + void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() + +# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ + namespace GTEST_CASE_NAMESPACE_(CaseName) { \ + typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ + } \ + static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ + GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ + __FILE__, __LINE__, #__VA_ARGS__) + +// The 'Types' template argument below must have spaces around it +// since some compilers may choke on '>>' when passing a template +// instance (e.g. Types) +# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ + bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ + ::testing::internal::TypeParameterizedTestCase::type>::Register(\ + #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) + +#endif // GTEST_HAS_TYPED_TEST_P + +#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ + +// Depending on the platform, different string classes are available. +// On Linux, in addition to ::std::string, Google also makes use of +// class ::string, which has the same interface as ::std::string, but +// has a different implementation. +// +// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that +// ::string is available AND is a distinct type to ::std::string, or +// define it to 0 to indicate otherwise. +// +// If the user's ::std::string and ::string are the same class due to +// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. +// +// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined +// heuristically. + +namespace testing { + +// Declares the flags. + +// This flag temporary enables the disabled tests. +GTEST_DECLARE_bool_(also_run_disabled_tests); + +// This flag brings the debugger on an assertion failure. +GTEST_DECLARE_bool_(break_on_failure); + +// This flag controls whether Google Test catches all test-thrown exceptions +// and logs them as failures. +GTEST_DECLARE_bool_(catch_exceptions); + +// This flag enables using colors in terminal output. Available values are +// "yes" to enable colors, "no" (disable colors), or "auto" (the default) +// to let Google Test decide. +GTEST_DECLARE_string_(color); + +// This flag sets up the filter to select by name using a glob pattern +// the tests to run. If the filter is not given all tests are executed. +GTEST_DECLARE_string_(filter); + +// This flag causes the Google Test to list tests. None of the tests listed +// are actually run if the flag is provided. +GTEST_DECLARE_bool_(list_tests); + +// This flag controls whether Google Test emits a detailed XML report to a file +// in addition to its normal textual output. +GTEST_DECLARE_string_(output); + +// This flags control whether Google Test prints the elapsed time for each +// test. +GTEST_DECLARE_bool_(print_time); + +// This flag specifies the random number seed. +GTEST_DECLARE_int32_(random_seed); + +// This flag sets how many times the tests are repeated. The default value +// is 1. If the value is -1 the tests are repeating forever. +GTEST_DECLARE_int32_(repeat); + +// This flag controls whether Google Test includes Google Test internal +// stack frames in failure stack traces. +GTEST_DECLARE_bool_(show_internal_stack_frames); + +// When this flag is specified, tests' order is randomized on every iteration. +GTEST_DECLARE_bool_(shuffle); + +// This flag specifies the maximum number of stack frames to be +// printed in a failure message. +GTEST_DECLARE_int32_(stack_trace_depth); + +// When this flag is specified, a failed assertion will throw an +// exception if exceptions are enabled, or exit the program with a +// non-zero code otherwise. +GTEST_DECLARE_bool_(throw_on_failure); + +// When this flag is set with a "host:port" string, on supported +// platforms test results are streamed to the specified port on +// the specified host machine. +GTEST_DECLARE_string_(stream_result_to); + +// The upper limit for valid stack trace depths. +const int kMaxStackTraceDepth = 100; + +namespace internal { + +class AssertHelper; +class DefaultGlobalTestPartResultReporter; +class ExecDeathTest; +class NoExecDeathTest; +class FinalSuccessChecker; +class GTestFlagSaver; +class StreamingListenerTest; +class TestResultAccessor; +class TestEventListenersAccessor; +class TestEventRepeater; +class UnitTestRecordPropertyTestHelper; +class WindowsDeathTest; +class UnitTestImpl* GetUnitTestImpl(); +void ReportFailureInUnknownLocation(TestPartResult::Type result_type, + const std::string& message); + +} // namespace internal + +// The friend relationship of some of these classes is cyclic. +// If we don't forward declare them the compiler might confuse the classes +// in friendship clauses with same named classes on the scope. +class Test; +class TestCase; +class TestInfo; +class UnitTest; + +// A class for indicating whether an assertion was successful. When +// the assertion wasn't successful, the AssertionResult object +// remembers a non-empty message that describes how it failed. +// +// To create an instance of this class, use one of the factory functions +// (AssertionSuccess() and AssertionFailure()). +// +// This class is useful for two purposes: +// 1. Defining predicate functions to be used with Boolean test assertions +// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts +// 2. Defining predicate-format functions to be +// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). +// +// For example, if you define IsEven predicate: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) +// will print the message +// +// Value of: IsEven(Fib(5)) +// Actual: false (5 is odd) +// Expected: true +// +// instead of a more opaque +// +// Value of: IsEven(Fib(5)) +// Actual: false +// Expected: true +// +// in case IsEven is a simple Boolean predicate. +// +// If you expect your predicate to be reused and want to support informative +// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up +// about half as often as positive ones in our tests), supply messages for +// both success and failure cases: +// +// testing::AssertionResult IsEven(int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess() << n << " is even"; +// else +// return testing::AssertionFailure() << n << " is odd"; +// } +// +// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print +// +// Value of: IsEven(Fib(6)) +// Actual: true (8 is even) +// Expected: false +// +// NB: Predicates that support negative Boolean assertions have reduced +// performance in positive ones so be careful not to use them in tests +// that have lots (tens of thousands) of positive Boolean assertions. +// +// To use this class with EXPECT_PRED_FORMAT assertions such as: +// +// // Verifies that Foo() returns an even number. +// EXPECT_PRED_FORMAT1(IsEven, Foo()); +// +// you need to define: +// +// testing::AssertionResult IsEven(const char* expr, int n) { +// if ((n % 2) == 0) +// return testing::AssertionSuccess(); +// else +// return testing::AssertionFailure() +// << "Expected: " << expr << " is even\n Actual: it's " << n; +// } +// +// If Foo() returns 5, you will see the following message: +// +// Expected: Foo() is even +// Actual: it's 5 +// +class GTEST_API_ AssertionResult { + public: + // Copy constructor. + // Used in EXPECT_TRUE/FALSE(assertion_result). + AssertionResult(const AssertionResult& other); + // Used in the EXPECT_TRUE/FALSE(bool_expression). + explicit AssertionResult(bool success) : success_(success) {} + + // Returns true iff the assertion succeeded. + operator bool() const { return success_; } // NOLINT + + // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. + AssertionResult operator!() const; + + // Returns the text streamed into this AssertionResult. Test assertions + // use it when they fail (i.e., the predicate's outcome doesn't match the + // assertion's expectation). When nothing has been streamed into the + // object, returns an empty string. + const char* message() const { + return message_.get() != NULL ? message_->c_str() : ""; + } + // TODO(vladl@google.com): Remove this after making sure no clients use it. + // Deprecated; please use message() instead. + const char* failure_message() const { return message(); } + + // Streams a custom failure message into this object. + template AssertionResult& operator<<(const T& value) { + AppendMessage(Message() << value); + return *this; + } + + // Allows streaming basic output manipulators such as endl or flush into + // this object. + AssertionResult& operator<<( + ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { + AppendMessage(Message() << basic_manipulator); + return *this; + } + + private: + // Appends the contents of message to message_. + void AppendMessage(const Message& a_message) { + if (message_.get() == NULL) + message_.reset(new ::std::string); + message_->append(a_message.GetString().c_str()); + } + + // Stores result of the assertion predicate. + bool success_; + // Stores the message describing the condition in case the expectation + // construct is not satisfied with the predicate's outcome. + // Referenced via a pointer to avoid taking too much stack frame space + // with test assertions. + internal::scoped_ptr< ::std::string> message_; + + GTEST_DISALLOW_ASSIGN_(AssertionResult); +}; + +// Makes a successful assertion result. +GTEST_API_ AssertionResult AssertionSuccess(); + +// Makes a failed assertion result. +GTEST_API_ AssertionResult AssertionFailure(); + +// Makes a failed assertion result with the given failure message. +// Deprecated; use AssertionFailure() << msg. +GTEST_API_ AssertionResult AssertionFailure(const Message& msg); + +// The abstract class that all tests inherit from. +// +// In Google Test, a unit test program contains one or many TestCases, and +// each TestCase contains one or many Tests. +// +// When you define a test using the TEST macro, you don't need to +// explicitly derive from Test - the TEST macro automatically does +// this for you. +// +// The only time you derive from Test is when defining a test fixture +// to be used a TEST_F. For example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { ... } +// virtual void TearDown() { ... } +// ... +// }; +// +// TEST_F(FooTest, Bar) { ... } +// TEST_F(FooTest, Baz) { ... } +// +// Test is not copyable. +class GTEST_API_ Test { + public: + friend class TestInfo; + + // Defines types for pointers to functions that set up and tear down + // a test case. + typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; + typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; + + // The d'tor is virtual as we intend to inherit from Test. + virtual ~Test(); + + // Sets up the stuff shared by all tests in this test case. + // + // Google Test will call Foo::SetUpTestCase() before running the first + // test in test case Foo. Hence a sub-class can define its own + // SetUpTestCase() method to shadow the one defined in the super + // class. + static void SetUpTestCase() {} + + // Tears down the stuff shared by all tests in this test case. + // + // Google Test will call Foo::TearDownTestCase() after running the last + // test in test case Foo. Hence a sub-class can define its own + // TearDownTestCase() method to shadow the one defined in the super + // class. + static void TearDownTestCase() {} + + // Returns true iff the current test has a fatal failure. + static bool HasFatalFailure(); + + // Returns true iff the current test has a non-fatal failure. + static bool HasNonfatalFailure(); + + // Returns true iff the current test has a (either fatal or + // non-fatal) failure. + static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } + + // Logs a property for the current test, test case, or for the entire + // invocation of the test program when used outside of the context of a + // test case. Only the last value for a given key is remembered. These + // are public static so they can be called from utility functions that are + // not members of the test fixture. Calls to RecordProperty made during + // lifespan of the test (from the moment its constructor starts to the + // moment its destructor finishes) will be output in XML as attributes of + // the element. Properties recorded from fixture's + // SetUpTestCase or TearDownTestCase are logged as attributes of the + // corresponding element. Calls to RecordProperty made in the + // global context (before or after invocation of RUN_ALL_TESTS and from + // SetUp/TearDown method of Environment objects registered with Google + // Test) will be output as attributes of the element. + static void RecordProperty(const std::string& key, const std::string& value); + static void RecordProperty(const std::string& key, int value); + + protected: + // Creates a Test object. + Test(); + + // Sets up the test fixture. + virtual void SetUp(); + + // Tears down the test fixture. + virtual void TearDown(); + + private: + // Returns true iff the current test has the same fixture class as + // the first test in the current test case. + static bool HasSameFixtureClass(); + + // Runs the test after the test fixture has been set up. + // + // A sub-class must implement this to define the test logic. + // + // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. + // Instead, use the TEST or TEST_F macro. + virtual void TestBody() = 0; + + // Sets up, executes, and tears down the test. + void Run(); + + // Deletes self. We deliberately pick an unusual name for this + // internal method to avoid clashing with names used in user TESTs. + void DeleteSelf_() { delete this; } + + // Uses a GTestFlagSaver to save and restore all Google Test flags. + const internal::GTestFlagSaver* const gtest_flag_saver_; + + // Often a user mis-spells SetUp() as Setup() and spends a long time + // wondering why it is never called by Google Test. The declaration of + // the following method is solely for catching such an error at + // compile time: + // + // - The return type is deliberately chosen to be not void, so it + // will be a conflict if a user declares void Setup() in his test + // fixture. + // + // - This method is private, so it will be another compiler error + // if a user calls it from his test fixture. + // + // DO NOT OVERRIDE THIS FUNCTION. + // + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } + + // We disallow copying Tests. + GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); +}; + +typedef internal::TimeInMillis TimeInMillis; + +// A copyable object representing a user specified test property which can be +// output as a key/value string pair. +// +// Don't inherit from TestProperty as its destructor is not virtual. +class TestProperty { + public: + // C'tor. TestProperty does NOT have a default constructor. + // Always use this constructor (with parameters) to create a + // TestProperty object. + TestProperty(const std::string& a_key, const std::string& a_value) : + key_(a_key), value_(a_value) { + } + + // Gets the user supplied key. + const char* key() const { + return key_.c_str(); + } + + // Gets the user supplied value. + const char* value() const { + return value_.c_str(); + } + + // Sets a new value, overriding the one supplied in the constructor. + void SetValue(const std::string& new_value) { + value_ = new_value; + } + + private: + // The key supplied by the user. + std::string key_; + // The value supplied by the user. + std::string value_; +}; + +// The result of a single Test. This includes a list of +// TestPartResults, a list of TestProperties, a count of how many +// death tests there are in the Test, and how much time it took to run +// the Test. +// +// TestResult is not copyable. +class GTEST_API_ TestResult { + public: + // Creates an empty TestResult. + TestResult(); + + // D'tor. Do not inherit from TestResult. + ~TestResult(); + + // Gets the number of all test parts. This is the sum of the number + // of successful test parts and the number of failed test parts. + int total_part_count() const; + + // Returns the number of the test properties. + int test_property_count() const; + + // Returns true iff the test passed (i.e. no test part failed). + bool Passed() const { return !Failed(); } + + // Returns true iff the test failed. + bool Failed() const; + + // Returns true iff the test fatally failed. + bool HasFatalFailure() const; + + // Returns true iff the test has a non-fatal failure. + bool HasNonfatalFailure() const; + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test part result among all the results. i can range + // from 0 to test_property_count() - 1. If i is not in that range, aborts + // the program. + const TestPartResult& GetTestPartResult(int i) const; + + // Returns the i-th test property. i can range from 0 to + // test_property_count() - 1. If i is not in that range, aborts the + // program. + const TestProperty& GetTestProperty(int i) const; + + private: + friend class TestInfo; + friend class TestCase; + friend class UnitTest; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::ExecDeathTest; + friend class internal::TestResultAccessor; + friend class internal::UnitTestImpl; + friend class internal::WindowsDeathTest; + + // Gets the vector of TestPartResults. + const std::vector& test_part_results() const { + return test_part_results_; + } + + // Gets the vector of TestProperties. + const std::vector& test_properties() const { + return test_properties_; + } + + // Sets the elapsed time. + void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } + + // Adds a test property to the list. The property is validated and may add + // a non-fatal failure if invalid (e.g., if it conflicts with reserved + // key names). If a property is already recorded for the same key, the + // value will be updated, rather than storing multiple values for the same + // key. xml_element specifies the element for which the property is being + // recorded and is used for validation. + void RecordProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a failure if the key is a reserved attribute of Google Test + // testcase tags. Returns true if the property is valid. + // TODO(russr): Validate attribute names are legal and human readable. + static bool ValidateTestProperty(const std::string& xml_element, + const TestProperty& test_property); + + // Adds a test part result to the list. + void AddTestPartResult(const TestPartResult& test_part_result); + + // Returns the death test count. + int death_test_count() const { return death_test_count_; } + + // Increments the death test count, returning the new count. + int increment_death_test_count() { return ++death_test_count_; } + + // Clears the test part results. + void ClearTestPartResults(); + + // Clears the object. + void Clear(); + + // Protects mutable state of the property vector and of owned + // properties, whose values may be updated. + internal::Mutex test_properites_mutex_; + + // The vector of TestPartResults + std::vector test_part_results_; + // The vector of TestProperties + std::vector test_properties_; + // Running count of death tests. + int death_test_count_; + // The elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + + // We disallow copying TestResult. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); +}; // class TestResult + +// A TestInfo object stores the following information about a test: +// +// Test case name +// Test name +// Whether the test should be run +// A function pointer that creates the test object when invoked +// Test result +// +// The constructor of TestInfo registers itself with the UnitTest +// singleton such that the RUN_ALL_TESTS() macro knows which tests to +// run. +class GTEST_API_ TestInfo { + public: + // Destructs a TestInfo object. This function is not virtual, so + // don't inherit from TestInfo. + ~TestInfo(); + + // Returns the test case name. + const char* test_case_name() const { return test_case_name_.c_str(); } + + // Returns the test name. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a typed + // or a type-parameterized test. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns the text representation of the value parameter, or NULL if this + // is not a value-parameterized test. + const char* value_param() const { + if (value_param_.get() != NULL) + return value_param_->c_str(); + return NULL; + } + + // Returns true if this test should run, that is if the test is not + // disabled (or it is disabled but the also_run_disabled_tests flag has + // been specified) and its full name matches the user-specified filter. + // + // Google Test allows the user to filter the tests by their full names. + // The full name of a test Bar in test case Foo is defined as + // "Foo.Bar". Only the tests that match the filter will run. + // + // A filter is a colon-separated list of glob (not regex) patterns, + // optionally followed by a '-' and a colon-separated list of + // negative patterns (tests to exclude). A test is run if it + // matches one of the positive patterns and does not match any of + // the negative patterns. + // + // For example, *A*:Foo.* is a filter that matches any string that + // contains the character 'A' or starts with "Foo.". + bool should_run() const { return should_run_; } + + // Returns true iff this test will appear in the XML report. + bool is_reportable() const { + // For now, the XML report includes all tests matching the filter. + // In the future, we may trim tests that are excluded because of + // sharding. + return matches_filter_; + } + + // Returns the result of the test. + const TestResult* result() const { return &result_; } + + private: +#if GTEST_HAS_DEATH_TEST + friend class internal::DefaultDeathTestFactory; +#endif // GTEST_HAS_DEATH_TEST + friend class Test; + friend class TestCase; + friend class internal::UnitTestImpl; + friend class internal::StreamingListenerTest; + friend TestInfo* internal::MakeAndRegisterTestInfo( + const char* test_case_name, + const char* name, + const char* type_param, + const char* value_param, + internal::TypeId fixture_class_id, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc, + internal::TestFactoryBase* factory); + + // Constructs a TestInfo object. The newly constructed instance assumes + // ownership of the factory object. + TestInfo(const std::string& test_case_name, + const std::string& name, + const char* a_type_param, // NULL if not a type-parameterized test + const char* a_value_param, // NULL if not a value-parameterized test + internal::TypeId fixture_class_id, + internal::TestFactoryBase* factory); + + // Increments the number of death tests encountered in this test so + // far. + int increment_death_test_count() { + return result_.increment_death_test_count(); + } + + // Creates the test object, runs it, records its result, and then + // deletes it. + void Run(); + + static void ClearTestResult(TestInfo* test_info) { + test_info->result_.Clear(); + } + + // These fields are immutable properties of the test. + const std::string test_case_name_; // Test case name + const std::string name_; // Test name + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // Text representation of the value parameter, or NULL if this is not a + // value-parameterized test. + const internal::scoped_ptr value_param_; + const internal::TypeId fixture_class_id_; // ID of the test fixture class + bool should_run_; // True iff this test should run + bool is_disabled_; // True iff this test is disabled + bool matches_filter_; // True if this test matches the + // user-specified filter. + internal::TestFactoryBase* const factory_; // The factory that creates + // the test object + + // This field is mutable and needs to be reset before running the + // test for the second time. + TestResult result_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); +}; + +// A test case, which consists of a vector of TestInfos. +// +// TestCase is not copyable. +class GTEST_API_ TestCase { + public: + // Creates a TestCase with the given name. + // + // TestCase does NOT have a default constructor. Always use this + // constructor to create a TestCase object. + // + // Arguments: + // + // name: name of the test case + // a_type_param: the name of the test's type parameter, or NULL if + // this is not a type-parameterized test. + // set_up_tc: pointer to the function that sets up the test case + // tear_down_tc: pointer to the function that tears down the test case + TestCase(const char* name, const char* a_type_param, + Test::SetUpTestCaseFunc set_up_tc, + Test::TearDownTestCaseFunc tear_down_tc); + + // Destructor of TestCase. + virtual ~TestCase(); + + // Gets the name of the TestCase. + const char* name() const { return name_.c_str(); } + + // Returns the name of the parameter type, or NULL if this is not a + // type-parameterized test case. + const char* type_param() const { + if (type_param_.get() != NULL) + return type_param_->c_str(); + return NULL; + } + + // Returns true if any test in this test case should run. + bool should_run() const { return should_run_; } + + // Gets the number of successful tests in this test case. + int successful_test_count() const; + + // Gets the number of failed tests in this test case. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests in this test case. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Get the number of tests in this test case that should run. + int test_to_run_count() const; + + // Gets the number of all tests in this test case. + int total_test_count() const; + + // Returns true iff the test case passed. + bool Passed() const { return !Failed(); } + + // Returns true iff the test case failed. + bool Failed() const { return failed_test_count() > 0; } + + // Returns the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const { return elapsed_time_; } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + const TestInfo* GetTestInfo(int i) const; + + // Returns the TestResult that holds test properties recorded during + // execution of SetUpTestCase and TearDownTestCase. + const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } + + private: + friend class Test; + friend class internal::UnitTestImpl; + + // Gets the (mutable) vector of TestInfos in this TestCase. + std::vector& test_info_list() { return test_info_list_; } + + // Gets the (immutable) vector of TestInfos in this TestCase. + const std::vector& test_info_list() const { + return test_info_list_; + } + + // Returns the i-th test among all the tests. i can range from 0 to + // total_test_count() - 1. If i is not in that range, returns NULL. + TestInfo* GetMutableTestInfo(int i); + + // Sets the should_run member. + void set_should_run(bool should) { should_run_ = should; } + + // Adds a TestInfo to this test case. Will delete the TestInfo upon + // destruction of the TestCase object. + void AddTestInfo(TestInfo * test_info); + + // Clears the results of all tests in this test case. + void ClearResult(); + + // Clears the results of all tests in the given test case. + static void ClearTestCaseResult(TestCase* test_case) { + test_case->ClearResult(); + } + + // Runs every test in this TestCase. + void Run(); + + // Runs SetUpTestCase() for this TestCase. This wrapper is needed + // for catching exceptions thrown from SetUpTestCase(). + void RunSetUpTestCase() { (*set_up_tc_)(); } + + // Runs TearDownTestCase() for this TestCase. This wrapper is + // needed for catching exceptions thrown from TearDownTestCase(). + void RunTearDownTestCase() { (*tear_down_tc_)(); } + + // Returns true iff test passed. + static bool TestPassed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Passed(); + } + + // Returns true iff test failed. + static bool TestFailed(const TestInfo* test_info) { + return test_info->should_run() && test_info->result()->Failed(); + } + + // Returns true iff the test is disabled and will be reported in the XML + // report. + static bool TestReportableDisabled(const TestInfo* test_info) { + return test_info->is_reportable() && test_info->is_disabled_; + } + + // Returns true iff test is disabled. + static bool TestDisabled(const TestInfo* test_info) { + return test_info->is_disabled_; + } + + // Returns true iff this test will appear in the XML report. + static bool TestReportable(const TestInfo* test_info) { + return test_info->is_reportable(); + } + + // Returns true if the given test should run. + static bool ShouldRunTest(const TestInfo* test_info) { + return test_info->should_run(); + } + + // Shuffles the tests in this test case. + void ShuffleTests(internal::Random* random); + + // Restores the test order to before the first shuffle. + void UnshuffleTests(); + + // Name of the test case. + std::string name_; + // Name of the parameter type, or NULL if this is not a typed or a + // type-parameterized test. + const internal::scoped_ptr type_param_; + // The vector of TestInfos in their original order. It owns the + // elements in the vector. + std::vector test_info_list_; + // Provides a level of indirection for the test list to allow easy + // shuffling and restoring the test order. The i-th element in this + // vector is the index of the i-th test in the shuffled test list. + std::vector test_indices_; + // Pointer to the function that sets up the test case. + Test::SetUpTestCaseFunc set_up_tc_; + // Pointer to the function that tears down the test case. + Test::TearDownTestCaseFunc tear_down_tc_; + // True iff any test in this test case should run. + bool should_run_; + // Elapsed time, in milliseconds. + TimeInMillis elapsed_time_; + // Holds test properties recorded during execution of SetUpTestCase and + // TearDownTestCase. + TestResult ad_hoc_test_result_; + + // We disallow copying TestCases. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); +}; + +// An Environment object is capable of setting up and tearing down an +// environment. The user should subclass this to define his own +// environment(s). +// +// An Environment object does the set-up and tear-down in virtual +// methods SetUp() and TearDown() instead of the constructor and the +// destructor, as: +// +// 1. You cannot safely throw from a destructor. This is a problem +// as in some cases Google Test is used where exceptions are enabled, and +// we may want to implement ASSERT_* using exceptions where they are +// available. +// 2. You cannot use ASSERT_* directly in a constructor or +// destructor. +class Environment { + public: + // The d'tor is virtual as we need to subclass Environment. + virtual ~Environment() {} + + // Override this to define how to set up the environment. + virtual void SetUp() {} + + // Override this to define how to tear down the environment. + virtual void TearDown() {} + private: + // If you see an error about overriding the following function or + // about it being private, you have mis-spelled SetUp() as Setup(). + struct Setup_should_be_spelled_SetUp {}; + virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } +}; + +// The interface for tracing execution of tests. The methods are organized in +// the order the corresponding events are fired. +class TestEventListener { + public: + virtual ~TestEventListener() {} + + // Fired before any test activity starts. + virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; + + // Fired before each iteration of tests starts. There may be more than + // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration + // index, starting from 0. + virtual void OnTestIterationStart(const UnitTest& unit_test, + int iteration) = 0; + + // Fired before environment set-up for each iteration of tests starts. + virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; + + // Fired after environment set-up for each iteration of tests ends. + virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; + + // Fired before the test case starts. + virtual void OnTestCaseStart(const TestCase& test_case) = 0; + + // Fired before the test starts. + virtual void OnTestStart(const TestInfo& test_info) = 0; + + // Fired after a failed assertion or a SUCCEED() invocation. + virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; + + // Fired after the test ends. + virtual void OnTestEnd(const TestInfo& test_info) = 0; + + // Fired after the test case ends. + virtual void OnTestCaseEnd(const TestCase& test_case) = 0; + + // Fired before environment tear-down for each iteration of tests starts. + virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; + + // Fired after environment tear-down for each iteration of tests ends. + virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; + + // Fired after each iteration of tests finishes. + virtual void OnTestIterationEnd(const UnitTest& unit_test, + int iteration) = 0; + + // Fired after all test activities have ended. + virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; +}; + +// The convenience class for users who need to override just one or two +// methods and are not concerned that a possible change to a signature of +// the methods they override will not be caught during the build. For +// comments about each method please see the definition of TestEventListener +// above. +class EmptyTestEventListener : public TestEventListener { + public: + virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} + virtual void OnTestStart(const TestInfo& /*test_info*/) {} + virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} + virtual void OnTestEnd(const TestInfo& /*test_info*/) {} + virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} + virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} + virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} + virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, + int /*iteration*/) {} + virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} +}; + +// TestEventListeners lets users add listeners to track events in Google Test. +class GTEST_API_ TestEventListeners { + public: + TestEventListeners(); + ~TestEventListeners(); + + // Appends an event listener to the end of the list. Google Test assumes + // the ownership of the listener (i.e. it will delete the listener when + // the test program finishes). + void Append(TestEventListener* listener); + + // Removes the given event listener from the list and returns it. It then + // becomes the caller's responsibility to delete the listener. Returns + // NULL if the listener is not found in the list. + TestEventListener* Release(TestEventListener* listener); + + // Returns the standard listener responsible for the default console + // output. Can be removed from the listeners list to shut down default + // console output. Note that removing this object from the listener list + // with Release transfers its ownership to the caller and makes this + // function return NULL the next time. + TestEventListener* default_result_printer() const { + return default_result_printer_; + } + + // Returns the standard listener responsible for the default XML output + // controlled by the --gtest_output=xml flag. Can be removed from the + // listeners list by users who want to shut down the default XML output + // controlled by this flag and substitute it with custom one. Note that + // removing this object from the listener list with Release transfers its + // ownership to the caller and makes this function return NULL the next + // time. + TestEventListener* default_xml_generator() const { + return default_xml_generator_; + } + + private: + friend class TestCase; + friend class TestInfo; + friend class internal::DefaultGlobalTestPartResultReporter; + friend class internal::NoExecDeathTest; + friend class internal::TestEventListenersAccessor; + friend class internal::UnitTestImpl; + + // Returns repeater that broadcasts the TestEventListener events to all + // subscribers. + TestEventListener* repeater(); + + // Sets the default_result_printer attribute to the provided listener. + // The listener is also added to the listener list and previous + // default_result_printer is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultResultPrinter(TestEventListener* listener); + + // Sets the default_xml_generator attribute to the provided listener. The + // listener is also added to the listener list and previous + // default_xml_generator is removed from it and deleted. The listener can + // also be NULL in which case it will not be added to the list. Does + // nothing if the previous and the current listener objects are the same. + void SetDefaultXmlGenerator(TestEventListener* listener); + + // Controls whether events will be forwarded by the repeater to the + // listeners in the list. + bool EventForwardingEnabled() const; + void SuppressEventForwarding(); + + // The actual list of listeners. + internal::TestEventRepeater* repeater_; + // Listener responsible for the standard result output. + TestEventListener* default_result_printer_; + // Listener responsible for the creation of the XML output file. + TestEventListener* default_xml_generator_; + + // We disallow copying TestEventListeners. + GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); +}; + +// A UnitTest consists of a vector of TestCases. +// +// This is a singleton class. The only instance of UnitTest is +// created when UnitTest::GetInstance() is first called. This +// instance is never deleted. +// +// UnitTest is not copyable. +// +// This class is thread-safe as long as the methods are called +// according to their specification. +class GTEST_API_ UnitTest { + public: + // Gets the singleton UnitTest object. The first time this method + // is called, a UnitTest object is constructed and returned. + // Consecutive calls will return the same object. + static UnitTest* GetInstance(); + + // Runs all tests in this UnitTest object and prints the result. + // Returns 0 if successful, or 1 otherwise. + // + // This method can only be called from the main thread. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + int Run() GTEST_MUST_USE_RESULT_; + + // Returns the working directory when the first TEST() or TEST_F() + // was executed. The UnitTest object owns the string. + const char* original_working_dir() const; + + // Returns the TestCase object for the test that's currently running, + // or NULL if no test is running. + const TestCase* current_test_case() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the TestInfo object for the test that's currently running, + // or NULL if no test is running. + const TestInfo* current_test_info() const + GTEST_LOCK_EXCLUDED_(mutex_); + + // Returns the random seed used at the start of the current test run. + int random_seed() const; + +#if GTEST_HAS_PARAM_TEST + // Returns the ParameterizedTestCaseRegistry object used to keep track of + // value-parameterized tests and instantiate and register them. + // + // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + internal::ParameterizedTestCaseRegistry& parameterized_test_registry() + GTEST_LOCK_EXCLUDED_(mutex_); +#endif // GTEST_HAS_PARAM_TEST + + // Gets the number of successful test cases. + int successful_test_case_count() const; + + // Gets the number of failed test cases. + int failed_test_case_count() const; + + // Gets the number of all test cases. + int total_test_case_count() const; + + // Gets the number of all test cases that contain at least one test + // that should run. + int test_case_to_run_count() const; + + // Gets the number of successful tests. + int successful_test_count() const; + + // Gets the number of failed tests. + int failed_test_count() const; + + // Gets the number of disabled tests that will be reported in the XML report. + int reportable_disabled_test_count() const; + + // Gets the number of disabled tests. + int disabled_test_count() const; + + // Gets the number of tests to be printed in the XML report. + int reportable_test_count() const; + + // Gets the number of all tests. + int total_test_count() const; + + // Gets the number of tests that should run. + int test_to_run_count() const; + + // Gets the time of the test program start, in ms from the start of the + // UNIX epoch. + TimeInMillis start_timestamp() const; + + // Gets the elapsed time, in milliseconds. + TimeInMillis elapsed_time() const; + + // Returns true iff the unit test passed (i.e. all test cases passed). + bool Passed() const; + + // Returns true iff the unit test failed (i.e. some test case failed + // or something outside of all tests failed). + bool Failed() const; + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + const TestCase* GetTestCase(int i) const; + + // Returns the TestResult containing information on test failures and + // properties logged outside of individual test cases. + const TestResult& ad_hoc_test_result() const; + + // Returns the list of event listeners that can be used to track events + // inside Google Test. + TestEventListeners& listeners(); + + private: + // Registers and returns a global test environment. When a test + // program is run, all global test environments will be set-up in + // the order they were registered. After all tests in the program + // have finished, all global test environments will be torn-down in + // the *reverse* order they were registered. + // + // The UnitTest object takes ownership of the given environment. + // + // This method can only be called from the main thread. + Environment* AddEnvironment(Environment* env); + + // Adds a TestPartResult to the current TestResult object. All + // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) + // eventually call this to report their results. The user code + // should use the assertion macros instead of calling this directly. + void AddTestPartResult(TestPartResult::Type result_type, + const char* file_name, + int line_number, + const std::string& message, + const std::string& os_stack_trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Adds a TestProperty to the current TestResult object when invoked from + // inside a test, to current TestCase's ad_hoc_test_result_ when invoked + // from SetUpTestCase or TearDownTestCase, or to the global property set + // when invoked elsewhere. If the result already contains a property with + // the same key, the value will be updated. + void RecordProperty(const std::string& key, const std::string& value); + + // Gets the i-th test case among all the test cases. i can range from 0 to + // total_test_case_count() - 1. If i is not in that range, returns NULL. + TestCase* GetMutableTestCase(int i); + + // Accessors for the implementation object. + internal::UnitTestImpl* impl() { return impl_; } + const internal::UnitTestImpl* impl() const { return impl_; } + + // These classes and funcions are friends as they need to access private + // members of UnitTest. + friend class Test; + friend class internal::AssertHelper; + friend class internal::ScopedTrace; + friend class internal::StreamingListenerTest; + friend class internal::UnitTestRecordPropertyTestHelper; + friend Environment* AddGlobalTestEnvironment(Environment* env); + friend internal::UnitTestImpl* internal::GetUnitTestImpl(); + friend void internal::ReportFailureInUnknownLocation( + TestPartResult::Type result_type, + const std::string& message); + + // Creates an empty UnitTest. + UnitTest(); + + // D'tor + virtual ~UnitTest(); + + // Pushes a trace defined by SCOPED_TRACE() on to the per-thread + // Google Test trace stack. + void PushGTestTrace(const internal::TraceInfo& trace) + GTEST_LOCK_EXCLUDED_(mutex_); + + // Pops a trace from the per-thread Google Test trace stack. + void PopGTestTrace() + GTEST_LOCK_EXCLUDED_(mutex_); + + // Protects mutable state in *impl_. This is mutable as some const + // methods need to lock it too. + mutable internal::Mutex mutex_; + + // Opaque implementation object. This field is never changed once + // the object is constructed. We don't mark it as const here, as + // doing so will cause a warning in the constructor of UnitTest. + // Mutable state in *impl_ is protected by mutex_. + internal::UnitTestImpl* impl_; + + // We disallow copying UnitTest. + GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); +}; + +// A convenient wrapper for adding an environment for the test +// program. +// +// You should call this before RUN_ALL_TESTS() is called, probably in +// main(). If you use gtest_main, you need to call this before main() +// starts for it to take effect. For example, you can define a global +// variable like this: +// +// testing::Environment* const foo_env = +// testing::AddGlobalTestEnvironment(new FooEnvironment); +// +// However, we strongly recommend you to write your own main() and +// call AddGlobalTestEnvironment() there, as relying on initialization +// of global variables makes the code harder to read and may cause +// problems when you register multiple environments from different +// translation units and the environments have dependencies among them +// (remember that the compiler doesn't guarantee the order in which +// global variables from different translation units are initialized). +inline Environment* AddGlobalTestEnvironment(Environment* env) { + return UnitTest::GetInstance()->AddEnvironment(env); +} + +// Initializes Google Test. This must be called before calling +// RUN_ALL_TESTS(). In particular, it parses a command line for the +// flags that Google Test recognizes. Whenever a Google Test flag is +// seen, it is removed from argv, and *argc is decremented. +// +// No value is returned. Instead, the Google Test flag variables are +// updated. +// +// Calling the function for the second time has no user-visible effect. +GTEST_API_ void InitGoogleTest(int* argc, char** argv); + +// This overloaded version can be used in Windows programs compiled in +// UNICODE mode. +GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); + +namespace internal { + +// FormatForComparison::Format(value) formats a +// value of type ToPrint that is an operand of a comparison assertion +// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in +// the comparison, and is used to help determine the best way to +// format the value. In particular, when the value is a C string +// (char pointer) and the other operand is an STL string object, we +// want to format the C string as a string, since we know it is +// compared by value with the string object. If the value is a char +// pointer but the other operand is not an STL string object, we don't +// know whether the pointer is supposed to point to a NUL-terminated +// string, and thus want to print it as a pointer to be safe. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// The default case. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint& value) { + return ::testing::PrintToString(value); + } +}; + +// Array. +template +class FormatForComparison { + public: + static ::std::string Format(const ToPrint* value) { + return FormatForComparison::Format(value); + } +}; + +// By default, print C string as pointers to be safe, as we don't know +// whether they actually point to a NUL-terminated string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ + template \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(static_cast(value)); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); +GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ + +// If a C string is compared with an STL string object, we know it's meant +// to point to a NUL-terminated string, and thus can print it as a string. + +#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ + template <> \ + class FormatForComparison { \ + public: \ + static ::std::string Format(CharType* value) { \ + return ::testing::PrintToString(value); \ + } \ + } + +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); + +#if GTEST_HAS_GLOBAL_STRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); +#endif + +#if GTEST_HAS_GLOBAL_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); +#endif + +#if GTEST_HAS_STD_WSTRING +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); +GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); +#endif + +#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ + +// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) +// operand to be used in a failure message. The type (but not value) +// of the other operand may affect the format. This allows us to +// print a char* as a raw pointer when it is compared against another +// char* or void*, and print it as a C string when it is compared +// against an std::string object, for example. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +std::string FormatForComparisonFailureMessage( + const T1& value, const T2& /* other_operand */) { + return FormatForComparison::Format(value); +} + +// The helper function for {ASSERT|EXPECT}_EQ. +template +AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { +#ifdef _MSC_VER +# pragma warning(push) // Saves the current warning state. +# pragma warning(disable:4389) // Temporarily disables warning on + // signed/unsigned mismatch. +#endif + + if (expected == actual) { + return AssertionSuccess(); + } + +#ifdef _MSC_VER +# pragma warning(pop) // Restores the warning state. +#endif + + return EqFailure(expected_expression, + actual_expression, + FormatForComparisonFailureMessage(expected, actual), + FormatForComparisonFailureMessage(actual, expected), + false); +} + +// With this overloaded version, we allow anonymous enums to be used +// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums +// can be implicitly cast to BiggestInt. +GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual); + +// The helper class for {ASSERT|EXPECT}_EQ. The template argument +// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() +// is a null pointer literal. The following default implementation is +// for lhs_is_null_literal being false. +template +class EqHelper { + public: + // This templatized version is for the general case. + template + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // With this overloaded version, we allow anonymous enums to be used + // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous + // enums can be implicitly cast to BiggestInt. + // + // Even though its body looks the same as the above version, we + // cannot merge the two, as it will make anonymous enums unhappy. + static AssertionResult Compare(const char* expected_expression, + const char* actual_expression, + BiggestInt expected, + BiggestInt actual) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } +}; + +// This specialization is used when the first argument to ASSERT_EQ() +// is a null pointer literal, like NULL, false, or 0. +template <> +class EqHelper { + public: + // We define two overloaded versions of Compare(). The first + // version will be picked when the second argument to ASSERT_EQ() is + // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or + // EXPECT_EQ(false, a_bool). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + const T1& expected, + const T2& actual, + // The following line prevents this overload from being considered if T2 + // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) + // expands to Compare("", "", NULL, my_ptr), which requires a conversion + // to match the Secret* in the other overload, which would otherwise make + // this template match better. + typename EnableIf::value>::type* = 0) { + return CmpHelperEQ(expected_expression, actual_expression, expected, + actual); + } + + // This version will be picked when the second argument to ASSERT_EQ() is a + // pointer, e.g. ASSERT_EQ(NULL, a_pointer). + template + static AssertionResult Compare( + const char* expected_expression, + const char* actual_expression, + // We used to have a second template parameter instead of Secret*. That + // template parameter would deduce to 'long', making this a better match + // than the first overload even without the first overload's EnableIf. + // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to + // non-pointer argument" (even a deduced integral argument), so the old + // implementation caused warnings in user code. + Secret* /* expected (NULL) */, + T* actual) { + // We already know that 'expected' is a null pointer. + return CmpHelperEQ(expected_expression, actual_expression, + static_cast(NULL), actual); + } +}; + +// A macro for implementing the helper functions needed to implement +// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste +// of similar code. +// +// For each templatized helper function, we also define an overloaded +// version for BiggestInt in order to reduce code bloat and allow +// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled +// with gcc 4. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ +template \ +AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ + const T1& val1, const T2& val2) {\ + if (val1 op val2) {\ + return AssertionSuccess();\ + } else {\ + return AssertionFailure() \ + << "Expected: (" << expr1 << ") " #op " (" << expr2\ + << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ + << " vs " << FormatForComparisonFailureMessage(val2, val1);\ + }\ +}\ +GTEST_API_ AssertionResult CmpHelper##op_name(\ + const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) + +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. + +// Implements the helper function for {ASSERT|EXPECT}_NE +GTEST_IMPL_CMP_HELPER_(NE, !=); +// Implements the helper function for {ASSERT|EXPECT}_LE +GTEST_IMPL_CMP_HELPER_(LE, <=); +// Implements the helper function for {ASSERT|EXPECT}_LT +GTEST_IMPL_CMP_HELPER_(LT, <); +// Implements the helper function for {ASSERT|EXPECT}_GE +GTEST_IMPL_CMP_HELPER_(GE, >=); +// Implements the helper function for {ASSERT|EXPECT}_GT +GTEST_IMPL_CMP_HELPER_(GT, >); + +#undef GTEST_IMPL_CMP_HELPER_ + +// The helper function for {ASSERT|EXPECT}_STREQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRCASEEQ. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, + const char* actual_expression, + const char* expected, + const char* actual); + +// The helper function for {ASSERT|EXPECT}_STRNE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + +// The helper function for {ASSERT|EXPECT}_STRCASENE. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, + const char* s2_expression, + const char* s1, + const char* s2); + + +// Helper function for *_STREQ on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, + const char* actual_expression, + const wchar_t* expected, + const wchar_t* actual); + +// Helper function for *_STRNE on wide strings. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, + const char* s2_expression, + const wchar_t* s1, + const wchar_t* s2); + +} // namespace internal + +// IsSubstring() and IsNotSubstring() are intended to be used as the +// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by +// themselves. They check whether needle is a substring of haystack +// (NULL is considered a substring of itself only), and return an +// appropriate error message when they fail. +// +// The {needle,haystack}_expr arguments are the stringified +// expressions that generated the two real arguments. +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const char* needle, const char* haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const wchar_t* needle, const wchar_t* haystack); +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::string& needle, const ::std::string& haystack); + +#if GTEST_HAS_STD_WSTRING +GTEST_API_ AssertionResult IsSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +GTEST_API_ AssertionResult IsNotSubstring( + const char* needle_expr, const char* haystack_expr, + const ::std::wstring& needle, const ::std::wstring& haystack); +#endif // GTEST_HAS_STD_WSTRING + +namespace internal { + +// Helper template function for comparing floating-points. +// +// Template parameter: +// +// RawType: the raw floating-point type (either float or double) +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +template +AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, + const char* actual_expression, + RawType expected, + RawType actual) { + const FloatingPoint lhs(expected), rhs(actual); + + if (lhs.AlmostEquals(rhs)) { + return AssertionSuccess(); + } + + ::std::stringstream expected_ss; + expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << expected; + + ::std::stringstream actual_ss; + actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) + << actual; + + return EqFailure(expected_expression, + actual_expression, + StringStreamToString(&expected_ss), + StringStreamToString(&actual_ss), + false); +} + +// Helper function for implementing ASSERT_NEAR. +// +// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. +GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, + const char* expr2, + const char* abs_error_expr, + double val1, + double val2, + double abs_error); + +// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. +// A class that enables one to stream messages to assertion macros +class GTEST_API_ AssertHelper { + public: + // Constructor. + AssertHelper(TestPartResult::Type type, + const char* file, + int line, + const char* message); + ~AssertHelper(); + + // Message assignment is a semantic trick to enable assertion + // streaming; see the GTEST_MESSAGE_ macro below. + void operator=(const Message& message) const; + + private: + // We put our data in a struct so that the size of the AssertHelper class can + // be as small as possible. This is important because gcc is incapable of + // re-using stack space even for temporary variables, so every EXPECT_EQ + // reserves stack space for another AssertHelper. + struct AssertHelperData { + AssertHelperData(TestPartResult::Type t, + const char* srcfile, + int line_num, + const char* msg) + : type(t), file(srcfile), line(line_num), message(msg) { } + + TestPartResult::Type const type; + const char* const file; + int const line; + std::string const message; + + private: + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); + }; + + AssertHelperData* const data_; + + GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); +}; + +} // namespace internal + +#if GTEST_HAS_PARAM_TEST +// The pure interface class that all value-parameterized tests inherit from. +// A value-parameterized class must inherit from both ::testing::Test and +// ::testing::WithParamInterface. In most cases that just means inheriting +// from ::testing::TestWithParam, but more complicated test hierarchies +// may need to inherit from Test and WithParamInterface at different levels. +// +// This interface has support for accessing the test parameter value via +// the GetParam() method. +// +// Use it with one of the parameter generator defining functions, like Range(), +// Values(), ValuesIn(), Bool(), and Combine(). +// +// class FooTest : public ::testing::TestWithParam { +// protected: +// FooTest() { +// // Can use GetParam() here. +// } +// virtual ~FooTest() { +// // Can use GetParam() here. +// } +// virtual void SetUp() { +// // Can use GetParam() here. +// } +// virtual void TearDown { +// // Can use GetParam() here. +// } +// }; +// TEST_P(FooTest, DoesBar) { +// // Can use GetParam() method here. +// Foo foo; +// ASSERT_TRUE(foo.DoesBar(GetParam())); +// } +// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); + +template +class WithParamInterface { + public: + typedef T ParamType; + virtual ~WithParamInterface() {} + + // The current parameter value. Is also available in the test fixture's + // constructor. This member function is non-static, even though it only + // references static data, to reduce the opportunity for incorrect uses + // like writing 'WithParamInterface::GetParam()' for a test that + // uses a fixture whose parameter type is int. + const ParamType& GetParam() const { + GTEST_CHECK_(parameter_ != NULL) + << "GetParam() can only be called inside a value-parameterized test " + << "-- did you intend to write TEST_P instead of TEST_F?"; + return *parameter_; + } + + private: + // Sets parameter value. The caller is responsible for making sure the value + // remains alive and unchanged throughout the current test. + static void SetParam(const ParamType* parameter) { + parameter_ = parameter; + } + + // Static value used for accessing parameter during a test lifetime. + static const ParamType* parameter_; + + // TestClass must be a subclass of WithParamInterface and Test. + template friend class internal::ParameterizedTestFactory; +}; + +template +const T* WithParamInterface::parameter_ = NULL; + +// Most value-parameterized classes can ignore the existence of +// WithParamInterface, and can just inherit from ::testing::TestWithParam. + +template +class TestWithParam : public Test, public WithParamInterface { +}; + +#endif // GTEST_HAS_PARAM_TEST + +// Macros for indicating success/failure in test code. + +// ADD_FAILURE unconditionally adds a failure to the current test. +// SUCCEED generates a success - it doesn't automatically make the +// current test successful, as a test is only successful when it has +// no failure. +// +// EXPECT_* verifies that a certain condition is satisfied. If not, +// it behaves like ADD_FAILURE. In particular: +// +// EXPECT_TRUE verifies that a Boolean condition is true. +// EXPECT_FALSE verifies that a Boolean condition is false. +// +// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except +// that they will also abort the current function on failure. People +// usually want the fail-fast behavior of FAIL and ASSERT_*, but those +// writing data-driven tests often find themselves using ADD_FAILURE +// and EXPECT_* more. + +// Generates a nonfatal failure with a generic message. +#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") + +// Generates a nonfatal failure at the given source file location with +// a generic message. +#define ADD_FAILURE_AT(file, line) \ + GTEST_MESSAGE_AT_(file, line, "Failed", \ + ::testing::TestPartResult::kNonFatalFailure) + +// Generates a fatal failure with a generic message. +#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") + +// Define this macro to 1 to omit the definition of FAIL(), which is a +// generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_FAIL +# define FAIL() GTEST_FAIL() +#endif + +// Generates a success with a generic message. +#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") + +// Define this macro to 1 to omit the definition of SUCCEED(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_SUCCEED +# define SUCCEED() GTEST_SUCCEED() +#endif + +// Macros for testing exceptions. +// +// * {ASSERT|EXPECT}_THROW(statement, expected_exception): +// Tests that the statement throws the expected exception. +// * {ASSERT|EXPECT}_NO_THROW(statement): +// Tests that the statement doesn't throw any exception. +// * {ASSERT|EXPECT}_ANY_THROW(statement): +// Tests that the statement throws an exception. + +#define EXPECT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) +#define EXPECT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define EXPECT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) +#define ASSERT_THROW(statement, expected_exception) \ + GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) +#define ASSERT_NO_THROW(statement) \ + GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) +#define ASSERT_ANY_THROW(statement) \ + GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) + +// Boolean assertions. Condition can be either a Boolean expression or an +// AssertionResult. For more information on how to use AssertionResult with +// these macros see comments on that class. +#define EXPECT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_NONFATAL_FAILURE_) +#define EXPECT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_NONFATAL_FAILURE_) +#define ASSERT_TRUE(condition) \ + GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ + GTEST_FATAL_FAILURE_) +#define ASSERT_FALSE(condition) \ + GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ + GTEST_FATAL_FAILURE_) + +// Includes the auto-generated header that implements a family of +// generic predicate assertion macros. +// Copyright 2006, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. + +// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command +// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! +// +// Implements a family of generic predicate assertion macros. + +#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ +#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Makes sure this header is not included before gtest.h. +#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ +# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ + +// This header implements a family of generic predicate assertion +// macros: +// +// ASSERT_PRED_FORMAT1(pred_format, v1) +// ASSERT_PRED_FORMAT2(pred_format, v1, v2) +// ... +// +// where pred_format is a function or functor that takes n (in the +// case of ASSERT_PRED_FORMATn) values and their source expression +// text, and returns a testing::AssertionResult. See the definition +// of ASSERT_EQ in gtest.h for an example. +// +// If you don't care about formatting, you can use the more +// restrictive version: +// +// ASSERT_PRED1(pred, v1) +// ASSERT_PRED2(pred, v1, v2) +// ... +// +// where pred is an n-ary function or functor that returns bool, +// and the values v1, v2, ..., must support the << operator for +// streaming to std::ostream. +// +// We also define the EXPECT_* variations. +// +// For now we only support predicates whose arity is at most 5. +// Please email googletestframework@googlegroups.com if you need +// support for higher arities. + +// GTEST_ASSERT_ is the basic statement to which all of the assertions +// in this file reduce. Don't use this in your code. + +#define GTEST_ASSERT_(expression, on_failure) \ + GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ + if (const ::testing::AssertionResult gtest_ar = (expression)) \ + ; \ + else \ + on_failure(gtest_ar.failure_message()) + + +// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +template +AssertionResult AssertPred1Helper(const char* pred_text, + const char* e1, + Pred pred, + const T1& v1) { + if (pred(v1)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. +// Don't use this in your code. +#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, v1), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use +// this in your code. +#define GTEST_PRED1_(pred, v1, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ + #v1, \ + pred, \ + v1), on_failure) + +// Unary predicate assertion macros. +#define EXPECT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT1(pred_format, v1) \ + GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED1(pred, v1) \ + GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +template +AssertionResult AssertPred2Helper(const char* pred_text, + const char* e1, + const char* e2, + Pred pred, + const T1& v1, + const T2& v2) { + if (pred(v1, v2)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. +// Don't use this in your code. +#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use +// this in your code. +#define GTEST_PRED2_(pred, v1, v2, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ + #v1, \ + #v2, \ + pred, \ + v1, \ + v2), on_failure) + +// Binary predicate assertion macros. +#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ + GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED2(pred, v1, v2) \ + GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +template +AssertionResult AssertPred3Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3) { + if (pred(v1, v2, v3)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. +// Don't use this in your code. +#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use +// this in your code. +#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + pred, \ + v1, \ + v2, \ + v3), on_failure) + +// Ternary predicate assertion macros. +#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ + GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED3(pred, v1, v2, v3) \ + GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +template +AssertionResult AssertPred4Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4) { + if (pred(v1, v2, v3, v4)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. +// Don't use this in your code. +#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use +// this in your code. +#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4), on_failure) + +// 4-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ + GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ + GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) + + + +// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +template +AssertionResult AssertPred5Helper(const char* pred_text, + const char* e1, + const char* e2, + const char* e3, + const char* e4, + const char* e5, + Pred pred, + const T1& v1, + const T2& v2, + const T3& v3, + const T4& v4, + const T5& v5) { + if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); + + return AssertionFailure() << pred_text << "(" + << e1 << ", " + << e2 << ", " + << e3 << ", " + << e4 << ", " + << e5 << ") evaluates to false, where" + << "\n" << e1 << " evaluates to " << v1 + << "\n" << e2 << " evaluates to " << v2 + << "\n" << e3 << " evaluates to " << v3 + << "\n" << e4 << " evaluates to " << v4 + << "\n" << e5 << " evaluates to " << v5; +} + +// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. +// Don't use this in your code. +#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ + on_failure) + +// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use +// this in your code. +#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ + GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ + #v1, \ + #v2, \ + #v3, \ + #v4, \ + #v5, \ + pred, \ + v1, \ + v2, \ + v3, \ + v4, \ + v5), on_failure) + +// 5-ary predicate assertion macros. +#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) +#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ + GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) +#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ + GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) + + + +#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 +// +// When they are not, Google Test prints both the tested expressions and +// their actual values. The values must be compatible built-in types, +// or you will get a compiler error. By "compatible" we mean that the +// values can be compared by the respective operator. +// +// Note: +// +// 1. It is possible to make a user-defined type work with +// {ASSERT|EXPECT}_??(), but that requires overloading the +// comparison operators and is thus discouraged by the Google C++ +// Usage Guide. Therefore, you are advised to use the +// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are +// equal. +// +// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on +// pointers (in particular, C strings). Therefore, if you use it +// with two C strings, you are testing how their locations in memory +// are related, not how their content is related. To compare two C +// strings by content, use {ASSERT|EXPECT}_STR*(). +// +// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to +// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you +// what the actual value is when it fails, and similarly for the +// other comparisons. +// +// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() +// evaluate their arguments, which is undefined. +// +// 5. These macros evaluate their arguments exactly once. +// +// Examples: +// +// EXPECT_NE(5, Foo()); +// EXPECT_EQ(NULL, a_pointer); +// ASSERT_LT(i, array_size); +// ASSERT_GT(records.size(), 0) << "There is no record left."; + +#define EXPECT_EQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define EXPECT_NE(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) +#define EXPECT_LE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define EXPECT_LT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define EXPECT_GE(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define EXPECT_GT(val1, val2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +#define GTEST_ASSERT_EQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal:: \ + EqHelper::Compare, \ + expected, actual) +#define GTEST_ASSERT_NE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) +#define GTEST_ASSERT_LE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) +#define GTEST_ASSERT_LT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) +#define GTEST_ASSERT_GE(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) +#define GTEST_ASSERT_GT(val1, val2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) + +// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of +// ASSERT_XY(), which clashes with some users' own code. + +#if !GTEST_DONT_DEFINE_ASSERT_EQ +# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_NE +# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LE +# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_LT +# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GE +# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) +#endif + +#if !GTEST_DONT_DEFINE_ASSERT_GT +# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) +#endif + +// C-string Comparisons. All tests treat NULL and any non-NULL string +// as different. Two NULLs are equal. +// +// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 +// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 +// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case +// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case +// +// For wide or narrow string objects, you can use the +// {ASSERT|EXPECT}_??() macros. +// +// Don't depend on the order in which the arguments are evaluated, +// which is undefined. +// +// These macros evaluate their arguments exactly once. + +#define EXPECT_STREQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define EXPECT_STRNE(s1, s2) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define EXPECT_STRCASEEQ(expected, actual) \ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define EXPECT_STRCASENE(s1, s2)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +#define ASSERT_STREQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) +#define ASSERT_STRNE(s1, s2) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) +#define ASSERT_STRCASEEQ(expected, actual) \ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) +#define ASSERT_STRCASENE(s1, s2)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) + +// Macros for comparing floating-point numbers. +// +// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): +// Tests that two float values are almost equal. +// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): +// Tests that two double values are almost equal. +// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): +// Tests that v1 and v2 are within the given distance to each other. +// +// Google Test uses ULP-based comparison to automatically pick a default +// error bound that is appropriate for the operands. See the +// FloatingPoint template class in gtest-internal.h if you are +// interested in the implementation details. + +#define EXPECT_FLOAT_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_DOUBLE_EQ(expected, actual)\ + EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_FLOAT_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define ASSERT_DOUBLE_EQ(expected, actual)\ + ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ + expected, actual) + +#define EXPECT_NEAR(val1, val2, abs_error)\ + EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +#define ASSERT_NEAR(val1, val2, abs_error)\ + ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ + val1, val2, abs_error) + +// These predicate format functions work on floating-point values, and +// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. +// +// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); + +// Asserts that val1 is less than, or almost equal to, val2. Fails +// otherwise. In particular, it fails if either val1 or val2 is NaN. +GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, + float val1, float val2); +GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, + double val1, double val2); + + +#if GTEST_OS_WINDOWS + +// Macros that test for HRESULT failure and success, these are only useful +// on Windows, and rely on Windows SDK macros and APIs to compile. +// +// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) +// +// When expr unexpectedly fails or succeeds, Google Test prints the +// expected result and the actual result with both a human-readable +// string representation of the error, if available, as well as the +// hex result code. +# define EXPECT_HRESULT_SUCCEEDED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define ASSERT_HRESULT_SUCCEEDED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) + +# define EXPECT_HRESULT_FAILED(expr) \ + EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +# define ASSERT_HRESULT_FAILED(expr) \ + ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) + +#endif // GTEST_OS_WINDOWS + +// Macros that execute statement and check that it doesn't generate new fatal +// failures in the current thread. +// +// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); +// +// Examples: +// +// EXPECT_NO_FATAL_FAILURE(Process()); +// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; +// +#define ASSERT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) +#define EXPECT_NO_FATAL_FAILURE(statement) \ + GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) + +// Causes a trace (including the source file path, the current line +// number, and the given message) to be included in every test failure +// message generated by code in the current scope. The effect is +// undone when the control leaves the current scope. +// +// The message argument can be anything streamable to std::ostream. +// +// In the implementation, we include the current line number as part +// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s +// to appear in the same block - as long as they are on different +// lines. +#define SCOPED_TRACE(message) \ + ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ + __FILE__, __LINE__, ::testing::Message() << (message)) + +// Compile-time assertion for type equality. +// StaticAssertTypeEq() compiles iff type1 and type2 are +// the same type. The value it returns is not interesting. +// +// Instead of making StaticAssertTypeEq a class template, we make it a +// function template that invokes a helper class template. This +// prevents a user from misusing StaticAssertTypeEq by +// defining objects of that type. +// +// CAVEAT: +// +// When used inside a method of a class template, +// StaticAssertTypeEq() is effective ONLY IF the method is +// instantiated. For example, given: +// +// template class Foo { +// public: +// void Bar() { testing::StaticAssertTypeEq(); } +// }; +// +// the code: +// +// void Test1() { Foo foo; } +// +// will NOT generate a compiler error, as Foo::Bar() is never +// actually instantiated. Instead, you need: +// +// void Test2() { Foo foo; foo.Bar(); } +// +// to cause a compiler error. +template +bool StaticAssertTypeEq() { + (void)internal::StaticAssertTypeEqHelper(); + return true; +} + +// Defines a test. +// +// The first parameter is the name of the test case, and the second +// parameter is the name of the test within the test case. +// +// The convention is to end the test case name with "Test". For +// example, a test case for the Foo class can be named FooTest. +// +// The user should put his test code between braces after using this +// macro. Example: +// +// TEST(FooTest, InitializesCorrectly) { +// Foo foo; +// EXPECT_TRUE(foo.StatusIsOK()); +// } + +// Note that we call GetTestTypeId() instead of GetTypeId< +// ::testing::Test>() here to get the type ID of testing::Test. This +// is to work around a suspected linker bug when using Google Test as +// a framework on Mac OS X. The bug causes GetTypeId< +// ::testing::Test>() to return different values depending on whether +// the call is from the Google Test framework itself or from user test +// code. GetTestTypeId() is guaranteed to always return the same +// value, as it always calls GetTypeId<>() from the Google Test +// framework. +#define GTEST_TEST(test_case_name, test_name)\ + GTEST_TEST_(test_case_name, test_name, \ + ::testing::Test, ::testing::internal::GetTestTypeId()) + +// Define this macro to 1 to omit the definition of TEST(), which +// is a generic name and clashes with some other libraries. +#if !GTEST_DONT_DEFINE_TEST +# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) +#endif + +// Defines a test that uses a test fixture. +// +// The first parameter is the name of the test fixture class, which +// also doubles as the test case name. The second parameter is the +// name of the test within the test case. +// +// A test fixture class must be declared earlier. The user should put +// his test code between braces after using this macro. Example: +// +// class FooTest : public testing::Test { +// protected: +// virtual void SetUp() { b_.AddElement(3); } +// +// Foo a_; +// Foo b_; +// }; +// +// TEST_F(FooTest, InitializesCorrectly) { +// EXPECT_TRUE(a_.StatusIsOK()); +// } +// +// TEST_F(FooTest, ReturnsElementCountCorrectly) { +// EXPECT_EQ(0, a_.size()); +// EXPECT_EQ(1, b_.size()); +// } + +#define TEST_F(test_fixture, test_name)\ + GTEST_TEST_(test_fixture, test_name, test_fixture, \ + ::testing::internal::GetTypeId()) + +} // namespace testing + +// Use this function in main() to run all tests. It returns 0 if all +// tests are successful, or 1 otherwise. +// +// RUN_ALL_TESTS() should be invoked after the command line has been +// parsed by InitGoogleTest(). +// +// This function was formerly a macro; thus, it is in the global +// namespace and has an all-caps name. +int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; + +inline int RUN_ALL_TESTS() { + return ::testing::UnitTest::GetInstance()->Run(); +} + +#endif // GTEST_INCLUDE_GTEST_GTEST_H_ From 8431ca5fecbc26d7f23143c26599bc809e917565 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 31 Jul 2017 10:54:07 -0600 Subject: [PATCH 238/293] Remove tpls directory --- lib/kokkos/tpls/gtest/gtest/LICENSE | 28 - lib/kokkos/tpls/gtest/gtest/README | 13 - lib/kokkos/tpls/gtest/gtest/gtest-all.cc | 9594 -------- lib/kokkos/tpls/gtest/gtest/gtest-test-part.h | 1 - lib/kokkos/tpls/gtest/gtest/gtest.h | 20065 ---------------- 5 files changed, 29701 deletions(-) delete mode 100644 lib/kokkos/tpls/gtest/gtest/LICENSE delete mode 100644 lib/kokkos/tpls/gtest/gtest/README delete mode 100644 lib/kokkos/tpls/gtest/gtest/gtest-all.cc delete mode 120000 lib/kokkos/tpls/gtest/gtest/gtest-test-part.h delete mode 100644 lib/kokkos/tpls/gtest/gtest/gtest.h diff --git a/lib/kokkos/tpls/gtest/gtest/LICENSE b/lib/kokkos/tpls/gtest/gtest/LICENSE deleted file mode 100644 index 1941a11f8c..0000000000 --- a/lib/kokkos/tpls/gtest/gtest/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright 2008, Google Inc. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * 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. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. diff --git a/lib/kokkos/tpls/gtest/gtest/README b/lib/kokkos/tpls/gtest/gtest/README deleted file mode 100644 index 82964ecc32..0000000000 --- a/lib/kokkos/tpls/gtest/gtest/README +++ /dev/null @@ -1,13 +0,0 @@ -This is a fused source version of gtest 1.7.0. All that should be necessary to -start using gtest in your package is to declare the dependency and include -gtest/gtest.h. - -However, because some of the packages that are developed in Sierra do not use a -fused source version of gtest we need to make it possible for them to build with -this version as well as with their native build. To facilitate this we have -created symlinks for the other gtest headers that they use to the fused source -gtest.h. This will make it possible for them find the headers while still using -the fuse source version. This should not have any ill effects since the header is -protected and allows for only using the non-gtest.h headers in their files. - - diff --git a/lib/kokkos/tpls/gtest/gtest/gtest-all.cc b/lib/kokkos/tpls/gtest/gtest/gtest-all.cc deleted file mode 100644 index 538c78db93..0000000000 --- a/lib/kokkos/tpls/gtest/gtest/gtest-all.cc +++ /dev/null @@ -1,9594 +0,0 @@ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: mheule@google.com (Markus Heule) -// -// Google C++ Testing Framework (Google Test) -// -// Sometimes it's desirable to build Google Test by compiling a single file. -// This file serves this purpose. - -// This line ensures that gtest.h can be compiled on its own, even -// when it's fused. -#include "gtest/gtest.h" - -// The following lines pull in the real gtest *.cc files. -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) - -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// Utilities for testing Google Test itself and code that uses Google Test -// (e.g. frameworks built on top of Google Test). - -#ifndef GTEST_INCLUDE_GTEST_GTEST_SPI_H_ -#define GTEST_INCLUDE_GTEST_GTEST_SPI_H_ - - -namespace testing { - -// This helper class can be used to mock out Google Test failure reporting -// so that we can test Google Test or code that builds on Google Test. -// -// An object of this class appends a TestPartResult object to the -// TestPartResultArray object given in the constructor whenever a Google Test -// failure is reported. It can either intercept only failures that are -// generated in the same thread that created this object or it can intercept -// all generated failures. The scope of this mock object can be controlled with -// the second argument to the two arguments constructor. -class GTEST_API_ ScopedFakeTestPartResultReporter - : public TestPartResultReporterInterface { - public: - // The two possible mocking modes of this object. - enum InterceptMode { - INTERCEPT_ONLY_CURRENT_THREAD, // Intercepts only thread local failures. - INTERCEPT_ALL_THREADS // Intercepts all failures. - }; - - // The c'tor sets this object as the test part result reporter used - // by Google Test. The 'result' parameter specifies where to report the - // results. This reporter will only catch failures generated in the current - // thread. DEPRECATED - explicit ScopedFakeTestPartResultReporter(TestPartResultArray* result); - - // Same as above, but you can choose the interception scope of this object. - ScopedFakeTestPartResultReporter(InterceptMode intercept_mode, - TestPartResultArray* result); - - // The d'tor restores the previous test part result reporter. - virtual ~ScopedFakeTestPartResultReporter(); - - // Appends the TestPartResult object to the TestPartResultArray - // received in the constructor. - // - // This method is from the TestPartResultReporterInterface - // interface. - virtual void ReportTestPartResult(const TestPartResult& result); - private: - void Init(); - - const InterceptMode intercept_mode_; - TestPartResultReporterInterface* old_reporter_; - TestPartResultArray* const result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedFakeTestPartResultReporter); -}; - -namespace internal { - -// A helper class for implementing EXPECT_FATAL_FAILURE() and -// EXPECT_NONFATAL_FAILURE(). Its destructor verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -class GTEST_API_ SingleFailureChecker { - public: - // The constructor remembers the arguments. - SingleFailureChecker(const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr); - ~SingleFailureChecker(); - private: - const TestPartResultArray* const results_; - const TestPartResult::Type type_; - const string substr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SingleFailureChecker); -}; - -} // namespace internal - -} // namespace testing - -// A set of macros for testing Google Test assertions or code that's expected -// to generate Google Test fatal failures. It verifies that the given -// statement will cause exactly one fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_FATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_FATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - 'statement' cannot reference local non-static variables or -// non-static members of the current object. -// - 'statement' cannot return a value. -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. The AcceptsMacroThatExpandsToUnprotectedComma test in -// gtest_unittest.cc will fail to compile if we do that. -#define EXPECT_FATAL_FAILURE(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_FATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do { \ - class GTestExpectFatalFailureHelper {\ - public:\ - static void Execute() { statement; }\ - };\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ALL_THREADS, >est_failures);\ - GTestExpectFatalFailureHelper::Execute();\ - }\ - } while (::testing::internal::AlwaysFalse()) - -// A macro for testing Google Test assertions or code that's expected to -// generate Google Test non-fatal failures. It asserts that the given -// statement will cause exactly one non-fatal Google Test failure with 'substr' -// being part of the failure message. -// -// There are two different versions of this macro. EXPECT_NONFATAL_FAILURE only -// affects and considers failures generated in the current thread and -// EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS does the same but for all threads. -// -// 'statement' is allowed to reference local variables and members of -// the current object. -// -// The verification of the assertion is done correctly even when the statement -// throws an exception or aborts the current function. -// -// Known restrictions: -// - You cannot stream a failure message to this macro. -// -// Note that even though the implementations of the following two -// macros are much alike, we cannot refactor them to use a common -// helper macro, due to some peculiarity in how the preprocessor -// works. If we do that, the code won't compile when the user gives -// EXPECT_NONFATAL_FAILURE() a statement that contains a macro that -// expands to code containing an unprotected comma. The -// AcceptsMacroThatExpandsToUnprotectedComma test in gtest_unittest.cc -// catches that. -// -// For the same reason, we have to write -// if (::testing::internal::AlwaysTrue()) { statement; } -// instead of -// GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) -// to avoid an MSVC warning on unreachable code. -#define EXPECT_NONFATAL_FAILURE(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter:: \ - INTERCEPT_ONLY_CURRENT_THREAD, >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#define EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(statement, substr) \ - do {\ - ::testing::TestPartResultArray gtest_failures;\ - ::testing::internal::SingleFailureChecker gtest_checker(\ - >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ - (substr));\ - {\ - ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ - ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ - >est_failures);\ - if (::testing::internal::AlwaysTrue()) { statement; }\ - }\ - } while (::testing::internal::AlwaysFalse()) - -#endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include // NOLINT -#include -#include - -#if GTEST_OS_LINUX - -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -# include // NOLINT -# include // NOLINT -# include // NOLINT -// Declares vsnprintf(). This header is not available on Windows. -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include - -#elif GTEST_OS_SYMBIAN -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -#elif GTEST_OS_ZOS -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT - -// On z/OS we additionally need strings.h for strcasecmp. -# include // NOLINT - -#elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. - -# include // NOLINT - -#elif GTEST_OS_WINDOWS // We are on Windows proper. - -# include // NOLINT -# include // NOLINT -# include // NOLINT -# include // NOLINT - -# if GTEST_OS_WINDOWS_MINGW -// MinGW has gettimeofday() but not _ftime64(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -// TODO(kenton@google.com): There are other ways to get the time on -// Windows, like GetTickCount() or GetSystemTimeAsFileTime(). MinGW -// supports these. consider using them instead. -# define GTEST_HAS_GETTIMEOFDAY_ 1 -# include // NOLINT -# endif // GTEST_OS_WINDOWS_MINGW - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT - -#else - -// Assume other platforms have gettimeofday(). -// TODO(kenton@google.com): Use autoconf to detect availability of -// gettimeofday(). -# define GTEST_HAS_GETTIMEOFDAY_ 1 - -// cpplint thinks that the header is already included, so we want to -// silence it. -# include // NOLINT -# include // NOLINT - -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -# include -#endif - -#if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -#endif - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. - -// Utility functions and classes used by the Google C++ testing framework. -// -// Author: wan@google.com (Zhanyong Wan) -// -// This file contains purely Google Test's internal implementation. Please -// DO NOT #INCLUDE IT IN A USER PROGRAM. - -#ifndef GTEST_SRC_GTEST_INTERNAL_INL_H_ -#define GTEST_SRC_GTEST_INTERNAL_INL_H_ - -// GTEST_IMPLEMENTATION_ is defined to 1 iff the current translation unit is -// part of Google Test's implementation; otherwise it's undefined. -#if !GTEST_IMPLEMENTATION_ -// A user is trying to include this from his code - just say no. -# error "gtest-internal-inl.h is part of Google Test's internal implementation." -# error "It must not be included except by Google Test itself." -#endif // GTEST_IMPLEMENTATION_ - -#ifndef _WIN32_WCE -# include -#endif // !_WIN32_WCE -#include -#include // For strtoll/_strtoul64/malloc/free. -#include // For memmove. - -#include -#include -#include - - -#if GTEST_CAN_STREAM_RESULTS_ -# include // NOLINT -# include // NOLINT -#endif - -#if GTEST_OS_WINDOWS -# include // NOLINT -#endif // GTEST_OS_WINDOWS - - -namespace testing { - -// Declares the flags. -// -// We don't want the users to modify this flag in the code, but want -// Google Test's own unit tests to be able to access it. Therefore we -// declare it here as opposed to in gtest.h. -GTEST_DECLARE_bool_(death_test_use_fork); - -namespace internal { - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -GTEST_API_ extern const TypeId kTestTypeIdInGoogleTest; - -// Names of the flags (needed for parsing Google Test flags). -const char kAlsoRunDisabledTestsFlag[] = "also_run_disabled_tests"; -const char kBreakOnFailureFlag[] = "break_on_failure"; -const char kCatchExceptionsFlag[] = "catch_exceptions"; -const char kColorFlag[] = "color"; -const char kFilterFlag[] = "filter"; -const char kListTestsFlag[] = "list_tests"; -const char kOutputFlag[] = "output"; -const char kPrintTimeFlag[] = "print_time"; -const char kRandomSeedFlag[] = "random_seed"; -const char kRepeatFlag[] = "repeat"; -const char kShuffleFlag[] = "shuffle"; -const char kStackTraceDepthFlag[] = "stack_trace_depth"; -const char kStreamResultToFlag[] = "stream_result_to"; -const char kThrowOnFailureFlag[] = "throw_on_failure"; - -// A valid random seed must be in [1, kMaxRandomSeed]. -const int kMaxRandomSeed = 99999; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -GTEST_API_ extern bool g_help_flag; - -// Returns the current time in milliseconds. -GTEST_API_ TimeInMillis GetTimeInMillis(); - -// Returns true iff Google Test should use colors in the output. -GTEST_API_ bool ShouldUseColor(bool stdout_is_tty); - -// Formats the given time in milliseconds as seconds. -GTEST_API_ std::string FormatTimeInMillisAsSeconds(TimeInMillis ms); - -// Converts the given time in milliseconds to a date string in the ISO 8601 -// format, without the timezone information. N.B.: due to the use the -// non-reentrant localtime() function, this function is not thread safe. Do -// not use it in any code that can be called from multiple threads. -GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms); - -// Parses a string for an Int32 flag, in the form of "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -GTEST_API_ bool ParseInt32Flag( - const char* str, const char* flag, Int32* value); - -// Returns a random seed in range [1, kMaxRandomSeed] based on the -// given --gtest_random_seed flag value. -inline int GetRandomSeedFromFlag(Int32 random_seed_flag) { - const unsigned int raw_seed = (random_seed_flag == 0) ? - static_cast(GetTimeInMillis()) : - static_cast(random_seed_flag); - - // Normalizes the actual seed to range [1, kMaxRandomSeed] such that - // it's easy to type. - const int normalized_seed = - static_cast((raw_seed - 1U) % - static_cast(kMaxRandomSeed)) + 1; - return normalized_seed; -} - -// Returns the first valid random seed after 'seed'. The behavior is -// undefined if 'seed' is invalid. The seed after kMaxRandomSeed is -// considered to be 1. -inline int GetNextRandomSeed(int seed) { - GTEST_CHECK_(1 <= seed && seed <= kMaxRandomSeed) - << "Invalid random seed " << seed << " - must be in [1, " - << kMaxRandomSeed << "]."; - const int next_seed = seed + 1; - return (next_seed > kMaxRandomSeed) ? 1 : next_seed; -} - -// This class saves the values of all Google Test flags in its c'tor, and -// restores them in its d'tor. -class GTestFlagSaver { - public: - // The c'tor. - GTestFlagSaver() { - also_run_disabled_tests_ = GTEST_FLAG(also_run_disabled_tests); - break_on_failure_ = GTEST_FLAG(break_on_failure); - catch_exceptions_ = GTEST_FLAG(catch_exceptions); - color_ = GTEST_FLAG(color); - death_test_style_ = GTEST_FLAG(death_test_style); - death_test_use_fork_ = GTEST_FLAG(death_test_use_fork); - filter_ = GTEST_FLAG(filter); - internal_run_death_test_ = GTEST_FLAG(internal_run_death_test); - list_tests_ = GTEST_FLAG(list_tests); - output_ = GTEST_FLAG(output); - print_time_ = GTEST_FLAG(print_time); - random_seed_ = GTEST_FLAG(random_seed); - repeat_ = GTEST_FLAG(repeat); - shuffle_ = GTEST_FLAG(shuffle); - stack_trace_depth_ = GTEST_FLAG(stack_trace_depth); - stream_result_to_ = GTEST_FLAG(stream_result_to); - throw_on_failure_ = GTEST_FLAG(throw_on_failure); - } - - // The d'tor is not virtual. DO NOT INHERIT FROM THIS CLASS. - ~GTestFlagSaver() { - GTEST_FLAG(also_run_disabled_tests) = also_run_disabled_tests_; - GTEST_FLAG(break_on_failure) = break_on_failure_; - GTEST_FLAG(catch_exceptions) = catch_exceptions_; - GTEST_FLAG(color) = color_; - GTEST_FLAG(death_test_style) = death_test_style_; - GTEST_FLAG(death_test_use_fork) = death_test_use_fork_; - GTEST_FLAG(filter) = filter_; - GTEST_FLAG(internal_run_death_test) = internal_run_death_test_; - GTEST_FLAG(list_tests) = list_tests_; - GTEST_FLAG(output) = output_; - GTEST_FLAG(print_time) = print_time_; - GTEST_FLAG(random_seed) = random_seed_; - GTEST_FLAG(repeat) = repeat_; - GTEST_FLAG(shuffle) = shuffle_; - GTEST_FLAG(stack_trace_depth) = stack_trace_depth_; - GTEST_FLAG(stream_result_to) = stream_result_to_; - GTEST_FLAG(throw_on_failure) = throw_on_failure_; - } - - private: - // Fields for saving the original values of flags. - bool also_run_disabled_tests_; - bool break_on_failure_; - bool catch_exceptions_; - std::string color_; - std::string death_test_style_; - bool death_test_use_fork_; - std::string filter_; - std::string internal_run_death_test_; - bool list_tests_; - std::string output_; - bool print_time_; - internal::Int32 random_seed_; - internal::Int32 repeat_; - bool shuffle_; - internal::Int32 stack_trace_depth_; - std::string stream_result_to_; - bool throw_on_failure_; -} GTEST_ATTRIBUTE_UNUSED_; - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted -// to "(Invalid Unicode 0xXXXXXXXX)". -GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -GTEST_API_ std::string WideStringToUtf8(const wchar_t* str, int num_chars); - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded(); - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (e.g., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -GTEST_API_ bool ShouldShard(const char* total_shards_str, - const char* shard_index_str, - bool in_subprocess_for_death_test); - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error and -// and aborts. -GTEST_API_ Int32 Int32FromEnvOrDie(const char* env_var, Int32 default_val); - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -GTEST_API_ bool ShouldRunTestOnShard( - int total_shards, int shard_index, int test_id); - -// STL container utilities. - -// Returns the number of elements in the given container that satisfy -// the given predicate. -template -inline int CountIf(const Container& c, Predicate predicate) { - // Implemented as an explicit loop since std::count_if() in libCstd on - // Solaris has a non-standard signature. - int count = 0; - for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { - if (predicate(*it)) - ++count; - } - return count; -} - -// Applies a function/functor to each element in the container. -template -void ForEach(const Container& c, Functor functor) { - std::for_each(c.begin(), c.end(), functor); -} - -// Returns the i-th element of the vector, or default_value if i is not -// in range [0, v.size()). -template -inline E GetElementOr(const std::vector& v, int i, E default_value) { - return (i < 0 || i >= static_cast(v.size())) ? default_value : v[i]; -} - -// Performs an in-place shuffle of a range of the vector's elements. -// 'begin' and 'end' are element indices as an STL-style range; -// i.e. [begin, end) are shuffled, where 'end' == size() means to -// shuffle to the end of the vector. -template -void ShuffleRange(internal::Random* random, int begin, int end, - std::vector* v) { - const int size = static_cast(v->size()); - GTEST_CHECK_(0 <= begin && begin <= size) - << "Invalid shuffle range start " << begin << ": must be in range [0, " - << size << "]."; - GTEST_CHECK_(begin <= end && end <= size) - << "Invalid shuffle range finish " << end << ": must be in range [" - << begin << ", " << size << "]."; - - // Fisher-Yates shuffle, from - // http://en.wikipedia.org/wiki/Fisher-Yates_shuffle - for (int range_width = end - begin; range_width >= 2; range_width--) { - const int last_in_range = begin + range_width - 1; - const int selected = begin + random->Generate(range_width); - std::swap((*v)[selected], (*v)[last_in_range]); - } -} - -// Performs an in-place shuffle of the vector's elements. -template -inline void Shuffle(internal::Random* random, std::vector* v) { - ShuffleRange(random, 0, static_cast(v->size()), v); -} - -// A function for deleting an object. Handy for being used as a -// functor. -template -static void Delete(T* x) { - delete x; -} - -// A predicate that checks the key of a TestProperty against a known key. -// -// TestPropertyKeyIs is copyable. -class TestPropertyKeyIs { - public: - // Constructor. - // - // TestPropertyKeyIs has NO default constructor. - explicit TestPropertyKeyIs(const std::string& key) : key_(key) {} - - // Returns true iff the test name of test property matches on key_. - bool operator()(const TestProperty& test_property) const { - return test_property.key() == key_; - } - - private: - std::string key_; -}; - -// Class UnitTestOptions. -// -// This class contains functions for processing options the user -// specifies when running the tests. It has only static members. -// -// In most cases, the user can specify an option using either an -// environment variable or a command line flag. E.g. you can set the -// test filter using either GTEST_FILTER or --gtest_filter. If both -// the variable and the flag are present, the latter overrides the -// former. -class GTEST_API_ UnitTestOptions { - public: - // Functions for processing the gtest_output flag. - - // Returns the output format, or "" for normal printed output. - static std::string GetOutputFormat(); - - // Returns the absolute path of the requested output file, or the - // default (test_detail.xml in the original working directory) if - // none was explicitly specified. - static std::string GetAbsolutePathToOutputFile(); - - // Functions for processing the gtest_filter flag. - - // Returns true iff the wildcard pattern matches the string. The - // first ':' or '\0' character in pattern marks the end of it. - // - // This recursive algorithm isn't very efficient, but is clear and - // works well enough for matching test names, which are short. - static bool PatternMatchesString(const char *pattern, const char *str); - - // Returns true iff the user-specified filter matches the test case - // name and the test name. - static bool FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name); - -#if GTEST_OS_WINDOWS - // Function for supporting the gtest_catch_exception flag. - - // Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the - // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. - // This function is useful as an __except condition. - static int GTestShouldProcessSEH(DWORD exception_code); -#endif // GTEST_OS_WINDOWS - - // Returns true if "name" matches the ':' separated list of glob-style - // filters in "filter". - static bool MatchesFilter(const std::string& name, const char* filter); -}; - -// Returns the current application's name, removing directory path if that -// is present. Used by UnitTestOptions::GetOutputFile. -GTEST_API_ FilePath GetCurrentExecutableName(); - -// The role interface for getting the OS stack trace as a string. -class OsStackTraceGetterInterface { - public: - OsStackTraceGetterInterface() {} - virtual ~OsStackTraceGetterInterface() {} - - // Returns the current OS stack trace as an std::string. Parameters: - // - // max_depth - the maximum number of stack frames to be included - // in the trace. - // skip_count - the number of top frames to be skipped; doesn't count - // against max_depth. - virtual string CurrentStackTrace(int max_depth, int skip_count) = 0; - - // UponLeavingGTest() should be called immediately before Google Test calls - // user code. It saves some information about the current stack that - // CurrentStackTrace() will use to find and hide Google Test stack frames. - virtual void UponLeavingGTest() = 0; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); -}; - -// A working implementation of the OsStackTraceGetterInterface interface. -class OsStackTraceGetter : public OsStackTraceGetterInterface { - public: - OsStackTraceGetter() : caller_frame_(NULL) {} - - virtual string CurrentStackTrace(int max_depth, int skip_count) - GTEST_LOCK_EXCLUDED_(mutex_); - - virtual void UponLeavingGTest() GTEST_LOCK_EXCLUDED_(mutex_); - - // This string is inserted in place of stack frames that are part of - // Google Test's implementation. - static const char* const kElidedFramesMarker; - - private: - Mutex mutex_; // protects all internal state - - // We save the stack frame below the frame that calls user code. - // We do this because the address of the frame immediately below - // the user code changes between the call to UponLeavingGTest() - // and any calls to CurrentStackTrace() from within the user code. - void* caller_frame_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); -}; - -// Information about a Google Test trace point. -struct TraceInfo { - const char* file; - int line; - std::string message; -}; - -// This is the default global test part result reporter used in UnitTestImpl. -// This class should only be used by UnitTestImpl. -class DefaultGlobalTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultGlobalTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. Reports the test part - // result in the current test. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultGlobalTestPartResultReporter); -}; - -// This is the default per thread test part result reporter used in -// UnitTestImpl. This class should only be used by UnitTestImpl. -class DefaultPerThreadTestPartResultReporter - : public TestPartResultReporterInterface { - public: - explicit DefaultPerThreadTestPartResultReporter(UnitTestImpl* unit_test); - // Implements the TestPartResultReporterInterface. The implementation just - // delegates to the current global test part result reporter of *unit_test_. - virtual void ReportTestPartResult(const TestPartResult& result); - - private: - UnitTestImpl* const unit_test_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultPerThreadTestPartResultReporter); -}; - -// The private implementation of the UnitTest class. We don't protect -// the methods under a mutex, as this class is not accessible by a -// user and the UnitTest class that delegates work to this class does -// proper locking. -class GTEST_API_ UnitTestImpl { - public: - explicit UnitTestImpl(UnitTest* parent); - virtual ~UnitTestImpl(); - - // There are two different ways to register your own TestPartResultReporter. - // You can register your own repoter to listen either only for test results - // from the current thread or for results from all threads. - // By default, each per-thread test result repoter just passes a new - // TestPartResult to the global test result reporter, which registers the - // test part result for the currently running test. - - // Returns the global test part result reporter. - TestPartResultReporterInterface* GetGlobalTestPartResultReporter(); - - // Sets the global test part result reporter. - void SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter); - - // Returns the test part result reporter for the current thread. - TestPartResultReporterInterface* GetTestPartResultReporterForCurrentThread(); - - // Sets the test part result reporter for the current thread. - void SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter); - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp() const { return start_timestamp_; } - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const { return !Failed(); } - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const { - return failed_test_case_count() > 0 || ad_hoc_test_result()->Failed(); - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[i]; - } - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i) { - const int index = GetElementOr(test_case_indices_, i, -1); - return index < 0 ? NULL : test_cases_[index]; - } - - // Provides access to the event listener list. - TestEventListeners* listeners() { return &listeners_; } - - // Returns the TestResult for the test that's currently running, or - // the TestResult for the ad hoc test if no test is running. - TestResult* current_test_result(); - - // Returns the TestResult for the ad hoc test. - const TestResult* ad_hoc_test_result() const { return &ad_hoc_test_result_; } - - // Sets the OS stack trace getter. - // - // Does nothing if the input and the current OS stack trace getter - // are the same; otherwise, deletes the old getter and makes the - // input the current getter. - void set_os_stack_trace_getter(OsStackTraceGetterInterface* getter); - - // Returns the current OS stack trace getter if it is not NULL; - // otherwise, creates an OsStackTraceGetter, makes it the current - // getter, and returns it. - OsStackTraceGetterInterface* os_stack_trace_getter(); - - // Returns the current OS stack trace as an std::string. - // - // The maximum number of stack frames to be included is specified by - // the gtest_stack_trace_depth flag. The skip_count parameter - // specifies the number of top frames to be skipped, which doesn't - // count against the number of frames to be included. - // - // For example, if Foo() calls Bar(), which in turn calls - // CurrentOsStackTraceExceptTop(1), Foo() will be included in the - // trace but Bar() and CurrentOsStackTraceExceptTop() won't. - std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; - - // Finds and returns a TestCase with the given name. If one doesn't - // exist, creates one and returns it. - // - // Arguments: - // - // test_case_name: name of the test case - // type_param: the name of the test's type parameter, or NULL if - // this is not a typed or a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase* GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Adds a TestInfo to the unit test. - // - // Arguments: - // - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - // test_info: the TestInfo object - void AddTestInfo(Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - TestInfo* test_info) { - // In order to support thread-safe death tests, we need to - // remember the original working directory when the test program - // was first invoked. We cannot do this in RUN_ALL_TESTS(), as - // the user may have changed the current directory before calling - // RUN_ALL_TESTS(). Therefore we capture the current directory in - // AddTestInfo(), which is called to register a TEST or TEST_F - // before main() is reached. - if (original_working_dir_.IsEmpty()) { - original_working_dir_.Set(FilePath::GetCurrentDir()); - GTEST_CHECK_(!original_working_dir_.IsEmpty()) - << "Failed to get the current working directory."; - } - - GetTestCase(test_info->test_case_name(), - test_info->type_param(), - set_up_tc, - tear_down_tc)->AddTestInfo(test_info); - } - -#if GTEST_HAS_PARAM_TEST - // Returns ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() { - return parameterized_test_registry_; - } -#endif // GTEST_HAS_PARAM_TEST - - // Sets the TestCase object for the test that's currently running. - void set_current_test_case(TestCase* a_current_test_case) { - current_test_case_ = a_current_test_case; - } - - // Sets the TestInfo object for the test that's currently running. If - // current_test_info is NULL, the assertion results will be stored in - // ad_hoc_test_result_. - void set_current_test_info(TestInfo* a_current_test_info) { - current_test_info_ = a_current_test_info; - } - - // Registers all parameterized tests defined using TEST_P and - // INSTANTIATE_TEST_CASE_P, creating regular tests for each test/parameter - // combination. This method can be called more then once; it has guards - // protecting from registering the tests more then once. If - // value-parameterized tests are disabled, RegisterParameterizedTests is - // present but does nothing. - void RegisterParameterizedTests(); - - // Runs all tests in this UnitTest object, prints the result, and - // returns true if all tests are successful. If any exception is - // thrown during a test, this test is considered to be failed, but - // the rest of the tests will still be run. - bool RunAllTests(); - - // Clears the results of all tests, except the ad hoc tests. - void ClearNonAdHocTestResult() { - ForEach(test_cases_, TestCase::ClearTestCaseResult); - } - - // Clears the results of ad-hoc test assertions. - void ClearAdHocTestResult() { - ad_hoc_test_result_.Clear(); - } - - // Adds a TestProperty to the current TestResult object when invoked in a - // context of a test or a test case, or to the global property set. If the - // result already contains a property with the same key, the value will be - // updated. - void RecordProperty(const TestProperty& test_property); - - enum ReactionToSharding { - HONOR_SHARDING_PROTOCOL, - IGNORE_SHARDING_PROTOCOL - }; - - // Matches the full name of each test against the user-specified - // filter to decide whether the test should run, then records the - // result in each TestCase and TestInfo object. - // If shard_tests == HONOR_SHARDING_PROTOCOL, further filters tests - // based on sharding variables in the environment. - // Returns the number of tests that should run. - int FilterTests(ReactionToSharding shard_tests); - - // Prints the names of the tests matching the user-specified filter flag. - void ListTestsMatchingFilter(); - - const TestCase* current_test_case() const { return current_test_case_; } - TestInfo* current_test_info() { return current_test_info_; } - const TestInfo* current_test_info() const { return current_test_info_; } - - // Returns the vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector& environments() { return environments_; } - - // Getters for the per-thread Google Test trace stack. - std::vector& gtest_trace_stack() { - return *(gtest_trace_stack_.pointer()); - } - const std::vector& gtest_trace_stack() const { - return gtest_trace_stack_.get(); - } - -#if GTEST_HAS_DEATH_TEST - void InitDeathTestSubprocessControlInfo() { - internal_run_death_test_flag_.reset(ParseInternalRunDeathTestFlag()); - } - // Returns a pointer to the parsed --gtest_internal_run_death_test - // flag, or NULL if that flag was not specified. - // This information is useful only in a death test child process. - // Must not be called before a call to InitGoogleTest. - const InternalRunDeathTestFlag* internal_run_death_test_flag() const { - return internal_run_death_test_flag_.get(); - } - - // Returns a pointer to the current death test factory. - internal::DeathTestFactory* death_test_factory() { - return death_test_factory_.get(); - } - - void SuppressTestEventsIfInSubprocess(); - - friend class ReplaceDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - - // Initializes the event listener performing XML output as specified by - // UnitTestOptions. Must not be called before InitGoogleTest. - void ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Initializes the event listener for streaming test results to a socket. - // Must not be called before InitGoogleTest. - void ConfigureStreamingOutput(); -#endif - - // Performs initialization dependent upon flag values obtained in - // ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to - // ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest - // this function is also called from RunAllTests. Since this function can be - // called more than once, it has to be idempotent. - void PostFlagParsingInit(); - - // Gets the random seed used at the start of the current test iteration. - int random_seed() const { return random_seed_; } - - // Gets the random number generator. - internal::Random* random() { return &random_; } - - // Shuffles all test cases, and the tests within each test case, - // making sure that death tests are still run first. - void ShuffleTests(); - - // Restores the test cases and tests to their order before the first shuffle. - void UnshuffleTests(); - - // Returns the value of GTEST_FLAG(catch_exceptions) at the moment - // UnitTest::Run() starts. - bool catch_exceptions() const { return catch_exceptions_; } - - private: - friend class ::testing::UnitTest; - - // Used by UnitTest::Run() to capture the state of - // GTEST_FLAG(catch_exceptions) at the moment it starts. - void set_catch_exceptions(bool value) { catch_exceptions_ = value; } - - // The UnitTest object that owns this implementation object. - UnitTest* const parent_; - - // The working directory when the first TEST() or TEST_F() was - // executed. - internal::FilePath original_working_dir_; - - // The default test part result reporters. - DefaultGlobalTestPartResultReporter default_global_test_part_result_reporter_; - DefaultPerThreadTestPartResultReporter - default_per_thread_test_part_result_reporter_; - - // Points to (but doesn't own) the global test part result reporter. - TestPartResultReporterInterface* global_test_part_result_repoter_; - - // Protects read and write access to global_test_part_result_reporter_. - internal::Mutex global_test_part_result_reporter_mutex_; - - // Points to (but doesn't own) the per-thread test part result reporter. - internal::ThreadLocal - per_thread_test_part_result_reporter_; - - // The vector of environments that need to be set-up/torn-down - // before/after the tests are run. - std::vector environments_; - - // The vector of TestCases in their original order. It owns the - // elements in the vector. - std::vector test_cases_; - - // Provides a level of indirection for the test case list to allow - // easy shuffling and restoring the test case order. The i-th - // element of this vector is the index of the i-th test case in the - // shuffled order. - std::vector test_case_indices_; - -#if GTEST_HAS_PARAM_TEST - // ParameterizedTestRegistry object used to register value-parameterized - // tests. - internal::ParameterizedTestCaseRegistry parameterized_test_registry_; - - // Indicates whether RegisterParameterizedTests() has been called already. - bool parameterized_tests_registered_; -#endif // GTEST_HAS_PARAM_TEST - - // Index of the last death test case registered. Initially -1. - int last_death_test_case_; - - // This points to the TestCase for the currently running test. It - // changes as Google Test goes through one test case after another. - // When no test is running, this is set to NULL and Google Test - // stores assertion results in ad_hoc_test_result_. Initially NULL. - TestCase* current_test_case_; - - // This points to the TestInfo for the currently running test. It - // changes as Google Test goes through one test after another. When - // no test is running, this is set to NULL and Google Test stores - // assertion results in ad_hoc_test_result_. Initially NULL. - TestInfo* current_test_info_; - - // Normally, a user only writes assertions inside a TEST or TEST_F, - // or inside a function called by a TEST or TEST_F. Since Google - // Test keeps track of which test is current running, it can - // associate such an assertion with the test it belongs to. - // - // If an assertion is encountered when no TEST or TEST_F is running, - // Google Test attributes the assertion result to an imaginary "ad hoc" - // test, and records the result in ad_hoc_test_result_. - TestResult ad_hoc_test_result_; - - // The list of event listeners that can be used to track events inside - // Google Test. - TestEventListeners listeners_; - - // The OS stack trace getter. Will be deleted when the UnitTest - // object is destructed. By default, an OsStackTraceGetter is used, - // but the user can set this field to use a custom getter if that is - // desired. - OsStackTraceGetterInterface* os_stack_trace_getter_; - - // True iff PostFlagParsingInit() has been called. - bool post_flag_parse_init_performed_; - - // The random number seed used at the beginning of the test run. - int random_seed_; - - // Our random number generator. - internal::Random random_; - - // The time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp_; - - // How long the test took to run, in milliseconds. - TimeInMillis elapsed_time_; - -#if GTEST_HAS_DEATH_TEST - // The decomposed components of the gtest_internal_run_death_test flag, - // parsed when RUN_ALL_TESTS is called. - internal::scoped_ptr internal_run_death_test_flag_; - internal::scoped_ptr death_test_factory_; -#endif // GTEST_HAS_DEATH_TEST - - // A per-thread stack of traces created by the SCOPED_TRACE() macro. - internal::ThreadLocal > gtest_trace_stack_; - - // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() - // starts. - bool catch_exceptions_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); -}; // class UnitTestImpl - -// Convenience function for accessing the global UnitTest -// implementation object. -inline UnitTestImpl* GetUnitTestImpl() { - return UnitTest::GetInstance()->impl(); -} - -#if GTEST_USES_SIMPLE_RE - -// Internal helper functions for implementing the simple regular -// expression matcher. -GTEST_API_ bool IsInSet(char ch, const char* str); -GTEST_API_ bool IsAsciiDigit(char ch); -GTEST_API_ bool IsAsciiPunct(char ch); -GTEST_API_ bool IsRepeat(char ch); -GTEST_API_ bool IsAsciiWhiteSpace(char ch); -GTEST_API_ bool IsAsciiWordChar(char ch); -GTEST_API_ bool IsValidEscape(char ch); -GTEST_API_ bool AtomMatchesChar(bool escaped, char pattern, char ch); -GTEST_API_ bool ValidateRegex(const char* regex); -GTEST_API_ bool MatchRegexAtHead(const char* regex, const char* str); -GTEST_API_ bool MatchRepetitionAndRegexAtHead( - bool escaped, char ch, char repeat, const char* regex, const char* str); -GTEST_API_ bool MatchRegexAnywhere(const char* regex, const char* str); - -#endif // GTEST_USES_SIMPLE_RE - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, char** argv); -GTEST_API_ void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv); - -#if GTEST_HAS_DEATH_TEST - -// Returns the message describing the last system error, regardless of the -// platform. -GTEST_API_ std::string GetLastErrnoDescription(); - -# if GTEST_OS_WINDOWS -// Provides leak-safe Windows kernel handle ownership. -class AutoHandle { - public: - AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} - explicit AutoHandle(HANDLE handle) : handle_(handle) {} - - ~AutoHandle() { Reset(); } - - HANDLE Get() const { return handle_; } - void Reset() { Reset(INVALID_HANDLE_VALUE); } - void Reset(HANDLE handle) { - if (handle != handle_) { - if (handle_ != INVALID_HANDLE_VALUE) - ::CloseHandle(handle_); - handle_ = handle; - } - } - - private: - HANDLE handle_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); -}; -# endif // GTEST_OS_WINDOWS - -// Attempts to parse a string into a positive integer pointed to by the -// number parameter. Returns true if that is possible. -// GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we can use -// it here. -template -bool ParseNaturalNumber(const ::std::string& str, Integer* number) { - // Fail fast if the given string does not begin with a digit; - // this bypasses strtoXXX's "optional leading whitespace and plus - // or minus sign" semantics, which are undesirable here. - if (str.empty() || !IsDigit(str[0])) { - return false; - } - errno = 0; - - char* end; - // BiggestConvertible is the largest integer type that system-provided - // string-to-number conversion routines can return. - -# if GTEST_OS_WINDOWS && !defined(__GNUC__) - - // MSVC and C++ Builder define __int64 instead of the standard long long. - typedef unsigned __int64 BiggestConvertible; - const BiggestConvertible parsed = _strtoui64(str.c_str(), &end, 10); - -# else - - typedef unsigned long long BiggestConvertible; // NOLINT - const BiggestConvertible parsed = strtoull(str.c_str(), &end, 10); - -# endif // GTEST_OS_WINDOWS && !defined(__GNUC__) - - const bool parse_success = *end == '\0' && errno == 0; - - // TODO(vladl@google.com): Convert this to compile time assertion when it is - // available. - GTEST_CHECK_(sizeof(Integer) <= sizeof(parsed)); - - const Integer result = static_cast(parsed); - if (parse_success && static_cast(result) == parsed) { - *number = result; - return true; - } - return false; -} -#endif // GTEST_HAS_DEATH_TEST - -// TestResult contains some private methods that should be hidden from -// Google Test user but are required for testing. This class allow our tests -// to access them. -// -// This class is supplied only for the purpose of testing Google Test's own -// constructs. Do not use it in user tests, either directly or indirectly. -class TestResultAccessor { - public: - static void RecordProperty(TestResult* test_result, - const std::string& xml_element, - const TestProperty& property) { - test_result->RecordProperty(xml_element, property); - } - - static void ClearTestPartResults(TestResult* test_result) { - test_result->ClearTestPartResults(); - } - - static const std::vector& test_part_results( - const TestResult& test_result) { - return test_result.test_part_results(); - } -}; - -#if GTEST_CAN_STREAM_RESULTS_ - -// Streams test results to the given port on the given host machine. -class StreamingListener : public EmptyTestEventListener { - public: - // Abstract base class for writing strings to a socket. - class AbstractSocketWriter { - public: - virtual ~AbstractSocketWriter() {} - - // Sends a string to the socket. - virtual void Send(const string& message) = 0; - - // Closes the socket. - virtual void CloseConnection() {} - - // Sends a string and a newline to the socket. - void SendLn(const string& message) { - Send(message + "\n"); - } - }; - - // Concrete class for actually writing strings to a socket. - class SocketWriter : public AbstractSocketWriter { - public: - SocketWriter(const string& host, const string& port) - : sockfd_(-1), host_name_(host), port_num_(port) { - MakeConnection(); - } - - virtual ~SocketWriter() { - if (sockfd_ != -1) - CloseConnection(); - } - - // Sends a string to the socket. - virtual void Send(const string& message) { - GTEST_CHECK_(sockfd_ != -1) - << "Send() can be called only when there is a connection."; - - const int len = static_cast(message.length()); - if (write(sockfd_, message.c_str(), len) != len) { - GTEST_LOG_(WARNING) - << "stream_result_to: failed to stream to " - << host_name_ << ":" << port_num_; - } - } - - private: - // Creates a client socket and connects to the server. - void MakeConnection(); - - // Closes the socket. - void CloseConnection() { - GTEST_CHECK_(sockfd_ != -1) - << "CloseConnection() can be called only when there is a connection."; - - close(sockfd_); - sockfd_ = -1; - } - - int sockfd_; // socket file descriptor - const string host_name_; - const string port_num_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); - }; // class SocketWriter - - // Escapes '=', '&', '%', and '\n' characters in str as "%xx". - static string UrlEncode(const char* str); - - StreamingListener(const string& host, const string& port) - : socket_writer_(new SocketWriter(host, port)) { Start(); } - - explicit StreamingListener(AbstractSocketWriter* socket_writer) - : socket_writer_(socket_writer) { Start(); } - - void OnTestProgramStart(const UnitTest& /* unit_test */) { - SendLn("event=TestProgramStart"); - } - - void OnTestProgramEnd(const UnitTest& unit_test) { - // Note that Google Test current only report elapsed time for each - // test iteration, not for the entire test program. - SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); - - // Notify the streaming server to stop. - socket_writer_->CloseConnection(); - } - - void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { - SendLn("event=TestIterationStart&iteration=" + - StreamableToString(iteration)); - } - - void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { - SendLn("event=TestIterationEnd&passed=" + - FormatBool(unit_test.Passed()) + "&elapsed_time=" + - StreamableToString(unit_test.elapsed_time()) + "ms"); - } - - void OnTestCaseStart(const TestCase& test_case) { - SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); - } - - void OnTestCaseEnd(const TestCase& test_case) { - SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) - + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) - + "ms"); - } - - void OnTestStart(const TestInfo& test_info) { - SendLn(std::string("event=TestStart&name=") + test_info.name()); - } - - void OnTestEnd(const TestInfo& test_info) { - SendLn("event=TestEnd&passed=" + - FormatBool((test_info.result())->Passed()) + - "&elapsed_time=" + - StreamableToString((test_info.result())->elapsed_time()) + "ms"); - } - - void OnTestPartResult(const TestPartResult& test_part_result) { - const char* file_name = test_part_result.file_name(); - if (file_name == NULL) - file_name = ""; - SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + - "&line=" + StreamableToString(test_part_result.line_number()) + - "&message=" + UrlEncode(test_part_result.message())); - } - - private: - // Sends the given message and a newline to the socket. - void SendLn(const string& message) { socket_writer_->SendLn(message); } - - // Called at the start of streaming to notify the receiver what - // protocol we are using. - void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } - - string FormatBool(bool value) { return value ? "1" : "0"; } - - const scoped_ptr socket_writer_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); -}; // class StreamingListener - -#endif // GTEST_CAN_STREAM_RESULTS_ - -} // namespace internal -} // namespace testing - -#endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ -#undef GTEST_IMPLEMENTATION_ - -#if GTEST_OS_WINDOWS -# define vsnprintf _vsnprintf -#endif // GTEST_OS_WINDOWS - -namespace testing { - -using internal::CountIf; -using internal::ForEach; -using internal::GetElementOr; -using internal::Shuffle; - -// Constants. - -// A test whose test case name or test name matches this filter is -// disabled and not run. -static const char kDisableTestFilter[] = "DISABLED_*:*/DISABLED_*"; - -// A test case whose name matches this filter is considered a death -// test case and will be run before test cases whose name doesn't -// match this filter. -static const char kDeathTestCaseFilter[] = "*DeathTest:*DeathTest/*"; - -// A test filter that matches everything. -static const char kUniversalFilter[] = "*"; - -// The default output file for XML output. -static const char kDefaultOutputFile[] = "test_detail.xml"; - -// The environment variable name for the test shard index. -static const char kTestShardIndex[] = "GTEST_SHARD_INDEX"; -// The environment variable name for the total number of test shards. -static const char kTestTotalShards[] = "GTEST_TOTAL_SHARDS"; -// The environment variable name for the test shard status file. -static const char kTestShardStatusFile[] = "GTEST_SHARD_STATUS_FILE"; - -namespace internal { - -// The text used in failure messages to indicate the start of the -// stack trace. -const char kStackTraceMarker[] = "\nStack trace:\n"; - -// g_help_flag is true iff the --help flag or an equivalent form is -// specified on the command line. -bool g_help_flag = false; - -} // namespace internal - -static const char* GetDefaultFilter() { - return kUniversalFilter; -} - -GTEST_DEFINE_bool_( - also_run_disabled_tests, - internal::BoolFromGTestEnv("also_run_disabled_tests", false), - "Run disabled tests too, in addition to the tests normally being run."); - -GTEST_DEFINE_bool_( - break_on_failure, - internal::BoolFromGTestEnv("break_on_failure", false), - "True iff a failed assertion should be a debugger break-point."); - -GTEST_DEFINE_bool_( - catch_exceptions, - internal::BoolFromGTestEnv("catch_exceptions", true), - "True iff " GTEST_NAME_ - " should catch exceptions and treat them as test failures."); - -GTEST_DEFINE_string_( - color, - internal::StringFromGTestEnv("color", "auto"), - "Whether to use colors in the output. Valid values: yes, no, " - "and auto. 'auto' means to use colors if the output is " - "being sent to a terminal and the TERM environment variable " - "is set to a terminal type that supports colors."); - -GTEST_DEFINE_string_( - filter, - internal::StringFromGTestEnv("filter", GetDefaultFilter()), - "A colon-separated list of glob (not regex) patterns " - "for filtering the tests to run, optionally followed by a " - "'-' and a : separated list of negative patterns (tests to " - "exclude). A test is run if it matches one of the positive " - "patterns and does not match any of the negative patterns."); - -GTEST_DEFINE_bool_(list_tests, false, - "List all tests without running them."); - -GTEST_DEFINE_string_( - output, - internal::StringFromGTestEnv("output", ""), - "A format (currently must be \"xml\"), optionally followed " - "by a colon and an output file name or directory. A directory " - "is indicated by a trailing pathname separator. " - "Examples: \"xml:filename.xml\", \"xml::directoryname/\". " - "If a directory is specified, output files will be created " - "within that directory, with file-names based on the test " - "executable's name and, if necessary, made unique by adding " - "digits."); - -GTEST_DEFINE_bool_( - print_time, - internal::BoolFromGTestEnv("print_time", true), - "True iff " GTEST_NAME_ - " should display elapsed time in text output."); - -GTEST_DEFINE_int32_( - random_seed, - internal::Int32FromGTestEnv("random_seed", 0), - "Random number seed to use when shuffling test orders. Must be in range " - "[1, 99999], or 0 to use a seed based on the current time."); - -GTEST_DEFINE_int32_( - repeat, - internal::Int32FromGTestEnv("repeat", 1), - "How many times to repeat each test. Specify a negative number " - "for repeating forever. Useful for shaking out flaky tests."); - -GTEST_DEFINE_bool_( - show_internal_stack_frames, false, - "True iff " GTEST_NAME_ " should include internal stack frames when " - "printing test failure stack traces."); - -GTEST_DEFINE_bool_( - shuffle, - internal::BoolFromGTestEnv("shuffle", false), - "True iff " GTEST_NAME_ - " should randomize tests' order on every run."); - -GTEST_DEFINE_int32_( - stack_trace_depth, - internal::Int32FromGTestEnv("stack_trace_depth", kMaxStackTraceDepth), - "The maximum number of stack frames to print when an " - "assertion fails. The valid range is 0 through 100, inclusive."); - -GTEST_DEFINE_string_( - stream_result_to, - internal::StringFromGTestEnv("stream_result_to", ""), - "This flag specifies the host name and the port number on which to stream " - "test results. Example: \"localhost:555\". The flag is effective only on " - "Linux."); - -GTEST_DEFINE_bool_( - throw_on_failure, - internal::BoolFromGTestEnv("throw_on_failure", false), - "When this flag is specified, a failed assertion will throw an exception " - "if exceptions are enabled or exit the program with a non-zero code " - "otherwise."); - -namespace internal { - -// Generates a random number from [0, range), using a Linear -// Congruential Generator (LCG). Crashes if 'range' is 0 or greater -// than kMaxRange. -UInt32 Random::Generate(UInt32 range) { - // These constants are the same as are used in glibc's rand(3). - state_ = (1103515245U*state_ + 12345U) % kMaxRange; - - GTEST_CHECK_(range > 0) - << "Cannot generate a number in the range [0, 0)."; - GTEST_CHECK_(range <= kMaxRange) - << "Generation of a number in [0, " << range << ") was requested, " - << "but this can only generate numbers in [0, " << kMaxRange << ")."; - - // Converting via modulus introduces a bit of downward bias, but - // it's simple, and a linear congruential generator isn't too good - // to begin with. - return state_ % range; -} - -// GTestIsInitialized() returns true iff the user has initialized -// Google Test. Useful for catching the user mistake of not initializing -// Google Test before calling RUN_ALL_TESTS(). -// -// A user must call testing::InitGoogleTest() to initialize Google -// Test. g_init_gtest_count is set to the number of times -// InitGoogleTest() has been called. We don't protect this variable -// under a mutex as it is only accessed in the main thread. -GTEST_API_ int g_init_gtest_count = 0; -static bool GTestIsInitialized() { return g_init_gtest_count != 0; } - -// Iterates over a vector of TestCases, keeping a running sum of the -// results of calling a given int-returning method on each. -// Returns the sum. -static int SumOverTestCaseList(const std::vector& case_list, - int (TestCase::*method)() const) { - int sum = 0; - for (size_t i = 0; i < case_list.size(); i++) { - sum += (case_list[i]->*method)(); - } - return sum; -} - -// Returns true iff the test case passed. -static bool TestCasePassed(const TestCase* test_case) { - return test_case->should_run() && test_case->Passed(); -} - -// Returns true iff the test case failed. -static bool TestCaseFailed(const TestCase* test_case) { - return test_case->should_run() && test_case->Failed(); -} - -// Returns true iff test_case contains at least one test that should -// run. -static bool ShouldRunTestCase(const TestCase* test_case) { - return test_case->should_run(); -} - -// AssertHelper constructor. -AssertHelper::AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message) - : data_(new AssertHelperData(type, file, line, message)) { -} - -AssertHelper::~AssertHelper() { - delete data_; -} - -// Message assignment, for assertion streaming support. -void AssertHelper::operator=(const Message& message) const { - UnitTest::GetInstance()-> - AddTestPartResult(data_->type, data_->file, data_->line, - AppendUserMessage(data_->message, message), - UnitTest::GetInstance()->impl() - ->CurrentOsStackTraceExceptTop(1) - // Skips the stack frame for this function itself. - ); // NOLINT -} - -// Mutex for linked pointers. -GTEST_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// Application pathname gotten in InitGoogleTest. -std::string g_executable_path; - -// Returns the current application's name, removing directory path if that -// is present. -FilePath GetCurrentExecutableName() { - FilePath result; - -#if GTEST_OS_WINDOWS - result.Set(FilePath(g_executable_path).RemoveExtension("exe")); -#else - result.Set(FilePath(g_executable_path)); -#endif // GTEST_OS_WINDOWS - - return result.RemoveDirectoryName(); -} - -// Functions for processing the gtest_output flag. - -// Returns the output format, or "" for normal printed output. -std::string UnitTestOptions::GetOutputFormat() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) return std::string(""); - - const char* const colon = strchr(gtest_output_flag, ':'); - return (colon == NULL) ? - std::string(gtest_output_flag) : - std::string(gtest_output_flag, colon - gtest_output_flag); -} - -// Returns the name of the requested output file, or the default if none -// was explicitly specified. -std::string UnitTestOptions::GetAbsolutePathToOutputFile() { - const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); - if (gtest_output_flag == NULL) - return ""; - - const char* const colon = strchr(gtest_output_flag, ':'); - if (colon == NULL) - return internal::FilePath::ConcatPaths( - internal::FilePath( - UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(kDefaultOutputFile)).string(); - - internal::FilePath output_name(colon + 1); - if (!output_name.IsAbsolutePath()) - // TODO(wan@google.com): on Windows \some\path is not an absolute - // path (as its meaning depends on the current drive), yet the - // following logic for turning it into an absolute path is wrong. - // Fix it. - output_name = internal::FilePath::ConcatPaths( - internal::FilePath(UnitTest::GetInstance()->original_working_dir()), - internal::FilePath(colon + 1)); - - if (!output_name.IsDirectory()) - return output_name.string(); - - internal::FilePath result(internal::FilePath::GenerateUniqueFileName( - output_name, internal::GetCurrentExecutableName(), - GetOutputFormat().c_str())); - return result.string(); -} - -// Returns true iff the wildcard pattern matches the string. The -// first ':' or '\0' character in pattern marks the end of it. -// -// This recursive algorithm isn't very efficient, but is clear and -// works well enough for matching test names, which are short. -bool UnitTestOptions::PatternMatchesString(const char *pattern, - const char *str) { - switch (*pattern) { - case '\0': - case ':': // Either ':' or '\0' marks the end of the pattern. - return *str == '\0'; - case '?': // Matches any single character. - return *str != '\0' && PatternMatchesString(pattern + 1, str + 1); - case '*': // Matches any string (possibly empty) of characters. - return (*str != '\0' && PatternMatchesString(pattern, str + 1)) || - PatternMatchesString(pattern + 1, str); - default: // Non-special character. Matches itself. - return *pattern == *str && - PatternMatchesString(pattern + 1, str + 1); - } -} - -bool UnitTestOptions::MatchesFilter( - const std::string& name, const char* filter) { - const char *cur_pattern = filter; - for (;;) { - if (PatternMatchesString(cur_pattern, name.c_str())) { - return true; - } - - // Finds the next pattern in the filter. - cur_pattern = strchr(cur_pattern, ':'); - - // Returns if no more pattern can be found. - if (cur_pattern == NULL) { - return false; - } - - // Skips the pattern separater (the ':' character). - cur_pattern++; - } -} - -// Returns true iff the user-specified filter matches the test case -// name and the test name. -bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, - const std::string &test_name) { - const std::string& full_name = test_case_name + "." + test_name.c_str(); - - // Split --gtest_filter at '-', if there is one, to separate into - // positive filter and negative filter portions - const char* const p = GTEST_FLAG(filter).c_str(); - const char* const dash = strchr(p, '-'); - std::string positive; - std::string negative; - if (dash == NULL) { - positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter - negative = ""; - } else { - positive = std::string(p, dash); // Everything up to the dash - negative = std::string(dash + 1); // Everything after the dash - if (positive.empty()) { - // Treat '-test1' as the same as '*-test1' - positive = kUniversalFilter; - } - } - - // A filter is a colon-separated list of patterns. It matches a - // test if any pattern in it matches the test. - return (MatchesFilter(full_name, positive.c_str()) && - !MatchesFilter(full_name, negative.c_str())); -} - -#if GTEST_HAS_SEH -// Returns EXCEPTION_EXECUTE_HANDLER if Google Test should handle the -// given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise. -// This function is useful as an __except condition. -int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) { - // Google Test should handle a SEH exception if: - // 1. the user wants it to, AND - // 2. this is not a breakpoint exception, AND - // 3. this is not a C++ exception (VC++ implements them via SEH, - // apparently). - // - // SEH exception code for C++ exceptions. - // (see http://support.microsoft.com/kb/185294 for more information). - const DWORD kCxxExceptionCode = 0xe06d7363; - - bool should_handle = true; - - if (!GTEST_FLAG(catch_exceptions)) - should_handle = false; - else if (exception_code == EXCEPTION_BREAKPOINT) - should_handle = false; - else if (exception_code == kCxxExceptionCode) - should_handle = false; - - return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; -} -#endif // GTEST_HAS_SEH - -} // namespace internal - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. Intercepts only failures from the current thread. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - TestPartResultArray* result) - : intercept_mode_(INTERCEPT_ONLY_CURRENT_THREAD), - result_(result) { - Init(); -} - -// The c'tor sets this object as the test part result reporter used by -// Google Test. The 'result' parameter specifies where to report the -// results. -ScopedFakeTestPartResultReporter::ScopedFakeTestPartResultReporter( - InterceptMode intercept_mode, TestPartResultArray* result) - : intercept_mode_(intercept_mode), - result_(result) { - Init(); -} - -void ScopedFakeTestPartResultReporter::Init() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - old_reporter_ = impl->GetGlobalTestPartResultReporter(); - impl->SetGlobalTestPartResultReporter(this); - } else { - old_reporter_ = impl->GetTestPartResultReporterForCurrentThread(); - impl->SetTestPartResultReporterForCurrentThread(this); - } -} - -// The d'tor restores the test part result reporter used by Google Test -// before. -ScopedFakeTestPartResultReporter::~ScopedFakeTestPartResultReporter() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - if (intercept_mode_ == INTERCEPT_ALL_THREADS) { - impl->SetGlobalTestPartResultReporter(old_reporter_); - } else { - impl->SetTestPartResultReporterForCurrentThread(old_reporter_); - } -} - -// Increments the test part result count and remembers the result. -// This method is from the TestPartResultReporterInterface interface. -void ScopedFakeTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - result_->Append(result); -} - -namespace internal { - -// Returns the type ID of ::testing::Test. We should always call this -// instead of GetTypeId< ::testing::Test>() to get the type ID of -// testing::Test. This is to work around a suspected linker bug when -// using Google Test as a framework on Mac OS X. The bug causes -// GetTypeId< ::testing::Test>() to return different values depending -// on whether the call is from the Google Test framework itself or -// from user test code. GetTestTypeId() is guaranteed to always -// return the same value, as it always calls GetTypeId<>() from the -// gtest.cc, which is within the Google Test framework. -TypeId GetTestTypeId() { - return GetTypeId(); -} - -// The value of GetTestTypeId() as seen from within the Google Test -// library. This is solely for testing GetTestTypeId(). -extern const TypeId kTestTypeIdInGoogleTest = GetTestTypeId(); - -// This predicate-formatter checks that 'results' contains a test part -// failure of the given type and that the failure message contains the -// given substring. -AssertionResult HasOneFailure(const char* /* results_expr */, - const char* /* type_expr */, - const char* /* substr_expr */, - const TestPartResultArray& results, - TestPartResult::Type type, - const string& substr) { - const std::string expected(type == TestPartResult::kFatalFailure ? - "1 fatal failure" : - "1 non-fatal failure"); - Message msg; - if (results.size() != 1) { - msg << "Expected: " << expected << "\n" - << " Actual: " << results.size() << " failures"; - for (int i = 0; i < results.size(); i++) { - msg << "\n" << results.GetTestPartResult(i); - } - return AssertionFailure() << msg; - } - - const TestPartResult& r = results.GetTestPartResult(0); - if (r.type() != type) { - return AssertionFailure() << "Expected: " << expected << "\n" - << " Actual:\n" - << r; - } - - if (strstr(r.message(), substr.c_str()) == NULL) { - return AssertionFailure() << "Expected: " << expected << " containing \"" - << substr << "\"\n" - << " Actual:\n" - << r; - } - - return AssertionSuccess(); -} - -// The constructor of SingleFailureChecker remembers where to look up -// test part results, what type of failure we expect, and what -// substring the failure message should contain. -SingleFailureChecker:: SingleFailureChecker( - const TestPartResultArray* results, - TestPartResult::Type type, - const string& substr) - : results_(results), - type_(type), - substr_(substr) {} - -// The destructor of SingleFailureChecker verifies that the given -// TestPartResultArray contains exactly one failure that has the given -// type and contains the given substring. If that's not the case, a -// non-fatal failure will be generated. -SingleFailureChecker::~SingleFailureChecker() { - EXPECT_PRED_FORMAT3(HasOneFailure, *results_, type_, substr_); -} - -DefaultGlobalTestPartResultReporter::DefaultGlobalTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultGlobalTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->current_test_result()->AddTestPartResult(result); - unit_test_->listeners()->repeater()->OnTestPartResult(result); -} - -DefaultPerThreadTestPartResultReporter::DefaultPerThreadTestPartResultReporter( - UnitTestImpl* unit_test) : unit_test_(unit_test) {} - -void DefaultPerThreadTestPartResultReporter::ReportTestPartResult( - const TestPartResult& result) { - unit_test_->GetGlobalTestPartResultReporter()->ReportTestPartResult(result); -} - -// Returns the global test part result reporter. -TestPartResultReporterInterface* -UnitTestImpl::GetGlobalTestPartResultReporter() { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - return global_test_part_result_repoter_; -} - -// Sets the global test part result reporter. -void UnitTestImpl::SetGlobalTestPartResultReporter( - TestPartResultReporterInterface* reporter) { - internal::MutexLock lock(&global_test_part_result_reporter_mutex_); - global_test_part_result_repoter_ = reporter; -} - -// Returns the test part result reporter for the current thread. -TestPartResultReporterInterface* -UnitTestImpl::GetTestPartResultReporterForCurrentThread() { - return per_thread_test_part_result_reporter_.get(); -} - -// Sets the test part result reporter for the current thread. -void UnitTestImpl::SetTestPartResultReporterForCurrentThread( - TestPartResultReporterInterface* reporter) { - per_thread_test_part_result_reporter_.set(reporter); -} - -// Gets the number of successful test cases. -int UnitTestImpl::successful_test_case_count() const { - return CountIf(test_cases_, TestCasePassed); -} - -// Gets the number of failed test cases. -int UnitTestImpl::failed_test_case_count() const { - return CountIf(test_cases_, TestCaseFailed); -} - -// Gets the number of all test cases. -int UnitTestImpl::total_test_case_count() const { - return static_cast(test_cases_.size()); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTestImpl::test_case_to_run_count() const { - return CountIf(test_cases_, ShouldRunTestCase); -} - -// Gets the number of successful tests. -int UnitTestImpl::successful_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::successful_test_count); -} - -// Gets the number of failed tests. -int UnitTestImpl::failed_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::failed_test_count); -} - -// Gets the number of disabled tests that will be reported in the XML report. -int UnitTestImpl::reportable_disabled_test_count() const { - return SumOverTestCaseList(test_cases_, - &TestCase::reportable_disabled_test_count); -} - -// Gets the number of disabled tests. -int UnitTestImpl::disabled_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::disabled_test_count); -} - -// Gets the number of tests to be printed in the XML report. -int UnitTestImpl::reportable_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::reportable_test_count); -} - -// Gets the number of all tests. -int UnitTestImpl::total_test_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::total_test_count); -} - -// Gets the number of tests that should run. -int UnitTestImpl::test_to_run_count() const { - return SumOverTestCaseList(test_cases_, &TestCase::test_to_run_count); -} - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// CurrentOsStackTraceExceptTop(1), Foo() will be included in the -// trace but Bar() and CurrentOsStackTraceExceptTop() won't. -std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { - (void)skip_count; - return ""; -} - -// Returns the current time in milliseconds. -TimeInMillis GetTimeInMillis() { -#if GTEST_OS_WINDOWS_MOBILE || defined(__BORLANDC__) - // Difference between 1970-01-01 and 1601-01-01 in milliseconds. - // http://analogous.blogspot.com/2005/04/epoch.html - const TimeInMillis kJavaEpochToWinFileTimeDelta = - static_cast(116444736UL) * 100000UL; - const DWORD kTenthMicrosInMilliSecond = 10000; - - SYSTEMTIME now_systime; - FILETIME now_filetime; - ULARGE_INTEGER now_int64; - // TODO(kenton@google.com): Shouldn't this just use - // GetSystemTimeAsFileTime()? - GetSystemTime(&now_systime); - if (SystemTimeToFileTime(&now_systime, &now_filetime)) { - now_int64.LowPart = now_filetime.dwLowDateTime; - now_int64.HighPart = now_filetime.dwHighDateTime; - now_int64.QuadPart = (now_int64.QuadPart / kTenthMicrosInMilliSecond) - - kJavaEpochToWinFileTimeDelta; - return now_int64.QuadPart; - } - return 0; -#elif GTEST_OS_WINDOWS && !GTEST_HAS_GETTIMEOFDAY_ - __timeb64 now; - -# ifdef _MSC_VER - - // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 - // (deprecated function) there. - // TODO(kenton@google.com): Use GetTickCount()? Or use - // SystemTimeToFileTime() -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996. - _ftime64(&now); -# pragma warning(pop) // Restores the warning state. -# else - - _ftime64(&now); - -# endif // _MSC_VER - - return static_cast(now.time) * 1000 + now.millitm; -#elif GTEST_HAS_GETTIMEOFDAY_ - struct timeval now; - gettimeofday(&now, NULL); - return static_cast(now.tv_sec) * 1000 + now.tv_usec / 1000; -#else -# error "Don't know how to get the current time on your system." -#endif -} - -// Utilities - -// class String. - -#if GTEST_OS_WINDOWS_MOBILE -// Creates a UTF-16 wide string from the given ANSI string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the wide string, or NULL if the -// input is NULL. -LPCWSTR String::AnsiToUtf16(const char* ansi) { - if (!ansi) return NULL; - const int length = strlen(ansi); - const int unicode_length = - MultiByteToWideChar(CP_ACP, 0, ansi, length, - NULL, 0); - WCHAR* unicode = new WCHAR[unicode_length + 1]; - MultiByteToWideChar(CP_ACP, 0, ansi, length, - unicode, unicode_length); - unicode[unicode_length] = 0; - return unicode; -} - -// Creates an ANSI string from the given wide string, allocating -// memory using new. The caller is responsible for deleting the return -// value using delete[]. Returns the ANSI string, or NULL if the -// input is NULL. -const char* String::Utf16ToAnsi(LPCWSTR utf16_str) { - if (!utf16_str) return NULL; - const int ansi_length = - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - NULL, 0, NULL, NULL); - char* ansi = new char[ansi_length + 1]; - WideCharToMultiByte(CP_ACP, 0, utf16_str, -1, - ansi, ansi_length, NULL, NULL); - ansi[ansi_length] = 0; - return ansi; -} - -#endif // GTEST_OS_WINDOWS_MOBILE - -// Compares two C strings. Returns true iff they have the same content. -// -// Unlike strcmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CStringEquals(const char * lhs, const char * rhs) { - if ( lhs == NULL ) return rhs == NULL; - - if ( rhs == NULL ) return false; - - return strcmp(lhs, rhs) == 0; -} - -#if GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -// Converts an array of wide chars to a narrow string using the UTF-8 -// encoding, and streams the result to the given Message object. -static void StreamWideCharsToMessage(const wchar_t* wstr, size_t length, - Message* msg) { - for (size_t i = 0; i != length; ) { // NOLINT - if (wstr[i] != L'\0') { - *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); - while (i != length && wstr[i] != L'\0') - i++; - } else { - *msg << '\0'; - i++; - } - } -} - -#endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING - -} // namespace internal - -// Constructs an empty Message. -// We allocate the stringstream separately because otherwise each use of -// ASSERT/EXPECT in a procedure adds over 200 bytes to the procedure's -// stack frame leading to huge stack frames in some cases; gcc does not reuse -// the stack space. -Message::Message() : ss_(new ::std::stringstream) { - // By default, we want there to be enough precision when printing - // a double to a Message. - *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); -} - -// These two overloads allow streaming a wide C string to a Message -// using the UTF-8 encoding. -Message& Message::operator <<(const wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); -} -Message& Message::operator <<(wchar_t* wide_c_str) { - return *this << internal::String::ShowWideCString(wide_c_str); -} - -#if GTEST_HAS_STD_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::std::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING -// Converts the given wide string to a narrow string using the UTF-8 -// encoding, and streams the result to this Message object. -Message& Message::operator <<(const ::wstring& wstr) { - internal::StreamWideCharsToMessage(wstr.c_str(), wstr.length(), this); - return *this; -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Gets the text streamed to this object so far as an std::string. -// Each '\0' character in the buffer is replaced with "\\0". -std::string Message::GetString() const { - return internal::StringStreamToString(ss_.get()); -} - -// AssertionResult constructors. -// Used in EXPECT_TRUE/FALSE(assertion_result). -AssertionResult::AssertionResult(const AssertionResult& other) - : success_(other.success_), - message_(other.message_.get() != NULL ? - new ::std::string(*other.message_) : - static_cast< ::std::string*>(NULL)) { -} - -// Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. -AssertionResult AssertionResult::operator!() const { - AssertionResult negation(!success_); - if (message_.get() != NULL) - negation << *message_; - return negation; -} - -// Makes a successful assertion result. -AssertionResult AssertionSuccess() { - return AssertionResult(true); -} - -// Makes a failed assertion result. -AssertionResult AssertionFailure() { - return AssertionResult(false); -} - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << message. -AssertionResult AssertionFailure(const Message& message) { - return AssertionFailure() << message; -} - -namespace internal { - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, - bool ignoring_case) { - Message msg; - msg << "Value of: " << actual_expression; - if (actual_value != actual_expression) { - msg << "\n Actual: " << actual_value; - } - - msg << "\nExpected: " << expected_expression; - if (ignoring_case) { - msg << " (ignoring case)"; - } - if (expected_value != expected_expression) { - msg << "\nWhich is: " << expected_value; - } - - return AssertionFailure() << msg; -} - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value) { - const char* actual_message = assertion_result.message(); - Message msg; - msg << "Value of: " << expression_text - << "\n Actual: " << actual_predicate_value; - if (actual_message[0] != '\0') - msg << " (" << actual_message << ")"; - msg << "\nExpected: " << expected_predicate_value; - return msg.GetString(); -} - -// Helper function for implementing ASSERT_NEAR. -AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error) { - const double diff = fabs(val1 - val2); - if (diff <= abs_error) return AssertionSuccess(); - - // TODO(wan): do not print the value of an expression if it's - // already a literal. - return AssertionFailure() - << "The difference between " << expr1 << " and " << expr2 - << " is " << diff << ", which exceeds " << abs_error_expr << ", where\n" - << expr1 << " evaluates to " << val1 << ",\n" - << expr2 << " evaluates to " << val2 << ", and\n" - << abs_error_expr << " evaluates to " << abs_error << "."; -} - - -// Helper template for implementing FloatLE() and DoubleLE(). -template -AssertionResult FloatingPointLE(const char* expr1, - const char* expr2, - RawType val1, - RawType val2) { - // Returns success if val1 is less than val2, - if (val1 < val2) { - return AssertionSuccess(); - } - - // or if val1 is almost equal to val2. - const FloatingPoint lhs(val1), rhs(val2); - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - // Note that the above two checks will both fail if either val1 or - // val2 is NaN, as the IEEE floating-point standard requires that - // any predicate involving a NaN must return false. - - ::std::stringstream val1_ss; - val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val1; - - ::std::stringstream val2_ss; - val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << val2; - - return AssertionFailure() - << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" - << " Actual: " << StringStreamToString(&val1_ss) << " vs " - << StringStreamToString(&val2_ss); -} - -} // namespace internal - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2) { - return internal::FloatingPointLE(expr1, expr2, val1, val2); -} - -namespace internal { - -// The helper function for {ASSERT|EXPECT}_EQ with int or enum -// arguments. -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - if (expected == actual) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_?? with integer or enum arguments. It is here -// just to avoid copy-and-paste of similar code. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - BiggestInt val1, BiggestInt val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - }\ -} - -// Implements the helper function for {ASSERT|EXPECT}_NE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(NE, !=) -// Implements the helper function for {ASSERT|EXPECT}_LE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LE, <=) -// Implements the helper function for {ASSERT|EXPECT}_LT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(LT, < ) -// Implements the helper function for {ASSERT|EXPECT}_GE with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GE, >=) -// Implements the helper function for {ASSERT|EXPECT}_GT with int or -// enum arguments. -GTEST_IMPL_CMP_HELPER_(GT, > ) - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - false); -} - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual) { - if (String::CaseInsensitiveCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - true); -} - -// The helper function for {ASSERT|EXPECT}_STRNE. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2) { - if (!String::CaseInsensitiveCStringEquals(s1, s2)) { - return AssertionSuccess(); - } else { - return AssertionFailure() - << "Expected: (" << s1_expression << ") != (" - << s2_expression << ") (ignoring case), actual: \"" - << s1 << "\" vs \"" << s2 << "\""; - } -} - -} // namespace internal - -namespace { - -// Helper functions for implementing IsSubString() and IsNotSubstring(). - -// This group of overloaded functions return true iff needle is a -// substring of haystack. NULL is considered a substring of itself -// only. - -bool IsSubstringPred(const char* needle, const char* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return strstr(haystack, needle) != NULL; -} - -bool IsSubstringPred(const wchar_t* needle, const wchar_t* haystack) { - if (needle == NULL || haystack == NULL) - return needle == haystack; - - return wcsstr(haystack, needle) != NULL; -} - -// StringType here can be either ::std::string or ::std::wstring. -template -bool IsSubstringPred(const StringType& needle, - const StringType& haystack) { - return haystack.find(needle) != StringType::npos; -} - -// This function implements either IsSubstring() or IsNotSubstring(), -// depending on the value of the expected_to_be_substring parameter. -// StringType here can be const char*, const wchar_t*, ::std::string, -// or ::std::wstring. -template -AssertionResult IsSubstringImpl( - bool expected_to_be_substring, - const char* needle_expr, const char* haystack_expr, - const StringType& needle, const StringType& haystack) { - if (IsSubstringPred(needle, haystack) == expected_to_be_substring) - return AssertionSuccess(); - - const bool is_wide_string = sizeof(needle[0]) > 1; - const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; - return AssertionFailure() - << "Value of: " << needle_expr << "\n" - << " Actual: " << begin_string_quote << needle << "\"\n" - << "Expected: " << (expected_to_be_substring ? "" : "not ") - << "a substring of " << haystack_expr << "\n" - << "Which is: " << begin_string_quote << haystack << "\""; -} - -} // namespace - -// IsSubstring() and IsNotSubstring() check whether needle is a -// substring of haystack (NULL is considered a substring of itself -// only), and return an appropriate error message when they fail. - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} - -#if GTEST_HAS_STD_WSTRING -AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(true, needle_expr, haystack_expr, needle, haystack); -} - -AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack) { - return IsSubstringImpl(false, needle_expr, haystack_expr, needle, haystack); -} -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -#if GTEST_OS_WINDOWS - -namespace { - -// Helper function for IsHRESULT{SuccessFailure} predicates -AssertionResult HRESULTFailureHelper(const char* expr, - const char* expected, - long hr) { // NOLINT -# if GTEST_OS_WINDOWS_MOBILE - - // Windows CE doesn't support FormatMessage. - const char error_text[] = ""; - -# else - - // Looks up the human-readable system message for the HRESULT code - // and since we're not passing any params to FormatMessage, we don't - // want inserts expanded. - const DWORD kFlags = FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS; - const DWORD kBufSize = 4096; - // Gets the system's human readable message string for this HRESULT. - char error_text[kBufSize] = { '\0' }; - DWORD message_length = ::FormatMessageA(kFlags, - 0, // no source, we're asking system - hr, // the error - 0, // no line width restrictions - error_text, // output buffer - kBufSize, // buf size - NULL); // no arguments for inserts - // Trims tailing white space (FormatMessage leaves a trailing CR-LF) - for (; message_length && IsSpace(error_text[message_length - 1]); - --message_length) { - error_text[message_length - 1] = '\0'; - } - -# endif // GTEST_OS_WINDOWS_MOBILE - - const std::string error_hex("0x" + String::FormatHexInt(hr)); - return ::testing::AssertionFailure() - << "Expected: " << expr << " " << expected << ".\n" - << " Actual: " << error_hex << " " << error_text << "\n"; -} - -} // namespace - -AssertionResult IsHRESULTSuccess(const char* expr, long hr) { // NOLINT - if (SUCCEEDED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "succeeds", hr); -} - -AssertionResult IsHRESULTFailure(const char* expr, long hr) { // NOLINT - if (FAILED(hr)) { - return AssertionSuccess(); - } - return HRESULTFailureHelper(expr, "fails", hr); -} - -#endif // GTEST_OS_WINDOWS - -// Utility functions for encoding Unicode text (wide strings) in -// UTF-8. - -// A Unicode code-point can have upto 21 bits, and is encoded in UTF-8 -// like this: -// -// Code-point length Encoding -// 0 - 7 bits 0xxxxxxx -// 8 - 11 bits 110xxxxx 10xxxxxx -// 12 - 16 bits 1110xxxx 10xxxxxx 10xxxxxx -// 17 - 21 bits 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx - -// The maximum code-point a one-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint1 = (static_cast(1) << 7) - 1; - -// The maximum code-point a two-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; - -// The maximum code-point a three-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; - -// The maximum code-point a four-byte UTF-8 sequence can represent. -const UInt32 kMaxCodePoint4 = (static_cast(1) << (3 + 3*6)) - 1; - -// Chops off the n lowest bits from a bit pattern. Returns the n -// lowest bits. As a side effect, the original bit pattern will be -// shifted to the right by n bits. -inline UInt32 ChopLowBits(UInt32* bits, int n) { - const UInt32 low_bits = *bits & ((static_cast(1) << n) - 1); - *bits >>= n; - return low_bits; -} - -// Converts a Unicode code point to a narrow string in UTF-8 encoding. -// code_point parameter is of type UInt32 because wchar_t may not be -// wide enough to contain a code point. -// If the code_point is not a valid Unicode code point -// (i.e. outside of Unicode range U+0 to U+10FFFF) it will be converted -// to "(Invalid Unicode 0xXXXXXXXX)". -std::string CodePointToUtf8(UInt32 code_point) { - if (code_point > kMaxCodePoint4) { - return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; - } - - char str[5]; // Big enough for the largest valid code point. - if (code_point <= kMaxCodePoint1) { - str[1] = '\0'; - str[0] = static_cast(code_point); // 0xxxxxxx - } else if (code_point <= kMaxCodePoint2) { - str[2] = '\0'; - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xC0 | code_point); // 110xxxxx - } else if (code_point <= kMaxCodePoint3) { - str[3] = '\0'; - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xE0 | code_point); // 1110xxxx - } else { // code_point <= kMaxCodePoint4 - str[4] = '\0'; - str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx - str[0] = static_cast(0xF0 | code_point); // 11110xxx - } - return str; -} - -// The following two functions only make sense if the the system -// uses UTF-16 for wide string encoding. All supported systems -// with 16 bit wchar_t (Windows, Cygwin, Symbian OS) do use UTF-16. - -// Determines if the arguments constitute UTF-16 surrogate pair -// and thus should be combined into a single Unicode code point -// using CreateCodePointFromUtf16SurrogatePair. -inline bool IsUtf16SurrogatePair(wchar_t first, wchar_t second) { - return sizeof(wchar_t) == 2 && - (first & 0xFC00) == 0xD800 && (second & 0xFC00) == 0xDC00; -} - -// Creates a Unicode code point from UTF16 surrogate pair. -inline UInt32 CreateCodePointFromUtf16SurrogatePair(wchar_t first, - wchar_t second) { - const UInt32 mask = (1 << 10) - 1; - return (sizeof(wchar_t) == 2) ? - (((first & mask) << 10) | (second & mask)) + 0x10000 : - // This function should not be called when the condition is - // false, but we provide a sensible default in case it is. - static_cast(first); -} - -// Converts a wide string to a narrow string in UTF-8 encoding. -// The wide string is assumed to have the following encoding: -// UTF-16 if sizeof(wchar_t) == 2 (on Windows, Cygwin, Symbian OS) -// UTF-32 if sizeof(wchar_t) == 4 (on Linux) -// Parameter str points to a null-terminated wide string. -// Parameter num_chars may additionally limit the number -// of wchar_t characters processed. -1 is used when the entire string -// should be processed. -// If the string contains code points that are not valid Unicode code points -// (i.e. outside of Unicode range U+0 to U+10FFFF) they will be output -// as '(Invalid Unicode 0xXXXXXXXX)'. If the string is in UTF16 encoding -// and contains invalid UTF-16 surrogate pairs, values in those pairs -// will be encoded as individual Unicode characters from Basic Normal Plane. -std::string WideStringToUtf8(const wchar_t* str, int num_chars) { - if (num_chars == -1) - num_chars = static_cast(wcslen(str)); - - ::std::stringstream stream; - for (int i = 0; i < num_chars; ++i) { - UInt32 unicode_code_point; - - if (str[i] == L'\0') { - break; - } else if (i + 1 < num_chars && IsUtf16SurrogatePair(str[i], str[i + 1])) { - unicode_code_point = CreateCodePointFromUtf16SurrogatePair(str[i], - str[i + 1]); - i++; - } else { - unicode_code_point = static_cast(str[i]); - } - - stream << CodePointToUtf8(unicode_code_point); - } - return StringStreamToString(&stream); -} - -// Converts a wide C string to an std::string using the UTF-8 encoding. -// NULL will be converted to "(null)". -std::string String::ShowWideCString(const wchar_t * wide_c_str) { - if (wide_c_str == NULL) return "(null)"; - - return internal::WideStringToUtf8(wide_c_str, -1); -} - -// Compares two wide C strings. Returns true iff they have the same -// content. -// -// Unlike wcscmp(), this function can handle NULL argument(s). A NULL -// C string is considered different to any non-NULL C string, -// including the empty string. -bool String::WideCStringEquals(const wchar_t * lhs, const wchar_t * rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - - return wcscmp(lhs, rhs) == 0; -} - -// Helper function for *_STREQ on wide strings. -AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual) { - if (String::WideCStringEquals(expected, actual)) { - return AssertionSuccess(); - } - - return EqFailure(expected_expression, - actual_expression, - PrintToString(expected), - PrintToString(actual), - false); -} - -// Helper function for *_STRNE on wide strings. -AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2) { - if (!String::WideCStringEquals(s1, s2)) { - return AssertionSuccess(); - } - - return AssertionFailure() << "Expected: (" << s1_expression << ") != (" - << s2_expression << "), actual: " - << PrintToString(s1) - << " vs " << PrintToString(s2); -} - -// Compares two C strings, ignoring case. Returns true iff they have -// the same content. -// -// Unlike strcasecmp(), this function can handle NULL argument(s). A -// NULL C string is considered different to any non-NULL C string, -// including the empty string. -bool String::CaseInsensitiveCStringEquals(const char * lhs, const char * rhs) { - if (lhs == NULL) - return rhs == NULL; - if (rhs == NULL) - return false; - return posix::StrCaseCmp(lhs, rhs) == 0; -} - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. -bool String::CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs) { - if (lhs == NULL) return rhs == NULL; - - if (rhs == NULL) return false; - -#if GTEST_OS_WINDOWS - return _wcsicmp(lhs, rhs) == 0; -#elif GTEST_OS_LINUX && !GTEST_OS_LINUX_ANDROID - return wcscasecmp(lhs, rhs) == 0; -#else - // Android, Mac OS X and Cygwin don't define wcscasecmp. - // Other unknown OSes may not define it either. - wint_t left, right; - do { - left = towlower(*lhs++); - right = towlower(*rhs++); - } while (left && left == right); - return left == right; -#endif // OS selector -} - -// Returns true iff str ends with the given suffix, ignoring case. -// Any string is considered to end with an empty suffix. -bool String::EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix) { - const size_t str_len = str.length(); - const size_t suffix_len = suffix.length(); - return (str_len >= suffix_len) && - CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, - suffix.c_str()); -} - -// Formats an int value as "%02d". -std::string String::FormatIntWidth2(int value) { - std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << value; - return ss.str(); -} - -// Formats an int value as "%X". -std::string String::FormatHexInt(int value) { - std::stringstream ss; - ss << std::hex << std::uppercase << value; - return ss.str(); -} - -// Formats a byte as "%02X". -std::string String::FormatByte(unsigned char value) { - std::stringstream ss; - ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase - << static_cast(value); - return ss.str(); -} - -// Converts the buffer in a stringstream to an std::string, converting NUL -// bytes to "\\0" along the way. -std::string StringStreamToString(::std::stringstream* ss) { - const ::std::string& str = ss->str(); - const char* const start = str.c_str(); - const char* const end = start + str.length(); - - std::string result; - result.reserve(2 * (end - start)); - for (const char* ch = start; ch != end; ++ch) { - if (*ch == '\0') { - result += "\\0"; // Replaces NUL with "\\0"; - } else { - result += *ch; - } - } - - return result; -} - -// Appends the user-supplied message to the Google-Test-generated message. -std::string AppendUserMessage(const std::string& gtest_msg, - const Message& user_msg) { - // Appends the user message if it's non-empty. - const std::string user_msg_string = user_msg.GetString(); - if (user_msg_string.empty()) { - return gtest_msg; - } - - return gtest_msg + "\n" + user_msg_string; -} - -} // namespace internal - -// class TestResult - -// Creates an empty TestResult. -TestResult::TestResult() - : death_test_count_(0), - elapsed_time_(0) { -} - -// D'tor. -TestResult::~TestResult() { -} - -// Returns the i-th test part result among all the results. i can -// range from 0 to total_part_count() - 1. If i is not in that range, -// aborts the program. -const TestPartResult& TestResult::GetTestPartResult(int i) const { - if (i < 0 || i >= total_part_count()) - internal::posix::Abort(); - return test_part_results_.at(i); -} - -// Returns the i-th test property. i can range from 0 to -// test_property_count() - 1. If i is not in that range, aborts the -// program. -const TestProperty& TestResult::GetTestProperty(int i) const { - if (i < 0 || i >= test_property_count()) - internal::posix::Abort(); - return test_properties_.at(i); -} - -// Clears the test part results. -void TestResult::ClearTestPartResults() { - test_part_results_.clear(); -} - -// Adds a test part result to the list. -void TestResult::AddTestPartResult(const TestPartResult& test_part_result) { - test_part_results_.push_back(test_part_result); -} - -// Adds a test property to the list. If a property with the same key as the -// supplied property is already represented, the value of this test_property -// replaces the old value for that key. -void TestResult::RecordProperty(const std::string& xml_element, - const TestProperty& test_property) { - if (!ValidateTestProperty(xml_element, test_property)) { - return; - } - internal::MutexLock lock(&test_properites_mutex_); - const std::vector::iterator property_with_matching_key = - std::find_if(test_properties_.begin(), test_properties_.end(), - internal::TestPropertyKeyIs(test_property.key())); - if (property_with_matching_key == test_properties_.end()) { - test_properties_.push_back(test_property); - return; - } - property_with_matching_key->SetValue(test_property.value()); -} - -// The list of reserved attributes used in the element of XML -// output. -static const char* const kReservedTestSuitesAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "random_seed", - "tests", - "time", - "timestamp" -}; - -// The list of reserved attributes used in the element of XML -// output. -static const char* const kReservedTestSuiteAttributes[] = { - "disabled", - "errors", - "failures", - "name", - "tests", - "time" -}; - -// The list of reserved attributes used in the element of XML output. -static const char* const kReservedTestCaseAttributes[] = { - "classname", - "name", - "status", - "time", - "type_param", - "value_param" -}; - -template -std::vector ArrayAsVector(const char* const (&array)[kSize]) { - return std::vector(array, array + kSize); -} - -static std::vector GetReservedAttributesForElement( - const std::string& xml_element) { - if (xml_element == "testsuites") { - return ArrayAsVector(kReservedTestSuitesAttributes); - } else if (xml_element == "testsuite") { - return ArrayAsVector(kReservedTestSuiteAttributes); - } else if (xml_element == "testcase") { - return ArrayAsVector(kReservedTestCaseAttributes); - } else { - GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; - } - // This code is unreachable but some compilers may not realizes that. - return std::vector(); -} - -static std::string FormatWordList(const std::vector& words) { - Message word_list; - for (size_t i = 0; i < words.size(); ++i) { - if (i > 0 && words.size() > 2) { - word_list << ", "; - } - if (i == words.size() - 1) { - word_list << "and "; - } - word_list << "'" << words[i] << "'"; - } - return word_list.GetString(); -} - -bool ValidateTestPropertyName(const std::string& property_name, - const std::vector& reserved_names) { - if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != - reserved_names.end()) { - ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name - << " (" << FormatWordList(reserved_names) - << " are reserved by " << GTEST_NAME_ << ")"; - return false; - } - return true; -} - -// Adds a failure if the key is a reserved attribute of the element named -// xml_element. Returns true if the property is valid. -bool TestResult::ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property) { - return ValidateTestPropertyName(test_property.key(), - GetReservedAttributesForElement(xml_element)); -} - -// Clears the object. -void TestResult::Clear() { - test_part_results_.clear(); - test_properties_.clear(); - death_test_count_ = 0; - elapsed_time_ = 0; -} - -// Returns true iff the test failed. -bool TestResult::Failed() const { - for (int i = 0; i < total_part_count(); ++i) { - if (GetTestPartResult(i).failed()) - return true; - } - return false; -} - -// Returns true iff the test part fatally failed. -static bool TestPartFatallyFailed(const TestPartResult& result) { - return result.fatally_failed(); -} - -// Returns true iff the test fatally failed. -bool TestResult::HasFatalFailure() const { - return CountIf(test_part_results_, TestPartFatallyFailed) > 0; -} - -// Returns true iff the test part non-fatally failed. -static bool TestPartNonfatallyFailed(const TestPartResult& result) { - return result.nonfatally_failed(); -} - -// Returns true iff the test has a non-fatal failure. -bool TestResult::HasNonfatalFailure() const { - return CountIf(test_part_results_, TestPartNonfatallyFailed) > 0; -} - -// Gets the number of all test parts. This is the sum of the number -// of successful test parts and the number of failed test parts. -int TestResult::total_part_count() const { - return static_cast(test_part_results_.size()); -} - -// Returns the number of the test properties. -int TestResult::test_property_count() const { - return static_cast(test_properties_.size()); -} - -// class Test - -// Creates a Test object. - -// The c'tor saves the values of all Google Test flags. -Test::Test() - : gtest_flag_saver_(new internal::GTestFlagSaver) { -} - -// The d'tor restores the values of all Google Test flags. -Test::~Test() { - delete gtest_flag_saver_; -} - -// Sets up the test fixture. -// -// A sub-class may override this. -void Test::SetUp() { -} - -// Tears down the test fixture. -// -// A sub-class may override this. -void Test::TearDown() { -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, const std::string& value) { - UnitTest::GetInstance()->RecordProperty(key, value); -} - -// Allows user supplied key value pairs to be recorded for later output. -void Test::RecordProperty(const std::string& key, int value) { - Message value_message; - value_message << value; - RecordProperty(key, value_message.GetString().c_str()); -} - -namespace internal { - -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message) { - // This function is a friend of UnitTest and as such has access to - // AddTestPartResult. - UnitTest::GetInstance()->AddTestPartResult( - result_type, - NULL, // No info about the source file where the exception occurred. - -1, // We have no info on which line caused the exception. - message, - ""); // No stack trace, either. -} - -} // namespace internal - -// Google Test requires all tests in the same test case to use the same test -// fixture class. This function checks if the current test has the -// same fixture class as the first test in the current test case. If -// yes, it returns true; otherwise it generates a Google Test failure and -// returns false. -bool Test::HasSameFixtureClass() { - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - const TestCase* const test_case = impl->current_test_case(); - - // Info about the first test in the current test case. - const TestInfo* const first_test_info = test_case->test_info_list()[0]; - const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_; - const char* const first_test_name = first_test_info->name(); - - // Info about the current test. - const TestInfo* const this_test_info = impl->current_test_info(); - const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_; - const char* const this_test_name = this_test_info->name(); - - if (this_fixture_id != first_fixture_id) { - // Is the first test defined using TEST? - const bool first_is_TEST = first_fixture_id == internal::GetTestTypeId(); - // Is this test defined using TEST? - const bool this_is_TEST = this_fixture_id == internal::GetTestTypeId(); - - if (first_is_TEST || this_is_TEST) { - // The user mixed TEST and TEST_F in this test case - we'll tell - // him/her how to fix it. - - // Gets the name of the TEST and the name of the TEST_F. Note - // that first_is_TEST and this_is_TEST cannot both be true, as - // the fixture IDs are different for the two tests. - const char* const TEST_name = - first_is_TEST ? first_test_name : this_test_name; - const char* const TEST_F_name = - first_is_TEST ? this_test_name : first_test_name; - - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class, so mixing TEST_F and TEST in the same test case is\n" - << "illegal. In test case " << this_test_info->test_case_name() - << ",\n" - << "test " << TEST_F_name << " is defined using TEST_F but\n" - << "test " << TEST_name << " is defined using TEST. You probably\n" - << "want to change the TEST to TEST_F or move it to another test\n" - << "case."; - } else { - // The user defined two fixture classes with the same name in - // two namespaces - we'll tell him/her how to fix it. - ADD_FAILURE() - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " - << this_test_info->test_case_name() << ",\n" - << "you defined test " << first_test_name - << " and test " << this_test_name << "\n" - << "using two different test fixture classes. This can happen if\n" - << "the two classes are from different namespaces or translation\n" - << "units and have the same name. You should probably rename one\n" - << "of the classes to put the tests into different test cases."; - } - return false; - } - - return true; -} - -#if GTEST_HAS_SEH - -// Adds an "exception thrown" fatal failure to the current test. This -// function returns its result via an output parameter pointer because VC++ -// prohibits creation of objects with destructors on stack in functions -// using __try (see error C2712). -static std::string* FormatSehExceptionMessage(DWORD exception_code, - const char* location) { - Message message; - message << "SEH exception with code 0x" << std::setbase(16) << - exception_code << std::setbase(10) << " thrown in " << location << "."; - - return new std::string(message.GetString()); -} - -#endif // GTEST_HAS_SEH - -namespace internal { - -#if GTEST_HAS_EXCEPTIONS - -// Adds an "exception thrown" fatal failure to the current test. -static std::string FormatCxxExceptionMessage(const char* description, - const char* location) { - Message message; - if (description != NULL) { - message << "C++ exception with description \"" << description << "\""; - } else { - message << "Unknown C++ exception"; - } - message << " thrown in " << location << "."; - - return message.GetString(); -} - -static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result); - -GoogleTestFailureException::GoogleTestFailureException( - const TestPartResult& failure) - : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} - -#endif // GTEST_HAS_EXCEPTIONS - -// We put these helper functions in the internal namespace as IBM's xlC -// compiler rejects the code if they were declared static. - -// Runs the given method and handles SEH exceptions it throws, when -// SEH is supported; returns the 0-value for type Result in case of an -// SEH exception. (Microsoft compilers cannot handle SEH and C++ -// exceptions in the same function. Therefore, we provide a separate -// wrapper function for handling SEH exceptions.) -template -Result HandleSehExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { -#if GTEST_HAS_SEH - __try { - return (object->*method)(); - } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT - GetExceptionCode())) { - // We create the exception message on the heap because VC++ prohibits - // creation of objects with destructors on stack in functions using __try - // (see error C2712). - std::string* exception_message = FormatSehExceptionMessage( - GetExceptionCode(), location); - internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, - *exception_message); - delete exception_message; - return static_cast(0); - } -#else - (void)location; - return (object->*method)(); -#endif // GTEST_HAS_SEH -} - -// Runs the given method and catches and reports C++ and/or SEH-style -// exceptions, if they are supported; returns the 0-value for type -// Result in case of an SEH exception. -template -Result HandleExceptionsInMethodIfSupported( - T* object, Result (T::*method)(), const char* location) { - // NOTE: The user code can affect the way in which Google Test handles - // exceptions by setting GTEST_FLAG(catch_exceptions), but only before - // RUN_ALL_TESTS() starts. It is technically possible to check the flag - // after the exception is caught and either report or re-throw the - // exception based on the flag's value: - // - // try { - // // Perform the test method. - // } catch (...) { - // if (GTEST_FLAG(catch_exceptions)) - // // Report the exception as failure. - // else - // throw; // Re-throws the original exception. - // } - // - // However, the purpose of this flag is to allow the program to drop into - // the debugger when the exception is thrown. On most platforms, once the - // control enters the catch block, the exception origin information is - // lost and the debugger will stop the program at the point of the - // re-throw in this function -- instead of at the point of the original - // throw statement in the code under test. For this reason, we perform - // the check early, sacrificing the ability to affect Google Test's - // exception handling in the method where the exception is thrown. - if (internal::GetUnitTestImpl()->catch_exceptions()) { -#if GTEST_HAS_EXCEPTIONS - try { - return HandleSehExceptionsInMethodIfSupported(object, method, location); - } catch (const internal::GoogleTestFailureException&) { // NOLINT - // This exception type can only be thrown by a failed Google - // Test assertion with the intention of letting another testing - // framework catch it. Therefore we just re-throw it. - throw; - } catch (const std::exception& e) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(e.what(), location)); - } catch (...) { // NOLINT - internal::ReportFailureInUnknownLocation( - TestPartResult::kFatalFailure, - FormatCxxExceptionMessage(NULL, location)); - } - return static_cast(0); -#else - return HandleSehExceptionsInMethodIfSupported(object, method, location); -#endif // GTEST_HAS_EXCEPTIONS - } else { - return (object->*method)(); - } -} - -} // namespace internal - -// Runs the test and updates the test result. -void Test::Run() { - if (!HasSameFixtureClass()) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); - // We will run the test only if SetUp() was successful. - if (!HasFatalFailure()) { - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TestBody, "the test body"); - } - - // However, we want to clean up as much as possible. Hence we will - // always call TearDown(), even if SetUp() or the test body has - // failed. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &Test::TearDown, "TearDown()"); -} - -// Returns true iff the current test has a fatal failure. -bool Test::HasFatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure(); -} - -// Returns true iff the current test has a non-fatal failure. -bool Test::HasNonfatalFailure() { - return internal::GetUnitTestImpl()->current_test_result()-> - HasNonfatalFailure(); -} - -// class TestInfo - -// Constructs a TestInfo object. It assumes ownership of the test factory -// object. -TestInfo::TestInfo(const std::string& a_test_case_name, - const std::string& a_name, - const char* a_type_param, - const char* a_value_param, - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory) - : test_case_name_(a_test_case_name), - name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - value_param_(a_value_param ? new std::string(a_value_param) : NULL), - fixture_class_id_(fixture_class_id), - should_run_(false), - is_disabled_(false), - matches_filter_(false), - factory_(factory), - result_() {} - -// Destructs a TestInfo object. -TestInfo::~TestInfo() { delete factory_; } - -namespace internal { - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// type_param: the name of the test's type parameter, or NULL if -// this is not a typed or a type-parameterized test. -// value_param: text representation of the test's value parameter, -// or NULL if this is not a value-parameterized test. -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory) { - TestInfo* const test_info = - new TestInfo(test_case_name, name, type_param, value_param, - fixture_class_id, factory); - GetUnitTestImpl()->AddTestInfo(set_up_tc, tear_down_tc, test_info); - return test_info; -} - -#if GTEST_HAS_PARAM_TEST -void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line) { - Message errors; - errors - << "Attempted redefinition of test case " << test_case_name << ".\n" - << "All tests in the same test case must use the same test fixture\n" - << "class. However, in test case " << test_case_name << ", you tried\n" - << "to define a test using a fixture class different from the one\n" - << "used earlier. This can happen if the two fixture classes are\n" - << "from different namespaces and have the same name. You should\n" - << "probably rename one of the classes to put the tests into different\n" - << "test cases."; - - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors.GetString().c_str()); -} -#endif // GTEST_HAS_PARAM_TEST - -} // namespace internal - -namespace { - -// A predicate that checks the test name of a TestInfo against a known -// value. -// -// This is used for implementation of the TestCase class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestNameIs is copyable. - -//Commenting out this class since its not used and wherefor produces warnings -// class TestNameIs { -// public: -// // Constructor. -// // -// // TestNameIs has NO default constructor. -// explicit TestNameIs(const char* name) -// : name_(name) {} -// -// // Returns true iff the test name of test_info matches name_. -// bool operator()(const TestInfo * test_info) const { -// return test_info && test_info->name() == name_; -// } -// -// private: -// std::string name_; -//}; - -} // namespace - -namespace internal { - -// This method expands all parameterized tests registered with macros TEST_P -// and INSTANTIATE_TEST_CASE_P into regular tests and registers those. -// This will be done just once during the program runtime. -void UnitTestImpl::RegisterParameterizedTests() { -#if GTEST_HAS_PARAM_TEST - if (!parameterized_tests_registered_) { - parameterized_test_registry_.RegisterTests(); - parameterized_tests_registered_ = true; - } -#endif -} - -} // namespace internal - -// Creates the test object, runs it, records its result, and then -// deletes it. -void TestInfo::Run() { - if (!should_run_) return; - - // Tells UnitTest where to store test result. - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_info(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - // Notifies the unit test event listeners that a test is about to start. - repeater->OnTestStart(*this); - - const TimeInMillis start = internal::GetTimeInMillis(); - - impl->os_stack_trace_getter()->UponLeavingGTest(); - - // Creates the test object. - Test* const test = internal::HandleExceptionsInMethodIfSupported( - factory_, &internal::TestFactoryBase::CreateTest, - "the test fixture's constructor"); - - // Runs the test only if the test object was created and its - // constructor didn't generate a fatal failure. - if ((test != NULL) && !Test::HasFatalFailure()) { - // This doesn't throw as all user code that can throw are wrapped into - // exception handling code. - test->Run(); - } - - // Deletes the test object. - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - test, &Test::DeleteSelf_, "the test fixture's destructor"); - - result_.set_elapsed_time(internal::GetTimeInMillis() - start); - - // Notifies the unit test event listener that a test has just finished. - repeater->OnTestEnd(*this); - - // Tells UnitTest to stop associating assertion results to this - // test. - impl->set_current_test_info(NULL); -} - -// class TestCase - -// Gets the number of successful tests in this test case. -int TestCase::successful_test_count() const { - return CountIf(test_info_list_, TestPassed); -} - -// Gets the number of failed tests in this test case. -int TestCase::failed_test_count() const { - return CountIf(test_info_list_, TestFailed); -} - -// Gets the number of disabled tests that will be reported in the XML report. -int TestCase::reportable_disabled_test_count() const { - return CountIf(test_info_list_, TestReportableDisabled); -} - -// Gets the number of disabled tests in this test case. -int TestCase::disabled_test_count() const { - return CountIf(test_info_list_, TestDisabled); -} - -// Gets the number of tests to be printed in the XML report. -int TestCase::reportable_test_count() const { - return CountIf(test_info_list_, TestReportable); -} - -// Get the number of tests in this test case that should run. -int TestCase::test_to_run_count() const { - return CountIf(test_info_list_, ShouldRunTest); -} - -// Gets the number of all tests. -int TestCase::total_test_count() const { - return static_cast(test_info_list_.size()); -} - -// Creates a TestCase with the given name. -// -// Arguments: -// -// name: name of the test case -// a_type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase::TestCase(const char* a_name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) - : name_(a_name), - type_param_(a_type_param ? new std::string(a_type_param) : NULL), - set_up_tc_(set_up_tc), - tear_down_tc_(tear_down_tc), - should_run_(false), - elapsed_time_(0) { -} - -// Destructor of TestCase. -TestCase::~TestCase() { - // Deletes every Test in the collection. - ForEach(test_info_list_, internal::Delete); -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -const TestInfo* TestCase::GetTestInfo(int i) const { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Returns the i-th test among all the tests. i can range from 0 to -// total_test_count() - 1. If i is not in that range, returns NULL. -TestInfo* TestCase::GetMutableTestInfo(int i) { - const int index = GetElementOr(test_indices_, i, -1); - return index < 0 ? NULL : test_info_list_[index]; -} - -// Adds a test to this test case. Will delete the test upon -// destruction of the TestCase object. -void TestCase::AddTestInfo(TestInfo * test_info) { - test_info_list_.push_back(test_info); - test_indices_.push_back(static_cast(test_indices_.size())); -} - -// Runs every test in this TestCase. -void TestCase::Run() { - if (!should_run_) return; - - internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); - impl->set_current_test_case(this); - - TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); - - repeater->OnTestCaseStart(*this); - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); - - const internal::TimeInMillis start = internal::GetTimeInMillis(); - for (int i = 0; i < total_test_count(); i++) { - GetMutableTestInfo(i)->Run(); - } - elapsed_time_ = internal::GetTimeInMillis() - start; - - impl->os_stack_trace_getter()->UponLeavingGTest(); - internal::HandleExceptionsInMethodIfSupported( - this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); - - repeater->OnTestCaseEnd(*this); - impl->set_current_test_case(NULL); -} - -// Clears the results of all tests in this test case. -void TestCase::ClearResult() { - ad_hoc_test_result_.Clear(); - ForEach(test_info_list_, TestInfo::ClearTestResult); -} - -// Shuffles the tests in this test case. -void TestCase::ShuffleTests(internal::Random* random) { - Shuffle(random, &test_indices_); -} - -// Restores the test order to before the first shuffle. -void TestCase::UnshuffleTests() { - for (size_t i = 0; i < test_indices_.size(); i++) { - test_indices_[i] = static_cast(i); - } -} - -// Formats a countable noun. Depending on its quantity, either the -// singular form or the plural form is used. e.g. -// -// FormatCountableNoun(1, "formula", "formuli") returns "1 formula". -// FormatCountableNoun(5, "book", "books") returns "5 books". -static std::string FormatCountableNoun(int count, - const char * singular_form, - const char * plural_form) { - return internal::StreamableToString(count) + " " + - (count == 1 ? singular_form : plural_form); -} - -// Formats the count of tests. -static std::string FormatTestCount(int test_count) { - return FormatCountableNoun(test_count, "test", "tests"); -} - -// Formats the count of test cases. -static std::string FormatTestCaseCount(int test_case_count) { - return FormatCountableNoun(test_case_count, "test case", "test cases"); -} - -// Converts a TestPartResult::Type enum to human-friendly string -// representation. Both kNonFatalFailure and kFatalFailure are translated -// to "Failure", as the user usually doesn't care about the difference -// between the two when viewing the test result. -static const char * TestPartResultTypeToString(TestPartResult::Type type) { - switch (type) { - case TestPartResult::kSuccess: - return "Success"; - - case TestPartResult::kNonFatalFailure: - case TestPartResult::kFatalFailure: -#ifdef _MSC_VER - return "error: "; -#else - return "Failure\n"; -#endif - default: - return "Unknown result type"; - } -} - -namespace internal { - -// Prints a TestPartResult to an std::string. -static std::string PrintTestPartResultToString( - const TestPartResult& test_part_result) { - return (Message() - << internal::FormatFileLocation(test_part_result.file_name(), - test_part_result.line_number()) - << " " << TestPartResultTypeToString(test_part_result.type()) - << test_part_result.message()).GetString(); -} - -// Prints a TestPartResult. -static void PrintTestPartResult(const TestPartResult& test_part_result) { - const std::string& result = - PrintTestPartResultToString(test_part_result); - printf("%s\n", result.c_str()); - fflush(stdout); - // If the test program runs in Visual Studio or a debugger, the - // following statements add the test part result message to the Output - // window such that the user can double-click on it to jump to the - // corresponding source code location; otherwise they do nothing. -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - // We don't call OutputDebugString*() on Windows Mobile, as printing - // to stdout is done by OutputDebugString() there already - we don't - // want the same message printed twice. - ::OutputDebugStringA(result.c_str()); - ::OutputDebugStringA("\n"); -#endif -} - -// class PrettyUnitTestResultPrinter - -enum GTestColor { - COLOR_DEFAULT, - COLOR_RED, - COLOR_GREEN, - COLOR_YELLOW -}; - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns the character attribute for the given color. -WORD GetColorAttribute(GTestColor color) { - switch (color) { - case COLOR_RED: return FOREGROUND_RED; - case COLOR_GREEN: return FOREGROUND_GREEN; - case COLOR_YELLOW: return FOREGROUND_RED | FOREGROUND_GREEN; - default: return 0; - } -} - -#else - -// Returns the ANSI color code for the given color. COLOR_DEFAULT is -// an invalid input. -const char* GetAnsiColorCode(GTestColor color) { - switch (color) { - case COLOR_RED: return "1"; - case COLOR_GREEN: return "2"; - case COLOR_YELLOW: return "3"; - default: return NULL; - }; -} - -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - -// Returns true iff Google Test should use colors in the output. -bool ShouldUseColor(bool stdout_is_tty) { - const char* const gtest_color = GTEST_FLAG(color).c_str(); - - if (String::CaseInsensitiveCStringEquals(gtest_color, "auto")) { -#if GTEST_OS_WINDOWS - // On Windows the TERM variable is usually not set, but the - // console there does support colors. - return stdout_is_tty; -#else - // On non-Windows platforms, we rely on the TERM variable. - const char* const term = posix::GetEnv("TERM"); - const bool term_supports_color = - String::CStringEquals(term, "xterm") || - String::CStringEquals(term, "xterm-color") || - String::CStringEquals(term, "xterm-256color") || - String::CStringEquals(term, "screen") || - String::CStringEquals(term, "screen-256color") || - String::CStringEquals(term, "linux") || - String::CStringEquals(term, "cygwin"); - return stdout_is_tty && term_supports_color; -#endif // GTEST_OS_WINDOWS - } - - return String::CaseInsensitiveCStringEquals(gtest_color, "yes") || - String::CaseInsensitiveCStringEquals(gtest_color, "true") || - String::CaseInsensitiveCStringEquals(gtest_color, "t") || - String::CStringEquals(gtest_color, "1"); - // We take "yes", "true", "t", and "1" as meaning "yes". If the - // value is neither one of these nor "auto", we treat it as "no" to - // be conservative. -} - -// Helpers for printing colored strings to stdout. Note that on Windows, we -// cannot simply emit special characters and have the terminal change colors. -// This routine must actually emit the characters rather than return a string -// that would be colored when printed, as can be done on Linux. -void ColoredPrintf(GTestColor color, const char* fmt, ...) { - va_list args; - va_start(args, fmt); - -#if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS || GTEST_OS_IOS - const bool use_color = false; -#else - static const bool in_color_mode = - ShouldUseColor(posix::IsATTY(posix::FileNo(stdout)) != 0); - const bool use_color = in_color_mode && (color != COLOR_DEFAULT); -#endif // GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || GTEST_OS_ZOS - // The '!= 0' comparison is necessary to satisfy MSVC 7.1. - - if (!use_color) { - vprintf(fmt, args); - va_end(args); - return; - } - -#if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - const HANDLE stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE); - - // Gets the current text color. - CONSOLE_SCREEN_BUFFER_INFO buffer_info; - GetConsoleScreenBufferInfo(stdout_handle, &buffer_info); - const WORD old_color_attrs = buffer_info.wAttributes; - - // We need to flush the stream buffers into the console before each - // SetConsoleTextAttribute call lest it affect the text that is already - // printed but has not yet reached the console. - fflush(stdout); - SetConsoleTextAttribute(stdout_handle, - GetColorAttribute(color) | FOREGROUND_INTENSITY); - vprintf(fmt, args); - - fflush(stdout); - // Restores the text color. - SetConsoleTextAttribute(stdout_handle, old_color_attrs); -#else - printf("\033[0;3%sm", GetAnsiColorCode(color)); - vprintf(fmt, args); - printf("\033[m"); // Resets the terminal to default. -#endif // GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE - va_end(args); -} - -// Text printed in Google Test's text output and --gunit_list_tests -// output to label the type parameter and value parameter for a test. -static const char kTypeParamLabel[] = "TypeParam"; -static const char kValueParamLabel[] = "GetParam()"; - -void PrintFullTestCommentIfPresent(const TestInfo& test_info) { - const char* const type_param = test_info.type_param(); - const char* const value_param = test_info.value_param(); - - if (type_param != NULL || value_param != NULL) { - printf(", where "); - if (type_param != NULL) { - printf("%s = %s", kTypeParamLabel, type_param); - if (value_param != NULL) - printf(" and "); - } - if (value_param != NULL) { - printf("%s = %s", kValueParamLabel, value_param); - } - } -} - -// This class implements the TestEventListener interface. -// -// Class PrettyUnitTestResultPrinter is copyable. -class PrettyUnitTestResultPrinter : public TestEventListener { - public: - PrettyUnitTestResultPrinter() {} - static void PrintTestName(const char * test_case, const char * test) { - printf("%s.%s", test_case, test); - } - - // The following methods override what's in the TestEventListener class. - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} - - private: - static void PrintFailedTests(const UnitTest& unit_test); -}; - - // Fired before each iteration of tests starts. -void PrettyUnitTestResultPrinter::OnTestIterationStart( - const UnitTest& unit_test, int iteration) { - if (GTEST_FLAG(repeat) != 1) - printf("\nRepeating all tests (iteration %d) . . .\n\n", iteration + 1); - - const char* const filter = GTEST_FLAG(filter).c_str(); - - // Prints the filter if it's not *. This reminds the user that some - // tests may be skipped. - if (!String::CStringEquals(filter, kUniversalFilter)) { - ColoredPrintf(COLOR_YELLOW, - "Note: %s filter = %s\n", GTEST_NAME_, filter); - } - - if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { - const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); - ColoredPrintf(COLOR_YELLOW, - "Note: This is test shard %d of %s.\n", - static_cast(shard_index) + 1, - internal::posix::GetEnv(kTestTotalShards)); - } - - if (GTEST_FLAG(shuffle)) { - ColoredPrintf(COLOR_YELLOW, - "Note: Randomizing tests' orders with a seed of %d .\n", - unit_test.random_seed()); - } - - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("Running %s from %s.\n", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsSetUpStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment set-up.\n"); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseStart(const TestCase& test_case) { - const std::string counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s", counts.c_str(), test_case.name()); - if (test_case.type_param() == NULL) { - printf("\n"); - } else { - printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { - ColoredPrintf(COLOR_GREEN, "[ RUN ] "); - PrintTestName(test_info.test_case_name(), test_info.name()); - printf("\n"); - fflush(stdout); -} - -// Called after an assertion failure. -void PrettyUnitTestResultPrinter::OnTestPartResult( - const TestPartResult& result) { - // If the test part succeeded, we don't need to do anything. - if (result.type() == TestPartResult::kSuccess) - return; - - // Print failure message from the assertion (e.g. expected this and got that). - PrintTestPartResult(result); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestEnd(const TestInfo& test_info) { - if (test_info.result()->Passed()) { - ColoredPrintf(COLOR_GREEN, "[ OK ] "); - } else { - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - } - PrintTestName(test_info.test_case_name(), test_info.name()); - if (test_info.result()->Failed()) - PrintFullTestCommentIfPresent(test_info); - - if (GTEST_FLAG(print_time)) { - printf(" (%s ms)\n", internal::StreamableToString( - test_info.result()->elapsed_time()).c_str()); - } else { - printf("\n"); - } - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnTestCaseEnd(const TestCase& test_case) { - if (!GTEST_FLAG(print_time)) return; - - const std::string counts = - FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("%s from %s (%s ms total)\n\n", - counts.c_str(), test_case.name(), - internal::StreamableToString(test_case.elapsed_time()).c_str()); - fflush(stdout); -} - -void PrettyUnitTestResultPrinter::OnEnvironmentsTearDownStart( - const UnitTest& /*unit_test*/) { - ColoredPrintf(COLOR_GREEN, "[----------] "); - printf("Global test environment tear-down\n"); - fflush(stdout); -} - -// Internal helper for printing the list of failed tests. -void PrettyUnitTestResultPrinter::PrintFailedTests(const UnitTest& unit_test) { - const int failed_test_count = unit_test.failed_test_count(); - if (failed_test_count == 0) { - return; - } - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - const TestCase& test_case = *unit_test.GetTestCase(i); - if (!test_case.should_run() || (test_case.failed_test_count() == 0)) { - continue; - } - for (int j = 0; j < test_case.total_test_count(); ++j) { - const TestInfo& test_info = *test_case.GetTestInfo(j); - if (!test_info.should_run() || test_info.result()->Passed()) { - continue; - } - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s.%s", test_case.name(), test_info.name()); - PrintFullTestCommentIfPresent(test_info); - printf("\n"); - } - } -} - -void PrettyUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - ColoredPrintf(COLOR_GREEN, "[==========] "); - printf("%s from %s ran.", - FormatTestCount(unit_test.test_to_run_count()).c_str(), - FormatTestCaseCount(unit_test.test_case_to_run_count()).c_str()); - if (GTEST_FLAG(print_time)) { - printf(" (%s ms total)", - internal::StreamableToString(unit_test.elapsed_time()).c_str()); - } - printf("\n"); - ColoredPrintf(COLOR_GREEN, "[ PASSED ] "); - printf("%s.\n", FormatTestCount(unit_test.successful_test_count()).c_str()); - - int num_failures = unit_test.failed_test_count(); - if (!unit_test.Passed()) { - const int failed_test_count = unit_test.failed_test_count(); - ColoredPrintf(COLOR_RED, "[ FAILED ] "); - printf("%s, listed below:\n", FormatTestCount(failed_test_count).c_str()); - PrintFailedTests(unit_test); - printf("\n%2d FAILED %s\n", num_failures, - num_failures == 1 ? "TEST" : "TESTS"); - } - - int num_disabled = unit_test.reportable_disabled_test_count(); - if (num_disabled && !GTEST_FLAG(also_run_disabled_tests)) { - if (!num_failures) { - printf("\n"); // Add a spacer if no FAILURE banner is displayed. - } - ColoredPrintf(COLOR_YELLOW, - " YOU HAVE %d DISABLED %s\n\n", - num_disabled, - num_disabled == 1 ? "TEST" : "TESTS"); - } - // Ensure that Google Test output is printed before, e.g., heapchecker output. - fflush(stdout); -} - -// End PrettyUnitTestResultPrinter - -// class TestEventRepeater -// -// This class forwards events to other event listeners. -class TestEventRepeater : public TestEventListener { - public: - TestEventRepeater() : forwarding_enabled_(true) {} - virtual ~TestEventRepeater(); - void Append(TestEventListener *listener); - TestEventListener* Release(TestEventListener* listener); - - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled() const { return forwarding_enabled_; } - void set_forwarding_enabled(bool enable) { forwarding_enabled_ = enable; } - - virtual void OnTestProgramStart(const UnitTest& unit_test); - virtual void OnTestIterationStart(const UnitTest& unit_test, int iteration); - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test); - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test); - virtual void OnTestCaseStart(const TestCase& test_case); - virtual void OnTestStart(const TestInfo& test_info); - virtual void OnTestPartResult(const TestPartResult& result); - virtual void OnTestEnd(const TestInfo& test_info); - virtual void OnTestCaseEnd(const TestCase& test_case); - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test); - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test); - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - virtual void OnTestProgramEnd(const UnitTest& unit_test); - - private: - // Controls whether events will be forwarded to listeners_. Set to false - // in death test child processes. - bool forwarding_enabled_; - // The list of listeners that receive events. - std::vector listeners_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); -}; - -TestEventRepeater::~TestEventRepeater() { - ForEach(listeners_, Delete); -} - -void TestEventRepeater::Append(TestEventListener *listener) { - listeners_.push_back(listener); -} - -// TODO(vladl@google.com): Factor the search functionality into Vector::Find. -TestEventListener* TestEventRepeater::Release(TestEventListener *listener) { - for (size_t i = 0; i < listeners_.size(); ++i) { - if (listeners_[i] == listener) { - listeners_.erase(listeners_.begin() + i); - return listener; - } - } - - return NULL; -} - -// Since most methods are very similar, use macros to reduce boilerplate. -// This defines a member that forwards the call to all listeners. -#define GTEST_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (size_t i = 0; i < listeners_.size(); i++) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} -// This defines a member that forwards the call to all listeners in reverse -// order. -#define GTEST_REVERSE_REPEATER_METHOD_(Name, Type) \ -void TestEventRepeater::Name(const Type& parameter) { \ - if (forwarding_enabled_) { \ - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { \ - listeners_[i]->Name(parameter); \ - } \ - } \ -} - -GTEST_REPEATER_METHOD_(OnTestProgramStart, UnitTest) -GTEST_REPEATER_METHOD_(OnEnvironmentsSetUpStart, UnitTest) -GTEST_REPEATER_METHOD_(OnTestCaseStart, TestCase) -GTEST_REPEATER_METHOD_(OnTestStart, TestInfo) -GTEST_REPEATER_METHOD_(OnTestPartResult, TestPartResult) -GTEST_REPEATER_METHOD_(OnEnvironmentsTearDownStart, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsSetUpEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnEnvironmentsTearDownEnd, UnitTest) -GTEST_REVERSE_REPEATER_METHOD_(OnTestEnd, TestInfo) -GTEST_REVERSE_REPEATER_METHOD_(OnTestCaseEnd, TestCase) -GTEST_REVERSE_REPEATER_METHOD_(OnTestProgramEnd, UnitTest) - -#undef GTEST_REPEATER_METHOD_ -#undef GTEST_REVERSE_REPEATER_METHOD_ - -void TestEventRepeater::OnTestIterationStart(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (size_t i = 0; i < listeners_.size(); i++) { - listeners_[i]->OnTestIterationStart(unit_test, iteration); - } - } -} - -void TestEventRepeater::OnTestIterationEnd(const UnitTest& unit_test, - int iteration) { - if (forwarding_enabled_) { - for (int i = static_cast(listeners_.size()) - 1; i >= 0; i--) { - listeners_[i]->OnTestIterationEnd(unit_test, iteration); - } - } -} - -// End TestEventRepeater - -// This class generates an XML output file. -class XmlUnitTestResultPrinter : public EmptyTestEventListener { - public: - explicit XmlUnitTestResultPrinter(const char* output_file); - - virtual void OnTestIterationEnd(const UnitTest& unit_test, int iteration); - - private: - // Is c a whitespace character that is normalized to a space character - // when it appears in an XML attribute value? - static bool IsNormalizableWhitespace(char c) { - return c == 0x9 || c == 0xA || c == 0xD; - } - - // May c appear in a well-formed XML document? - static bool IsValidXmlCharacter(char c) { - return IsNormalizableWhitespace(c) || c >= 0x20; - } - - // Returns an XML-escaped copy of the input string str. If - // is_attribute is true, the text is meant to appear as an attribute - // value, and normalizable whitespace is preserved by replacing it - // with character references. - static std::string EscapeXml(const std::string& str, bool is_attribute); - - // Returns the given string with all characters invalid in XML removed. - static std::string RemoveInvalidXmlCharacters(const std::string& str); - - // Convenience wrapper around EscapeXml when str is an attribute value. - static std::string EscapeXmlAttribute(const std::string& str) { - return EscapeXml(str, true); - } - - // Convenience wrapper around EscapeXml when str is not an attribute value. - static std::string EscapeXmlText(const char* str) { - return EscapeXml(str, false); - } - - // Verifies that the given attribute belongs to the given element and - // streams the attribute as XML. - static void OutputXmlAttribute(std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value); - - // Streams an XML CDATA section, escaping invalid CDATA sequences as needed. - static void OutputXmlCDataSection(::std::ostream* stream, const char* data); - - // Streams an XML representation of a TestInfo object. - static void OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info); - - // Prints an XML representation of a TestCase object - static void PrintXmlTestCase(::std::ostream* stream, - const TestCase& test_case); - - // Prints an XML summary of unit_test to output stream out. - static void PrintXmlUnitTest(::std::ostream* stream, - const UnitTest& unit_test); - - // Produces a string representing the test properties in a result as space - // delimited XML attributes based on the property key="value" pairs. - // When the std::string is not empty, it includes a space at the beginning, - // to delimit this attribute from prior attributes. - static std::string TestPropertiesAsXmlAttributes(const TestResult& result); - - // The output file. - const std::string output_file_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(XmlUnitTestResultPrinter); -}; - -// Creates a new XmlUnitTestResultPrinter. -XmlUnitTestResultPrinter::XmlUnitTestResultPrinter(const char* output_file) - : output_file_(output_file) { - if (output_file_.c_str() == NULL || output_file_.empty()) { - fprintf(stderr, "XML output file may not be null\n"); - fflush(stderr); - exit(EXIT_FAILURE); - } -} - -// Called after the unit test ends. -void XmlUnitTestResultPrinter::OnTestIterationEnd(const UnitTest& unit_test, - int /*iteration*/) { - FILE* xmlout = NULL; - FilePath output_file(output_file_); - FilePath output_dir(output_file.RemoveFileName()); - - if (output_dir.CreateDirectoriesRecursively()) { - xmlout = posix::FOpen(output_file_.c_str(), "w"); - } - if (xmlout == NULL) { - // TODO(wan): report the reason of the failure. - // - // We don't do it for now as: - // - // 1. There is no urgent need for it. - // 2. It's a bit involved to make the errno variable thread-safe on - // all three operating systems (Linux, Windows, and Mac OS). - // 3. To interpret the meaning of errno in a thread-safe way, - // we need the strerror_r() function, which is not available on - // Windows. - fprintf(stderr, - "Unable to open file \"%s\"\n", - output_file_.c_str()); - fflush(stderr); - exit(EXIT_FAILURE); - } - std::stringstream stream; - PrintXmlUnitTest(&stream, unit_test); - fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); - fclose(xmlout); -} - -// Returns an XML-escaped copy of the input string str. If is_attribute -// is true, the text is meant to appear as an attribute value, and -// normalizable whitespace is preserved by replacing it with character -// references. -// -// Invalid XML characters in str, if any, are stripped from the output. -// It is expected that most, if not all, of the text processed by this -// module will consist of ordinary English text. -// If this module is ever modified to produce version 1.1 XML output, -// most invalid characters can be retained using character references. -// TODO(wan): It might be nice to have a minimally invasive, human-readable -// escaping scheme for invalid characters, rather than dropping them. -std::string XmlUnitTestResultPrinter::EscapeXml( - const std::string& str, bool is_attribute) { - Message m; - - for (size_t i = 0; i < str.size(); ++i) { - const char ch = str[i]; - switch (ch) { - case '<': - m << "<"; - break; - case '>': - m << ">"; - break; - case '&': - m << "&"; - break; - case '\'': - if (is_attribute) - m << "'"; - else - m << '\''; - break; - case '"': - if (is_attribute) - m << """; - else - m << '"'; - break; - default: - if (IsValidXmlCharacter(ch)) { - if (is_attribute && IsNormalizableWhitespace(ch)) - m << "&#x" << String::FormatByte(static_cast(ch)) - << ";"; - else - m << ch; - } - break; - } - } - - return m.GetString(); -} - -// Returns the given string with all characters invalid in XML removed. -// Currently invalid characters are dropped from the string. An -// alternative is to replace them with certain characters such as . or ?. -std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( - const std::string& str) { - std::string output; - output.reserve(str.size()); - for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) - if (IsValidXmlCharacter(*it)) - output.push_back(*it); - - return output; -} - -// The following routines generate an XML representation of a UnitTest -// object. -// -// This is how Google Test concepts map to the DTD: -// -// <-- corresponds to a UnitTest object -// <-- corresponds to a TestCase object -// <-- corresponds to a TestInfo object -// ... -// ... -// ... -// <-- individual assertion failures -// -// -// - -// Formats the given time in milliseconds as seconds. -std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { - ::std::stringstream ss; - ss << ms/1000.0; - return ss.str(); -} - -// Converts the given epoch time in milliseconds to a date string in the ISO -// 8601 format, without the timezone information. -std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { - // Using non-reentrant version as localtime_r is not portable. - time_t seconds = static_cast(ms / 1000); -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4996) // Temporarily disables warning 4996 - // (function or variable may be unsafe). - const struct tm* const time_struct = localtime(&seconds); // NOLINT -# pragma warning(pop) // Restores the warning state again. -#else - const struct tm* const time_struct = localtime(&seconds); // NOLINT -#endif - if (time_struct == NULL) - return ""; // Invalid ms value - - // YYYY-MM-DDThh:mm:ss - return StreamableToString(time_struct->tm_year + 1900) + "-" + - String::FormatIntWidth2(time_struct->tm_mon + 1) + "-" + - String::FormatIntWidth2(time_struct->tm_mday) + "T" + - String::FormatIntWidth2(time_struct->tm_hour) + ":" + - String::FormatIntWidth2(time_struct->tm_min) + ":" + - String::FormatIntWidth2(time_struct->tm_sec); -} - -// Streams an XML CDATA section, escaping invalid CDATA sequences as needed. -void XmlUnitTestResultPrinter::OutputXmlCDataSection(::std::ostream* stream, - const char* data) { - const char* segment = data; - *stream << ""); - if (next_segment != NULL) { - stream->write( - segment, static_cast(next_segment - segment)); - *stream << "]]>]]>"); - } else { - *stream << segment; - break; - } - } - *stream << "]]>"; -} - -void XmlUnitTestResultPrinter::OutputXmlAttribute( - std::ostream* stream, - const std::string& element_name, - const std::string& name, - const std::string& value) { - const std::vector& allowed_names = - GetReservedAttributesForElement(element_name); - - GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != - allowed_names.end()) - << "Attribute " << name << " is not allowed for element <" << element_name - << ">."; - - *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; -} - -// Prints an XML representation of a TestInfo object. -// TODO(wan): There is also value in printing properties with the plain printer. -void XmlUnitTestResultPrinter::OutputXmlTestInfo(::std::ostream* stream, - const char* test_case_name, - const TestInfo& test_info) { - const TestResult& result = *test_info.result(); - const std::string kTestcase = "testcase"; - - *stream << " \n"; - } - const string location = internal::FormatCompilerIndependentFileLocation( - part.file_name(), part.line_number()); - const string summary = location + "\n" + part.summary(); - *stream << " "; - const string detail = location + "\n" + part.message(); - OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); - *stream << "\n"; - } - } - - if (failures == 0) - *stream << " />\n"; - else - *stream << " \n"; -} - -// Prints an XML representation of a TestCase object -void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, - const TestCase& test_case) { - const std::string kTestsuite = "testsuite"; - *stream << " <" << kTestsuite; - OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); - OutputXmlAttribute(stream, kTestsuite, "tests", - StreamableToString(test_case.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuite, "failures", - StreamableToString(test_case.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuite, "disabled", - StreamableToString(test_case.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuite, "errors", "0"); - OutputXmlAttribute(stream, kTestsuite, "time", - FormatTimeInMillisAsSeconds(test_case.elapsed_time())); - *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) - << ">\n"; - - for (int i = 0; i < test_case.total_test_count(); ++i) { - if (test_case.GetTestInfo(i)->is_reportable()) - OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); - } - *stream << " \n"; -} - -// Prints an XML summary of unit_test to output stream out. -void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, - const UnitTest& unit_test) { - const std::string kTestsuites = "testsuites"; - - *stream << "\n"; - *stream << "<" << kTestsuites; - - OutputXmlAttribute(stream, kTestsuites, "tests", - StreamableToString(unit_test.reportable_test_count())); - OutputXmlAttribute(stream, kTestsuites, "failures", - StreamableToString(unit_test.failed_test_count())); - OutputXmlAttribute( - stream, kTestsuites, "disabled", - StreamableToString(unit_test.reportable_disabled_test_count())); - OutputXmlAttribute(stream, kTestsuites, "errors", "0"); - OutputXmlAttribute( - stream, kTestsuites, "timestamp", - FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); - OutputXmlAttribute(stream, kTestsuites, "time", - FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); - - if (GTEST_FLAG(shuffle)) { - OutputXmlAttribute(stream, kTestsuites, "random_seed", - StreamableToString(unit_test.random_seed())); - } - - *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); - - OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); - *stream << ">\n"; - - for (int i = 0; i < unit_test.total_test_case_count(); ++i) { - if (unit_test.GetTestCase(i)->reportable_test_count() > 0) - PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); - } - *stream << "\n"; -} - -// Produces a string representing the test properties in a result as space -// delimited XML attributes based on the property key="value" pairs. -std::string XmlUnitTestResultPrinter::TestPropertiesAsXmlAttributes( - const TestResult& result) { - Message attributes; - for (int i = 0; i < result.test_property_count(); ++i) { - const TestProperty& property = result.GetTestProperty(i); - attributes << " " << property.key() << "=" - << "\"" << EscapeXmlAttribute(property.value()) << "\""; - } - return attributes.GetString(); -} - -// End XmlUnitTestResultPrinter - -#if GTEST_CAN_STREAM_RESULTS_ - -// Checks if str contains '=', '&', '%' or '\n' characters. If yes, -// replaces them by "%xx" where xx is their hexadecimal value. For -// example, replaces "=" with "%3D". This algorithm is O(strlen(str)) -// in both time and space -- important as the input str may contain an -// arbitrarily long test failure message and stack trace. -string StreamingListener::UrlEncode(const char* str) { - string result; - result.reserve(strlen(str) + 1); - for (char ch = *str; ch != '\0'; ch = *++str) { - switch (ch) { - case '%': - case '=': - case '&': - case '\n': - result.append("%" + String::FormatByte(static_cast(ch))); - break; - default: - result.push_back(ch); - break; - } - } - return result; -} - -void StreamingListener::SocketWriter::MakeConnection() { - GTEST_CHECK_(sockfd_ == -1) - << "MakeConnection() can't be called when there is already a connection."; - - addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. - hints.ai_socktype = SOCK_STREAM; - addrinfo* servinfo = NULL; - - // Use the getaddrinfo() to get a linked list of IP addresses for - // the given host name. - const int error_num = getaddrinfo( - host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); - if (error_num != 0) { - GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " - << gai_strerror(error_num); - } - - // Loop through all the results and connect to the first we can. - for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; - cur_addr = cur_addr->ai_next) { - sockfd_ = socket( - cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); - if (sockfd_ != -1) { - // Connect the client socket to the server socket. - if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { - close(sockfd_); - sockfd_ = -1; - } - } - } - - freeaddrinfo(servinfo); // all done with this structure - - if (sockfd_ == -1) { - GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " - << host_name_ << ":" << port_num_; - } -} - -// End of class Streaming Listener -#endif // GTEST_CAN_STREAM_RESULTS__ - -// Class ScopedTrace - -// Pushes the given source file location and message onto a per-thread -// trace stack maintained by Google Test. -ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - TraceInfo trace; - trace.file = file; - trace.line = line; - trace.message = message.GetString(); - - UnitTest::GetInstance()->PushGTestTrace(trace); -} - -// Pops the info pushed by the c'tor. -ScopedTrace::~ScopedTrace() - GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { - UnitTest::GetInstance()->PopGTestTrace(); -} - - -// class OsStackTraceGetter - -// Returns the current OS stack trace as an std::string. Parameters: -// -// max_depth - the maximum number of stack frames to be included -// in the trace. -// skip_count - the number of top frames to be skipped; doesn't count -// against max_depth. -// -string OsStackTraceGetter::CurrentStackTrace(int /* max_depth */, - int /* skip_count */) - GTEST_LOCK_EXCLUDED_(mutex_) { - return ""; -} - -void OsStackTraceGetter::UponLeavingGTest() - GTEST_LOCK_EXCLUDED_(mutex_) { -} - -const char* const -OsStackTraceGetter::kElidedFramesMarker = - "... " GTEST_NAME_ " internal frames ..."; - -// A helper class that creates the premature-exit file in its -// constructor and deletes the file in its destructor. -class ScopedPrematureExitFile { - public: - explicit ScopedPrematureExitFile(const char* premature_exit_filepath) - : premature_exit_filepath_(premature_exit_filepath) { - // If a path to the premature-exit file is specified... - if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { - // create the file with a single "0" character in it. I/O - // errors are ignored as there's nothing better we can do and we - // don't want to fail the test because of this. - FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); - fwrite("0", 1, 1, pfile); - fclose(pfile); - } - } - - ~ScopedPrematureExitFile() { - if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { - remove(premature_exit_filepath_); - } - } - - private: - const char* const premature_exit_filepath_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); -}; - -} // namespace internal - -// class TestEventListeners - -TestEventListeners::TestEventListeners() - : repeater_(new internal::TestEventRepeater()), - default_result_printer_(NULL), - default_xml_generator_(NULL) { -} - -TestEventListeners::~TestEventListeners() { delete repeater_; } - -// Returns the standard listener responsible for the default console -// output. Can be removed from the listeners list to shut down default -// console output. Note that removing this object from the listener list -// with Release transfers its ownership to the user. -void TestEventListeners::Append(TestEventListener* listener) { - repeater_->Append(listener); -} - -// Removes the given event listener from the list and returns it. It then -// becomes the caller's responsibility to delete the listener. Returns -// NULL if the listener is not found in the list. -TestEventListener* TestEventListeners::Release(TestEventListener* listener) { - if (listener == default_result_printer_) - default_result_printer_ = NULL; - else if (listener == default_xml_generator_) - default_xml_generator_ = NULL; - return repeater_->Release(listener); -} - -// Returns repeater that broadcasts the TestEventListener events to all -// subscribers. -TestEventListener* TestEventListeners::repeater() { return repeater_; } - -// Sets the default_result_printer attribute to the provided listener. -// The listener is also added to the listener list and previous -// default_result_printer is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultResultPrinter(TestEventListener* listener) { - if (default_result_printer_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_result_printer_); - default_result_printer_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Sets the default_xml_generator attribute to the provided listener. The -// listener is also added to the listener list and previous -// default_xml_generator is removed from it and deleted. The listener can -// also be NULL in which case it will not be added to the list. Does -// nothing if the previous and the current listener objects are the same. -void TestEventListeners::SetDefaultXmlGenerator(TestEventListener* listener) { - if (default_xml_generator_ != listener) { - // It is an error to pass this method a listener that is already in the - // list. - delete Release(default_xml_generator_); - default_xml_generator_ = listener; - if (listener != NULL) - Append(listener); - } -} - -// Controls whether events will be forwarded by the repeater to the -// listeners in the list. -bool TestEventListeners::EventForwardingEnabled() const { - return repeater_->forwarding_enabled(); -} - -void TestEventListeners::SuppressEventForwarding() { - repeater_->set_forwarding_enabled(false); -} - -// class UnitTest - -// Gets the singleton UnitTest object. The first time this method is -// called, a UnitTest object is constructed and returned. Consecutive -// calls will return the same object. -// -// We don't protect this under mutex_ as a user is not supposed to -// call this before main() starts, from which point on the return -// value will never change. -UnitTest* UnitTest::GetInstance() { - // When compiled with MSVC 7.1 in optimized mode, destroying the - // UnitTest object upon exiting the program messes up the exit code, - // causing successful tests to appear failed. We have to use a - // different implementation in this case to bypass the compiler bug. - // This implementation makes the compiler happy, at the cost of - // leaking the UnitTest object. - - // CodeGear C++Builder insists on a public destructor for the - // default implementation. Use this implementation to keep good OO - // design with private destructor. - -#if (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) - static UnitTest* const instance = new UnitTest; - return instance; -#else - static UnitTest instance; - return &instance; -#endif // (_MSC_VER == 1310 && !defined(_DEBUG)) || defined(__BORLANDC__) -} - -// Gets the number of successful test cases. -int UnitTest::successful_test_case_count() const { - return impl()->successful_test_case_count(); -} - -// Gets the number of failed test cases. -int UnitTest::failed_test_case_count() const { - return impl()->failed_test_case_count(); -} - -// Gets the number of all test cases. -int UnitTest::total_test_case_count() const { - return impl()->total_test_case_count(); -} - -// Gets the number of all test cases that contain at least one test -// that should run. -int UnitTest::test_case_to_run_count() const { - return impl()->test_case_to_run_count(); -} - -// Gets the number of successful tests. -int UnitTest::successful_test_count() const { - return impl()->successful_test_count(); -} - -// Gets the number of failed tests. -int UnitTest::failed_test_count() const { return impl()->failed_test_count(); } - -// Gets the number of disabled tests that will be reported in the XML report. -int UnitTest::reportable_disabled_test_count() const { - return impl()->reportable_disabled_test_count(); -} - -// Gets the number of disabled tests. -int UnitTest::disabled_test_count() const { - return impl()->disabled_test_count(); -} - -// Gets the number of tests to be printed in the XML report. -int UnitTest::reportable_test_count() const { - return impl()->reportable_test_count(); -} - -// Gets the number of all tests. -int UnitTest::total_test_count() const { return impl()->total_test_count(); } - -// Gets the number of tests that should run. -int UnitTest::test_to_run_count() const { return impl()->test_to_run_count(); } - -// Gets the time of the test program start, in ms from the start of the -// UNIX epoch. -internal::TimeInMillis UnitTest::start_timestamp() const { - return impl()->start_timestamp(); -} - -// Gets the elapsed time, in milliseconds. -internal::TimeInMillis UnitTest::elapsed_time() const { - return impl()->elapsed_time(); -} - -// Returns true iff the unit test passed (i.e. all test cases passed). -bool UnitTest::Passed() const { return impl()->Passed(); } - -// Returns true iff the unit test failed (i.e. some test case failed -// or something outside of all tests failed). -bool UnitTest::Failed() const { return impl()->Failed(); } - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -const TestCase* UnitTest::GetTestCase(int i) const { - return impl()->GetTestCase(i); -} - -// Returns the TestResult containing information on test failures and -// properties logged outside of individual test cases. -const TestResult& UnitTest::ad_hoc_test_result() const { - return *impl()->ad_hoc_test_result(); -} - -// Gets the i-th test case among all the test cases. i can range from 0 to -// total_test_case_count() - 1. If i is not in that range, returns NULL. -TestCase* UnitTest::GetMutableTestCase(int i) { - return impl()->GetMutableTestCase(i); -} - -// Returns the list of event listeners that can be used to track events -// inside Google Test. -TestEventListeners& UnitTest::listeners() { - return *impl()->listeners(); -} - -// Registers and returns a global test environment. When a test -// program is run, all global test environments will be set-up in the -// order they were registered. After all tests in the program have -// finished, all global test environments will be torn-down in the -// *reverse* order they were registered. -// -// The UnitTest object takes ownership of the given environment. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -Environment* UnitTest::AddEnvironment(Environment* env) { - if (env == NULL) { - return NULL; - } - - impl_->environments().push_back(env); - return env; -} - -// Adds a TestPartResult to the current TestResult object. All Google Test -// assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call -// this to report their results. The user code should use the -// assertion macros instead of calling this directly. -void UnitTest::AddTestPartResult( - TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { - Message msg; - msg << message; - - internal::MutexLock lock(&mutex_); - if (impl_->gtest_trace_stack().size() > 0) { - msg << "\n" << GTEST_NAME_ << " trace:"; - - for (int i = static_cast(impl_->gtest_trace_stack().size()); - i > 0; --i) { - const internal::TraceInfo& trace = impl_->gtest_trace_stack()[i - 1]; - msg << "\n" << internal::FormatFileLocation(trace.file, trace.line) - << " " << trace.message; - } - } - - if (os_stack_trace.c_str() != NULL && !os_stack_trace.empty()) { - msg << internal::kStackTraceMarker << os_stack_trace; - } - - const TestPartResult result = - TestPartResult(result_type, file_name, line_number, - msg.GetString().c_str()); - impl_->GetTestPartResultReporterForCurrentThread()-> - ReportTestPartResult(result); - - if (result_type != TestPartResult::kSuccess) { - // gtest_break_on_failure takes precedence over - // gtest_throw_on_failure. This allows a user to set the latter - // in the code (perhaps in order to use Google Test assertions - // with another testing framework) and specify the former on the - // command line for debugging. - if (GTEST_FLAG(break_on_failure)) { -#if GTEST_OS_WINDOWS - // Using DebugBreak on Windows allows gtest to still break into a debugger - // when a failure happens and both the --gtest_break_on_failure and - // the --gtest_catch_exceptions flags are specified. - DebugBreak(); -#else - // Dereference NULL through a volatile pointer to prevent the compiler - // from removing. We use this rather than abort() or __builtin_trap() for - // portability: Symbian doesn't implement abort() well, and some debuggers - // don't correctly trap abort(). - *static_cast(NULL) = 1; -#endif // GTEST_OS_WINDOWS - } else if (GTEST_FLAG(throw_on_failure)) { -#if GTEST_HAS_EXCEPTIONS - throw internal::GoogleTestFailureException(result); -#else - // We cannot call abort() as it generates a pop-up in debug mode - // that cannot be suppressed in VC 7.1 or below. - exit(1); -#endif - } - } -} - -// Adds a TestProperty to the current TestResult object when invoked from -// inside a test, to current TestCase's ad_hoc_test_result_ when invoked -// from SetUpTestCase or TearDownTestCase, or to the global property set -// when invoked elsewhere. If the result already contains a property with -// the same key, the value will be updated. -void UnitTest::RecordProperty(const std::string& key, - const std::string& value) { - impl_->RecordProperty(TestProperty(key, value)); -} - -// Runs all tests in this UnitTest object and prints the result. -// Returns 0 if successful, or 1 otherwise. -// -// We don't protect this under mutex_, as we only support calling it -// from the main thread. -int UnitTest::Run() { - const bool in_death_test_child_process = - internal::GTEST_FLAG(internal_run_death_test).length() > 0; - - // Google Test implements this protocol for catching that a test - // program exits before returning control to Google Test: - // - // 1. Upon start, Google Test creates a file whose absolute path - // is specified by the environment variable - // TEST_PREMATURE_EXIT_FILE. - // 2. When Google Test has finished its work, it deletes the file. - // - // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before - // running a Google-Test-based test program and check the existence - // of the file at the end of the test execution to see if it has - // exited prematurely. - - // If we are in the child process of a death test, don't - // create/delete the premature exit file, as doing so is unnecessary - // and will confuse the parent process. Otherwise, create/delete - // the file upon entering/leaving this function. If the program - // somehow exits before this function has a chance to return, the - // premature-exit file will be left undeleted, causing a test runner - // that understands the premature-exit-file protocol to report the - // test as having failed. - const internal::ScopedPrematureExitFile premature_exit_file( - in_death_test_child_process ? - NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); - - // Captures the value of GTEST_FLAG(catch_exceptions). This value will be - // used for the duration of the program. - impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); - -#if GTEST_HAS_SEH - // Either the user wants Google Test to catch exceptions thrown by the - // tests or this is executing in the context of death test child - // process. In either case the user does not want to see pop-up dialogs - // about crashes - they are expected. - if (impl()->catch_exceptions() || in_death_test_child_process) { -# if !GTEST_OS_WINDOWS_MOBILE - // SetErrorMode doesn't exist on CE. - SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOALIGNMENTFAULTEXCEPT | - SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); -# endif // !GTEST_OS_WINDOWS_MOBILE - -# if (defined(_MSC_VER) || GTEST_OS_WINDOWS_MINGW) && !GTEST_OS_WINDOWS_MOBILE - // Death test children can be terminated with _abort(). On Windows, - // _abort() can show a dialog with a warning message. This forces the - // abort message to go to stderr instead. - _set_error_mode(_OUT_TO_STDERR); -# endif - -# if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE - // In the debug version, Visual Studio pops up a separate dialog - // offering a choice to debug the aborted program. We need to suppress - // this dialog or it will pop up for every EXPECT/ASSERT_DEATH statement - // executed. Google Test will notify the user of any unexpected - // failure via stderr. - // - // VC++ doesn't define _set_abort_behavior() prior to the version 8.0. - // Users of prior VC versions shall suffer the agony and pain of - // clicking through the countless debug dialogs. - // TODO(vladl@google.com): find a way to suppress the abort dialog() in the - // debug mode when compiled with VC 7.1 or lower. - if (!GTEST_FLAG(break_on_failure)) - _set_abort_behavior( - 0x0, // Clear the following flags: - _WRITE_ABORT_MSG | _CALL_REPORTFAULT); // pop-up window, core dump. -# endif - } -#endif // GTEST_HAS_SEH - - return internal::HandleExceptionsInMethodIfSupported( - impl(), - &internal::UnitTestImpl::RunAllTests, - "auxiliary test code (environments or event listeners)") ? 0 : 1; -} - -// Returns the working directory when the first TEST() or TEST_F() was -// executed. -const char* UnitTest::original_working_dir() const { - return impl_->original_working_dir_.c_str(); -} - -// Returns the TestCase object for the test that's currently running, -// or NULL if no test is running. -const TestCase* UnitTest::current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - return impl_->current_test_case(); -} - -// Returns the TestInfo object for the test that's currently running, -// or NULL if no test is running. -const TestInfo* UnitTest::current_test_info() const - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - return impl_->current_test_info(); -} - -// Returns the random seed used at the start of the current test run. -int UnitTest::random_seed() const { return impl_->random_seed(); } - -#if GTEST_HAS_PARAM_TEST -// Returns ParameterizedTestCaseRegistry object used to keep track of -// value-parameterized tests and instantiate and register them. -internal::ParameterizedTestCaseRegistry& - UnitTest::parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_) { - return impl_->parameterized_test_registry(); -} -#endif // GTEST_HAS_PARAM_TEST - -// Creates an empty UnitTest. -UnitTest::UnitTest() { - impl_ = new internal::UnitTestImpl(this); -} - -// Destructor of UnitTest. -UnitTest::~UnitTest() { - delete impl_; -} - -// Pushes a trace defined by SCOPED_TRACE() on to the per-thread -// Google Test trace stack. -void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().push_back(trace); -} - -// Pops a trace from the per-thread Google Test trace stack. -void UnitTest::PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_) { - internal::MutexLock lock(&mutex_); - impl_->gtest_trace_stack().pop_back(); -} - -namespace internal { - -UnitTestImpl::UnitTestImpl(UnitTest* parent) - : parent_(parent), -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4355) // Temporarily disables warning 4355 - // (using this in initializer). - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -# pragma warning(pop) // Restores the warning state again. -#else - default_global_test_part_result_reporter_(this), - default_per_thread_test_part_result_reporter_(this), -#endif // _MSC_VER - global_test_part_result_repoter_( - &default_global_test_part_result_reporter_), - per_thread_test_part_result_reporter_( - &default_per_thread_test_part_result_reporter_), -#if GTEST_HAS_PARAM_TEST - parameterized_test_registry_(), - parameterized_tests_registered_(false), -#endif // GTEST_HAS_PARAM_TEST - last_death_test_case_(-1), - current_test_case_(NULL), - current_test_info_(NULL), - ad_hoc_test_result_(), - os_stack_trace_getter_(NULL), - post_flag_parse_init_performed_(false), - random_seed_(0), // Will be overridden by the flag before first use. - random_(0), // Will be reseeded before first use. - start_timestamp_(0), - elapsed_time_(0), -#if GTEST_HAS_DEATH_TEST - death_test_factory_(new DefaultDeathTestFactory), -#endif - // Will be overridden by the flag before first use. - catch_exceptions_(false) { - listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); -} - -UnitTestImpl::~UnitTestImpl() { - // Deletes every TestCase. - ForEach(test_cases_, internal::Delete); - - // Deletes every Environment. - ForEach(environments_, internal::Delete); - - delete os_stack_trace_getter_; -} - -// Adds a TestProperty to the current TestResult object when invoked in a -// context of a test, to current test case's ad_hoc_test_result when invoke -// from SetUpTestCase/TearDownTestCase, or to the global property set -// otherwise. If the result already contains a property with the same key, -// the value will be updated. -void UnitTestImpl::RecordProperty(const TestProperty& test_property) { - std::string xml_element; - TestResult* test_result; // TestResult appropriate for property recording. - - if (current_test_info_ != NULL) { - xml_element = "testcase"; - test_result = &(current_test_info_->result_); - } else if (current_test_case_ != NULL) { - xml_element = "testsuite"; - test_result = &(current_test_case_->ad_hoc_test_result_); - } else { - xml_element = "testsuites"; - test_result = &ad_hoc_test_result_; - } - test_result->RecordProperty(xml_element, test_property); -} - -#if GTEST_HAS_DEATH_TEST -// Disables event forwarding if the control is currently in a death test -// subprocess. Must not be called before InitGoogleTest. -void UnitTestImpl::SuppressTestEventsIfInSubprocess() { - if (internal_run_death_test_flag_.get() != NULL) - listeners()->SuppressEventForwarding(); -} -#endif // GTEST_HAS_DEATH_TEST - -// Initializes event listeners performing XML output as specified by -// UnitTestOptions. Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureXmlOutput() { - const std::string& output_format = UnitTestOptions::GetOutputFormat(); - if (output_format == "xml") { - listeners()->SetDefaultXmlGenerator(new XmlUnitTestResultPrinter( - UnitTestOptions::GetAbsolutePathToOutputFile().c_str())); - } else if (output_format != "") { - printf("WARNING: unrecognized output format \"%s\" ignored.\n", - output_format.c_str()); - fflush(stdout); - } -} - -#if GTEST_CAN_STREAM_RESULTS_ -// Initializes event listeners for streaming test results in string form. -// Must not be called before InitGoogleTest. -void UnitTestImpl::ConfigureStreamingOutput() { - const std::string& target = GTEST_FLAG(stream_result_to); - if (!target.empty()) { - const size_t pos = target.find(':'); - if (pos != std::string::npos) { - listeners()->Append(new StreamingListener(target.substr(0, pos), - target.substr(pos+1))); - } else { - printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", - target.c_str()); - fflush(stdout); - } - } -} -#endif // GTEST_CAN_STREAM_RESULTS_ - -// Performs initialization dependent upon flag values obtained in -// ParseGoogleTestFlagsOnly. Is called from InitGoogleTest after the call to -// ParseGoogleTestFlagsOnly. In case a user neglects to call InitGoogleTest -// this function is also called from RunAllTests. Since this function can be -// called more than once, it has to be idempotent. -void UnitTestImpl::PostFlagParsingInit() { - // Ensures that this function does not execute more than once. - if (!post_flag_parse_init_performed_) { - post_flag_parse_init_performed_ = true; - -#if GTEST_HAS_DEATH_TEST - InitDeathTestSubprocessControlInfo(); - SuppressTestEventsIfInSubprocess(); -#endif // GTEST_HAS_DEATH_TEST - - // Registers parameterized tests. This makes parameterized tests - // available to the UnitTest reflection API without running - // RUN_ALL_TESTS. - RegisterParameterizedTests(); - - // Configures listeners for XML output. This makes it possible for users - // to shut down the default XML output before invoking RUN_ALL_TESTS. - ConfigureXmlOutput(); - -#if GTEST_CAN_STREAM_RESULTS_ - // Configures listeners for streaming test results to the specified server. - ConfigureStreamingOutput(); -#endif // GTEST_CAN_STREAM_RESULTS_ - } -} - -// A predicate that checks the name of a TestCase against a known -// value. -// -// This is used for implementation of the UnitTest class only. We put -// it in the anonymous namespace to prevent polluting the outer -// namespace. -// -// TestCaseNameIs is copyable. -class TestCaseNameIs { - public: - // Constructor. - explicit TestCaseNameIs(const std::string& name) - : name_(name) {} - - // Returns true iff the name of test_case matches name_. - bool operator()(const TestCase* test_case) const { - return test_case != NULL && strcmp(test_case->name(), name_.c_str()) == 0; - } - - private: - std::string name_; -}; - -// Finds and returns a TestCase with the given name. If one doesn't -// exist, creates one and returns it. It's the CALLER'S -// RESPONSIBILITY to ensure that this function is only called WHEN THE -// TESTS ARE NOT SHUFFLED. -// -// Arguments: -// -// test_case_name: name of the test case -// type_param: the name of the test case's type parameter, or NULL if -// this is not a typed or a type-parameterized test case. -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -TestCase* UnitTestImpl::GetTestCase(const char* test_case_name, - const char* type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc) { - // Can we find a TestCase with the given name? - const std::vector::const_iterator test_case = - std::find_if(test_cases_.begin(), test_cases_.end(), - TestCaseNameIs(test_case_name)); - - if (test_case != test_cases_.end()) - return *test_case; - - // No. Let's create one. - TestCase* const new_test_case = - new TestCase(test_case_name, type_param, set_up_tc, tear_down_tc); - - // Is this a death test case? - if (internal::UnitTestOptions::MatchesFilter(test_case_name, - kDeathTestCaseFilter)) { - // Yes. Inserts the test case after the last death test case - // defined so far. This only works when the test cases haven't - // been shuffled. Otherwise we may end up running a death test - // after a non-death test. - ++last_death_test_case_; - test_cases_.insert(test_cases_.begin() + last_death_test_case_, - new_test_case); - } else { - // No. Appends to the end of the list. - test_cases_.push_back(new_test_case); - } - - test_case_indices_.push_back(static_cast(test_case_indices_.size())); - return new_test_case; -} - -// Helpers for setting up / tearing down the given environment. They -// are for use in the ForEach() function. -static void SetUpEnvironment(Environment* env) { env->SetUp(); } -static void TearDownEnvironment(Environment* env) { env->TearDown(); } - -// Runs all tests in this UnitTest object, prints the result, and -// returns true if all tests are successful. If any exception is -// thrown during a test, the test is considered to be failed, but the -// rest of the tests will still be run. -// -// When parameterized tests are enabled, it expands and registers -// parameterized tests first in RegisterParameterizedTests(). -// All other functions called from RunAllTests() may safely assume that -// parameterized tests are ready to be counted and run. -bool UnitTestImpl::RunAllTests() { - // Makes sure InitGoogleTest() was called. - if (!GTestIsInitialized()) { - printf("%s", - "\nThis test program did NOT call ::testing::InitGoogleTest " - "before calling RUN_ALL_TESTS(). Please fix it.\n"); - return false; - } - - // Do not run any test if the --help flag was specified. - if (g_help_flag) - return true; - - // Repeats the call to the post-flag parsing initialization in case the - // user didn't call InitGoogleTest. - PostFlagParsingInit(); - - // Even if sharding is not on, test runners may want to use the - // GTEST_SHARD_STATUS_FILE to query whether the test supports the sharding - // protocol. - internal::WriteToShardStatusFileIfNeeded(); - - // True iff we are in a subprocess for running a thread-safe-style - // death test. - bool in_subprocess_for_death_test = false; - -#if GTEST_HAS_DEATH_TEST - in_subprocess_for_death_test = (internal_run_death_test_flag_.get() != NULL); -#endif // GTEST_HAS_DEATH_TEST - - const bool should_shard = ShouldShard(kTestTotalShards, kTestShardIndex, - in_subprocess_for_death_test); - - // Compares the full test names with the filter to decide which - // tests to run. - const bool has_tests_to_run = FilterTests(should_shard - ? HONOR_SHARDING_PROTOCOL - : IGNORE_SHARDING_PROTOCOL) > 0; - - // Lists the tests and exits if the --gtest_list_tests flag was specified. - if (GTEST_FLAG(list_tests)) { - // This must be called *after* FilterTests() has been called. - ListTestsMatchingFilter(); - return true; - } - - random_seed_ = GTEST_FLAG(shuffle) ? - GetRandomSeedFromFlag(GTEST_FLAG(random_seed)) : 0; - - // True iff at least one test has failed. - bool failed = false; - - TestEventListener* repeater = listeners()->repeater(); - - start_timestamp_ = GetTimeInMillis(); - repeater->OnTestProgramStart(*parent_); - - // How many times to repeat the tests? We don't want to repeat them - // when we are inside the subprocess of a death test. - const int repeat = in_subprocess_for_death_test ? 1 : GTEST_FLAG(repeat); - // Repeats forever if the repeat count is negative. - const bool forever = repeat < 0; - for (int i = 0; forever || i != repeat; i++) { - // We want to preserve failures generated by ad-hoc test - // assertions executed before RUN_ALL_TESTS(). - ClearNonAdHocTestResult(); - - const TimeInMillis start = GetTimeInMillis(); - - // Shuffles test cases and tests if requested. - if (has_tests_to_run && GTEST_FLAG(shuffle)) { - random()->Reseed(random_seed_); - // This should be done before calling OnTestIterationStart(), - // such that a test event listener can see the actual test order - // in the event. - ShuffleTests(); - } - - // Tells the unit test event listeners that the tests are about to start. - repeater->OnTestIterationStart(*parent_, i); - - // Runs each test case if there is at least one test to run. - if (has_tests_to_run) { - // Sets up all environments beforehand. - repeater->OnEnvironmentsSetUpStart(*parent_); - ForEach(environments_, SetUpEnvironment); - repeater->OnEnvironmentsSetUpEnd(*parent_); - - // Runs the tests only if there was no fatal failure during global - // set-up. - if (!Test::HasFatalFailure()) { - for (int test_index = 0; test_index < total_test_case_count(); - test_index++) { - GetMutableTestCase(test_index)->Run(); - } - } - - // Tears down all environments in reverse order afterwards. - repeater->OnEnvironmentsTearDownStart(*parent_); - std::for_each(environments_.rbegin(), environments_.rend(), - TearDownEnvironment); - repeater->OnEnvironmentsTearDownEnd(*parent_); - } - - elapsed_time_ = GetTimeInMillis() - start; - - // Tells the unit test event listener that the tests have just finished. - repeater->OnTestIterationEnd(*parent_, i); - - // Gets the result and clears it. - if (!Passed()) { - failed = true; - } - - // Restores the original test order after the iteration. This - // allows the user to quickly repro a failure that happens in the - // N-th iteration without repeating the first (N - 1) iterations. - // This is not enclosed in "if (GTEST_FLAG(shuffle)) { ... }", in - // case the user somehow changes the value of the flag somewhere - // (it's always safe to unshuffle the tests). - UnshuffleTests(); - - if (GTEST_FLAG(shuffle)) { - // Picks a new random seed for each iteration. - random_seed_ = GetNextRandomSeed(random_seed_); - } - } - - repeater->OnTestProgramEnd(*parent_); - - return !failed; -} - -// Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file -// if the variable is present. If a file already exists at this location, this -// function will write over it. If the variable is present, but the file cannot -// be created, prints an error and exits. -void WriteToShardStatusFileIfNeeded() { - const char* const test_shard_file = posix::GetEnv(kTestShardStatusFile); - if (test_shard_file != NULL) { - FILE* const file = posix::FOpen(test_shard_file, "w"); - if (file == NULL) { - ColoredPrintf(COLOR_RED, - "Could not write to the test shard status file \"%s\" " - "specified by the %s environment variable.\n", - test_shard_file, kTestShardStatusFile); - fflush(stdout); - exit(EXIT_FAILURE); - } - fclose(file); - } -} - -// Checks whether sharding is enabled by examining the relevant -// environment variable values. If the variables are present, -// but inconsistent (i.e., shard_index >= total_shards), prints -// an error and exits. If in_subprocess_for_death_test, sharding is -// disabled because it must only be applied to the original test -// process. Otherwise, we could filter out death tests we intended to execute. -bool ShouldShard(const char* total_shards_env, - const char* shard_index_env, - bool in_subprocess_for_death_test) { - if (in_subprocess_for_death_test) { - return false; - } - - const Int32 total_shards = Int32FromEnvOrDie(total_shards_env, -1); - const Int32 shard_index = Int32FromEnvOrDie(shard_index_env, -1); - - if (total_shards == -1 && shard_index == -1) { - return false; - } else if (total_shards == -1 && shard_index != -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestShardIndex << " = " << shard_index - << ", but have left " << kTestTotalShards << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (total_shards != -1 && shard_index == -1) { - const Message msg = Message() - << "Invalid environment variables: you have " - << kTestTotalShards << " = " << total_shards - << ", but have left " << kTestShardIndex << " unset.\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } else if (shard_index < 0 || shard_index >= total_shards) { - const Message msg = Message() - << "Invalid environment variables: we require 0 <= " - << kTestShardIndex << " < " << kTestTotalShards - << ", but you have " << kTestShardIndex << "=" << shard_index - << ", " << kTestTotalShards << "=" << total_shards << ".\n"; - ColoredPrintf(COLOR_RED, msg.GetString().c_str()); - fflush(stdout); - exit(EXIT_FAILURE); - } - - return total_shards > 1; -} - -// Parses the environment variable var as an Int32. If it is unset, -// returns default_val. If it is not an Int32, prints an error -// and aborts. -Int32 Int32FromEnvOrDie(const char* var, Int32 default_val) { - const char* str_val = posix::GetEnv(var); - if (str_val == NULL) { - return default_val; - } - - Int32 result; - if (!ParseInt32(Message() << "The value of environment variable " << var, - str_val, &result)) { - exit(EXIT_FAILURE); - } - return result; -} - -// Given the total number of shards, the shard index, and the test id, -// returns true iff the test should be run on this shard. The test id is -// some arbitrary but unique non-negative integer assigned to each test -// method. Assumes that 0 <= shard_index < total_shards. -bool ShouldRunTestOnShard(int total_shards, int shard_index, int test_id) { - return (test_id % total_shards) == shard_index; -} - -// Compares the name of each test with the user-specified filter to -// decide whether the test should be run, then records the result in -// each TestCase and TestInfo object. -// If shard_tests == true, further filters tests based on sharding -// variables in the environment - see -// http://code.google.com/p/googletest/wiki/GoogleTestAdvancedGuide. -// Returns the number of tests that should run. -int UnitTestImpl::FilterTests(ReactionToSharding shard_tests) { - const Int32 total_shards = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestTotalShards, -1) : -1; - const Int32 shard_index = shard_tests == HONOR_SHARDING_PROTOCOL ? - Int32FromEnvOrDie(kTestShardIndex, -1) : -1; - - // num_runnable_tests are the number of tests that will - // run across all shards (i.e., match filter and are not disabled). - // num_selected_tests are the number of tests to be run on - // this shard. - int num_runnable_tests = 0; - int num_selected_tests = 0; - for (size_t i = 0; i < test_cases_.size(); i++) { - TestCase* const test_case = test_cases_[i]; - const std::string &test_case_name = test_case->name(); - test_case->set_should_run(false); - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - TestInfo* const test_info = test_case->test_info_list()[j]; - const std::string test_name(test_info->name()); - // A test is disabled if test case name or test name matches - // kDisableTestFilter. - const bool is_disabled = - internal::UnitTestOptions::MatchesFilter(test_case_name, - kDisableTestFilter) || - internal::UnitTestOptions::MatchesFilter(test_name, - kDisableTestFilter); - test_info->is_disabled_ = is_disabled; - - const bool matches_filter = - internal::UnitTestOptions::FilterMatchesTest(test_case_name, - test_name); - test_info->matches_filter_ = matches_filter; - - const bool is_runnable = - (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) && - matches_filter; - - const bool is_selected = is_runnable && - (shard_tests == IGNORE_SHARDING_PROTOCOL || - ShouldRunTestOnShard(total_shards, shard_index, - num_runnable_tests)); - - num_runnable_tests += is_runnable; - num_selected_tests += is_selected; - - test_info->should_run_ = is_selected; - test_case->set_should_run(test_case->should_run() || is_selected); - } - } - return num_selected_tests; -} - -// Prints the given C-string on a single line by replacing all '\n' -// characters with string "\\n". If the output takes more than -// max_length characters, only prints the first max_length characters -// and "...". -static void PrintOnOneLine(const char* str, int max_length) { - if (str != NULL) { - for (int i = 0; *str != '\0'; ++str) { - if (i >= max_length) { - printf("..."); - break; - } - if (*str == '\n') { - printf("\\n"); - i += 2; - } else { - printf("%c", *str); - ++i; - } - } - } -} - -// Prints the names of the tests matching the user-specified filter flag. -void UnitTestImpl::ListTestsMatchingFilter() { - // Print at most this many characters for each type/value parameter. - const int kMaxParamLength = 250; - - for (size_t i = 0; i < test_cases_.size(); i++) { - const TestCase* const test_case = test_cases_[i]; - bool printed_test_case_name = false; - - for (size_t j = 0; j < test_case->test_info_list().size(); j++) { - const TestInfo* const test_info = - test_case->test_info_list()[j]; - if (test_info->matches_filter_) { - if (!printed_test_case_name) { - printed_test_case_name = true; - printf("%s.", test_case->name()); - if (test_case->type_param() != NULL) { - printf(" # %s = ", kTypeParamLabel); - // We print the type parameter on a single line to make - // the output easy to parse by a program. - PrintOnOneLine(test_case->type_param(), kMaxParamLength); - } - printf("\n"); - } - printf(" %s", test_info->name()); - if (test_info->value_param() != NULL) { - printf(" # %s = ", kValueParamLabel); - // We print the value parameter on a single line to make the - // output easy to parse by a program. - PrintOnOneLine(test_info->value_param(), kMaxParamLength); - } - printf("\n"); - } - } - } - fflush(stdout); -} - -// Sets the OS stack trace getter. -// -// Does nothing if the input and the current OS stack trace getter are -// the same; otherwise, deletes the old getter and makes the input the -// current getter. -void UnitTestImpl::set_os_stack_trace_getter( - OsStackTraceGetterInterface* getter) { - if (os_stack_trace_getter_ != getter) { - delete os_stack_trace_getter_; - os_stack_trace_getter_ = getter; - } -} - -// Returns the current OS stack trace getter if it is not NULL; -// otherwise, creates an OsStackTraceGetter, makes it the current -// getter, and returns it. -OsStackTraceGetterInterface* UnitTestImpl::os_stack_trace_getter() { - if (os_stack_trace_getter_ == NULL) { - os_stack_trace_getter_ = new OsStackTraceGetter; - } - - return os_stack_trace_getter_; -} - -// Returns the TestResult for the test that's currently running, or -// the TestResult for the ad hoc test if no test is running. -TestResult* UnitTestImpl::current_test_result() { - return current_test_info_ ? - &(current_test_info_->result_) : &ad_hoc_test_result_; -} - -// Shuffles all test cases, and the tests within each test case, -// making sure that death tests are still run first. -void UnitTestImpl::ShuffleTests() { - // Shuffles the death test cases. - ShuffleRange(random(), 0, last_death_test_case_ + 1, &test_case_indices_); - - // Shuffles the non-death test cases. - ShuffleRange(random(), last_death_test_case_ + 1, - static_cast(test_cases_.size()), &test_case_indices_); - - // Shuffles the tests inside each test case. - for (size_t i = 0; i < test_cases_.size(); i++) { - test_cases_[i]->ShuffleTests(random()); - } -} - -// Restores the test cases and tests to their order before the first shuffle. -void UnitTestImpl::UnshuffleTests() { - for (size_t i = 0; i < test_cases_.size(); i++) { - // Unshuffles the tests in each test case. - test_cases_[i]->UnshuffleTests(); - // Resets the index of each test case. - test_case_indices_[i] = static_cast(i); - } -} - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -std::string GetCurrentOsStackTraceExceptTop(UnitTest* /*unit_test*/, - int skip_count) { - // We pass skip_count + 1 to skip this wrapper function in addition - // to what the user really wants to skip. - return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1); -} - -// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to -// suppress unreachable code warnings. -namespace { -class ClassUniqueToAlwaysTrue {}; -} - -bool IsTrue(bool condition) { return condition; } - -bool AlwaysTrue() { -#if GTEST_HAS_EXCEPTIONS - // This condition is always false so AlwaysTrue() never actually throws, - // but it makes the compiler think that it may throw. - if (IsTrue(false)) - throw ClassUniqueToAlwaysTrue(); -#endif // GTEST_HAS_EXCEPTIONS - return true; -} - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -bool SkipPrefix(const char* prefix, const char** pstr) { - const size_t prefix_len = strlen(prefix); - if (strncmp(*pstr, prefix, prefix_len) == 0) { - *pstr += prefix_len; - return true; - } - return false; -} - -// Parses a string as a command line flag. The string should have -// the format "--flag=value". When def_optional is true, the "=value" -// part can be omitted. -// -// Returns the value of the flag, or NULL if the parsing failed. -const char* ParseFlagValue(const char* str, - const char* flag, - bool def_optional) { - // str and flag must not be NULL. - if (str == NULL || flag == NULL) return NULL; - - // The flag must start with "--" followed by GTEST_FLAG_PREFIX_. - const std::string flag_str = std::string("--") + GTEST_FLAG_PREFIX_ + flag; - const size_t flag_len = flag_str.length(); - if (strncmp(str, flag_str.c_str(), flag_len) != 0) return NULL; - - // Skips the flag name. - const char* flag_end = str + flag_len; - - // When def_optional is true, it's OK to not have a "=value" part. - if (def_optional && (flag_end[0] == '\0')) { - return flag_end; - } - - // If def_optional is true and there are more characters after the - // flag name, or if def_optional is false, there must be a '=' after - // the flag name. - if (flag_end[0] != '=') return NULL; - - // Returns the string after "=". - return flag_end + 1; -} - -// Parses a string for a bool flag, in the form of either -// "--flag=value" or "--flag". -// -// In the former case, the value is taken as true as long as it does -// not start with '0', 'f', or 'F'. -// -// In the latter case, the value is taken as true. -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseBoolFlag(const char* str, const char* flag, bool* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, true); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Converts the string value to a bool. - *value = !(*value_str == '0' || *value_str == 'f' || *value_str == 'F'); - return true; -} - -// Parses a string for an Int32 flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseInt32Flag(const char* str, const char* flag, Int32* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - return ParseInt32(Message() << "The value of flag --" << flag, - value_str, value); -} - -// Parses a string for a string flag, in the form of -// "--flag=value". -// -// On success, stores the value of the flag in *value, and returns -// true. On failure, returns false without changing *value. -bool ParseStringFlag(const char* str, const char* flag, std::string* value) { - // Gets the value of the flag as a string. - const char* const value_str = ParseFlagValue(str, flag, false); - - // Aborts if the parsing failed. - if (value_str == NULL) return false; - - // Sets *value to the value of the flag. - *value = value_str; - return true; -} - -// Determines whether a string has a prefix that Google Test uses for its -// flags, i.e., starts with GTEST_FLAG_PREFIX_ or GTEST_FLAG_PREFIX_DASH_. -// If Google Test detects that a command line flag has its prefix but is not -// recognized, it will print its help message. Flags starting with -// GTEST_INTERNAL_PREFIX_ followed by "internal_" are considered Google Test -// internal flags and do not trigger the help message. -static bool HasGoogleTestFlagPrefix(const char* str) { - return (SkipPrefix("--", &str) || - SkipPrefix("-", &str) || - SkipPrefix("/", &str)) && - !SkipPrefix(GTEST_FLAG_PREFIX_ "internal_", &str) && - (SkipPrefix(GTEST_FLAG_PREFIX_, &str) || - SkipPrefix(GTEST_FLAG_PREFIX_DASH_, &str)); -} - -// Prints a string containing code-encoded text. The following escape -// sequences can be used in the string to control the text color: -// -// @@ prints a single '@' character. -// @R changes the color to red. -// @G changes the color to green. -// @Y changes the color to yellow. -// @D changes to the default terminal text color. -// -// TODO(wan@google.com): Write tests for this once we add stdout -// capturing to Google Test. -static void PrintColorEncoded(const char* str) { - GTestColor color = COLOR_DEFAULT; // The current color. - - // Conceptually, we split the string into segments divided by escape - // sequences. Then we print one segment at a time. At the end of - // each iteration, the str pointer advances to the beginning of the - // next segment. - for (;;) { - const char* p = strchr(str, '@'); - if (p == NULL) { - ColoredPrintf(color, "%s", str); - return; - } - - ColoredPrintf(color, "%s", std::string(str, p).c_str()); - - const char ch = p[1]; - str = p + 2; - if (ch == '@') { - ColoredPrintf(color, "@"); - } else if (ch == 'D') { - color = COLOR_DEFAULT; - } else if (ch == 'R') { - color = COLOR_RED; - } else if (ch == 'G') { - color = COLOR_GREEN; - } else if (ch == 'Y') { - color = COLOR_YELLOW; - } else { - --str; - } - } -} - -static const char kColorEncodedHelpMessage[] = -"This program contains tests written using " GTEST_NAME_ ". You can use the\n" -"following command line flags to control its behavior:\n" -"\n" -"Test Selection:\n" -" @G--" GTEST_FLAG_PREFIX_ "list_tests@D\n" -" List the names of all tests instead of running them. The name of\n" -" TEST(Foo, Bar) is \"Foo.Bar\".\n" -" @G--" GTEST_FLAG_PREFIX_ "filter=@YPOSTIVE_PATTERNS" - "[@G-@YNEGATIVE_PATTERNS]@D\n" -" Run only the tests whose name matches one of the positive patterns but\n" -" none of the negative patterns. '?' matches any single character; '*'\n" -" matches any substring; ':' separates two patterns.\n" -" @G--" GTEST_FLAG_PREFIX_ "also_run_disabled_tests@D\n" -" Run all disabled tests too.\n" -"\n" -"Test Execution:\n" -" @G--" GTEST_FLAG_PREFIX_ "repeat=@Y[COUNT]@D\n" -" Run the tests repeatedly; use a negative count to repeat forever.\n" -" @G--" GTEST_FLAG_PREFIX_ "shuffle@D\n" -" Randomize tests' orders on every iteration.\n" -" @G--" GTEST_FLAG_PREFIX_ "random_seed=@Y[NUMBER]@D\n" -" Random number seed to use for shuffling test orders (between 1 and\n" -" 99999, or 0 to use a seed based on the current time).\n" -"\n" -"Test Output:\n" -" @G--" GTEST_FLAG_PREFIX_ "color=@Y(@Gyes@Y|@Gno@Y|@Gauto@Y)@D\n" -" Enable/disable colored output. The default is @Gauto@D.\n" -" -@G-" GTEST_FLAG_PREFIX_ "print_time=0@D\n" -" Don't print the elapsed time of each test.\n" -" @G--" GTEST_FLAG_PREFIX_ "output=xml@Y[@G:@YDIRECTORY_PATH@G" - GTEST_PATH_SEP_ "@Y|@G:@YFILE_PATH]@D\n" -" Generate an XML report in the given directory or with the given file\n" -" name. @YFILE_PATH@D defaults to @Gtest_details.xml@D.\n" -#if GTEST_CAN_STREAM_RESULTS_ -" @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" -" Stream test results to the given server.\n" -#endif // GTEST_CAN_STREAM_RESULTS_ -"\n" -"Assertion Behavior:\n" -#if GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "death_test_style=@Y(@Gfast@Y|@Gthreadsafe@Y)@D\n" -" Set the default death test style.\n" -#endif // GTEST_HAS_DEATH_TEST && !GTEST_OS_WINDOWS -" @G--" GTEST_FLAG_PREFIX_ "break_on_failure@D\n" -" Turn assertion failures into debugger break-points.\n" -" @G--" GTEST_FLAG_PREFIX_ "throw_on_failure@D\n" -" Turn assertion failures into C++ exceptions.\n" -" @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" -" Do not report exceptions as test failures. Instead, allow them\n" -" to crash the program or throw a pop-up (on Windows).\n" -"\n" -"Except for @G--" GTEST_FLAG_PREFIX_ "list_tests@D, you can alternatively set " - "the corresponding\n" -"environment variable of a flag (all letters in upper-case). For example, to\n" -"disable colored text output, you can either specify @G--" GTEST_FLAG_PREFIX_ - "color=no@D or set\n" -"the @G" GTEST_FLAG_PREFIX_UPPER_ "COLOR@D environment variable to @Gno@D.\n" -"\n" -"For more information, please read the " GTEST_NAME_ " documentation at\n" -"@G" GTEST_PROJECT_URL_ "@D. If you find a bug in " GTEST_NAME_ "\n" -"(not one in your own code or tests), please report it to\n" -"@G<" GTEST_DEV_EMAIL_ ">@D.\n"; - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. The type parameter CharType can be -// instantiated to either char or wchar_t. -template -void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { - for (int i = 1; i < *argc; i++) { - const std::string arg_string = StreamableToString(argv[i]); - const char* const arg = arg_string.c_str(); - - using internal::ParseBoolFlag; - using internal::ParseInt32Flag; - using internal::ParseStringFlag; - - // Do we see a Google Test flag? - if (ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, - >EST_FLAG(also_run_disabled_tests)) || - ParseBoolFlag(arg, kBreakOnFailureFlag, - >EST_FLAG(break_on_failure)) || - ParseBoolFlag(arg, kCatchExceptionsFlag, - >EST_FLAG(catch_exceptions)) || - ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || - ParseStringFlag(arg, kDeathTestStyleFlag, - >EST_FLAG(death_test_style)) || - ParseBoolFlag(arg, kDeathTestUseFork, - >EST_FLAG(death_test_use_fork)) || - ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || - ParseStringFlag(arg, kInternalRunDeathTestFlag, - >EST_FLAG(internal_run_death_test)) || - ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || - ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || - ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || - ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || - ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || - ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || - ParseInt32Flag(arg, kStackTraceDepthFlag, - >EST_FLAG(stack_trace_depth)) || - ParseStringFlag(arg, kStreamResultToFlag, - >EST_FLAG(stream_result_to)) || - ParseBoolFlag(arg, kThrowOnFailureFlag, - >EST_FLAG(throw_on_failure)) - ) { - // Yes. Shift the remainder of the argv list left by one. Note - // that argv has (*argc + 1) elements, the last one always being - // NULL. The following loop moves the trailing NULL element as - // well. - for (int j = i; j != *argc; j++) { - argv[j] = argv[j + 1]; - } - - // Decrements the argument count. - (*argc)--; - - // We also need to decrement the iterator as we just removed - // an element. - i--; - } else if (arg_string == "--help" || arg_string == "-h" || - arg_string == "-?" || arg_string == "/?" || - HasGoogleTestFlagPrefix(arg)) { - // Both help flag and unrecognized Google Test flags (excluding - // internal ones) trigger help display. - g_help_flag = true; - } - } - - if (g_help_flag) { - // We print the help here instead of in RUN_ALL_TESTS(), as the - // latter may not be called at all if the user is using Google - // Test with another testing framework. - PrintColorEncoded(kColorEncodedHelpMessage); - } -} - -// Parses the command line for Google Test flags, without initializing -// other parts of Google Test. -void ParseGoogleTestFlagsOnly(int* argc, char** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} -void ParseGoogleTestFlagsOnly(int* argc, wchar_t** argv) { - ParseGoogleTestFlagsOnlyImpl(argc, argv); -} - -// The internal implementation of InitGoogleTest(). -// -// The type parameter CharType can be instantiated to either char or -// wchar_t. -template -void InitGoogleTestImpl(int* argc, CharType** argv) { - g_init_gtest_count++; - - // We don't want to run the initialization code twice. - if (g_init_gtest_count != 1) return; - - if (*argc <= 0) return; - - internal::g_executable_path = internal::StreamableToString(argv[0]); - -#if GTEST_HAS_DEATH_TEST - - g_argvs.clear(); - for (int i = 0; i != *argc; i++) { - g_argvs.push_back(StreamableToString(argv[i])); - } - -#endif // GTEST_HAS_DEATH_TEST - - ParseGoogleTestFlagsOnly(argc, argv); - GetUnitTestImpl()->PostFlagParsingInit(); -} - -} // namespace internal - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -void InitGoogleTest(int* argc, char** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -void InitGoogleTest(int* argc, wchar_t** argv) { - internal::InitGoogleTestImpl(argc, argv); -} - -} // namespace testing -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan), vladl@google.com (Vlad Losev) -// -// This file implements death tests. - - -#if GTEST_HAS_DEATH_TEST - -# if GTEST_OS_MAC -# include -# endif // GTEST_OS_MAC - -# include -# include -# include - -# if GTEST_OS_LINUX -# include -# endif // GTEST_OS_LINUX - -# include - -# if GTEST_OS_WINDOWS -# include -# else -# include -# include -# endif // GTEST_OS_WINDOWS - -# if GTEST_OS_QNX -# include -# endif // GTEST_OS_QNX - -#endif // GTEST_HAS_DEATH_TEST - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -// Constants. - -// The default death test style. -static const char kDefaultDeathTestStyle[] = "fast"; - -GTEST_DEFINE_string_( - death_test_style, - internal::StringFromGTestEnv("death_test_style", kDefaultDeathTestStyle), - "Indicates how to run a death test in a forked child process: " - "\"threadsafe\" (child process re-executes the test binary " - "from the beginning, running only the specific death test) or " - "\"fast\" (child process runs the death test immediately " - "after forking)."); - -GTEST_DEFINE_bool_( - death_test_use_fork, - internal::BoolFromGTestEnv("death_test_use_fork", false), - "Instructs to use fork()/_exit() instead of clone() in death tests. " - "Ignored and always uses fork() on POSIX systems where clone() is not " - "implemented. Useful when running under valgrind or similar tools if " - "those do not support clone(). Valgrind 3.3.1 will just fail if " - "it sees an unsupported combination of clone() flags. " - "It is not recommended to use this flag w/o valgrind though it will " - "work in 99% of the cases. Once valgrind is fixed, this flag will " - "most likely be removed."); - -namespace internal { -GTEST_DEFINE_string_( - internal_run_death_test, "", - "Indicates the file, line number, temporal index of " - "the single death test to run, and a file descriptor to " - "which a success code may be sent, all separated by " - "the '|' characters. This flag is specified if and only if the current " - "process is a sub-process launched for running a thread-safe " - "death test. FOR INTERNAL USE ONLY."); -} // namespace internal - -#if GTEST_HAS_DEATH_TEST - -namespace internal { - -// Valid only for fast death tests. Indicates the code is running in the -// child process of a fast style death test. -static bool g_in_fast_death_test_child = false; - -// Returns a Boolean value indicating whether the caller is currently -// executing in the context of the death test child process. Tools such as -// Valgrind heap checkers may need this to modify their behavior in death -// tests. IMPORTANT: This is an internal utility. Using it may break the -// implementation of death tests. User code MUST NOT use it. -bool InDeathTestChild() { -# if GTEST_OS_WINDOWS - - // On Windows, death tests are thread-safe regardless of the value of the - // death_test_style flag. - return !GTEST_FLAG(internal_run_death_test).empty(); - -# else - - if (GTEST_FLAG(death_test_style) == "threadsafe") - return !GTEST_FLAG(internal_run_death_test).empty(); - else - return g_in_fast_death_test_child; -#endif -} - -} // namespace internal - -// ExitedWithCode constructor. -ExitedWithCode::ExitedWithCode(int exit_code) : exit_code_(exit_code) { -} - -// ExitedWithCode function-call operator. -bool ExitedWithCode::operator()(int exit_status) const { -# if GTEST_OS_WINDOWS - - return exit_status == exit_code_; - -# else - - return WIFEXITED(exit_status) && WEXITSTATUS(exit_status) == exit_code_; - -# endif // GTEST_OS_WINDOWS -} - -# if !GTEST_OS_WINDOWS -// KilledBySignal constructor. -KilledBySignal::KilledBySignal(int signum) : signum_(signum) { -} - -// KilledBySignal function-call operator. -bool KilledBySignal::operator()(int exit_status) const { - return WIFSIGNALED(exit_status) && WTERMSIG(exit_status) == signum_; -} -# endif // !GTEST_OS_WINDOWS - -namespace internal { - -// Utilities needed for death tests. - -// Generates a textual description of a given exit code, in the format -// specified by wait(2). -static std::string ExitSummary(int exit_code) { - Message m; - -# if GTEST_OS_WINDOWS - - m << "Exited with exit status " << exit_code; - -# else - - if (WIFEXITED(exit_code)) { - m << "Exited with exit status " << WEXITSTATUS(exit_code); - } else if (WIFSIGNALED(exit_code)) { - m << "Terminated by signal " << WTERMSIG(exit_code); - } -# ifdef WCOREDUMP - if (WCOREDUMP(exit_code)) { - m << " (core dumped)"; - } -# endif -# endif // GTEST_OS_WINDOWS - - return m.GetString(); -} - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -bool ExitedUnsuccessfully(int exit_status) { - return !ExitedWithCode(0)(exit_status); -} - -# if !GTEST_OS_WINDOWS -// Generates a textual failure message when a death test finds more than -// one thread running, or cannot determine the number of threads, prior -// to executing the given statement. It is the responsibility of the -// caller not to pass a thread_count of 1. -static std::string DeathTestThreadWarning(size_t thread_count) { - Message msg; - msg << "Death tests use fork(), which is unsafe particularly" - << " in a threaded context. For this test, " << GTEST_NAME_ << " "; - if (thread_count == 0) - msg << "couldn't detect the number of threads."; - else - msg << "detected " << thread_count << " threads."; - return msg.GetString(); -} -# endif // !GTEST_OS_WINDOWS - -// Flag characters for reporting a death test that did not die. -static const char kDeathTestLived = 'L'; -static const char kDeathTestReturned = 'R'; -static const char kDeathTestThrew = 'T'; -static const char kDeathTestInternalError = 'I'; - -// An enumeration describing all of the possible ways that a death test can -// conclude. DIED means that the process died while executing the test -// code; LIVED means that process lived beyond the end of the test code; -// RETURNED means that the test statement attempted to execute a return -// statement, which is not allowed; THREW means that the test statement -// returned control by throwing an exception. IN_PROGRESS means the test -// has not yet concluded. -// TODO(vladl@google.com): Unify names and possibly values for -// AbortReason, DeathTestOutcome, and flag characters above. -enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; - -// Routine for aborting the program which is safe to call from an -// exec-style death test child process, in which case the error -// message is propagated back to the parent process. Otherwise, the -// message is simply printed to stderr. In either case, the program -// then exits with status 1. -void DeathTestAbort(const std::string& message) { - // On a POSIX system, this function may be called from a threadsafe-style - // death test child process, which operates on a very small stack. Use - // the heap for any additional non-minuscule memory requirements. - const InternalRunDeathTestFlag* const flag = - GetUnitTestImpl()->internal_run_death_test_flag(); - if (flag != NULL) { - FILE* parent = posix::FDOpen(flag->write_fd(), "w"); - fputc(kDeathTestInternalError, parent); - fprintf(parent, "%s", message.c_str()); - fflush(parent); - _exit(1); - } else { - fprintf(stderr, "%s", message.c_str()); - fflush(stderr); - posix::Abort(); - } -} - -// A replacement for CHECK that calls DeathTestAbort if the assertion -// fails. -# define GTEST_DEATH_TEST_CHECK_(expression) \ - do { \ - if (!::testing::internal::IsTrue(expression)) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// This macro is similar to GTEST_DEATH_TEST_CHECK_, but it is meant for -// evaluating any system call that fulfills two conditions: it must return -// -1 on failure, and set errno to EINTR when it is interrupted and -// should be tried again. The macro expands to a loop that repeatedly -// evaluates the expression as long as it evaluates to -1 and sets -// errno to EINTR. If the expression evaluates to -1 but errno is -// something other than EINTR, DeathTestAbort is called. -# define GTEST_DEATH_TEST_CHECK_SYSCALL_(expression) \ - do { \ - int gtest_retval; \ - do { \ - gtest_retval = (expression); \ - } while (gtest_retval == -1 && errno == EINTR); \ - if (gtest_retval == -1) { \ - DeathTestAbort( \ - ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ - + ::testing::internal::StreamableToString(__LINE__) + ": " \ - + #expression + " != -1"); \ - } \ - } while (::testing::internal::AlwaysFalse()) - -// Returns the message describing the last system error in errno. -std::string GetLastErrnoDescription() { - return errno == 0 ? "" : posix::StrError(errno); -} - -// This is called from a death test parent process to read a failure -// message from the death test child process and log it with the FATAL -// severity. On Windows, the message is read from a pipe handle. On other -// platforms, it is read from a file descriptor. -static void FailFromInternalError(int fd) { - Message error; - char buffer[256]; - int num_read; - - do { - while ((num_read = posix::Read(fd, buffer, 255)) > 0) { - buffer[num_read] = '\0'; - error << buffer; - } - } while (num_read == -1 && errno == EINTR); - - if (num_read == 0) { - GTEST_LOG_(FATAL) << error.GetString(); - } else { - const int last_error = errno; - GTEST_LOG_(FATAL) << "Error while reading death test internal: " - << GetLastErrnoDescription() << " [" << last_error << "]"; - } -} - -// Death test constructor. Increments the running death test count -// for the current test. -DeathTest::DeathTest() { - TestInfo* const info = GetUnitTestImpl()->current_test_info(); - if (info == NULL) { - DeathTestAbort("Cannot run a death test outside of a TEST or " - "TEST_F construct"); - } -} - -// Creates and returns a death test by dispatching to the current -// death test factory. -bool DeathTest::Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) { - return GetUnitTestImpl()->death_test_factory()->Create( - statement, regex, file, line, test); -} - -const char* DeathTest::LastMessage() { - return last_death_test_message_.c_str(); -} - -void DeathTest::set_last_death_test_message(const std::string& message) { - last_death_test_message_ = message; -} - -std::string DeathTest::last_death_test_message_; - -// Provides cross platform implementation for some death functionality. -class DeathTestImpl : public DeathTest { - protected: - DeathTestImpl(const char* a_statement, const RE* a_regex) - : statement_(a_statement), - regex_(a_regex), - spawned_(false), - status_(-1), - outcome_(IN_PROGRESS), - read_fd_(-1), - write_fd_(-1) {} - - // read_fd_ is expected to be closed and cleared by a derived class. - ~DeathTestImpl() { GTEST_DEATH_TEST_CHECK_(read_fd_ == -1); } - - void Abort(AbortReason reason); - virtual bool Passed(bool status_ok); - - const char* statement() const { return statement_; } - const RE* regex() const { return regex_; } - bool spawned() const { return spawned_; } - void set_spawned(bool is_spawned) { spawned_ = is_spawned; } - int status() const { return status_; } - void set_status(int a_status) { status_ = a_status; } - DeathTestOutcome outcome() const { return outcome_; } - void set_outcome(DeathTestOutcome an_outcome) { outcome_ = an_outcome; } - int read_fd() const { return read_fd_; } - void set_read_fd(int fd) { read_fd_ = fd; } - int write_fd() const { return write_fd_; } - void set_write_fd(int fd) { write_fd_ = fd; } - - // Called in the parent process only. Reads the result code of the death - // test child process via a pipe, interprets it to set the outcome_ - // member, and closes read_fd_. Outputs diagnostics and terminates in - // case of unexpected codes. - void ReadAndInterpretStatusByte(); - - private: - // The textual content of the code this object is testing. This class - // doesn't own this string and should not attempt to delete it. - const char* const statement_; - // The regular expression which test output must match. DeathTestImpl - // doesn't own this object and should not attempt to delete it. - const RE* const regex_; - // True if the death test child process has been successfully spawned. - bool spawned_; - // The exit status of the child process. - int status_; - // How the death test concluded. - DeathTestOutcome outcome_; - // Descriptor to the read end of the pipe to the child process. It is - // always -1 in the child process. The child keeps its write end of the - // pipe in write_fd_. - int read_fd_; - // Descriptor to the child's write end of the pipe to the parent process. - // It is always -1 in the parent process. The parent keeps its end of the - // pipe in read_fd_. - int write_fd_; -}; - -// Called in the parent process only. Reads the result code of the death -// test child process via a pipe, interprets it to set the outcome_ -// member, and closes read_fd_. Outputs diagnostics and terminates in -// case of unexpected codes. -void DeathTestImpl::ReadAndInterpretStatusByte() { - char flag; - int bytes_read; - - // The read() here blocks until data is available (signifying the - // failure of the death test) or until the pipe is closed (signifying - // its success), so it's okay to call this in the parent before - // the child process has exited. - do { - bytes_read = posix::Read(read_fd(), &flag, 1); - } while (bytes_read == -1 && errno == EINTR); - - if (bytes_read == 0) { - set_outcome(DIED); - } else if (bytes_read == 1) { - switch (flag) { - case kDeathTestReturned: - set_outcome(RETURNED); - break; - case kDeathTestThrew: - set_outcome(THREW); - break; - case kDeathTestLived: - set_outcome(LIVED); - break; - case kDeathTestInternalError: - FailFromInternalError(read_fd()); // Does not return. - break; - default: - GTEST_LOG_(FATAL) << "Death test child process reported " - << "unexpected status byte (" - << static_cast(flag) << ")"; - } - } else { - GTEST_LOG_(FATAL) << "Read from death test child process failed: " - << GetLastErrnoDescription(); - } - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Close(read_fd())); - set_read_fd(-1); -} - -// Signals that the death test code which should have exited, didn't. -// Should be called only in a death test child process. -// Writes a status byte to the child's status file descriptor, then -// calls _exit(1). -void DeathTestImpl::Abort(AbortReason reason) { - // The parent process considers the death test to be a failure if - // it finds any data in our pipe. So, here we write a single flag byte - // to the pipe, then exit. - const char status_ch = - reason == TEST_DID_NOT_DIE ? kDeathTestLived : - reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; - - GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); - // We are leaking the descriptor here because on some platforms (i.e., - // when built as Windows DLL), destructors of global objects will still - // run after calling _exit(). On such systems, write_fd_ will be - // indirectly closed from the destructor of UnitTestImpl, causing double - // close if it is also closed here. On debug configurations, double close - // may assert. As there are no in-process buffers to flush here, we are - // relying on the OS to close the descriptor after the process terminates - // when the destructors are not run. - _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) -} - -// Returns an indented copy of stderr output for a death test. -// This makes distinguishing death test output lines from regular log lines -// much easier. -static ::std::string FormatDeathTestOutput(const ::std::string& output) { - ::std::string ret; - for (size_t at = 0; ; ) { - const size_t line_end = output.find('\n', at); - ret += "[ DEATH ] "; - if (line_end == ::std::string::npos) { - ret += output.substr(at); - break; - } - ret += output.substr(at, line_end + 1 - at); - at = line_end + 1; - } - return ret; -} - -// Assesses the success or failure of a death test, using both private -// members which have previously been set, and one argument: -// -// Private data members: -// outcome: An enumeration describing how the death test -// concluded: DIED, LIVED, THREW, or RETURNED. The death test -// fails in the latter three cases. -// status: The exit status of the child process. On *nix, it is in the -// in the format specified by wait(2). On Windows, this is the -// value supplied to the ExitProcess() API or a numeric code -// of the exception that terminated the program. -// regex: A regular expression object to be applied to -// the test's captured standard error output; the death test -// fails if it does not match. -// -// Argument: -// status_ok: true if exit_status is acceptable in the context of -// this particular death test, which fails if it is false -// -// Returns true iff all of the above conditions are met. Otherwise, the -// first failing condition, in the order given above, is the one that is -// reported. Also sets the last death test message string. -bool DeathTestImpl::Passed(bool status_ok) { - if (!spawned()) - return false; - - const std::string error_message = GetCapturedStderr(); - - bool success = false; - Message buffer; - - buffer << "Death test: " << statement() << "\n"; - switch (outcome()) { - case LIVED: - buffer << " Result: failed to die.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case THREW: - buffer << " Result: threw an exception.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case RETURNED: - buffer << " Result: illegal return in test statement.\n" - << " Error msg:\n" << FormatDeathTestOutput(error_message); - break; - case DIED: - if (status_ok) { - const bool matched = RE::PartialMatch(error_message.c_str(), *regex()); - if (matched) { - success = true; - } else { - buffer << " Result: died but not with expected error.\n" - << " Expected: " << regex()->pattern() << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - } else { - buffer << " Result: died but not with expected exit code:\n" - << " " << ExitSummary(status()) << "\n" - << "Actual msg:\n" << FormatDeathTestOutput(error_message); - } - break; - case IN_PROGRESS: - default: - GTEST_LOG_(FATAL) - << "DeathTest::Passed somehow called before conclusion of test"; - } - - DeathTest::set_last_death_test_message(buffer.GetString()); - return success; -} - -# if GTEST_OS_WINDOWS -// WindowsDeathTest implements death tests on Windows. Due to the -// specifics of starting new processes on Windows, death tests there are -// always threadsafe, and Google Test considers the -// --gtest_death_test_style=fast setting to be equivalent to -// --gtest_death_test_style=threadsafe there. -// -// A few implementation notes: Like the Linux version, the Windows -// implementation uses pipes for child-to-parent communication. But due to -// the specifics of pipes on Windows, some extra steps are required: -// -// 1. The parent creates a communication pipe and stores handles to both -// ends of it. -// 2. The parent starts the child and provides it with the information -// necessary to acquire the handle to the write end of the pipe. -// 3. The child acquires the write end of the pipe and signals the parent -// using a Windows event. -// 4. Now the parent can release the write end of the pipe on its side. If -// this is done before step 3, the object's reference count goes down to -// 0 and it is destroyed, preventing the child from acquiring it. The -// parent now has to release it, or read operations on the read end of -// the pipe will not return when the child terminates. -// 5. The parent reads child's output through the pipe (outcome code and -// any possible error messages) from the pipe, and its stderr and then -// determines whether to fail the test. -// -// Note: to distinguish Win32 API calls from the local method and function -// calls, the former are explicitly resolved in the global namespace. -// -class WindowsDeathTest : public DeathTestImpl { - public: - WindowsDeathTest(const char* a_statement, - const RE* a_regex, - const char* file, - int line) - : DeathTestImpl(a_statement, a_regex), file_(file), line_(line) {} - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - virtual TestRole AssumeRole(); - - private: - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; - // Handle to the write end of the pipe to the child process. - AutoHandle write_handle_; - // Child process handle. - AutoHandle child_handle_; - // Event the child process uses to signal the parent that it has - // acquired the handle to the write end of the pipe. After seeing this - // event the parent can release its own handles to make sure its - // ReadFile() calls return when the child terminates. - AutoHandle event_handle_; -}; - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int WindowsDeathTest::Wait() { - if (!spawned()) - return 0; - - // Wait until the child either signals that it has acquired the write end - // of the pipe or it dies. - const HANDLE wait_handles[2] = { child_handle_.Get(), event_handle_.Get() }; - switch (::WaitForMultipleObjects(2, - wait_handles, - FALSE, // Waits for any of the handles. - INFINITE)) { - case WAIT_OBJECT_0: - case WAIT_OBJECT_0 + 1: - break; - default: - GTEST_DEATH_TEST_CHECK_(false); // Should not get here. - } - - // The child has acquired the write end of the pipe or exited. - // We release the handle on our side and continue. - write_handle_.Reset(); - event_handle_.Reset(); - - ReadAndInterpretStatusByte(); - - // Waits for the child process to exit if it haven't already. This - // returns immediately if the child has already exited, regardless of - // whether previous calls to WaitForMultipleObjects synchronized on this - // handle or not. - GTEST_DEATH_TEST_CHECK_( - WAIT_OBJECT_0 == ::WaitForSingleObject(child_handle_.Get(), - INFINITE)); - DWORD status_code; - GTEST_DEATH_TEST_CHECK_( - ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); - child_handle_.Reset(); - set_status(static_cast(status_code)); - return status(); -} - -// The AssumeRole process for a Windows death test. It creates a child -// process with the same executable as the current process to run the -// death test. The child process is given the --gtest_filter and -// --gtest_internal_run_death_test flags such that it knows to run the -// current death test only. -DeathTest::TestRole WindowsDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - // ParseInternalRunDeathTestFlag() has performed all the necessary - // processing. - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - // WindowsDeathTest uses an anonymous pipe to communicate results of - // a death test. - SECURITY_ATTRIBUTES handles_are_inheritable = { - sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; - HANDLE read_handle, write_handle; - GTEST_DEATH_TEST_CHECK_( - ::CreatePipe(&read_handle, &write_handle, &handles_are_inheritable, - 0) // Default buffer size. - != FALSE); - set_read_fd(::_open_osfhandle(reinterpret_cast(read_handle), - O_RDONLY)); - write_handle_.Reset(write_handle); - event_handle_.Reset(::CreateEvent( - &handles_are_inheritable, - TRUE, // The event will automatically reset to non-signaled state. - FALSE, // The initial state is non-signalled. - NULL)); // The even is unnamed. - GTEST_DEATH_TEST_CHECK_(event_handle_.Get() != NULL); - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + - info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + - "=" + file_ + "|" + StreamableToString(line_) + "|" + - StreamableToString(death_test_index) + "|" + - StreamableToString(static_cast(::GetCurrentProcessId())) + - // size_t has the same width as pointers on both 32-bit and 64-bit - // Windows platforms. - // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. - "|" + StreamableToString(reinterpret_cast(write_handle)) + - "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); - - char executable_path[_MAX_PATH + 1]; // NOLINT - GTEST_DEATH_TEST_CHECK_( - _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, - executable_path, - _MAX_PATH)); - - std::string command_line = - std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + - internal_flag + "\""; - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // Flush the log buffers since the log streams are shared with the child. - FlushInfoLog(); - - // The child process will share the standard handles with the parent. - STARTUPINFOA startup_info; - memset(&startup_info, 0, sizeof(STARTUPINFO)); - startup_info.dwFlags = STARTF_USESTDHANDLES; - startup_info.hStdInput = ::GetStdHandle(STD_INPUT_HANDLE); - startup_info.hStdOutput = ::GetStdHandle(STD_OUTPUT_HANDLE); - startup_info.hStdError = ::GetStdHandle(STD_ERROR_HANDLE); - - PROCESS_INFORMATION process_info; - GTEST_DEATH_TEST_CHECK_(::CreateProcessA( - executable_path, - const_cast(command_line.c_str()), - NULL, // Retuned process handle is not inheritable. - NULL, // Retuned thread handle is not inheritable. - TRUE, // Child inherits all inheritable handles (for write_handle_). - 0x0, // Default creation flags. - NULL, // Inherit the parent's environment. - UnitTest::GetInstance()->original_working_dir(), - &startup_info, - &process_info) != FALSE); - child_handle_.Reset(process_info.hProcess); - ::CloseHandle(process_info.hThread); - set_spawned(true); - return OVERSEE_TEST; -} -# else // We are not on Windows. - -// ForkingDeathTest provides implementations for most of the abstract -// methods of the DeathTest interface. Only the AssumeRole method is -// left undefined. -class ForkingDeathTest : public DeathTestImpl { - public: - ForkingDeathTest(const char* statement, const RE* regex); - - // All of these virtual functions are inherited from DeathTest. - virtual int Wait(); - - protected: - void set_child_pid(pid_t child_pid) { child_pid_ = child_pid; } - - private: - // PID of child process during death test; 0 in the child process itself. - pid_t child_pid_; -}; - -// Constructs a ForkingDeathTest. -ForkingDeathTest::ForkingDeathTest(const char* a_statement, const RE* a_regex) - : DeathTestImpl(a_statement, a_regex), - child_pid_(-1) {} - -// Waits for the child in a death test to exit, returning its exit -// status, or 0 if no child process exists. As a side effect, sets the -// outcome data member. -int ForkingDeathTest::Wait() { - if (!spawned()) - return 0; - - ReadAndInterpretStatusByte(); - - int status_value; - GTEST_DEATH_TEST_CHECK_SYSCALL_(waitpid(child_pid_, &status_value, 0)); - set_status(status_value); - return status_value; -} - -// A concrete death test class that forks, then immediately runs the test -// in the child process. -class NoExecDeathTest : public ForkingDeathTest { - public: - NoExecDeathTest(const char* a_statement, const RE* a_regex) : - ForkingDeathTest(a_statement, a_regex) { } - virtual TestRole AssumeRole(); -}; - -// The AssumeRole process for a fork-and-run death test. It implements a -// straightforward fork, with a simple pipe to transmit the status byte. -DeathTest::TestRole NoExecDeathTest::AssumeRole() { - const size_t thread_count = GetThreadCount(); - if (thread_count != 1) { - GTEST_LOG_(WARNING) << DeathTestThreadWarning(thread_count); - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - - DeathTest::set_last_death_test_message(""); - CaptureStderr(); - // When we fork the process below, the log file buffers are copied, but the - // file descriptors are shared. We flush all log files here so that closing - // the file descriptors in the child process doesn't throw off the - // synchronization between descriptors and buffers in the parent process. - // This is as close to the fork as possible to avoid a race condition in case - // there are multiple threads running before the death test, and another - // thread writes to the log file. - FlushInfoLog(); - - const pid_t child_pid = fork(); - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - set_child_pid(child_pid); - if (child_pid == 0) { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[0])); - set_write_fd(pipe_fd[1]); - // Redirects all logging to stderr in the child process to prevent - // concurrent writes to the log files. We capture stderr in the parent - // process and append the child process' output to a log. - LogToStderr(); - // Event forwarding to the listeners of event listener API mush be shut - // down in death test subprocesses. - GetUnitTestImpl()->listeners()->SuppressEventForwarding(); - g_in_fast_death_test_child = true; - return EXECUTE_TEST; - } else { - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; - } -} - -// A concrete death test class that forks and re-executes the main -// program from the beginning, with command-line flags set that cause -// only this specific death test to be run. -class ExecDeathTest : public ForkingDeathTest { - public: - ExecDeathTest(const char* a_statement, const RE* a_regex, - const char* file, int line) : - ForkingDeathTest(a_statement, a_regex), file_(file), line_(line) { } - virtual TestRole AssumeRole(); - private: - static ::std::vector - GetArgvsForDeathTestChildProcess() { - ::std::vector args = GetInjectableArgvs(); - return args; - } - // The name of the file in which the death test is located. - const char* const file_; - // The line number on which the death test is located. - const int line_; -}; - -// Utility class for accumulating command-line arguments. -class Arguments { - public: - Arguments() { - args_.push_back(NULL); - } - - ~Arguments() { - for (std::vector::iterator i = args_.begin(); i != args_.end(); - ++i) { - free(*i); - } - } - void AddArgument(const char* argument) { - args_.insert(args_.end() - 1, posix::StrDup(argument)); - } - - template - void AddArguments(const ::std::vector& arguments) { - for (typename ::std::vector::const_iterator i = arguments.begin(); - i != arguments.end(); - ++i) { - args_.insert(args_.end() - 1, posix::StrDup(i->c_str())); - } - } - char* const* Argv() { - return &args_[0]; - } - - private: - std::vector args_; -}; - -// A struct that encompasses the arguments to the child process of a -// threadsafe-style death test process. -struct ExecDeathTestArgs { - char* const* argv; // Command-line arguments for the child's call to exec - int close_fd; // File descriptor to close; the read end of a pipe -}; - -# if GTEST_OS_MAC -inline char** GetEnviron() { - // When Google Test is built as a framework on MacOS X, the environ variable - // is unavailable. Apple's documentation (man environ) recommends using - // _NSGetEnviron() instead. - return *_NSGetEnviron(); -} -# else -// Some POSIX platforms expect you to declare environ. extern "C" makes -// it reside in the global namespace. -extern "C" char** environ; -inline char** GetEnviron() { return environ; } -# endif // GTEST_OS_MAC - -# if !GTEST_OS_QNX -// The main function for a threadsafe-style death test child process. -// This function is called in a clone()-ed process and thus must avoid -// any potentially unsafe operations like malloc or libc functions. -static int ExecDeathTestChildMain(void* child_arg) { - ExecDeathTestArgs* const args = static_cast(child_arg); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd)); - - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; - } - - // We can safely call execve() as it's a direct system call. We - // cannot use execvp() as it's a libc function and thus potentially - // unsafe. Since execve() doesn't search the PATH, the user must - // invoke the test program via a valid path that contains at least - // one path separator. - execve(args->argv[0], args->argv, GetEnviron()); - DeathTestAbort(std::string("execve(") + args->argv[0] + ", ...) in " + - original_dir + " failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; -} -# endif // !GTEST_OS_QNX - -// Two utility routines that together determine the direction the stack -// grows. -// This could be accomplished more elegantly by a single recursive -// function, but we want to guard against the unlikely possibility of -// a smart compiler optimizing the recursion away. -// -// GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining -// StackLowerThanAddress into StackGrowsDown, which then doesn't give -// correct answer. -void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; -void StackLowerThanAddress(const void* ptr, bool* result) { - int dummy; - *result = (&dummy < ptr); -} - -bool StackGrowsDown() { - int dummy; - bool result; - StackLowerThanAddress(&dummy, &result); - return result; -} - -// Spawns a child process with the same executable as the current process in -// a thread-safe manner and instructs it to run the death test. The -// implementation uses fork(2) + exec. On systems where clone(2) is -// available, it is used instead, being slightly more thread-safe. On QNX, -// fork supports only single-threaded environments, so this function uses -// spawn(2) there instead. The function dies with an error message if -// anything goes wrong. -static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { - ExecDeathTestArgs args = { argv, close_fd }; - pid_t child_pid = -1; - -# if GTEST_OS_QNX - // Obtains the current directory and sets it to be closed in the child - // process. - const int cwd_fd = open(".", O_RDONLY); - GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); - GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); - // We need to execute the test program in the same environment where - // it was originally invoked. Therefore we change to the original - // working directory first. - const char* const original_dir = - UnitTest::GetInstance()->original_working_dir(); - // We can safely call chdir() as it's a direct system call. - if (chdir(original_dir) != 0) { - DeathTestAbort(std::string("chdir(\"") + original_dir + "\") failed: " + - GetLastErrnoDescription()); - return EXIT_FAILURE; - } - - int fd_flags; - // Set close_fd to be closed after spawn. - GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); - GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, - fd_flags | FD_CLOEXEC)); - struct inheritance inherit = {0}; - // spawn is a system call. - child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); - // Restores the current working directory. - GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); - -# else // GTEST_OS_QNX -# if GTEST_OS_LINUX - // When a SIGPROF signal is received while fork() or clone() are executing, - // the process may hang. To avoid this, we ignore SIGPROF here and re-enable - // it after the call to fork()/clone() is complete. - struct sigaction saved_sigprof_action; - struct sigaction ignore_sigprof_action; - memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); - sigemptyset(&ignore_sigprof_action.sa_mask); - ignore_sigprof_action.sa_handler = SIG_IGN; - GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( - SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); -# endif // GTEST_OS_LINUX - -# if GTEST_HAS_CLONE - const bool use_fork = GTEST_FLAG(death_test_use_fork); - - if (!use_fork) { - static const bool stack_grows_down = StackGrowsDown(); - const size_t stack_size = getpagesize(); - // MMAP_ANONYMOUS is not defined on Mac, so we use MAP_ANON instead. - void* const stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, - MAP_ANON | MAP_PRIVATE, -1, 0); - GTEST_DEATH_TEST_CHECK_(stack != MAP_FAILED); - - // Maximum stack alignment in bytes: For a downward-growing stack, this - // amount is subtracted from size of the stack space to get an address - // that is within the stack space and is aligned on all systems we care - // about. As far as I know there is no ABI with stack alignment greater - // than 64. We assume stack and stack_size already have alignment of - // kMaxStackAlignment. - const size_t kMaxStackAlignment = 64; - void* const stack_top = - static_cast(stack) + - (stack_grows_down ? stack_size - kMaxStackAlignment : 0); - GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && - reinterpret_cast(stack_top) % kMaxStackAlignment == 0); - - child_pid = clone(&ExecDeathTestChildMain, stack_top, SIGCHLD, &args); - - GTEST_DEATH_TEST_CHECK_(munmap(stack, stack_size) != -1); - } -# else - const bool use_fork = true; -# endif // GTEST_HAS_CLONE - - if (use_fork && (child_pid = fork()) == 0) { - ExecDeathTestChildMain(&args); - _exit(0); - } -# endif // GTEST_OS_QNX -# if GTEST_OS_LINUX - GTEST_DEATH_TEST_CHECK_SYSCALL_( - sigaction(SIGPROF, &saved_sigprof_action, NULL)); -# endif // GTEST_OS_LINUX - - GTEST_DEATH_TEST_CHECK_(child_pid != -1); - return child_pid; -} - -// The AssumeRole process for a fork-and-exec death test. It re-executes the -// main program from the beginning, setting the --gtest_filter -// and --gtest_internal_run_death_test flags to cause only the current -// death test to be re-run. -DeathTest::TestRole ExecDeathTest::AssumeRole() { - const UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const TestInfo* const info = impl->current_test_info(); - const int death_test_index = info->result()->death_test_count(); - - if (flag != NULL) { - set_write_fd(flag->write_fd()); - return EXECUTE_TEST; - } - - int pipe_fd[2]; - GTEST_DEATH_TEST_CHECK_(pipe(pipe_fd) != -1); - // Clear the close-on-exec flag on the write end of the pipe, lest - // it be closed when the child process does an exec: - GTEST_DEATH_TEST_CHECK_(fcntl(pipe_fd[1], F_SETFD, 0) != -1); - - const std::string filter_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" - + info->test_case_name() + "." + info->name(); - const std::string internal_flag = - std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" - + file_ + "|" + StreamableToString(line_) + "|" - + StreamableToString(death_test_index) + "|" - + StreamableToString(pipe_fd[1]); - Arguments args; - args.AddArguments(GetArgvsForDeathTestChildProcess()); - args.AddArgument(filter_flag.c_str()); - args.AddArgument(internal_flag.c_str()); - - DeathTest::set_last_death_test_message(""); - - CaptureStderr(); - // See the comment in NoExecDeathTest::AssumeRole for why the next line - // is necessary. - FlushInfoLog(); - - const pid_t child_pid = ExecDeathTestSpawnChild(args.Argv(), pipe_fd[0]); - GTEST_DEATH_TEST_CHECK_SYSCALL_(close(pipe_fd[1])); - set_child_pid(child_pid); - set_read_fd(pipe_fd[0]); - set_spawned(true); - return OVERSEE_TEST; -} - -# endif // !GTEST_OS_WINDOWS - -// Creates a concrete DeathTest-derived class that depends on the -// --gtest_death_test_style flag, and sets the pointer pointed to -// by the "test" argument to its address. If the test should be -// skipped, sets that pointer to NULL. Returns true, unless the -// flag is set to an invalid value. -bool DefaultDeathTestFactory::Create(const char* statement, const RE* regex, - const char* file, int line, - DeathTest** test) { - UnitTestImpl* const impl = GetUnitTestImpl(); - const InternalRunDeathTestFlag* const flag = - impl->internal_run_death_test_flag(); - const int death_test_index = impl->current_test_info() - ->increment_death_test_count(); - - if (flag != NULL) { - if (death_test_index > flag->index()) { - DeathTest::set_last_death_test_message( - "Death test count (" + StreamableToString(death_test_index) - + ") somehow exceeded expected maximum (" - + StreamableToString(flag->index()) + ")"); - return false; - } - - if (!(flag->file() == file && flag->line() == line && - flag->index() == death_test_index)) { - *test = NULL; - return true; - } - } - -# if GTEST_OS_WINDOWS - - if (GTEST_FLAG(death_test_style) == "threadsafe" || - GTEST_FLAG(death_test_style) == "fast") { - *test = new WindowsDeathTest(statement, regex, file, line); - } - -# else - - if (GTEST_FLAG(death_test_style) == "threadsafe") { - *test = new ExecDeathTest(statement, regex, file, line); - } else if (GTEST_FLAG(death_test_style) == "fast") { - *test = new NoExecDeathTest(statement, regex); - } - -# endif // GTEST_OS_WINDOWS - - else { // NOLINT - this is more readable than unbalanced brackets inside #if. - DeathTest::set_last_death_test_message( - "Unknown death test style \"" + GTEST_FLAG(death_test_style) - + "\" encountered"); - return false; - } - - return true; -} - -// Splits a given string on a given delimiter, populating a given -// vector with the fields. GTEST_HAS_DEATH_TEST implies that we have -// ::std::string, so we can use it here. -static void SplitString(const ::std::string& str, char delimiter, - ::std::vector< ::std::string>* dest) { - ::std::vector< ::std::string> parsed; - ::std::string::size_type pos = 0; - while (::testing::internal::AlwaysTrue()) { - const ::std::string::size_type colon = str.find(delimiter, pos); - if (colon == ::std::string::npos) { - parsed.push_back(str.substr(pos)); - break; - } else { - parsed.push_back(str.substr(pos, colon - pos)); - pos = colon + 1; - } - } - dest->swap(parsed); -} - -# if GTEST_OS_WINDOWS -// Recreates the pipe and event handles from the provided parameters, -// signals the event, and returns a file descriptor wrapped around the pipe -// handle. This function is called in the child process only. -int GetStatusFileDescriptor(unsigned int parent_process_id, - size_t write_handle_as_size_t, - size_t event_handle_as_size_t) { - AutoHandle parent_process_handle(::OpenProcess(PROCESS_DUP_HANDLE, - FALSE, // Non-inheritable. - parent_process_id)); - if (parent_process_handle.Get() == INVALID_HANDLE_VALUE) { - DeathTestAbort("Unable to open parent process " + - StreamableToString(parent_process_id)); - } - - // TODO(vladl@google.com): Replace the following check with a - // compile-time assertion when available. - GTEST_CHECK_(sizeof(HANDLE) <= sizeof(size_t)); - - const HANDLE write_handle = - reinterpret_cast(write_handle_as_size_t); - HANDLE dup_write_handle; - - // The newly initialized handle is accessible only in in the parent - // process. To obtain one accessible within the child, we need to use - // DuplicateHandle. - if (!::DuplicateHandle(parent_process_handle.Get(), write_handle, - ::GetCurrentProcess(), &dup_write_handle, - 0x0, // Requested privileges ignored since - // DUPLICATE_SAME_ACCESS is used. - FALSE, // Request non-inheritable handler. - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort("Unable to duplicate the pipe handle " + - StreamableToString(write_handle_as_size_t) + - " from the parent process " + - StreamableToString(parent_process_id)); - } - - const HANDLE event_handle = reinterpret_cast(event_handle_as_size_t); - HANDLE dup_event_handle; - - if (!::DuplicateHandle(parent_process_handle.Get(), event_handle, - ::GetCurrentProcess(), &dup_event_handle, - 0x0, - FALSE, - DUPLICATE_SAME_ACCESS)) { - DeathTestAbort("Unable to duplicate the event handle " + - StreamableToString(event_handle_as_size_t) + - " from the parent process " + - StreamableToString(parent_process_id)); - } - - const int write_fd = - ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); - if (write_fd == -1) { - DeathTestAbort("Unable to convert pipe handle " + - StreamableToString(write_handle_as_size_t) + - " to a file descriptor"); - } - - // Signals the parent that the write end of the pipe has been acquired - // so the parent can release its own write end. - ::SetEvent(dup_event_handle); - - return write_fd; -} -# endif // GTEST_OS_WINDOWS - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag() { - if (GTEST_FLAG(internal_run_death_test) == "") return NULL; - - // GTEST_HAS_DEATH_TEST implies that we have ::std::string, so we - // can use it here. - int line = -1; - int index = -1; - ::std::vector< ::std::string> fields; - SplitString(GTEST_FLAG(internal_run_death_test).c_str(), '|', &fields); - int write_fd = -1; - -# if GTEST_OS_WINDOWS - - unsigned int parent_process_id = 0; - size_t write_handle_as_size_t = 0; - size_t event_handle_as_size_t = 0; - - if (fields.size() != 6 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &parent_process_id) - || !ParseNaturalNumber(fields[4], &write_handle_as_size_t) - || !ParseNaturalNumber(fields[5], &event_handle_as_size_t)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " + - GTEST_FLAG(internal_run_death_test)); - } - write_fd = GetStatusFileDescriptor(parent_process_id, - write_handle_as_size_t, - event_handle_as_size_t); -# else - - if (fields.size() != 4 - || !ParseNaturalNumber(fields[1], &line) - || !ParseNaturalNumber(fields[2], &index) - || !ParseNaturalNumber(fields[3], &write_fd)) { - DeathTestAbort("Bad --gtest_internal_run_death_test flag: " - + GTEST_FLAG(internal_run_death_test)); - } - -# endif // GTEST_OS_WINDOWS - - return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); -} - -} // namespace internal - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: keith.ray@gmail.com (Keith Ray) - - -#include - -#if GTEST_OS_WINDOWS_MOBILE -# include -#elif GTEST_OS_WINDOWS -# include -# include -#elif GTEST_OS_SYMBIAN -// Symbian OpenC has PATH_MAX in sys/syslimits.h -# include -#else -# include -# include // Some Linux distributions define PATH_MAX here. -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_WINDOWS -# define GTEST_PATH_MAX_ _MAX_PATH -#elif defined(PATH_MAX) -# define GTEST_PATH_MAX_ PATH_MAX -#elif defined(_XOPEN_PATH_MAX) -# define GTEST_PATH_MAX_ _XOPEN_PATH_MAX -#else -# define GTEST_PATH_MAX_ _POSIX_PATH_MAX -#endif // GTEST_OS_WINDOWS - - -namespace testing { -namespace internal { - -#if GTEST_OS_WINDOWS -// On Windows, '\\' is the standard path separator, but many tools and the -// Windows API also accept '/' as an alternate path separator. Unless otherwise -// noted, a file path can contain either kind of path separators, or a mixture -// of them. -const char kPathSeparator = '\\'; -const char kAlternatePathSeparator = '/'; -//const char kPathSeparatorString[] = "\\"; -const char kAlternatePathSeparatorString[] = "/"; -# if GTEST_OS_WINDOWS_MOBILE -// Windows CE doesn't have a current directory. You should not use -// the current directory in tests on Windows CE, but this at least -// provides a reasonable fallback. -const char kCurrentDirectoryString[] = "\\"; -// Windows CE doesn't define INVALID_FILE_ATTRIBUTES -const DWORD kInvalidFileAttributes = 0xffffffff; -# else -const char kCurrentDirectoryString[] = ".\\"; -# endif // GTEST_OS_WINDOWS_MOBILE -#else -const char kPathSeparator = '/'; -//const char kPathSeparatorString[] = "/"; -const char kCurrentDirectoryString[] = "./"; -#endif // GTEST_OS_WINDOWS - -// Returns whether the given character is a valid path separator. -static bool IsPathSeparator(char c) { -#if GTEST_HAS_ALT_PATH_SEP_ - return (c == kPathSeparator) || (c == kAlternatePathSeparator); -#else - return c == kPathSeparator; -#endif -} - -// Returns the current working directory, or "" if unsuccessful. -FilePath FilePath::GetCurrentDir() { -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE doesn't have a current directory, so we just return - // something reasonable. - return FilePath(kCurrentDirectoryString); -#elif GTEST_OS_WINDOWS - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(_getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#else - char cwd[GTEST_PATH_MAX_ + 1] = { '\0' }; - return FilePath(getcwd(cwd, sizeof(cwd)) == NULL ? "" : cwd); -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns a copy of the FilePath with the case-insensitive extension removed. -// Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns -// FilePath("dir/file"). If a case-insensitive extension is not -// found, returns a copy of the original FilePath. -FilePath FilePath::RemoveExtension(const char* extension) const { - const std::string dot_extension = std::string(".") + extension; - if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { - return FilePath(pathname_.substr( - 0, pathname_.length() - dot_extension.length())); - } - return *this; -} - -// Returns a pointer to the last occurence of a valid path separator in -// the FilePath. On Windows, for example, both '/' and '\' are valid path -// separators. Returns NULL if no path separator was found. -const char* FilePath::FindLastPathSeparator() const { - const char* const last_sep = strrchr(c_str(), kPathSeparator); -#if GTEST_HAS_ALT_PATH_SEP_ - const char* const last_alt_sep = strrchr(c_str(), kAlternatePathSeparator); - // Comparing two pointers of which only one is NULL is undefined. - if (last_alt_sep != NULL && - (last_sep == NULL || last_alt_sep > last_sep)) { - return last_alt_sep; - } -#endif - return last_sep; -} - -// Returns a copy of the FilePath with the directory part removed. -// Example: FilePath("path/to/file").RemoveDirectoryName() returns -// FilePath("file"). If there is no directory part ("just_a_file"), it returns -// the FilePath unmodified. If there is no file part ("just_a_dir/") it -// returns an empty FilePath (""). -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveDirectoryName() const { - const char* const last_sep = FindLastPathSeparator(); - return last_sep ? FilePath(last_sep + 1) : *this; -} - -// RemoveFileName returns the directory path with the filename removed. -// Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". -// If the FilePath is "a_file" or "/a_file", RemoveFileName returns -// FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does -// not have a file, like "just/a/dir/", it returns the FilePath unmodified. -// On Windows platform, '\' is the path separator, otherwise it is '/'. -FilePath FilePath::RemoveFileName() const { - const char* const last_sep = FindLastPathSeparator(); - std::string dir; - if (last_sep) { - dir = std::string(c_str(), last_sep + 1 - c_str()); - } else { - dir = kCurrentDirectoryString; - } - return FilePath(dir); -} - -// Helper functions for naming files in a directory for xml output. - -// Given directory = "dir", base_name = "test", number = 0, -// extension = "xml", returns "dir/test.xml". If number is greater -// than zero (e.g., 12), returns "dir/test_12.xml". -// On Windows platform, uses \ as the separator rather than /. -FilePath FilePath::MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension) { - std::string file; - if (number == 0) { - file = base_name.string() + "." + extension; - } else { - file = base_name.string() + "_" + StreamableToString(number) - + "." + extension; - } - return ConcatPaths(directory, FilePath(file)); -} - -// Given directory = "dir", relative_path = "test.xml", returns "dir/test.xml". -// On Windows, uses \ as the separator rather than /. -FilePath FilePath::ConcatPaths(const FilePath& directory, - const FilePath& relative_path) { - if (directory.IsEmpty()) - return relative_path; - const FilePath dir(directory.RemoveTrailingPathSeparator()); - return FilePath(dir.string() + kPathSeparator + relative_path.string()); -} - -// Returns true if pathname describes something findable in the file-system, -// either a file, directory, or whatever. -bool FilePath::FileOrDirectoryExists() const { -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(pathname_.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - return attributes != kInvalidFileAttributes; -#else - posix::StatStruct file_stat; - return posix::Stat(pathname_.c_str(), &file_stat) == 0; -#endif // GTEST_OS_WINDOWS_MOBILE -} - -// Returns true if pathname describes a directory in the file-system -// that exists. -bool FilePath::DirectoryExists() const { - bool result = false; -#if GTEST_OS_WINDOWS - // Don't strip off trailing separator if path is a root directory on - // Windows (like "C:\\"). - const FilePath& path(IsRootDirectory() ? *this : - RemoveTrailingPathSeparator()); -#else - const FilePath& path(*this); -#endif - -#if GTEST_OS_WINDOWS_MOBILE - LPCWSTR unicode = String::AnsiToUtf16(path.c_str()); - const DWORD attributes = GetFileAttributes(unicode); - delete [] unicode; - if ((attributes != kInvalidFileAttributes) && - (attributes & FILE_ATTRIBUTE_DIRECTORY)) { - result = true; - } -#else - posix::StatStruct file_stat; - result = posix::Stat(path.c_str(), &file_stat) == 0 && - posix::IsDir(file_stat); -#endif // GTEST_OS_WINDOWS_MOBILE - - return result; -} - -// Returns true if pathname describes a root directory. (Windows has one -// root directory per disk drive.) -bool FilePath::IsRootDirectory() const { -#if GTEST_OS_WINDOWS - // TODO(wan@google.com): on Windows a network share like - // \\server\share can be a root directory, although it cannot be the - // current directory. Handle this properly. - return pathname_.length() == 3 && IsAbsolutePath(); -#else - return pathname_.length() == 1 && IsPathSeparator(pathname_.c_str()[0]); -#endif -} - -// Returns true if pathname describes an absolute path. -bool FilePath::IsAbsolutePath() const { - const char* const name = pathname_.c_str(); -#if GTEST_OS_WINDOWS - return pathname_.length() >= 3 && - ((name[0] >= 'a' && name[0] <= 'z') || - (name[0] >= 'A' && name[0] <= 'Z')) && - name[1] == ':' && - IsPathSeparator(name[2]); -#else - return IsPathSeparator(name[0]); -#endif -} - -// Returns a pathname for a file that does not currently exist. The pathname -// will be directory/base_name.extension or -// directory/base_name_.extension if directory/base_name.extension -// already exists. The number will be incremented until a pathname is found -// that does not already exist. -// Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. -// There could be a race condition if two or more processes are calling this -// function at the same time -- they could both pick the same filename. -FilePath FilePath::GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension) { - FilePath full_pathname; - int number = 0; - do { - full_pathname.Set(MakeFileName(directory, base_name, number++, extension)); - } while (full_pathname.FileOrDirectoryExists()); - return full_pathname; -} - -// Returns true if FilePath ends with a path separator, which indicates that -// it is intended to represent a directory. Returns false otherwise. -// This does NOT check that a directory (or file) actually exists. -bool FilePath::IsDirectory() const { - return !pathname_.empty() && - IsPathSeparator(pathname_.c_str()[pathname_.length() - 1]); -} - -// Create directories so that path exists. Returns true if successful or if -// the directories already exist; returns false if unable to create directories -// for any reason. -bool FilePath::CreateDirectoriesRecursively() const { - if (!this->IsDirectory()) { - return false; - } - - if (pathname_.length() == 0 || this->DirectoryExists()) { - return true; - } - - const FilePath parent(this->RemoveTrailingPathSeparator().RemoveFileName()); - return parent.CreateDirectoriesRecursively() && this->CreateFolder(); -} - -// Create the directory so that path exists. Returns true if successful or -// if the directory already exists; returns false if unable to create the -// directory for any reason, including if the parent directory does not -// exist. Not named "CreateDirectory" because that's a macro on Windows. -bool FilePath::CreateFolder() const { -#if GTEST_OS_WINDOWS_MOBILE - FilePath removed_sep(this->RemoveTrailingPathSeparator()); - LPCWSTR unicode = String::AnsiToUtf16(removed_sep.c_str()); - int result = CreateDirectory(unicode, NULL) ? 0 : -1; - delete [] unicode; -#elif GTEST_OS_WINDOWS - int result = _mkdir(pathname_.c_str()); -#else - int result = mkdir(pathname_.c_str(), 0777); -#endif // GTEST_OS_WINDOWS_MOBILE - - if (result == -1) { - return this->DirectoryExists(); // An error is OK if the directory exists. - } - return true; // No error. -} - -// If input name has a trailing separator character, remove it and return the -// name, otherwise return the name string unmodified. -// On Windows platform, uses \ as the separator, other platforms use /. -FilePath FilePath::RemoveTrailingPathSeparator() const { - return IsDirectory() - ? FilePath(pathname_.substr(0, pathname_.length() - 1)) - : *this; -} - -// Removes any redundant separators that might be in the pathname. -// For example, "bar///foo" becomes "bar/foo". Does not eliminate other -// redundancies that might be in a pathname involving "." or "..". -// TODO(wan@google.com): handle Windows network shares (e.g. \\server\share). -void FilePath::Normalize() { - if (pathname_.c_str() == NULL) { - pathname_ = ""; - return; - } - const char* src = pathname_.c_str(); - char* const dest = new char[pathname_.length() + 1]; - char* dest_ptr = dest; - memset(dest_ptr, 0, pathname_.length() + 1); - - while (*src != '\0') { - *dest_ptr = *src; - if (!IsPathSeparator(*src)) { - src++; - } else { -#if GTEST_HAS_ALT_PATH_SEP_ - if (*dest_ptr == kAlternatePathSeparator) { - *dest_ptr = kPathSeparator; - } -#endif - while (IsPathSeparator(*src)) - src++; - } - dest_ptr++; - } - *dest_ptr = '\0'; - pathname_ = dest; - delete[] dest; -} - -} // namespace internal -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - - -#include -#include -#include -#include - -#if GTEST_OS_WINDOWS_MOBILE -# include // For TerminateProcess() -#elif GTEST_OS_WINDOWS -# include -# include -#else -# include -#endif // GTEST_OS_WINDOWS_MOBILE - -#if GTEST_OS_MAC -# include -# include -# include -#endif // GTEST_OS_MAC - -#if GTEST_OS_QNX -# include -# include -#endif // GTEST_OS_QNX - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { -namespace internal { - -#if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC and C++Builder do not provide a definition of STDERR_FILENO. -const int kStdOutFileno = 1; -const int kStdErrFileno = 2; -#else -const int kStdOutFileno = STDOUT_FILENO; -const int kStdErrFileno = STDERR_FILENO; -#endif // _MSC_VER - -#if GTEST_OS_MAC - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const task_t task = mach_task_self(); - mach_msg_type_number_t thread_count; - thread_act_array_t thread_list; - const kern_return_t status = task_threads(task, &thread_list, &thread_count); - if (status == KERN_SUCCESS) { - // task_threads allocates resources in thread_list and we need to free them - // to avoid leaks. - vm_deallocate(task, - reinterpret_cast(thread_list), - sizeof(thread_t) * thread_count); - return static_cast(thread_count); - } else { - return 0; - } -} - -#elif GTEST_OS_QNX - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -size_t GetThreadCount() { - const int fd = open("/proc/self/as", O_RDONLY); - if (fd < 0) { - return 0; - } - procfs_info process_info; - const int status = - devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); - close(fd); - if (status == EOK) { - return static_cast(process_info.num_threads); - } else { - return 0; - } -} - -#else - -size_t GetThreadCount() { - // There's no portable way to detect the number of threads, so we just - // return 0 to indicate that we cannot detect it. - return 0; -} - -#endif // GTEST_OS_MAC - -#if GTEST_USES_POSIX_RE - -// Implements RE. Currently only needed for death tests. - -RE::~RE() { - if (is_valid_) { - // regfree'ing an invalid regex might crash because the content - // of the regex is undefined. Since the regex's are essentially - // the same, one cannot be valid (or invalid) without the other - // being so too. - regfree(&partial_regex_); - regfree(&full_regex_); - } - free(const_cast(pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.full_regex_, str, 1, &match, 0) == 0; -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - if (!re.is_valid_) return false; - - regmatch_t match; - return regexec(&re.partial_regex_, str, 1, &match, 0) == 0; -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = posix::StrDup(regex); - - // Reserves enough bytes to hold the regular expression used for a - // full match. - const size_t full_regex_len = strlen(regex) + 10; - char* const full_pattern = new char[full_regex_len]; - - snprintf(full_pattern, full_regex_len, "^(%s)$", regex); - is_valid_ = regcomp(&full_regex_, full_pattern, REG_EXTENDED) == 0; - // We want to call regcomp(&partial_regex_, ...) even if the - // previous expression returns false. Otherwise partial_regex_ may - // not be properly initialized can may cause trouble when it's - // freed. - // - // Some implementation of POSIX regex (e.g. on at least some - // versions of Cygwin) doesn't accept the empty string as a valid - // regex. We change it to an equivalent form "()" to be safe. - if (is_valid_) { - const char* const partial_regex = (*regex == '\0') ? "()" : regex; - is_valid_ = regcomp(&partial_regex_, partial_regex, REG_EXTENDED) == 0; - } - EXPECT_TRUE(is_valid_) - << "Regular expression \"" << regex - << "\" is not a valid POSIX Extended regular expression."; - - delete[] full_pattern; -} - -#elif GTEST_USES_SIMPLE_RE - -// Returns true iff ch appears anywhere in str (excluding the -// terminating '\0' character). -bool IsInSet(char ch, const char* str) { - return ch != '\0' && strchr(str, ch) != NULL; -} - -// Returns true iff ch belongs to the given classification. Unlike -// similar functions in , these aren't affected by the -// current locale. -bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } -bool IsAsciiPunct(char ch) { - return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); -} -bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } -bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } -bool IsAsciiWordChar(char ch) { - return ('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z') || - ('0' <= ch && ch <= '9') || ch == '_'; -} - -// Returns true iff "\\c" is a supported escape sequence. -bool IsValidEscape(char c) { - return (IsAsciiPunct(c) || IsInSet(c, "dDfnrsStvwW")); -} - -// Returns true iff the given atom (specified by escaped and pattern) -// matches ch. The result is undefined if the atom is invalid. -bool AtomMatchesChar(bool escaped, char pattern_char, char ch) { - if (escaped) { // "\\p" where p is pattern_char. - switch (pattern_char) { - case 'd': return IsAsciiDigit(ch); - case 'D': return !IsAsciiDigit(ch); - case 'f': return ch == '\f'; - case 'n': return ch == '\n'; - case 'r': return ch == '\r'; - case 's': return IsAsciiWhiteSpace(ch); - case 'S': return !IsAsciiWhiteSpace(ch); - case 't': return ch == '\t'; - case 'v': return ch == '\v'; - case 'w': return IsAsciiWordChar(ch); - case 'W': return !IsAsciiWordChar(ch); - } - return IsAsciiPunct(pattern_char) && pattern_char == ch; - } - - return (pattern_char == '.' && ch != '\n') || pattern_char == ch; -} - -// Helper function used by ValidateRegex() to format error messages. -std::string FormatRegexSyntaxError(const char* regex, int index) { - return (Message() << "Syntax error at index " << index - << " in simple regular expression \"" << regex << "\": ").GetString(); -} - -// Generates non-fatal failures and returns false if regex is invalid; -// otherwise returns true. -bool ValidateRegex(const char* regex) { - if (regex == NULL) { - // TODO(wan@google.com): fix the source file location in the - // assertion failures to match where the regex is used in user - // code. - ADD_FAILURE() << "NULL is not a valid simple regular expression."; - return false; - } - - bool is_valid = true; - - // True iff ?, *, or + can follow the previous atom. - bool prev_repeatable = false; - for (int i = 0; regex[i]; i++) { - if (regex[i] == '\\') { // An escape sequence - i++; - if (regex[i] == '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "'\\' cannot appear at the end."; - return false; - } - - if (!IsValidEscape(regex[i])) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i - 1) - << "invalid escape sequence \"\\" << regex[i] << "\"."; - is_valid = false; - } - prev_repeatable = true; - } else { // Not an escape sequence. - const char ch = regex[i]; - - if (ch == '^' && i > 0) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'^' can only appear at the beginning."; - is_valid = false; - } else if (ch == '$' && regex[i + 1] != '\0') { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'$' can only appear at the end."; - is_valid = false; - } else if (IsInSet(ch, "()[]{}|")) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' is unsupported."; - is_valid = false; - } else if (IsRepeat(ch) && !prev_repeatable) { - ADD_FAILURE() << FormatRegexSyntaxError(regex, i) - << "'" << ch << "' can only follow a repeatable token."; - is_valid = false; - } - - prev_repeatable = !IsInSet(ch, "^$?*+"); - } - } - - return is_valid; -} - -// Matches a repeated regex atom followed by a valid simple regular -// expression. The regex atom is defined as c if escaped is false, -// or \c otherwise. repeat is the repetition meta character (?, *, -// or +). The behavior is undefined if str contains too many -// characters to be indexable by size_t, in which case the test will -// probably time out anyway. We are fine with this limitation as -// std::string has it too. -bool MatchRepetitionAndRegexAtHead( - bool escaped, char c, char repeat, const char* regex, - const char* str) { - const size_t min_count = (repeat == '+') ? 1 : 0; - const size_t max_count = (repeat == '?') ? 1 : - static_cast(-1) - 1; - // We cannot call numeric_limits::max() as it conflicts with the - // max() macro on Windows. - - for (size_t i = 0; i <= max_count; ++i) { - // We know that the atom matches each of the first i characters in str. - if (i >= min_count && MatchRegexAtHead(regex, str + i)) { - // We have enough matches at the head, and the tail matches too. - // Since we only care about *whether* the pattern matches str - // (as opposed to *how* it matches), there is no need to find a - // greedy match. - return true; - } - if (str[i] == '\0' || !AtomMatchesChar(escaped, c, str[i])) - return false; - } - return false; -} - -// Returns true iff regex matches a prefix of str. regex must be a -// valid simple regular expression and not start with "^", or the -// result is undefined. -bool MatchRegexAtHead(const char* regex, const char* str) { - if (*regex == '\0') // An empty regex matches a prefix of anything. - return true; - - // "$" only matches the end of a string. Note that regex being - // valid guarantees that there's nothing after "$" in it. - if (*regex == '$') - return *str == '\0'; - - // Is the first thing in regex an escape sequence? - const bool escaped = *regex == '\\'; - if (escaped) - ++regex; - if (IsRepeat(regex[1])) { - // MatchRepetitionAndRegexAtHead() calls MatchRegexAtHead(), so - // here's an indirect recursion. It terminates as the regex gets - // shorter in each recursion. - return MatchRepetitionAndRegexAtHead( - escaped, regex[0], regex[1], regex + 2, str); - } else { - // regex isn't empty, isn't "$", and doesn't start with a - // repetition. We match the first atom of regex with the first - // character of str and recurse. - return (*str != '\0') && AtomMatchesChar(escaped, *regex, *str) && - MatchRegexAtHead(regex + 1, str + 1); - } -} - -// Returns true iff regex matches any substring of str. regex must be -// a valid simple regular expression, or the result is undefined. -// -// The algorithm is recursive, but the recursion depth doesn't exceed -// the regex length, so we won't need to worry about running out of -// stack space normally. In rare cases the time complexity can be -// exponential with respect to the regex length + the string length, -// but usually it's must faster (often close to linear). -bool MatchRegexAnywhere(const char* regex, const char* str) { - if (regex == NULL || str == NULL) - return false; - - if (*regex == '^') - return MatchRegexAtHead(regex + 1, str); - - // A successful match can be anywhere in str. - do { - if (MatchRegexAtHead(regex, str)) - return true; - } while (*str++ != '\0'); - return false; -} - -// Implements the RE class. - -RE::~RE() { - free(const_cast(pattern_)); - free(const_cast(full_pattern_)); -} - -// Returns true iff regular expression re matches the entire str. -bool RE::FullMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.full_pattern_, str); -} - -// Returns true iff regular expression re matches a substring of str -// (including str itself). -bool RE::PartialMatch(const char* str, const RE& re) { - return re.is_valid_ && MatchRegexAnywhere(re.pattern_, str); -} - -// Initializes an RE from its string representation. -void RE::Init(const char* regex) { - pattern_ = full_pattern_ = NULL; - if (regex != NULL) { - pattern_ = posix::StrDup(regex); - } - - is_valid_ = ValidateRegex(regex); - if (!is_valid_) { - // No need to calculate the full pattern when the regex is invalid. - return; - } - - const size_t len = strlen(regex); - // Reserves enough bytes to hold the regular expression used for a - // full match: we need space to prepend a '^', append a '$', and - // terminate the string with '\0'. - char* buffer = static_cast(malloc(len + 3)); - full_pattern_ = buffer; - - if (*regex != '^') - *buffer++ = '^'; // Makes sure full_pattern_ starts with '^'. - - // We don't use snprintf or strncpy, as they trigger a warning when - // compiled with VC++ 8.0. - memcpy(buffer, regex, len); - buffer += len; - - if (len == 0 || regex[len - 1] != '$') - *buffer++ = '$'; // Makes sure full_pattern_ ends with '$'. - - *buffer = '\0'; -} - -#endif // GTEST_USES_POSIX_RE - -const char kUnknownFile[] = "unknown file"; - -// Formats a source file path and a line number as they would appear -// in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); - - if (line < 0) { - return file_name + ":"; - } -#ifdef _MSC_VER - return file_name + "(" + StreamableToString(line) + "):"; -#else - return file_name + ":" + StreamableToString(line) + ":"; -#endif // _MSC_VER -} - -// Formats a file location for compiler-independent XML output. -// Although this function is not platform dependent, we put it next to -// FormatFileLocation in order to contrast the two functions. -// Note that FormatCompilerIndependentFileLocation() does NOT append colon -// to the file location it produces, unlike FormatFileLocation(). -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( - const char* file, int line) { - const std::string file_name(file == NULL ? kUnknownFile : file); - - if (line < 0) - return file_name; - else - return file_name + ":" + StreamableToString(line); -} - - -GTestLog::GTestLog(GTestLogSeverity severity, const char* file, int line) - : severity_(severity) { - const char* const marker = - severity == GTEST_INFO ? "[ INFO ]" : - severity == GTEST_WARNING ? "[WARNING]" : - severity == GTEST_ERROR ? "[ ERROR ]" : "[ FATAL ]"; - GetStream() << ::std::endl << marker << " " - << FormatFileLocation(file, line).c_str() << ": "; -} - -// Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. -GTestLog::~GTestLog() { - GetStream() << ::std::endl; - if (severity_ == GTEST_FATAL) { - fflush(stderr); - posix::Abort(); - } -} -// Disable Microsoft deprecation warnings for POSIX functions called from -// this class (creat, dup, dup2, and close) -#ifdef _MSC_VER -# pragma warning(push) -# pragma warning(disable: 4996) -#endif // _MSC_VER - -#if GTEST_HAS_STREAM_REDIRECTION - -// Object that captures an output stream (stdout/stderr). -class CapturedStream { - public: - // The ctor redirects the stream to a temporary file. - explicit CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd)) { -# if GTEST_OS_WINDOWS - char temp_dir_path[MAX_PATH + 1] = { '\0' }; // NOLINT - char temp_file_path[MAX_PATH + 1] = { '\0' }; // NOLINT - - ::GetTempPathA(sizeof(temp_dir_path), temp_dir_path); - const UINT success = ::GetTempFileNameA(temp_dir_path, - "gtest_redir", - 0, // Generate unique file name. - temp_file_path); - GTEST_CHECK_(success != 0) - << "Unable to create a temporary file in " << temp_dir_path; - const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE); - GTEST_CHECK_(captured_fd != -1) << "Unable to open temporary file " - << temp_file_path; - filename_ = temp_file_path; -# else - // There's no guarantee that a test has write access to the current - // directory, so we create the temporary file in the /tmp directory - // instead. We use /tmp on most systems, and /sdcard on Android. - // That's because Android doesn't have /tmp. -# if GTEST_OS_LINUX_ANDROID - // Note: Android applications are expected to call the framework's - // Context.getExternalStorageDirectory() method through JNI to get - // the location of the world-writable SD Card directory. However, - // this requires a Context handle, which cannot be retrieved - // globally from native code. Doing so also precludes running the - // code as part of a regular standalone executable, which doesn't - // run in a Dalvik process (e.g. when running it through 'adb shell'). - // - // The location /sdcard is directly accessible from native code - // and is the only location (unofficially) supported by the Android - // team. It's generally a symlink to the real SD Card mount point - // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or - // other OEM-customized locations. Never rely on these, and always - // use /sdcard. - char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; -# else - char name_template[] = "/tmp/captured_stream.XXXXXX"; -# endif // GTEST_OS_LINUX_ANDROID - const int captured_fd = mkstemp(name_template); - filename_ = name_template; -# endif // GTEST_OS_WINDOWS - fflush(NULL); - dup2(captured_fd, fd_); - close(captured_fd); - } - - ~CapturedStream() { - remove(filename_.c_str()); - } - - std::string GetCapturedString() { - if (uncaptured_fd_ != -1) { - // Restores the original stream. - fflush(NULL); - dup2(uncaptured_fd_, fd_); - close(uncaptured_fd_); - uncaptured_fd_ = -1; - } - - FILE* const file = posix::FOpen(filename_.c_str(), "r"); - const std::string content = ReadEntireFile(file); - posix::FClose(file); - return content; - } - - private: - // Reads the entire content of a file as an std::string. - static std::string ReadEntireFile(FILE* file); - - // Returns the size (in bytes) of a file. - static size_t GetFileSize(FILE* file); - - const int fd_; // A stream to capture. - int uncaptured_fd_; - // Name of the temporary file holding the stderr output. - ::std::string filename_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(CapturedStream); -}; - -// Returns the size (in bytes) of a file. -size_t CapturedStream::GetFileSize(FILE* file) { - fseek(file, 0, SEEK_END); - return static_cast(ftell(file)); -} - -// Reads the entire content of a file as a string. -std::string CapturedStream::ReadEntireFile(FILE* file) { - const size_t file_size = GetFileSize(file); - char* const buffer = new char[file_size]; - - size_t bytes_last_read = 0; // # of bytes read in the last fread() - size_t bytes_read = 0; // # of bytes read so far - - fseek(file, 0, SEEK_SET); - - // Keeps reading the file until we cannot read further or the - // pre-determined file size is reached. - do { - bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file); - bytes_read += bytes_last_read; - } while (bytes_last_read > 0 && bytes_read < file_size); - - const std::string content(buffer, bytes_read); - delete[] buffer; - - return content; -} - -# ifdef _MSC_VER -# pragma warning(pop) -# endif // _MSC_VER - -static CapturedStream* g_captured_stderr = NULL; -static CapturedStream* g_captured_stdout = NULL; - -// Starts capturing an output stream (stdout/stderr). -void CaptureStream(int fd, const char* stream_name, CapturedStream** stream) { - if (*stream != NULL) { - GTEST_LOG_(FATAL) << "Only one " << stream_name - << " capturer can exist at a time."; - } - *stream = new CapturedStream(fd); -} - -// Stops capturing the output stream and returns the captured string. -std::string GetCapturedStream(CapturedStream** captured_stream) { - const std::string content = (*captured_stream)->GetCapturedString(); - - delete *captured_stream; - *captured_stream = NULL; - - return content; -} - -// Starts capturing stdout. -void CaptureStdout() { - CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); -} - -// Starts capturing stderr. -void CaptureStderr() { - CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); -} - -// Stops capturing stdout and returns the captured string. -std::string GetCapturedStdout() { - return GetCapturedStream(&g_captured_stdout); -} - -// Stops capturing stderr and returns the captured string. -std::string GetCapturedStderr() { - return GetCapturedStream(&g_captured_stderr); -} - -#endif // GTEST_HAS_STREAM_REDIRECTION - -#if GTEST_HAS_DEATH_TEST - -// A copy of all command line arguments. Set by InitGoogleTest(). -::std::vector g_argvs; - -static const ::std::vector* g_injected_test_argvs = - NULL; // Owned. - -void SetInjectableArgvs(const ::std::vector* argvs) { - if (g_injected_test_argvs != argvs) - delete g_injected_test_argvs; - g_injected_test_argvs = argvs; -} - -const ::std::vector& GetInjectableArgvs() { - if (g_injected_test_argvs != NULL) { - return *g_injected_test_argvs; - } - return g_argvs; -} -#endif // GTEST_HAS_DEATH_TEST - -#if GTEST_OS_WINDOWS_MOBILE -namespace posix { -void Abort() { - DebugBreak(); - TerminateProcess(GetCurrentProcess(), 1); -} -} // namespace posix -#endif // GTEST_OS_WINDOWS_MOBILE - -// Returns the name of the environment variable corresponding to the -// given flag. For example, FlagToEnvVar("foo") will return -// "GTEST_FOO" in the open-source version. -static std::string FlagToEnvVar(const char* flag) { - const std::string full_flag = - (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); - - Message env_var; - for (size_t i = 0; i != full_flag.length(); i++) { - env_var << ToUpper(full_flag.c_str()[i]); - } - - return env_var.GetString(); -} - -// Parses 'str' for a 32-bit signed integer. If successful, writes -// the result to *value and returns true; otherwise leaves *value -// unchanged and returns false. -bool ParseInt32(const Message& src_text, const char* str, Int32* value) { - // Parses the environment variable as a decimal integer. - char* end = NULL; - const long long_value = strtol(str, &end, 10); // NOLINT - - // Has strtol() consumed all characters in the string? - if (*end != '\0') { - // No - an invalid character was encountered. - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value \"" << str << "\".\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - // Is the parsed value in the range of an Int32? - const Int32 result = static_cast(long_value); - if (long_value == LONG_MAX || long_value == LONG_MIN || - // The parsed value overflows as a long. (strtol() returns - // LONG_MAX or LONG_MIN when the input overflows.) - result != long_value - // The parsed value overflows as an Int32. - ) { - Message msg; - msg << "WARNING: " << src_text - << " is expected to be a 32-bit integer, but actually" - << " has value " << str << ", which overflows.\n"; - printf("%s", msg.GetString().c_str()); - fflush(stdout); - return false; - } - - *value = result; - return true; -} - -// Reads and returns the Boolean environment variable corresponding to -// the given flag; if it's not set, returns default_value. -// -// The value is considered true iff it's not "0". -bool BoolFromGTestEnv(const char* flag, bool default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - return string_value == NULL ? - default_value : strcmp(string_value, "0") != 0; -} - -// Reads and returns a 32-bit integer stored in the environment -// variable corresponding to the given flag; if it isn't set or -// doesn't represent a valid 32-bit integer, returns default_value. -Int32 Int32FromGTestEnv(const char* flag, Int32 default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const string_value = posix::GetEnv(env_var.c_str()); - if (string_value == NULL) { - // The environment variable is not set. - return default_value; - } - - Int32 result = default_value; - if (!ParseInt32(Message() << "Environment variable " << env_var, - string_value, &result)) { - printf("The default value %s is used.\n", - (Message() << default_value).GetString().c_str()); - fflush(stdout); - return default_value; - } - - return result; -} - -// Reads and returns the string environment variable corresponding to -// the given flag; if it's not set, returns default_value. -const char* StringFromGTestEnv(const char* flag, const char* default_value) { - const std::string env_var = FlagToEnvVar(flag); - const char* const value = posix::GetEnv(env_var.c_str()); - return value == NULL ? default_value : value; -} - -} // namespace internal -} // namespace testing -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - -// Google Test - The Google C++ Testing Framework -// -// This file implements a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// It uses the << operator when possible, and prints the bytes in the -// object otherwise. A user can override its behavior for a class -// type Foo by defining either operator<<(::std::ostream&, const Foo&) -// or void PrintTo(const Foo&, ::std::ostream*) in the namespace that -// defines Foo. - -#include -#include -#include // NOLINT -#include - -namespace testing { - -namespace { - -using ::std::ostream; - -// Prints a segment of bytes in the given object. -void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, - size_t count, ostream* os) { - char text[5] = ""; - for (size_t i = 0; i != count; i++) { - const size_t j = start + i; - if (i != 0) { - // Organizes the bytes into groups of 2 for easy parsing by - // human. - if ((j % 2) == 0) - *os << ' '; - else - *os << '-'; - } - GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); - *os << text; - } -} - -// Prints the bytes in the given value to the given ostream. -void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, - ostream* os) { - // Tells the user how big the object is. - *os << count << "-byte object <"; - - const size_t kThreshold = 132; - const size_t kChunkSize = 64; - // If the object size is bigger than kThreshold, we'll have to omit - // some details by printing only the first and the last kChunkSize - // bytes. - // TODO(wan): let the user control the threshold using a flag. - if (count < kThreshold) { - PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); - } else { - PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); - *os << " ... "; - // Rounds up to 2-byte boundary. - const size_t resume_pos = (count - kChunkSize + 1)/2*2; - PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); - } - *os << ">"; -} - -} // namespace - -namespace internal2 { - -// Delegates to PrintBytesInObjectToImpl() to print the bytes in the -// given object. The delegation simplifies the implementation, which -// uses the << operator and thus is easier done outside of the -// ::testing::internal namespace, which contains a << operator that -// sometimes conflicts with the one in STL. -void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, - ostream* os) { - PrintBytesInObjectToImpl(obj_bytes, count, os); -} - -} // namespace internal2 - -namespace internal { - -// Depending on the value of a char (or wchar_t), we print it in one -// of three formats: -// - as is if it's a printable ASCII (e.g. 'a', '2', ' '), -// - as a hexidecimal escape sequence (e.g. '\x7F'), or -// - as a special escape sequence (e.g. '\r', '\n'). -enum CharFormat { - kAsIs, - kHexEscape, - kSpecialEscape -}; - -// Returns true if c is a printable ASCII character. We test the -// value of c directly instead of calling isprint(), which is buggy on -// Windows Mobile. -inline bool IsPrintableAscii(wchar_t c) { - return 0x20 <= c && c <= 0x7E; -} - -// Prints a wide or narrow char c as a character literal without the -// quotes, escaping it when necessary; returns how c was formatted. -// The template argument UnsignedChar is the unsigned version of Char, -// which is the type of c. -template -static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { - switch (static_cast(c)) { - case L'\0': - *os << "\\0"; - break; - case L'\'': - *os << "\\'"; - break; - case L'\\': - *os << "\\\\"; - break; - case L'\a': - *os << "\\a"; - break; - case L'\b': - *os << "\\b"; - break; - case L'\f': - *os << "\\f"; - break; - case L'\n': - *os << "\\n"; - break; - case L'\r': - *os << "\\r"; - break; - case L'\t': - *os << "\\t"; - break; - case L'\v': - *os << "\\v"; - break; - default: - if (IsPrintableAscii(c)) { - *os << static_cast(c); - return kAsIs; - } else { - *os << "\\x" + String::FormatHexInt(static_cast(c)); - return kHexEscape; - } - } - return kSpecialEscape; -} - -// Prints a wchar_t c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { - switch (c) { - case L'\'': - *os << "'"; - return kAsIs; - case L'"': - *os << "\\\""; - return kSpecialEscape; - default: - return PrintAsCharLiteralTo(c, os); - } -} - -// Prints a char c as if it's part of a string literal, escaping it when -// necessary; returns how c was formatted. -static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { - return PrintAsStringLiteralTo( - static_cast(static_cast(c)), os); -} - -// Prints a wide or narrow character c and its code. '\0' is printed -// as "'\\0'", other unprintable characters are also properly escaped -// using the standard C++ escape sequence. The template argument -// UnsignedChar is the unsigned version of Char, which is the type of c. -template -void PrintCharAndCodeTo(Char c, ostream* os) { - // First, print c as a literal in the most readable form we can find. - *os << ((sizeof(c) > 1) ? "L'" : "'"); - const CharFormat format = PrintAsCharLiteralTo(c, os); - *os << "'"; - - // To aid user debugging, we also print c's code in decimal, unless - // it's 0 (in which case c was printed as '\\0', making the code - // obvious). - if (c == 0) - return; - *os << " (" << static_cast(c); - - // For more convenience, we print c's code again in hexidecimal, - // unless c was already printed in the form '\x##' or the code is in - // [1, 9]. - if (format == kHexEscape || (1 <= c && c <= 9)) { - // Do nothing. - } else { - *os << ", 0x" << String::FormatHexInt(static_cast(c)); - } - *os << ")"; -} - -void PrintTo(unsigned char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} -void PrintTo(signed char c, ::std::ostream* os) { - PrintCharAndCodeTo(c, os); -} - -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its code. L'\0' is printed as "L'\\0'". -void PrintTo(wchar_t wc, ostream* os) { - PrintCharAndCodeTo(wc, os); -} - -// Prints the given array of characters to the ostream. CharType must be either -// char or wchar_t. -// The array starts at begin, the length is len, it may include '\0' characters -// and may not be NUL-terminated. -template -static void PrintCharsAsStringTo( - const CharType* begin, size_t len, ostream* os) { - const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; - *os << kQuoteBegin; - bool is_previous_hex = false; - for (size_t index = 0; index < len; ++index) { - const CharType cur = begin[index]; - if (is_previous_hex && IsXDigit(cur)) { - // Previous character is of '\x..' form and this character can be - // interpreted as another hexadecimal digit in its number. Break string to - // disambiguate. - *os << "\" " << kQuoteBegin; - } - is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; - } - *os << "\""; -} - -// Prints a (const) char/wchar_t array of 'len' elements, starting at address -// 'begin'. CharType must be either char or wchar_t. -template -static void UniversalPrintCharArray( - const CharType* begin, size_t len, ostream* os) { - // The code - // const char kFoo[] = "foo"; - // generates an array of 4, not 3, elements, with the last one being '\0'. - // - // Therefore when printing a char array, we don't print the last element if - // it's '\0', such that the output matches the string literal as it's - // written in the source code. - if (len > 0 && begin[len - 1] == '\0') { - PrintCharsAsStringTo(begin, len - 1, os); - return; - } - - // If, however, the last element in the array is not '\0', e.g. - // const char kFoo[] = { 'f', 'o', 'o' }; - // we must print the entire array. We also print a message to indicate - // that the array is not NUL-terminated. - PrintCharsAsStringTo(begin, len, os); - *os << " (no terminating NUL)"; -} - -// Prints a (const) char array of 'len' elements, starting at address 'begin'. -void UniversalPrintArray(const char* begin, size_t len, ostream* os) { - UniversalPrintCharArray(begin, len, os); -} - -// Prints a (const) wchar_t array of 'len' elements, starting at address -// 'begin'. -void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { - UniversalPrintCharArray(begin, len, os); -} - -// Prints the given C string to the ostream. -void PrintTo(const char* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, strlen(s), os); - } -} - -// MSVC compiler can be configured to define whar_t as a typedef -// of unsigned short. Defining an overload for const wchar_t* in that case -// would cause pointers to unsigned shorts be printed as wide strings, -// possibly accessing more memory than intended and causing invalid -// memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when -// wchar_t is implemented as a native type. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Prints the given wide C string to the ostream. -void PrintTo(const wchar_t* s, ostream* os) { - if (s == NULL) { - *os << "NULL"; - } else { - *os << ImplicitCast_(s) << " pointing to "; - PrintCharsAsStringTo(s, wcslen(s), os); - } -} -#endif // wchar_t is native - -// Prints a ::string object. -#if GTEST_HAS_GLOBAL_STRING -void PrintStringTo(const ::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -void PrintStringTo(const ::std::string& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} - -// Prints a ::wstring object. -#if GTEST_HAS_GLOBAL_WSTRING -void PrintWideStringTo(const ::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -void PrintWideStringTo(const ::std::wstring& s, ostream* os) { - PrintCharsAsStringTo(s.data(), s.size(), os); -} -#endif // GTEST_HAS_STD_WSTRING - -} // namespace internal - -} // namespace testing -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: mheule@google.com (Markus Heule) -// -// The Google C++ Testing Framework (Google Test) - - -// Indicates that this translation unit is part of Google Test's -// implementation. It must come before gtest-internal-inl.h is -// included, or there will be a compiler error. This trick is to -// prevent a user from accidentally including gtest-internal-inl.h in -// his code. -#define GTEST_IMPLEMENTATION_ 1 -#undef GTEST_IMPLEMENTATION_ - -namespace testing { - -using internal::GetUnitTestImpl; - -// Gets the summary of the failure message by omitting the stack trace -// in it. -std::string TestPartResult::ExtractSummary(const char* message) { - const char* const stack_trace = strstr(message, internal::kStackTraceMarker); - return stack_trace == NULL ? message : - std::string(message, stack_trace); -} - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result) { - return os - << result.file_name() << ":" << result.line_number() << ": " - << (result.type() == TestPartResult::kSuccess ? "Success" : - result.type() == TestPartResult::kFatalFailure ? "Fatal failure" : - "Non-fatal failure") << ":\n" - << result.message() << std::endl; -} - -// Appends a TestPartResult to the array. -void TestPartResultArray::Append(const TestPartResult& result) { - array_.push_back(result); -} - -// Returns the TestPartResult at the given index (0-based). -const TestPartResult& TestPartResultArray::GetTestPartResult(int index) const { - if (index < 0 || index >= size()) { - printf("\nInvalid index (%d) into TestPartResultArray.\n", index); - internal::posix::Abort(); - } - - return array_[index]; -} - -// Returns the number of TestPartResult objects in the array. -int TestPartResultArray::size() const { - return static_cast(array_.size()); -} - -namespace internal { - -HasNewFatalFailureHelper::HasNewFatalFailureHelper() - : has_new_fatal_failure_(false), - original_reporter_(GetUnitTestImpl()-> - GetTestPartResultReporterForCurrentThread()) { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread(this); -} - -HasNewFatalFailureHelper::~HasNewFatalFailureHelper() { - GetUnitTestImpl()->SetTestPartResultReporterForCurrentThread( - original_reporter_); -} - -void HasNewFatalFailureHelper::ReportTestPartResult( - const TestPartResult& result) { - if (result.fatally_failed()) - has_new_fatal_failure_ = true; - original_reporter_->ReportTestPartResult(result); -} - -} // namespace internal - -} // namespace testing -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - - -namespace testing { -namespace internal { - -#if GTEST_HAS_TYPED_TEST_P - -// Skips to the first non-space char in str. Returns an empty string if str -// contains only whitespace characters. -static const char* SkipSpaces(const char* str) { - while (IsSpace(*str)) - str++; - return str; -} - -// Verifies that registered_tests match the test names in -// defined_test_names_; returns registered_tests if successful, or -// aborts the program otherwise. -const char* TypedTestCasePState::VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests) { - typedef ::std::set::const_iterator DefinedTestIter; - registered_ = true; - - // Skip initial whitespace in registered_tests since some - // preprocessors prefix stringizied literals with whitespace. - registered_tests = SkipSpaces(registered_tests); - - Message errors; - ::std::set tests; - for (const char* names = registered_tests; names != NULL; - names = SkipComma(names)) { - const std::string name = GetPrefixUntilComma(names); - if (tests.count(name) != 0) { - errors << "Test " << name << " is listed more than once.\n"; - continue; - } - - bool found = false; - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (name == *it) { - found = true; - break; - } - } - - if (found) { - tests.insert(name); - } else { - errors << "No test named " << name - << " can be found in this test case.\n"; - } - } - - for (DefinedTestIter it = defined_test_names_.begin(); - it != defined_test_names_.end(); - ++it) { - if (tests.count(*it) == 0) { - errors << "You forgot to list test " << *it << ".\n"; - } - } - - const std::string& errors_str = errors.GetString(); - if (errors_str != "") { - fprintf(stderr, "%s %s", FormatFileLocation(file, line).c_str(), - errors_str.c_str()); - fflush(stderr); - posix::Abort(); - } - - return registered_tests; -} - -#endif // GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing diff --git a/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h b/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h deleted file mode 120000 index 48d39090f1..0000000000 --- a/lib/kokkos/tpls/gtest/gtest/gtest-test-part.h +++ /dev/null @@ -1 +0,0 @@ -gtest.h \ No newline at end of file diff --git a/lib/kokkos/tpls/gtest/gtest/gtest.h b/lib/kokkos/tpls/gtest/gtest/gtest.h deleted file mode 100644 index c74d098fa9..0000000000 --- a/lib/kokkos/tpls/gtest/gtest/gtest.h +++ /dev/null @@ -1,20065 +0,0 @@ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for Google Test. It should be -// included by any test program that uses Google Test. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! -// -// Acknowledgment: Google Test borrowed the idea of automatic test -// registration from Barthelemy Dagenais' (barthelemy@prologique.com) -// easyUnit framework. - -#ifdef __GNUC__ -#pragma GCC system_header -#endif - -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_H_ - -#include -#include -#include - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares functions and macros used internally by -// Google Test. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: wan@google.com (Zhanyong Wan) -// -// Low-level types and utilities for porting Google Test to various -// platforms. They are subject to change without notice. DO NOT USE -// THEM IN USER CODE. -// -// This file is fundamental to Google Test. All other Google Test source -// files are expected to #include this. Therefore, it cannot #include -// any other Google Test header. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - -// The user can define the following macros in the build script to -// control Google Test's behavior. If the user doesn't define a macro -// in this list, Google Test will define it. -// -// GTEST_HAS_CLONE - Define it to 1/0 to indicate that clone(2) -// is/isn't available. -// GTEST_HAS_EXCEPTIONS - Define it to 1/0 to indicate that exceptions -// are enabled. -// GTEST_HAS_GLOBAL_STRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::string, which is different to std::string). -// GTEST_HAS_GLOBAL_WSTRING - Define it to 1/0 to indicate that ::string -// is/isn't available (some systems define -// ::wstring, which is different to std::wstring). -// GTEST_HAS_POSIX_RE - Define it to 1/0 to indicate that POSIX regular -// expressions are/aren't available. -// GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that -// is/isn't available. -// GTEST_HAS_RTTI - Define it to 1/0 to indicate that RTTI is/isn't -// enabled. -// GTEST_HAS_STD_WSTRING - Define it to 1/0 to indicate that -// std::wstring does/doesn't work (Google Test can -// be used where std::wstring is unavailable). -// GTEST_HAS_TR1_TUPLE - Define it to 1/0 to indicate tr1::tuple -// is/isn't available. -// GTEST_HAS_SEH - Define it to 1/0 to indicate whether the -// compiler supports Microsoft's "Structured -// Exception Handling". -// GTEST_HAS_STREAM_REDIRECTION -// - Define it to 1/0 to indicate whether the -// platform supports I/O stream redirection using -// dup() and dup2(). -// GTEST_USE_OWN_TR1_TUPLE - Define it to 1/0 to indicate whether Google -// Test's own tr1 tuple implementation should be -// used. Unused when the user sets -// GTEST_HAS_TR1_TUPLE to 0. -// GTEST_LANG_CXX11 - Define it to 1/0 to indicate that Google Test -// is building in C++11/C++98 mode. -// GTEST_LINKED_AS_SHARED_LIBRARY -// - Define to 1 when compiling tests that use -// Google Test as a shared library (known as -// DLL on Windows). -// GTEST_CREATE_SHARED_LIBRARY -// - Define to 1 when compiling Google Test itself -// as a shared library. - -// This header defines the following utilities: -// -// Macros indicating the current platform (defined to 1 if compiled on -// the given platform; otherwise undefined): -// GTEST_OS_AIX - IBM AIX -// GTEST_OS_CYGWIN - Cygwin -// GTEST_OS_HPUX - HP-UX -// GTEST_OS_LINUX - Linux -// GTEST_OS_LINUX_ANDROID - Google Android -// GTEST_OS_MAC - Mac OS X -// GTEST_OS_IOS - iOS -// GTEST_OS_IOS_SIMULATOR - iOS simulator -// GTEST_OS_NACL - Google Native Client (NaCl) -// GTEST_OS_OPENBSD - OpenBSD -// GTEST_OS_QNX - QNX -// GTEST_OS_SOLARIS - Sun Solaris -// GTEST_OS_SYMBIAN - Symbian -// GTEST_OS_WINDOWS - Windows (Desktop, MinGW, or Mobile) -// GTEST_OS_WINDOWS_DESKTOP - Windows Desktop -// GTEST_OS_WINDOWS_MINGW - MinGW -// GTEST_OS_WINDOWS_MOBILE - Windows Mobile -// GTEST_OS_ZOS - z/OS -// -// Among the platforms, Cygwin, Linux, Max OS X, and Windows have the -// most stable support. Since core members of the Google Test project -// don't have access to other platforms, support for them may be less -// stable. If you notice any problems on your platform, please notify -// googletestframework@googlegroups.com (patches for fixing them are -// even more welcome!). -// -// Note that it is possible that none of the GTEST_OS_* macros are defined. -// -// Macros indicating available Google Test features (defined to 1 if -// the corresponding feature is supported; otherwise undefined): -// GTEST_HAS_COMBINE - the Combine() function (for value-parameterized -// tests) -// GTEST_HAS_DEATH_TEST - death tests -// GTEST_HAS_PARAM_TEST - value-parameterized tests -// GTEST_HAS_TYPED_TEST - typed tests -// GTEST_HAS_TYPED_TEST_P - type-parameterized tests -// GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with -// GTEST_HAS_POSIX_RE (see above) which users can -// define themselves. -// GTEST_USES_SIMPLE_RE - our own simple regex is used; -// the above two are mutually exclusive. -// GTEST_CAN_COMPARE_NULL - accepts untyped NULL in EXPECT_EQ(). -// -// Macros for basic C++ coding: -// GTEST_AMBIGUOUS_ELSE_BLOCKER_ - for disabling a gcc warning. -// GTEST_ATTRIBUTE_UNUSED_ - declares that a class' instances or a -// variable don't have to be used. -// GTEST_DISALLOW_ASSIGN_ - disables operator=. -// GTEST_DISALLOW_COPY_AND_ASSIGN_ - disables copy ctor and operator=. -// GTEST_MUST_USE_RESULT_ - declares that a function's result must be used. -// -// Synchronization: -// Mutex, MutexLock, ThreadLocal, GetThreadCount() -// - synchronization primitives. -// GTEST_IS_THREADSAFE - defined to 1 to indicate that the above -// synchronization primitives have real implementations -// and Google Test is thread-safe; or 0 otherwise. -// -// Template meta programming: -// is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. -// IteratorTraits - partial implementation of std::iterator_traits, which -// is not available in libCstd when compiled with Sun C++. -// -// Smart pointers: -// scoped_ptr - as in TR2. -// -// Regular expressions: -// RE - a simple regular expression class using the POSIX -// Extended Regular Expression syntax on UNIX-like -// platforms, or a reduced regular exception syntax on -// other platforms, including Windows. -// -// Logging: -// GTEST_LOG_() - logs messages at the specified severity level. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. -// -// Stdout and stderr capturing: -// CaptureStdout() - starts capturing stdout. -// GetCapturedStdout() - stops capturing stdout and returns the captured -// string. -// CaptureStderr() - starts capturing stderr. -// GetCapturedStderr() - stops capturing stderr and returns the captured -// string. -// -// Integer types: -// TypeWithSize - maps an integer to a int type. -// Int32, UInt32, Int64, UInt64, TimeInMillis -// - integers of known sizes. -// BiggestInt - the biggest signed integer type. -// -// Command-line utilities: -// GTEST_FLAG() - references a flag. -// GTEST_DECLARE_*() - declares a flag. -// GTEST_DEFINE_*() - defines a flag. -// GetInjectableArgvs() - returns the command line as a vector of strings. -// -// Environment variable utilities: -// GetEnv() - gets the value of an environment variable. -// BoolFromGTestEnv() - parses a bool environment variable. -// Int32FromGTestEnv() - parses an Int32 environment variable. -// StringFromGTestEnv() - parses a string environment variable. - -#include // for isspace, etc -#include // for ptrdiff_t -#include -#include -#include -#ifndef _WIN32_WCE -# include -# include -#endif // !_WIN32_WCE - -#if defined __APPLE__ -# include -# include -#endif - -#include // NOLINT -#include // NOLINT -#include // NOLINT - -#define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com" -#define GTEST_FLAG_PREFIX_ "gtest_" -#define GTEST_FLAG_PREFIX_DASH_ "gtest-" -#define GTEST_FLAG_PREFIX_UPPER_ "GTEST_" -#define GTEST_NAME_ "Google Test" -#define GTEST_PROJECT_URL_ "http://code.google.com/p/googletest/" - -// Determines the version of gcc that is used to compile this. -#ifdef __GNUC__ -// 40302 means version 4.3.2. -# define GTEST_GCC_VER_ \ - (__GNUC__*10000 + __GNUC_MINOR__*100 + __GNUC_PATCHLEVEL__) -#endif // __GNUC__ - -// Determines the platform on which Google Test is compiled. -#ifdef __CYGWIN__ -# define GTEST_OS_CYGWIN 1 -#elif defined __SYMBIAN32__ -# define GTEST_OS_SYMBIAN 1 -#elif defined _WIN32 -# define GTEST_OS_WINDOWS 1 -# ifdef _WIN32_WCE -# define GTEST_OS_WINDOWS_MOBILE 1 -# elif defined(__MINGW__) || defined(__MINGW32__) -# define GTEST_OS_WINDOWS_MINGW 1 -# else -# define GTEST_OS_WINDOWS_DESKTOP 1 -# endif // _WIN32_WCE -#elif defined __APPLE__ -# define GTEST_OS_MAC 1 -# if TARGET_OS_IPHONE -# define GTEST_OS_IOS 1 -# if TARGET_IPHONE_SIMULATOR -# define GTEST_OS_IOS_SIMULATOR 1 -# endif -# endif -#elif defined __linux__ -# define GTEST_OS_LINUX 1 -# if defined __ANDROID__ -# define GTEST_OS_LINUX_ANDROID 1 -# endif -#elif defined __MVS__ -# define GTEST_OS_ZOS 1 -#elif defined(__sun) && defined(__SVR4) -# define GTEST_OS_SOLARIS 1 -#elif defined(_AIX) -# define GTEST_OS_AIX 1 -#elif defined(__hpux) -# define GTEST_OS_HPUX 1 -#elif defined __native_client__ -# define GTEST_OS_NACL 1 -#elif defined __OpenBSD__ -# define GTEST_OS_OPENBSD 1 -#elif defined __QNX__ -# define GTEST_OS_QNX 1 -#endif // __CYGWIN__ - -#ifndef GTEST_LANG_CXX11 -// gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when -// -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a -// value for __cplusplus, and recent versions of clang, gcc, and -// probably other compilers set that too in C++11 mode. -# if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L -// Compiling in at least C++11 mode. -# define GTEST_LANG_CXX11 1 -# else -# define GTEST_LANG_CXX11 0 -# endif -#endif - -// Brings in definitions for functions used in the testing::internal::posix -// namespace (read, write, close, chdir, isatty, stat). We do not currently -// use them on Windows Mobile. -#if !GTEST_OS_WINDOWS -// This assumes that non-Windows OSes provide unistd.h. For OSes where this -// is not the case, we need to include headers that provide the functions -// mentioned above. -# include -# include -#elif !GTEST_OS_WINDOWS_MOBILE -# include -# include -#endif - -#if GTEST_OS_LINUX_ANDROID -// Used to define __ANDROID_API__ matching the target NDK API level. -# include // NOLINT -#endif - -// Defines this to true iff Google Test can use POSIX regular expressions. -#ifndef GTEST_HAS_POSIX_RE -# if GTEST_OS_LINUX_ANDROID -// On Android, is only available starting with Gingerbread. -# define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) -# else -# define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) -# endif -#endif - -#if GTEST_HAS_POSIX_RE - -// On some platforms, needs someone to define size_t, and -// won't compile otherwise. We can #include it here as we already -// included , which is guaranteed to define size_t through -// . -# include // NOLINT - -# define GTEST_USES_POSIX_RE 1 - -#elif GTEST_OS_WINDOWS - -// is not available on Windows. Use our own simple regex -// implementation instead. -# define GTEST_USES_SIMPLE_RE 1 - -#else - -// may not be available on this platform. Use our own -// simple regex implementation instead. -# define GTEST_USES_SIMPLE_RE 1 - -#endif // GTEST_HAS_POSIX_RE - -#ifndef GTEST_HAS_EXCEPTIONS -// The user didn't tell us whether exceptions are enabled, so we need -// to figure it out. -# if defined(_MSC_VER) || defined(__BORLANDC__) -// MSVC's and C++Builder's implementations of the STL use the _HAS_EXCEPTIONS -// macro to enable exceptions, so we'll do the same. -// Assumes that exceptions are enabled by default. -# ifndef _HAS_EXCEPTIONS -# define _HAS_EXCEPTIONS 1 -# endif // _HAS_EXCEPTIONS -# define GTEST_HAS_EXCEPTIONS _HAS_EXCEPTIONS -# elif defined(__GNUC__) && __EXCEPTIONS -// gcc defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__SUNPRO_CC) -// Sun Pro CC supports exceptions. However, there is no compile-time way of -// detecting whether they are enabled or not. Therefore, we assume that -// they are enabled unless the user tells us otherwise. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__IBMCPP__) && __EXCEPTIONS -// xlC defines __EXCEPTIONS to 1 iff exceptions are enabled. -# define GTEST_HAS_EXCEPTIONS 1 -# elif defined(__HP_aCC) -// Exception handling is in effect by default in HP aCC compiler. It has to -// be turned of by +noeh compiler option if desired. -# define GTEST_HAS_EXCEPTIONS 1 -# else -// For other compilers, we assume exceptions are disabled to be -// conservative. -# define GTEST_HAS_EXCEPTIONS 0 -# endif // defined(_MSC_VER) || defined(__BORLANDC__) -#endif // GTEST_HAS_EXCEPTIONS - -#if !defined(GTEST_HAS_STD_STRING) -// Even though we don't use this macro any longer, we keep it in case -// some clients still depend on it. -# define GTEST_HAS_STD_STRING 1 -#elif !GTEST_HAS_STD_STRING -// The user told us that ::std::string isn't available. -# error "Google Test cannot be used where ::std::string isn't available." -#endif // !defined(GTEST_HAS_STD_STRING) - -#ifndef GTEST_HAS_GLOBAL_STRING -// The user didn't tell us whether ::string is available, so we need -// to figure it out. - -# define GTEST_HAS_GLOBAL_STRING 0 - -#endif // GTEST_HAS_GLOBAL_STRING - -#ifndef GTEST_HAS_STD_WSTRING -// The user didn't tell us whether ::std::wstring is available, so we need -// to figure it out. -// TODO(wan@google.com): uses autoconf to detect whether ::std::wstring -// is available. - -// Cygwin 1.7 and below doesn't support ::std::wstring. -// Solaris' libc++ doesn't support it either. Android has -// no support for it at least as recent as Froyo (2.2). -# define GTEST_HAS_STD_WSTRING \ - (!(GTEST_OS_LINUX_ANDROID || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS)) - -#endif // GTEST_HAS_STD_WSTRING - -#ifndef GTEST_HAS_GLOBAL_WSTRING -// The user didn't tell us whether ::wstring is available, so we need -// to figure it out. -# define GTEST_HAS_GLOBAL_WSTRING \ - (GTEST_HAS_STD_WSTRING && GTEST_HAS_GLOBAL_STRING) -#endif // GTEST_HAS_GLOBAL_WSTRING - -// Determines whether RTTI is available. -#ifndef GTEST_HAS_RTTI -// The user didn't tell us whether RTTI is enabled, so we need to -// figure it out. - -# ifdef _MSC_VER - -# ifdef _CPPRTTI // MSVC defines this macro iff RTTI is enabled. -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif - -// Starting with version 4.3.2, gcc defines __GXX_RTTI iff RTTI is enabled. -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40302) - -# ifdef __GXX_RTTI -// When building against STLport with the Android NDK and with -// -frtti -fno-exceptions, the build fails at link time with undefined -// references to __cxa_bad_typeid. Note sure if STL or toolchain bug, -// so disable RTTI when detected. -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ - !defined(__EXCEPTIONS) -# define GTEST_HAS_RTTI 0 -# else -# define GTEST_HAS_RTTI 1 -# endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS -# else -# define GTEST_HAS_RTTI 0 -# endif // __GXX_RTTI - -// Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends -// using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the -// first version with C++ support. -# elif defined(__clang__) - -# define GTEST_HAS_RTTI __has_feature(cxx_rtti) - -// Starting with version 9.0 IBM Visual Age defines __RTTI_ALL__ to 1 if -// both the typeid and dynamic_cast features are present. -# elif defined(__IBMCPP__) && (__IBMCPP__ >= 900) - -# ifdef __RTTI_ALL__ -# define GTEST_HAS_RTTI 1 -# else -# define GTEST_HAS_RTTI 0 -# endif - -# else - -// For all other compilers, we assume RTTI is enabled. -# define GTEST_HAS_RTTI 1 - -# endif // _MSC_VER - -#endif // GTEST_HAS_RTTI - -// It's this header's responsibility to #include when RTTI -// is enabled. -#if GTEST_HAS_RTTI -# include -#endif - -// Determines whether Google Test can use the pthreads library. -#ifndef GTEST_HAS_PTHREAD -// The user didn't tell us explicitly, so we assume pthreads support is -// available on Linux and Mac. -// -// To disable threading support in Google Test, add -DGTEST_HAS_PTHREAD=0 -// to your compiler flags. -# define GTEST_HAS_PTHREAD (GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_HPUX \ - || GTEST_OS_QNX) -#endif // GTEST_HAS_PTHREAD - -#if GTEST_HAS_PTHREAD -// gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is -// true. -# include // NOLINT - -// For timespec and nanosleep, used below. -# include // NOLINT -#endif - -// Determines whether Google Test can use tr1/tuple. You can define -// this macro to 0 to prevent Google Test from using tuple (any -// feature depending on tuple with be disabled in this mode). -#ifndef GTEST_HAS_TR1_TUPLE -# if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) -// STLport, provided with the Android NDK, has neither or . -# define GTEST_HAS_TR1_TUPLE 0 -# else -// The user didn't tell us not to do it, so we assume it's OK. -# define GTEST_HAS_TR1_TUPLE 1 -# endif -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether Google Test's own tr1 tuple implementation -// should be used. -#ifndef GTEST_USE_OWN_TR1_TUPLE -// The user didn't tell us, so we need to figure it out. - -// We use our own TR1 tuple if we aren't sure the user has an -// implementation of it already. At this time, libstdc++ 4.0.0+ and -// MSVC 2010 are the only mainstream standard libraries that come -// with a TR1 tuple implementation. NVIDIA's CUDA NVCC compiler -// pretends to be GCC by defining __GNUC__ and friends, but cannot -// compile GCC's tuple implementation. MSVC 2008 (9.0) provides TR1 -// tuple in a 323 MB Feature Pack download, which we cannot assume the -// user has. QNX's QCC compiler is a modified GCC but it doesn't -// support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, -// and it can be used with some compilers that define __GNUC__. -# if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ - && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 -# define GTEST_ENV_HAS_TR1_TUPLE_ 1 -# endif - -// C++11 specifies that provides std::tuple. Use that if gtest is used -// in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 -// can build with clang but need to use gcc4.2's libstdc++). -# if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) -# define GTEST_ENV_HAS_STD_TUPLE_ 1 -# endif - -# if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ -# define GTEST_USE_OWN_TR1_TUPLE 0 -# else -# define GTEST_USE_OWN_TR1_TUPLE 1 -# endif - -#endif // GTEST_USE_OWN_TR1_TUPLE - -// To avoid conditional compilation everywhere, we make it -// gtest-port.h's responsibility to #include the header implementing -// tr1/tuple. -#if GTEST_HAS_TR1_TUPLE - -# if GTEST_USE_OWN_TR1_TUPLE -// This file was GENERATED by command: -// pump.py gtest-tuple.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2009 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - -// Implements a subset of TR1 tuple needed by Google Test and Google Mock. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ - -#include // For ::std::pair. - -// The compiler used in Symbian has a bug that prevents us from declaring the -// tuple template as a friend (it complains that tuple is redefined). This -// hack bypasses the bug by declaring the members that should otherwise be -// private as public. -// Sun Studio versions < 12 also have the above bug. -#if defined(__SYMBIAN32__) || (defined(__SUNPRO_CC) && __SUNPRO_CC < 0x590) -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ public: -#else -# define GTEST_DECLARE_TUPLE_AS_FRIEND_ \ - template friend class tuple; \ - private: -#endif - -// GTEST_n_TUPLE_(T) is the type of an n-tuple. -#define GTEST_0_TUPLE_(T) tuple<> -#define GTEST_1_TUPLE_(T) tuple -#define GTEST_2_TUPLE_(T) tuple -#define GTEST_3_TUPLE_(T) tuple -#define GTEST_4_TUPLE_(T) tuple -#define GTEST_5_TUPLE_(T) tuple -#define GTEST_6_TUPLE_(T) tuple -#define GTEST_7_TUPLE_(T) tuple -#define GTEST_8_TUPLE_(T) tuple -#define GTEST_9_TUPLE_(T) tuple -#define GTEST_10_TUPLE_(T) tuple - -// GTEST_n_TYPENAMES_(T) declares a list of n typenames. -#define GTEST_0_TYPENAMES_(T) -#define GTEST_1_TYPENAMES_(T) typename T##0 -#define GTEST_2_TYPENAMES_(T) typename T##0, typename T##1 -#define GTEST_3_TYPENAMES_(T) typename T##0, typename T##1, typename T##2 -#define GTEST_4_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3 -#define GTEST_5_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4 -#define GTEST_6_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5 -#define GTEST_7_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6 -#define GTEST_8_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, typename T##7 -#define GTEST_9_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8 -#define GTEST_10_TYPENAMES_(T) typename T##0, typename T##1, typename T##2, \ - typename T##3, typename T##4, typename T##5, typename T##6, \ - typename T##7, typename T##8, typename T##9 - -// In theory, defining stuff in the ::std namespace is undefined -// behavior. We can do this as we are playing the role of a standard -// library vendor. -namespace std { -namespace tr1 { - -template -class tuple; - -// Anything in namespace gtest_internal is Google Test's INTERNAL -// IMPLEMENTATION DETAIL and MUST NOT BE USED DIRECTLY in user code. -namespace gtest_internal { - -// ByRef::type is T if T is a reference; otherwise it's const T&. -template -struct ByRef { typedef const T& type; }; // NOLINT -template -struct ByRef { typedef T& type; }; // NOLINT - -// A handy wrapper for ByRef. -#define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type - -// AddRef::type is T if T is a reference; otherwise it's T&. This -// is the same as tr1::add_reference::type. -template -struct AddRef { typedef T& type; }; // NOLINT -template -struct AddRef { typedef T& type; }; // NOLINT - -// A handy wrapper for AddRef. -#define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type - -// A helper for implementing get(). -template class Get; - -// A helper for implementing tuple_element. kIndexValid is true -// iff k < the number of fields in tuple type T. -template -struct TupleElement; - -template -struct TupleElement { - typedef T0 type; -}; - -template -struct TupleElement { - typedef T1 type; -}; - -template -struct TupleElement { - typedef T2 type; -}; - -template -struct TupleElement { - typedef T3 type; -}; - -template -struct TupleElement { - typedef T4 type; -}; - -template -struct TupleElement { - typedef T5 type; -}; - -template -struct TupleElement { - typedef T6 type; -}; - -template -struct TupleElement { - typedef T7 type; -}; - -template -struct TupleElement { - typedef T8 type; -}; - -template -struct TupleElement { - typedef T9 type; -}; - -} // namespace gtest_internal - -template <> -class tuple<> { - public: - tuple() {} - tuple(const tuple& /* t */) {} - tuple& operator=(const tuple& /* t */) { return *this; } -}; - -template -class GTEST_1_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} - - tuple(const tuple& t) : f0_(t.f0_) {} - - template - tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_1_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { - f0_ = t.f0_; - return *this; - } - - T0 f0_; -}; - -template -class GTEST_2_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1) : f0_(f0), - f1_(f1) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_) {} - - template - tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} - template - tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_2_TUPLE_(U)& t) { - return CopyFrom(t); - } - template - tuple& operator=(const ::std::pair& p) { - f0_ = p.first; - f1_ = p.second; - return *this; - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - return *this; - } - - T0 f0_; - T1 f1_; -}; - -template -class GTEST_3_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2) : f0_(f0), f1_(f1), f2_(f2) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - template - tuple(const GTEST_3_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_3_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_3_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; -}; - -template -class GTEST_4_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_) {} - - template - tuple(const GTEST_4_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_4_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_4_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; -}; - -template -class GTEST_5_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, - GTEST_BY_REF_(T4) f4) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_) {} - - template - tuple(const GTEST_5_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_5_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_5_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; -}; - -template -class GTEST_6_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_) {} - - template - tuple(const GTEST_6_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_6_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_6_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; -}; - -template -class GTEST_7_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - template - tuple(const GTEST_7_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_7_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_7_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; -}; - -template -class GTEST_8_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, - GTEST_BY_REF_(T7) f7) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - template - tuple(const GTEST_8_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_8_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_8_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; -}; - -template -class GTEST_9_TUPLE_(T) { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8) : f0_(f0), f1_(f1), f2_(f2), f3_(f3), f4_(f4), - f5_(f5), f6_(f6), f7_(f7), f8_(f8) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - template - tuple(const GTEST_9_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_9_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_9_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; -}; - -template -class tuple { - public: - template friend class gtest_internal::Get; - - tuple() : f0_(), f1_(), f2_(), f3_(), f4_(), f5_(), f6_(), f7_(), f8_(), - f9_() {} - - explicit tuple(GTEST_BY_REF_(T0) f0, GTEST_BY_REF_(T1) f1, - GTEST_BY_REF_(T2) f2, GTEST_BY_REF_(T3) f3, GTEST_BY_REF_(T4) f4, - GTEST_BY_REF_(T5) f5, GTEST_BY_REF_(T6) f6, GTEST_BY_REF_(T7) f7, - GTEST_BY_REF_(T8) f8, GTEST_BY_REF_(T9) f9) : f0_(f0), f1_(f1), f2_(f2), - f3_(f3), f4_(f4), f5_(f5), f6_(f6), f7_(f7), f8_(f8), f9_(f9) {} - - tuple(const tuple& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), f3_(t.f3_), - f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), f9_(t.f9_) {} - - template - tuple(const GTEST_10_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_), f2_(t.f2_), - f3_(t.f3_), f4_(t.f4_), f5_(t.f5_), f6_(t.f6_), f7_(t.f7_), f8_(t.f8_), - f9_(t.f9_) {} - - tuple& operator=(const tuple& t) { return CopyFrom(t); } - - template - tuple& operator=(const GTEST_10_TUPLE_(U)& t) { - return CopyFrom(t); - } - - GTEST_DECLARE_TUPLE_AS_FRIEND_ - - template - tuple& CopyFrom(const GTEST_10_TUPLE_(U)& t) { - f0_ = t.f0_; - f1_ = t.f1_; - f2_ = t.f2_; - f3_ = t.f3_; - f4_ = t.f4_; - f5_ = t.f5_; - f6_ = t.f6_; - f7_ = t.f7_; - f8_ = t.f8_; - f9_ = t.f9_; - return *this; - } - - T0 f0_; - T1 f1_; - T2 f2_; - T3 f3_; - T4 f4_; - T5 f5_; - T6 f6_; - T7 f7_; - T8 f8_; - T9 f9_; -}; - -// 6.1.3.2 Tuple creation functions. - -// Known limitations: we don't support passing an -// std::tr1::reference_wrapper to make_tuple(). And we don't -// implement tie(). - -inline tuple<> make_tuple() { return tuple<>(); } - -template -inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { - return GTEST_1_TUPLE_(T)(f0); -} - -template -inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { - return GTEST_2_TUPLE_(T)(f0, f1); -} - -template -inline GTEST_3_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2) { - return GTEST_3_TUPLE_(T)(f0, f1, f2); -} - -template -inline GTEST_4_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3) { - return GTEST_4_TUPLE_(T)(f0, f1, f2, f3); -} - -template -inline GTEST_5_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4) { - return GTEST_5_TUPLE_(T)(f0, f1, f2, f3, f4); -} - -template -inline GTEST_6_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5) { - return GTEST_6_TUPLE_(T)(f0, f1, f2, f3, f4, f5); -} - -template -inline GTEST_7_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6) { - return GTEST_7_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6); -} - -template -inline GTEST_8_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7) { - return GTEST_8_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7); -} - -template -inline GTEST_9_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8) { - return GTEST_9_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8); -} - -template -inline GTEST_10_TUPLE_(T) make_tuple(const T0& f0, const T1& f1, const T2& f2, - const T3& f3, const T4& f4, const T5& f5, const T6& f6, const T7& f7, - const T8& f8, const T9& f9) { - return GTEST_10_TUPLE_(T)(f0, f1, f2, f3, f4, f5, f6, f7, f8, f9); -} - -// 6.1.3.3 Tuple helper classes. - -template struct tuple_size; - -template -struct tuple_size { - static const int value = 0; -}; - -template -struct tuple_size { - static const int value = 1; -}; - -template -struct tuple_size { - static const int value = 2; -}; - -template -struct tuple_size { - static const int value = 3; -}; - -template -struct tuple_size { - static const int value = 4; -}; - -template -struct tuple_size { - static const int value = 5; -}; - -template -struct tuple_size { - static const int value = 6; -}; - -template -struct tuple_size { - static const int value = 7; -}; - -template -struct tuple_size { - static const int value = 8; -}; - -template -struct tuple_size { - static const int value = 9; -}; - -template -struct tuple_size { - static const int value = 10; -}; - -template -struct tuple_element { - typedef typename gtest_internal::TupleElement< - k < (tuple_size::value), k, Tuple>::type type; -}; - -#define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type - -// 6.1.3.4 Element access. - -namespace gtest_internal { - -template <> -class Get<0> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - Field(Tuple& t) { return t.f0_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) - ConstField(const Tuple& t) { return t.f0_; } -}; - -template <> -class Get<1> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - Field(Tuple& t) { return t.f1_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) - ConstField(const Tuple& t) { return t.f1_; } -}; - -template <> -class Get<2> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - Field(Tuple& t) { return t.f2_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) - ConstField(const Tuple& t) { return t.f2_; } -}; - -template <> -class Get<3> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - Field(Tuple& t) { return t.f3_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) - ConstField(const Tuple& t) { return t.f3_; } -}; - -template <> -class Get<4> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - Field(Tuple& t) { return t.f4_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) - ConstField(const Tuple& t) { return t.f4_; } -}; - -template <> -class Get<5> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - Field(Tuple& t) { return t.f5_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) - ConstField(const Tuple& t) { return t.f5_; } -}; - -template <> -class Get<6> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - Field(Tuple& t) { return t.f6_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) - ConstField(const Tuple& t) { return t.f6_; } -}; - -template <> -class Get<7> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - Field(Tuple& t) { return t.f7_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) - ConstField(const Tuple& t) { return t.f7_; } -}; - -template <> -class Get<8> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - Field(Tuple& t) { return t.f8_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) - ConstField(const Tuple& t) { return t.f8_; } -}; - -template <> -class Get<9> { - public: - template - static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - Field(Tuple& t) { return t.f9_; } // NOLINT - - template - static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) - ConstField(const Tuple& t) { return t.f9_; } -}; - -} // namespace gtest_internal - -template -GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::Field(t); -} - -template -GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) -get(const GTEST_10_TUPLE_(T)& t) { - return gtest_internal::Get::ConstField(t); -} - -// 6.1.3.5 Relational operators - -// We only implement == and !=, as we don't have a need for the rest yet. - -namespace gtest_internal { - -// SameSizeTuplePrefixComparator::Eq(t1, t2) returns true if the -// first k fields of t1 equals the first k fields of t2. -// SameSizeTuplePrefixComparator(k1, k2) would be a compiler error if -// k1 != k2. -template -struct SameSizeTuplePrefixComparator; - -template <> -struct SameSizeTuplePrefixComparator<0, 0> { - template - static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { - return true; - } -}; - -template -struct SameSizeTuplePrefixComparator { - template - static bool Eq(const Tuple1& t1, const Tuple2& t2) { - return SameSizeTuplePrefixComparator::Eq(t1, t2) && - ::std::tr1::get(t1) == ::std::tr1::get(t2); - } -}; - -} // namespace gtest_internal - -template -inline bool operator==(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { - return gtest_internal::SameSizeTuplePrefixComparator< - tuple_size::value, - tuple_size::value>::Eq(t, u); -} - -template -inline bool operator!=(const GTEST_10_TUPLE_(T)& t, - const GTEST_10_TUPLE_(U)& u) { return !(t == u); } - -// 6.1.4 Pairs. -// Unimplemented. - -} // namespace tr1 -} // namespace std - -#undef GTEST_0_TUPLE_ -#undef GTEST_1_TUPLE_ -#undef GTEST_2_TUPLE_ -#undef GTEST_3_TUPLE_ -#undef GTEST_4_TUPLE_ -#undef GTEST_5_TUPLE_ -#undef GTEST_6_TUPLE_ -#undef GTEST_7_TUPLE_ -#undef GTEST_8_TUPLE_ -#undef GTEST_9_TUPLE_ -#undef GTEST_10_TUPLE_ - -#undef GTEST_0_TYPENAMES_ -#undef GTEST_1_TYPENAMES_ -#undef GTEST_2_TYPENAMES_ -#undef GTEST_3_TYPENAMES_ -#undef GTEST_4_TYPENAMES_ -#undef GTEST_5_TYPENAMES_ -#undef GTEST_6_TYPENAMES_ -#undef GTEST_7_TYPENAMES_ -#undef GTEST_8_TYPENAMES_ -#undef GTEST_9_TYPENAMES_ -#undef GTEST_10_TYPENAMES_ - -#undef GTEST_DECLARE_TUPLE_AS_FRIEND_ -#undef GTEST_BY_REF_ -#undef GTEST_ADD_REF_ -#undef GTEST_TUPLE_ELEMENT_ - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TUPLE_H_ -# elif GTEST_ENV_HAS_STD_TUPLE_ -# include -// C++11 puts its tuple into the ::std namespace rather than -// ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. -// This causes undefined behavior, but supported compilers react in -// the way we intend. -namespace std { -namespace tr1 { -using ::std::get; -using ::std::make_tuple; -using ::std::tuple; -using ::std::tuple_element; -using ::std::tuple_size; -} -} - -# elif GTEST_OS_SYMBIAN - -// On Symbian, BOOST_HAS_TR1_TUPLE causes Boost's TR1 tuple library to -// use STLport's tuple implementation, which unfortunately doesn't -// work as the copy of STLport distributed with Symbian is incomplete. -// By making sure BOOST_HAS_TR1_TUPLE is undefined, we force Boost to -// use its own tuple implementation. -# ifdef BOOST_HAS_TR1_TUPLE -# undef BOOST_HAS_TR1_TUPLE -# endif // BOOST_HAS_TR1_TUPLE - -// This prevents , which defines -// BOOST_HAS_TR1_TUPLE, from being #included by Boost's . -# define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED -# include - -# elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) -// GCC 4.0+ implements tr1/tuple in the header. This does -// not conform to the TR1 spec, which requires the header to be . - -# if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 -// Until version 4.3.2, gcc has a bug that causes , -// which is #included by , to not compile when RTTI is -// disabled. _TR1_FUNCTIONAL is the header guard for -// . Hence the following #define is a hack to prevent -// from being included. -# define _TR1_FUNCTIONAL 1 -# include -# undef _TR1_FUNCTIONAL // Allows the user to #include - // if he chooses to. -# else -# include // NOLINT -# endif // !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 - -# else -// If the compiler is not GCC 4.0+, we assume the user is using a -// spec-conforming TR1 implementation. -# include // NOLINT -# endif // GTEST_USE_OWN_TR1_TUPLE - -#endif // GTEST_HAS_TR1_TUPLE - -// Determines whether clone(2) is supported. -// Usually it will only be available on Linux, excluding -// Linux on the Itanium architecture. -// Also see http://linux.die.net/man/2/clone. -#ifndef GTEST_HAS_CLONE -// The user didn't tell us, so we need to figure it out. - -# if GTEST_OS_LINUX && !defined(__ia64__) -# if GTEST_OS_LINUX_ANDROID -// On Android, clone() is only available on ARM starting with Gingerbread. -# if defined(__arm__) && __ANDROID_API__ >= 9 -# define GTEST_HAS_CLONE 1 -# else -# define GTEST_HAS_CLONE 0 -# endif -# else -# define GTEST_HAS_CLONE 1 -# endif -# else -# define GTEST_HAS_CLONE 0 -# endif // GTEST_OS_LINUX && !defined(__ia64__) - -#endif // GTEST_HAS_CLONE - -// Determines whether to support stream redirection. This is used to test -// output correctness and to implement death tests. -#ifndef GTEST_HAS_STREAM_REDIRECTION -// By default, we assume that stream redirection is supported on all -// platforms except known mobile ones. -# if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN -# define GTEST_HAS_STREAM_REDIRECTION 0 -# else -# define GTEST_HAS_STREAM_REDIRECTION 1 -# endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN -#endif // GTEST_HAS_STREAM_REDIRECTION - -// Determines whether to support death tests. -// Google Test does not support death tests for VC 7.1 and earlier as -// abort() in a VC 7.1 application compiled as GUI in debug config -// pops up a dialog window that cannot be suppressed programmatically. -#if (GTEST_OS_LINUX || GTEST_OS_CYGWIN || GTEST_OS_SOLARIS || \ - (GTEST_OS_MAC && !GTEST_OS_IOS) || GTEST_OS_IOS_SIMULATOR || \ - (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ - GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ - GTEST_OS_OPENBSD || GTEST_OS_QNX) -# define GTEST_HAS_DEATH_TEST 1 -# include // NOLINT -#endif - -// We don't support MSVC 7.1 with exceptions disabled now. Therefore -// all the compilers we care about are adequate for supporting -// value-parameterized tests. -#define GTEST_HAS_PARAM_TEST 1 - -// Determines whether to support type-driven tests. - -// Typed tests need and variadic macros, which GCC, VC++ 8.0, -// Sun Pro CC, IBM Visual Age, and HP aCC support. -#if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ - defined(__IBMCPP__) || defined(__HP_aCC) -# define GTEST_HAS_TYPED_TEST 1 -# define GTEST_HAS_TYPED_TEST_P 1 -#endif - -// Determines whether to support Combine(). This only makes sense when -// value-parameterized tests are enabled. The implementation doesn't -// work on Sun Studio since it doesn't understand templated conversion -// operators. -#if GTEST_HAS_PARAM_TEST && GTEST_HAS_TR1_TUPLE && !defined(__SUNPRO_CC) -# define GTEST_HAS_COMBINE 1 -#endif - -// Determines whether the system compiler uses UTF-16 for encoding wide strings. -#define GTEST_WIDE_STRING_USES_UTF16_ \ - (GTEST_OS_WINDOWS || GTEST_OS_CYGWIN || GTEST_OS_SYMBIAN || GTEST_OS_AIX) - -// Determines whether test results can be streamed to a socket. -#if GTEST_OS_LINUX -# define GTEST_CAN_STREAM_RESULTS_ 1 -#endif - -// Defines some utility macros. - -// The GNU compiler emits a warning if nested "if" statements are followed by -// an "else" statement and braces are not used to explicitly disambiguate the -// "else" binding. This leads to problems with code like: -// -// if (gate) -// ASSERT_*(condition) << "Some message"; -// -// The "switch (0) case 0:" idiom is used to suppress this. -#ifdef __INTEL_COMPILER -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ -#else -# define GTEST_AMBIGUOUS_ELSE_BLOCKER_ switch (0) case 0: default: // NOLINT -#endif - -// Use this annotation at the end of a struct/class definition to -// prevent the compiler from optimizing away instances that are never -// used. This is useful when all interesting logic happens inside the -// c'tor and / or d'tor. Example: -// -// struct Foo { -// Foo() { ... } -// } GTEST_ATTRIBUTE_UNUSED_; -// -// Also use it after a variable or parameter declaration to tell the -// compiler the variable/parameter does not have to be used. -#if defined(__GNUC__) && !defined(COMPILER_ICC) -# define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) -#else -# define GTEST_ATTRIBUTE_UNUSED_ -#endif - -// A macro to disallow operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_ASSIGN_(type)\ - void operator=(type const &) - -// A macro to disallow copy constructor and operator= -// This should be used in the private: declarations for a class. -#define GTEST_DISALLOW_COPY_AND_ASSIGN_(type)\ - type(type const &);\ - GTEST_DISALLOW_ASSIGN_(type) - -// Tell the compiler to warn about unused return values for functions declared -// with this macro. The macro should be used on function declarations -// following the argument list: -// -// Sprocket* AllocateSprocket() GTEST_MUST_USE_RESULT_; -#if defined(__GNUC__) && (GTEST_GCC_VER_ >= 30400) && !defined(COMPILER_ICC) -# define GTEST_MUST_USE_RESULT_ __attribute__ ((warn_unused_result)) -#else -# define GTEST_MUST_USE_RESULT_ -#endif // __GNUC__ && (GTEST_GCC_VER_ >= 30400) && !COMPILER_ICC - -// Determine whether the compiler supports Microsoft's Structured Exception -// Handling. This is supported by several Windows compilers but generally -// does not exist on any other system. -#ifndef GTEST_HAS_SEH -// The user didn't tell us, so we need to figure it out. - -# if defined(_MSC_VER) || defined(__BORLANDC__) -// These two compilers are known to support SEH. -# define GTEST_HAS_SEH 1 -# else -// Assume no SEH. -# define GTEST_HAS_SEH 0 -# endif - -#endif // GTEST_HAS_SEH - -#ifdef _MSC_VER - -# if GTEST_LINKED_AS_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllimport) -# elif GTEST_CREATE_SHARED_LIBRARY -# define GTEST_API_ __declspec(dllexport) -# endif - -#endif // _MSC_VER - -#ifndef GTEST_API_ -# define GTEST_API_ -#endif - -#ifdef __GNUC__ -// Ask the compiler to never inline a given function. -# define GTEST_NO_INLINE_ __attribute__((noinline)) -#else -# define GTEST_NO_INLINE_ -#endif - -// _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. -#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) -# define GTEST_HAS_CXXABI_H_ 1 -#else -# define GTEST_HAS_CXXABI_H_ 0 -#endif - -namespace testing { - -class Message; - -namespace internal { - -// A secret type that Google Test users don't know about. It has no -// definition on purpose. Therefore it's impossible to create a -// Secret object, which is what we want. -class Secret; - -// The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time -// expression is true. For example, you could use it to verify the -// size of a static array: -// -// GTEST_COMPILE_ASSERT_(ARRAYSIZE(content_type_names) == CONTENT_NUM_TYPES, -// content_type_names_incorrect_size); -// -// or to make sure a struct is smaller than a certain size: -// -// GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); -// -// The second argument to the macro is the name of the variable. If -// the expression is false, most compilers will issue a warning/error -// containing the name of the variable. - -template -struct CompileAssert { -}; - -#define GTEST_COMPILE_ASSERT_(expr, msg) \ - typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ - msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ - -// Implementation details of GTEST_COMPILE_ASSERT_: -// -// - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 -// elements (and thus is invalid) when the expression is false. -// -// - The simpler definition -// -// #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] -// -// does not work, as gcc supports variable-length arrays whose sizes -// are determined at run-time (this is gcc's extension and not part -// of the C++ standard). As a result, gcc fails to reject the -// following code with the simple definition: -// -// int foo; -// GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is -// // not a compile-time constant. -// -// - By using the type CompileAssert<(bool(expr))>, we ensures that -// expr is a compile-time constant. (Template arguments must be -// determined at compile-time.) -// -// - The outter parentheses in CompileAssert<(bool(expr))> are necessary -// to work around a bug in gcc 3.4.4 and 4.0.1. If we had written -// -// CompileAssert -// -// instead, these compilers will refuse to compile -// -// GTEST_COMPILE_ASSERT_(5 > 0, some_message); -// -// (They seem to think the ">" in "5 > 0" marks the end of the -// template argument list.) -// -// - The array size is (bool(expr) ? 1 : -1), instead of simply -// -// ((expr) ? 1 : -1). -// -// This is to avoid running into a bug in MS VC 7.1, which -// causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. - -// StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. -// -// This template is declared, but intentionally undefined. -template -struct StaticAssertTypeEqHelper; - -template -struct StaticAssertTypeEqHelper {}; - -#if GTEST_HAS_GLOBAL_STRING -typedef ::string string; -#else -typedef ::std::string string; -#endif // GTEST_HAS_GLOBAL_STRING - -#if GTEST_HAS_GLOBAL_WSTRING -typedef ::wstring wstring; -#elif GTEST_HAS_STD_WSTRING -typedef ::std::wstring wstring; -#endif // GTEST_HAS_GLOBAL_WSTRING - -// A helper for suppressing warnings on constant condition. It just -// returns 'condition'. -GTEST_API_ bool IsTrue(bool condition); - -// Defines scoped_ptr. - -// This implementation of scoped_ptr is PARTIAL - it only contains -// enough stuff to satisfy Google Test's need. -template -class scoped_ptr { - public: - typedef T element_type; - - explicit scoped_ptr(T* p = NULL) : ptr_(p) {} - ~scoped_ptr() { reset(); } - - T& operator*() const { return *ptr_; } - T* operator->() const { return ptr_; } - T* get() const { return ptr_; } - - T* release() { - T* const ptr = ptr_; - ptr_ = NULL; - return ptr; - } - - void reset(T* p = NULL) { - if (p != ptr_) { - if (IsTrue(sizeof(T) > 0)) { // Makes sure T is a complete type. - delete ptr_; - } - ptr_ = p; - } - } - - private: - T* ptr_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); -}; - -// Defines RE. - -// A simple C++ wrapper for . It uses the POSIX Extended -// Regular Expression syntax. -class GTEST_API_ RE { - public: - // A copy constructor is required by the Standard to initialize object - // references from r-values. - RE(const RE& other) { Init(other.pattern()); } - - // Constructs an RE from a string. - RE(const ::std::string& regex) { Init(regex.c_str()); } // NOLINT - -#if GTEST_HAS_GLOBAL_STRING - - RE(const ::string& regex) { Init(regex.c_str()); } // NOLINT - -#endif // GTEST_HAS_GLOBAL_STRING - - RE(const char* regex) { Init(regex); } // NOLINT - ~RE(); - - // Returns the string representation of the regex. - const char* pattern() const { return pattern_; } - - // FullMatch(str, re) returns true iff regular expression re matches - // the entire str. - // PartialMatch(str, re) returns true iff regular expression re - // matches a substring of str (including str itself). - // - // TODO(wan@google.com): make FullMatch() and PartialMatch() work - // when str contains NUL characters. - static bool FullMatch(const ::std::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::std::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#if GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const ::string& str, const RE& re) { - return FullMatch(str.c_str(), re); - } - static bool PartialMatch(const ::string& str, const RE& re) { - return PartialMatch(str.c_str(), re); - } - -#endif // GTEST_HAS_GLOBAL_STRING - - static bool FullMatch(const char* str, const RE& re); - static bool PartialMatch(const char* str, const RE& re); - - private: - void Init(const char* regex); - - // We use a const char* instead of an std::string, as Google Test used to be - // used where std::string is not available. TODO(wan@google.com): change to - // std::string. - const char* pattern_; - bool is_valid_; - -#if GTEST_USES_POSIX_RE - - regex_t full_regex_; // For FullMatch(). - regex_t partial_regex_; // For PartialMatch(). - -#else // GTEST_USES_SIMPLE_RE - - const char* full_pattern_; // For FullMatch(); - -#endif - - GTEST_DISALLOW_ASSIGN_(RE); -}; - -// Formats a source file path and a line number as they would appear -// in an error message from the compiler used to compile this code. -GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); - -// Formats a file location for compiler-independent XML output. -// Although this function is not platform dependent, we put it next to -// FormatFileLocation in order to contrast the two functions. -GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, - int line); - -// Defines logging utilities: -// GTEST_LOG_(severity) - logs messages at the specified severity level. The -// message itself is streamed into the macro. -// LogToStderr() - directs all log messages to stderr. -// FlushInfoLog() - flushes informational log messages. - -enum GTestLogSeverity { - GTEST_INFO, - GTEST_WARNING, - GTEST_ERROR, - GTEST_FATAL -}; - -// Formats log entry severity, provides a stream object for streaming the -// log message, and terminates the message with a newline when going out of -// scope. -class GTEST_API_ GTestLog { - public: - GTestLog(GTestLogSeverity severity, const char* file, int line); - - // Flushes the buffers and, if severity is GTEST_FATAL, aborts the program. - ~GTestLog(); - - ::std::ostream& GetStream() { return ::std::cerr; } - - private: - const GTestLogSeverity severity_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestLog); -}; - -#define GTEST_LOG_(severity) \ - ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ - __FILE__, __LINE__).GetStream() - -inline void LogToStderr() {} -inline void FlushInfoLog() { fflush(NULL); } - -// INTERNAL IMPLEMENTATION - DO NOT USE. -// -// GTEST_CHECK_ is an all-mode assert. It aborts the program if the condition -// is not satisfied. -// Synopsys: -// GTEST_CHECK_(boolean_condition); -// or -// GTEST_CHECK_(boolean_condition) << "Additional message"; -// -// This checks the condition and if the condition is not satisfied -// it prints message about the condition violation, including the -// condition itself, plus additional message streamed into it, if any, -// and then it aborts the program. It aborts the program irrespective of -// whether it is built in the debug mode or not. -#define GTEST_CHECK_(condition) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::IsTrue(condition)) \ - ; \ - else \ - GTEST_LOG_(FATAL) << "Condition " #condition " failed. " - -// An all-mode assert to verify that the given POSIX-style function -// call returns 0 (indicating success). Known limitation: this -// doesn't expand to a balanced 'if' statement, so enclose the macro -// in {} if you need to use it as the only statement in an 'if' -// branch. -#define GTEST_CHECK_POSIX_SUCCESS_(posix_call) \ - if (const int gtest_error = (posix_call)) \ - GTEST_LOG_(FATAL) << #posix_call << "failed with error " \ - << gtest_error - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Use ImplicitCast_ as a safe version of static_cast for upcasting in -// the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a -// const Foo*). When you use ImplicitCast_, the compiler checks that -// the cast is safe. Such explicit ImplicitCast_s are necessary in -// surprisingly many situations where C++ demands an exact type match -// instead of an argument type convertable to a target type. -// -// The syntax for using ImplicitCast_ is the same as for static_cast: -// -// ImplicitCast_(expr) -// -// ImplicitCast_ would have been part of the C++ standard library, -// but the proposal was submitted too late. It will probably make -// its way into the language in the future. -// -// This relatively ugly name is intentional. It prevents clashes with -// similar functions users may have (e.g., implicit_cast). The internal -// namespace alone is not enough because the function can be found by ADL. -template -inline To ImplicitCast_(To x) { return x; } - -// When you upcast (that is, cast a pointer from type Foo to type -// SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts -// always succeed. When you downcast (that is, cast a pointer from -// type Foo to type SubclassOfFoo), static_cast<> isn't safe, because -// how do you know the pointer is really of type SubclassOfFoo? It -// could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, -// when you downcast, you should use this macro. In debug mode, we -// use dynamic_cast<> to double-check the downcast is legal (we die -// if it's not). In normal mode, we do the efficient static_cast<> -// instead. Thus, it's important to test in debug mode to make sure -// the cast is legal! -// This is the only place in the code we should use dynamic_cast<>. -// In particular, you SHOULDN'T be using dynamic_cast<> in order to -// do RTTI (eg code like this: -// if (dynamic_cast(foo)) HandleASubclass1Object(foo); -// if (dynamic_cast(foo)) HandleASubclass2Object(foo); -// You should design the code some other way not to need this. -// -// This relatively ugly name is intentional. It prevents clashes with -// similar functions users may have (e.g., down_cast). The internal -// namespace alone is not enough because the function can be found by ADL. -template // use like this: DownCast_(foo); -inline To DownCast_(From* f) { // so we only accept pointers - // Ensures that To is a sub-type of From *. This test is here only - // for compile-time type checking, and has no overhead in an - // optimized build at run-time, as it will be optimized away - // completely. - if (false) { - const To to = NULL; - ::testing::internal::ImplicitCast_(to); - } - -#if GTEST_HAS_RTTI - // RTTI: debug mode only! - GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); -#endif - return static_cast(f); -} - -// Downcasts the pointer of type Base to Derived. -// Derived must be a subclass of Base. The parameter MUST -// point to a class of type Derived, not any subclass of it. -// When RTTI is available, the function performs a runtime -// check to enforce this. -template -Derived* CheckedDowncastToActualType(Base* base) { -#if GTEST_HAS_RTTI - GTEST_CHECK_(typeid(*base) == typeid(Derived)); - return dynamic_cast(base); // NOLINT -#else - return static_cast(base); // Poor man's downcast. -#endif -} - -#if GTEST_HAS_STREAM_REDIRECTION - -// Defines the stderr capturer: -// CaptureStdout - starts capturing stdout. -// GetCapturedStdout - stops capturing stdout and returns the captured string. -// CaptureStderr - starts capturing stderr. -// GetCapturedStderr - stops capturing stderr and returns the captured string. -// -GTEST_API_ void CaptureStdout(); -GTEST_API_ std::string GetCapturedStdout(); -GTEST_API_ void CaptureStderr(); -GTEST_API_ std::string GetCapturedStderr(); - -#endif // GTEST_HAS_STREAM_REDIRECTION - - -#if GTEST_HAS_DEATH_TEST - -const ::std::vector& GetInjectableArgvs(); -void SetInjectableArgvs(const ::std::vector* - new_argvs); - -// A copy of all command line arguments. Set by InitGoogleTest(). -extern ::std::vector g_argvs; - -#endif // GTEST_HAS_DEATH_TEST - -// Defines synchronization primitives. - -#if GTEST_HAS_PTHREAD - -// Sleeps for (roughly) n milli-seconds. This function is only for -// testing Google Test's own constructs. Don't use it in user tests, -// either directly or indirectly. -inline void SleepMilliseconds(int n) { - const timespec time = { - 0, // 0 seconds. - n * 1000L * 1000L, // And n ms. - }; - nanosleep(&time, NULL); -} - -// Allows a controller thread to pause execution of newly created -// threads until notified. Instances of this class must be created -// and destroyed in the controller thread. -// -// This class is only for testing Google Test's own constructs. Do not -// use it in user tests, either directly or indirectly. -class Notification { - public: - Notification() : notified_(false) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - } - ~Notification() { - pthread_mutex_destroy(&mutex_); - } - - // Notifies all threads created with this notification to start. Must - // be called from the controller thread. - void Notify() { - pthread_mutex_lock(&mutex_); - notified_ = true; - pthread_mutex_unlock(&mutex_); - } - - // Blocks until the controller thread notifies. Must be called from a test - // thread. - void WaitForNotification() { - for (;;) { - pthread_mutex_lock(&mutex_); - const bool notified = notified_; - pthread_mutex_unlock(&mutex_); - if (notified) - break; - SleepMilliseconds(10); - } - } - - private: - pthread_mutex_t mutex_; - bool notified_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); -}; - -// As a C-function, ThreadFuncWithCLinkage cannot be templated itself. -// Consequently, it cannot select a correct instantiation of ThreadWithParam -// in order to call its Run(). Introducing ThreadWithParamBase as a -// non-templated base class for ThreadWithParam allows us to bypass this -// problem. -class ThreadWithParamBase { - public: - virtual ~ThreadWithParamBase() {} - virtual void Run() = 0; -}; - -// pthread_create() accepts a pointer to a function type with the C linkage. -// According to the Standard (7.5/1), function types with different linkages -// are different even if they are otherwise identical. Some compilers (for -// example, SunStudio) treat them as different types. Since class methods -// cannot be defined with C-linkage we need to define a free C-function to -// pass into pthread_create(). -extern "C" inline void* ThreadFuncWithCLinkage(void* thread) { - static_cast(thread)->Run(); - return NULL; -} - -// Helper class for testing Google Test's multi-threading constructs. -// To use it, write: -// -// void ThreadFunc(int param) { /* Do things with param */ } -// Notification thread_can_start; -// ... -// // The thread_can_start parameter is optional; you can supply NULL. -// ThreadWithParam thread(&ThreadFunc, 5, &thread_can_start); -// thread_can_start.Notify(); -// -// These classes are only for testing Google Test's own constructs. Do -// not use them in user tests, either directly or indirectly. -template -class ThreadWithParam : public ThreadWithParamBase { - public: - typedef void (*UserThreadFunc)(T); - - ThreadWithParam( - UserThreadFunc func, T param, Notification* thread_can_start) - : func_(func), - param_(param), - thread_can_start_(thread_can_start), - finished_(false) { - ThreadWithParamBase* const base = this; - // The thread can be created only after all fields except thread_ - // have been initialized. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_create(&thread_, 0, &ThreadFuncWithCLinkage, base)); - } - ~ThreadWithParam() { Join(); } - - void Join() { - if (!finished_) { - GTEST_CHECK_POSIX_SUCCESS_(pthread_join(thread_, 0)); - finished_ = true; - } - } - - virtual void Run() { - if (thread_can_start_ != NULL) - thread_can_start_->WaitForNotification(); - func_(param_); - } - - private: - const UserThreadFunc func_; // User-supplied thread function. - const T param_; // User-supplied parameter to the thread function. - // When non-NULL, used to block execution until the controller thread - // notifies. - Notification* const thread_can_start_; - bool finished_; // true iff we know that the thread function has finished. - pthread_t thread_; // The native thread object. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); -}; - -// MutexBase and Mutex implement mutex on pthreads-based platforms. They -// are used in conjunction with class MutexLock: -// -// Mutex mutex; -// ... -// MutexLock lock(&mutex); // Acquires the mutex and releases it at the end -// // of the current scope. -// -// MutexBase implements behavior for both statically and dynamically -// allocated mutexes. Do not use MutexBase directly. Instead, write -// the following to define a static mutex: -// -// GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); -// -// You can forward declare a static mutex like this: -// -// GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); -// -// To create a dynamic mutex, just define an object of type Mutex. -class MutexBase { - public: - // Acquires this mutex. - void Lock() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); - owner_ = pthread_self(); - has_owner_ = true; - } - - // Releases this mutex. - void Unlock() { - // Since the lock is being released the owner_ field should no longer be - // considered valid. We don't protect writing to has_owner_ here, as it's - // the caller's responsibility to ensure that the current thread holds the - // mutex when this is called. - has_owner_ = false; - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_unlock(&mutex_)); - } - - // Does nothing if the current thread holds the mutex. Otherwise, crashes - // with high probability. - void AssertHeld() const { - GTEST_CHECK_(has_owner_ && pthread_equal(owner_, pthread_self())) - << "The current thread is not holding the mutex @" << this; - } - - // A static mutex may be used before main() is entered. It may even - // be used before the dynamic initialization stage. Therefore we - // must be able to initialize a static mutex object at link time. - // This means MutexBase has to be a POD and its member variables - // have to be public. - public: - pthread_mutex_t mutex_; // The underlying pthread mutex. - // has_owner_ indicates whether the owner_ field below contains a valid thread - // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All - // accesses to the owner_ field should be protected by a check of this field. - // An alternative might be to memset() owner_ to all zeros, but there's no - // guarantee that a zero'd pthread_t is necessarily invalid or even different - // from pthread_self(). - bool has_owner_; - pthread_t owner_; // The thread holding the mutex. -}; - -// Forward-declares a static mutex. -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::MutexBase mutex - -// Defines and statically (i.e. at link time) initializes a static mutex. -// The initialization list here does not explicitly initialize each field, -// instead relying on default initialization for the unspecified fields. In -// particular, the owner_ field (a pthread_t) is not explicitly initialized. -// This allows initialization to work whether pthread_t is a scalar or struct. -// The flag -Wmissing-field-initializers must not be specified for this to work. -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ - ::testing::internal::MutexBase mutex = { PTHREAD_MUTEX_INITIALIZER, false } - -// The Mutex class can only be used for mutexes created at runtime. It -// shares its API with MutexBase otherwise. -class Mutex : public MutexBase { - public: - Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); - has_owner_ = false; - } - ~Mutex() { - GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); -}; - -// We cannot name this class MutexLock as the ctor declaration would -// conflict with a macro named MutexLock, which is defined on some -// platforms. Hence the typedef trick below. -class GTestMutexLock { - public: - explicit GTestMutexLock(MutexBase* mutex) - : mutex_(mutex) { mutex_->Lock(); } - - ~GTestMutexLock() { mutex_->Unlock(); } - - private: - MutexBase* const mutex_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); -}; - -typedef GTestMutexLock MutexLock; - -// Helpers for ThreadLocal. - -// pthread_key_create() requires DeleteThreadLocalValue() to have -// C-linkage. Therefore it cannot be templatized to access -// ThreadLocal. Hence the need for class -// ThreadLocalValueHolderBase. -class ThreadLocalValueHolderBase { - public: - virtual ~ThreadLocalValueHolderBase() {} -}; - -// Called by pthread to delete thread-local data stored by -// pthread_setspecific(). -extern "C" inline void DeleteThreadLocalValue(void* value_holder) { - delete static_cast(value_holder); -} - -// Implements thread-local storage on pthreads-based systems. -// -// // Thread 1 -// ThreadLocal tl(100); // 100 is the default value for each thread. -// -// // Thread 2 -// tl.set(150); // Changes the value for thread 2 only. -// EXPECT_EQ(150, tl.get()); -// -// // Thread 1 -// EXPECT_EQ(100, tl.get()); // In thread 1, tl has the original value. -// tl.set(200); -// EXPECT_EQ(200, tl.get()); -// -// The template type argument T must have a public copy constructor. -// In addition, the default ThreadLocal constructor requires T to have -// a public default constructor. -// -// An object managed for a thread by a ThreadLocal instance is deleted -// when the thread exits. Or, if the ThreadLocal instance dies in -// that thread, when the ThreadLocal dies. It's the user's -// responsibility to ensure that all other threads using a ThreadLocal -// have exited when it dies, or the per-thread objects for those -// threads will not be deleted. -// -// Google Test only uses global ThreadLocal objects. That means they -// will die after main() has returned. Therefore, no per-thread -// object managed by Google Test will be leaked as long as all threads -// using Google Test have exited when main() returns. -template -class ThreadLocal { - public: - ThreadLocal() : key_(CreateKey()), - default_() {} - explicit ThreadLocal(const T& value) : key_(CreateKey()), - default_(value) {} - - ~ThreadLocal() { - // Destroys the managed object for the current thread, if any. - DeleteThreadLocalValue(pthread_getspecific(key_)); - - // Releases resources associated with the key. This will *not* - // delete managed objects for other threads. - GTEST_CHECK_POSIX_SUCCESS_(pthread_key_delete(key_)); - } - - T* pointer() { return GetOrCreateValue(); } - const T* pointer() const { return GetOrCreateValue(); } - const T& get() const { return *pointer(); } - void set(const T& value) { *pointer() = value; } - - private: - // Holds a value of type T. - class ValueHolder : public ThreadLocalValueHolderBase { - public: - explicit ValueHolder(const T& value) : value_(value) {} - - T* pointer() { return &value_; } - - private: - T value_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); - }; - - static pthread_key_t CreateKey() { - pthread_key_t key; - // When a thread exits, DeleteThreadLocalValue() will be called on - // the object managed for that thread. - GTEST_CHECK_POSIX_SUCCESS_( - pthread_key_create(&key, &DeleteThreadLocalValue)); - return key; - } - - T* GetOrCreateValue() const { - ThreadLocalValueHolderBase* const holder = - static_cast(pthread_getspecific(key_)); - if (holder != NULL) { - return CheckedDowncastToActualType(holder)->pointer(); - } - - ValueHolder* const new_holder = new ValueHolder(default_); - ThreadLocalValueHolderBase* const holder_base = new_holder; - GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); - return new_holder->pointer(); - } - - // A key pthreads uses for looking up per-thread values. - const pthread_key_t key_; - const T default_; // The default value for each thread. - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); -}; - -# define GTEST_IS_THREADSAFE 1 - -#else // GTEST_HAS_PTHREAD - -// A dummy implementation of synchronization primitives (mutex, lock, -// and thread-local variable). Necessary for compiling Google Test where -// mutex is not supported - using Google Test in multiple threads is not -// supported on such platforms. - -class Mutex { - public: - Mutex() {} - void Lock() {} - void Unlock() {} - void AssertHeld() const {} -}; - -# define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ - extern ::testing::internal::Mutex mutex - -# define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex - -class GTestMutexLock { - public: - explicit GTestMutexLock(Mutex*) {} // NOLINT -}; - -typedef GTestMutexLock MutexLock; - -template -class ThreadLocal { - public: - ThreadLocal() : value_() {} - explicit ThreadLocal(const T& value) : value_(value) {} - T* pointer() { return &value_; } - const T* pointer() const { return &value_; } - const T& get() const { return value_; } - void set(const T& value) { value_ = value; } - private: - T value_; -}; - -// The above synchronization primitives have dummy implementations. -// Therefore Google Test is not thread-safe. -# define GTEST_IS_THREADSAFE 0 - -#endif // GTEST_HAS_PTHREAD - -// Returns the number of threads running in the process, or 0 to indicate that -// we cannot detect it. -GTEST_API_ size_t GetThreadCount(); - -// Passing non-POD classes through ellipsis (...) crashes the ARM -// compiler and generates a warning in Sun Studio. The Nokia Symbian -// and the IBM XL C/C++ compiler try to instantiate a copy constructor -// for objects passed through ellipsis (...), failing for uncopyable -// objects. We define this to ensure that only POD is passed through -// ellipsis on these systems. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) || defined(__SUNPRO_CC) -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_ELLIPSIS_NEEDS_POD_ 1 -#else -# define GTEST_CAN_COMPARE_NULL 1 -#endif - -// The Nokia Symbian and IBM XL C/C++ compilers cannot decide between -// const T& and const T* in a function template. These compilers -// _can_ decide between class template specializations for T and T*, -// so a tr1::type_traits-like is_pointer works. -#if defined(__SYMBIAN32__) || defined(__IBMCPP__) -# define GTEST_NEEDS_IS_POINTER_ 1 -#endif - -template -struct bool_constant { - typedef bool_constant type; - static const bool value = bool_value; -}; -template const bool bool_constant::value; - -typedef bool_constant false_type; -typedef bool_constant true_type; - -template -struct is_pointer : public false_type {}; - -template -struct is_pointer : public true_type {}; - -template -struct IteratorTraits { - typedef typename Iterator::value_type value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -template -struct IteratorTraits { - typedef T value_type; -}; - -#if GTEST_OS_WINDOWS -# define GTEST_PATH_SEP_ "\\" -# define GTEST_HAS_ALT_PATH_SEP_ 1 -// The biggest signed integer type the compiler supports. -typedef __int64 BiggestInt; -#else -# define GTEST_PATH_SEP_ "/" -# define GTEST_HAS_ALT_PATH_SEP_ 0 -typedef long long BiggestInt; // NOLINT -#endif // GTEST_OS_WINDOWS - -// Utilities for char. - -// isspace(int ch) and friends accept an unsigned char or EOF. char -// may be signed, depending on the compiler (or compiler flags). -// Therefore we need to cast a char to unsigned char before calling -// isspace(), etc. - -inline bool IsAlpha(char ch) { - return isalpha(static_cast(ch)) != 0; -} -inline bool IsAlNum(char ch) { - return isalnum(static_cast(ch)) != 0; -} -inline bool IsDigit(char ch) { - return isdigit(static_cast(ch)) != 0; -} -inline bool IsLower(char ch) { - return islower(static_cast(ch)) != 0; -} -inline bool IsSpace(char ch) { - return isspace(static_cast(ch)) != 0; -} -inline bool IsUpper(char ch) { - return isupper(static_cast(ch)) != 0; -} -inline bool IsXDigit(char ch) { - return isxdigit(static_cast(ch)) != 0; -} -inline bool IsXDigit(wchar_t ch) { - const unsigned char low_byte = static_cast(ch); - return ch == low_byte && isxdigit(low_byte) != 0; -} - -inline char ToLower(char ch) { - return static_cast(tolower(static_cast(ch))); -} -inline char ToUpper(char ch) { - return static_cast(toupper(static_cast(ch))); -} - -// The testing::internal::posix namespace holds wrappers for common -// POSIX functions. These wrappers hide the differences between -// Windows/MSVC and POSIX systems. Since some compilers define these -// standard functions as macros, the wrapper cannot have the same name -// as the wrapped function. - -namespace posix { - -// Functions with a different name on Windows. - -#if GTEST_OS_WINDOWS - -typedef struct _stat StatStruct; - -# ifdef __BORLANDC__ -inline int IsATTY(int fd) { return isatty(fd); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -# else // !__BORLANDC__ -# if GTEST_OS_WINDOWS_MOBILE -inline int IsATTY(int /* fd */) { return 0; } -# else -inline int IsATTY(int fd) { return _isatty(fd); } -# endif // GTEST_OS_WINDOWS_MOBILE -inline int StrCaseCmp(const char* s1, const char* s2) { - return _stricmp(s1, s2); -} -inline char* StrDup(const char* src) { return _strdup(src); } -# endif // __BORLANDC__ - -# if GTEST_OS_WINDOWS_MOBILE -inline int FileNo(FILE* file) { return reinterpret_cast(_fileno(file)); } -// Stat(), RmDir(), and IsDir() are not needed on Windows CE at this -// time and thus not defined there. -# else -inline int FileNo(FILE* file) { return _fileno(file); } -inline int Stat(const char* path, StatStruct* buf) { return _stat(path, buf); } -inline int RmDir(const char* dir) { return _rmdir(dir); } -inline bool IsDir(const StatStruct& st) { - return (_S_IFDIR & st.st_mode) != 0; -} -# endif // GTEST_OS_WINDOWS_MOBILE - -#else - -typedef struct stat StatStruct; - -inline int FileNo(FILE* file) { return fileno(file); } -inline int IsATTY(int fd) { return isatty(fd); } -inline int Stat(const char* path, StatStruct* buf) { return stat(path, buf); } -inline int StrCaseCmp(const char* s1, const char* s2) { - return strcasecmp(s1, s2); -} -inline char* StrDup(const char* src) { return strdup(src); } -inline int RmDir(const char* dir) { return rmdir(dir); } -inline bool IsDir(const StatStruct& st) { return S_ISDIR(st.st_mode); } - -#endif // GTEST_OS_WINDOWS - -// Functions deprecated by MSVC 8.0. - -#ifdef _MSC_VER -// Temporarily disable warning 4996 (deprecated function). -# pragma warning(push) -# pragma warning(disable:4996) -#endif - -inline const char* StrNCpy(char* dest, const char* src, size_t n) { - return strncpy(dest, src, n); -} - -// ChDir(), FReopen(), FDOpen(), Read(), Write(), Close(), and -// StrError() aren't needed on Windows CE at this time and thus not -// defined there. - -#if !GTEST_OS_WINDOWS_MOBILE -inline int ChDir(const char* dir) { return chdir(dir); } -#endif -inline FILE* FOpen(const char* path, const char* mode) { - return fopen(path, mode); -} -#if !GTEST_OS_WINDOWS_MOBILE -inline FILE *FReopen(const char* path, const char* mode, FILE* stream) { - return freopen(path, mode, stream); -} -inline FILE* FDOpen(int fd, const char* mode) { return fdopen(fd, mode); } -#endif -inline int FClose(FILE* fp) { return fclose(fp); } -#if !GTEST_OS_WINDOWS_MOBILE -inline int Read(int fd, void* buf, unsigned int count) { - return static_cast(read(fd, buf, count)); -} -inline int Write(int fd, const void* buf, unsigned int count) { - return static_cast(write(fd, buf, count)); -} -inline int Close(int fd) { return close(fd); } -inline const char* StrError(int errnum) { return strerror(errnum); } -#endif -inline const char* GetEnv(const char* name) { -#if GTEST_OS_WINDOWS_MOBILE - // We are on Windows CE, which has no environment variables. - return NULL; -#elif defined(__BORLANDC__) || defined(__SunOS_5_8) || defined(__SunOS_5_9) - // Environment variables which we programmatically clear will be set to the - // empty string rather than unset (NULL). Handle that case. - const char* const env = getenv(name); - return (env != NULL && env[0] != '\0') ? env : NULL; -#else - return getenv(name); -#endif -} - -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif - -#if GTEST_OS_WINDOWS_MOBILE -// Windows CE has no C library. The abort() function is used in -// several places in Google Test. This implementation provides a reasonable -// imitation of standard behaviour. -void Abort(); -#else -inline void Abort() { abort(); } -#endif // GTEST_OS_WINDOWS_MOBILE - -} // namespace posix - -// MSVC "deprecates" snprintf and issues warnings wherever it is used. In -// order to avoid these warnings, we need to use _snprintf or _snprintf_s on -// MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate -// function in order to achieve that. We use macro definition here because -// snprintf is a variadic function. -#if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE -// MSVC 2005 and above support variadic macros. -# define GTEST_SNPRINTF_(buffer, size, format, ...) \ - _snprintf_s(buffer, size, size, format, __VA_ARGS__) -#elif defined(_MSC_VER) -// Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't -// complain about _snprintf. -# define GTEST_SNPRINTF_ _snprintf -#else -# define GTEST_SNPRINTF_ snprintf -#endif - -// The maximum number a BiggestInt can represent. This definition -// works no matter BiggestInt is represented in one's complement or -// two's complement. -// -// We cannot rely on numeric_limits in STL, as __int64 and long long -// are not part of standard C++ and numeric_limits doesn't need to be -// defined for them. -const BiggestInt kMaxBiggestInt = - ~(static_cast(1) << (8*sizeof(BiggestInt) - 1)); - -// This template class serves as a compile-time function from size to -// type. It maps a size in bytes to a primitive type with that -// size. e.g. -// -// TypeWithSize<4>::UInt -// -// is typedef-ed to be unsigned int (unsigned integer made up of 4 -// bytes). -// -// Such functionality should belong to STL, but I cannot find it -// there. -// -// Google Test uses this class in the implementation of floating-point -// comparison. -// -// For now it only handles UInt (unsigned int) as that's all Google Test -// needs. Other types can be easily added in the future if need -// arises. -template -class TypeWithSize { - public: - // This prevents the user from using TypeWithSize with incorrect - // values of N. - typedef void UInt; -}; - -// The specialization for size 4. -template <> -class TypeWithSize<4> { - public: - // unsigned int has size 4 in both gcc and MSVC. - // - // As base/basictypes.h doesn't compile on Windows, we cannot use - // uint32, uint64, and etc here. - typedef int Int; - typedef unsigned int UInt; -}; - -// The specialization for size 8. -template <> -class TypeWithSize<8> { - public: -#if GTEST_OS_WINDOWS - typedef __int64 Int; - typedef unsigned __int64 UInt; -#else - typedef long long Int; // NOLINT - typedef unsigned long long UInt; // NOLINT -#endif // GTEST_OS_WINDOWS -}; - -// Integer types of known sizes. -typedef TypeWithSize<4>::Int Int32; -typedef TypeWithSize<4>::UInt UInt32; -typedef TypeWithSize<8>::Int Int64; -typedef TypeWithSize<8>::UInt UInt64; -typedef TypeWithSize<8>::Int TimeInMillis; // Represents time in milliseconds. - -// Utilities for command line flags and environment variables. - -// Macro for referencing flags. -#define GTEST_FLAG(name) FLAGS_gtest_##name - -// Macros for declaring flags. -#define GTEST_DECLARE_bool_(name) GTEST_API_ extern bool GTEST_FLAG(name) -#define GTEST_DECLARE_int32_(name) \ - GTEST_API_ extern ::testing::internal::Int32 GTEST_FLAG(name) -#define GTEST_DECLARE_string_(name) \ - GTEST_API_ extern ::std::string GTEST_FLAG(name) - -// Macros for defining flags. -#define GTEST_DEFINE_bool_(name, default_val, doc) \ - GTEST_API_ bool GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_int32_(name, default_val, doc) \ - GTEST_API_ ::testing::internal::Int32 GTEST_FLAG(name) = (default_val) -#define GTEST_DEFINE_string_(name, default_val, doc) \ - GTEST_API_ ::std::string GTEST_FLAG(name) = (default_val) - -// Thread annotations -#define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) -#define GTEST_LOCK_EXCLUDED_(locks) - -// Parses 'str' for a 32-bit signed integer. If successful, writes the result -// to *value and returns true; otherwise leaves *value unchanged and returns -// false. -// TODO(chandlerc): Find a better way to refactor flag and environment parsing -// out of both gtest-port.cc and gtest.cc to avoid exporting this utility -// function. -bool ParseInt32(const Message& src_text, const char* str, Int32* value); - -// Parses a bool/Int32/string from the environment variable -// corresponding to the given Google Test flag. -bool BoolFromGTestEnv(const char* flag, bool default_val); -GTEST_API_ Int32 Int32FromGTestEnv(const char* flag, Int32 default_val); -const char* StringFromGTestEnv(const char* flag, const char* default_val); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ - -#if GTEST_OS_LINUX -# include -# include -# include -# include -#endif // GTEST_OS_LINUX - -#if GTEST_HAS_EXCEPTIONS -# include -#endif - -#include -#include -#include -#include -#include -#include - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the Message class. -// -// IMPORTANT NOTE: Due to limitation of the C++ language, we have to -// leave some internal implementation details in this header file. -// They are clearly marked by comments like this: -// -// // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -// -// Such code is NOT meant to be used by a user directly, and is subject -// to CHANGE WITHOUT NOTICE. Therefore DO NOT DEPEND ON IT in a user -// program! - -#ifndef GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -#define GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ - -#include - - -// Ensures that there is at least one operator<< in the global namespace. -// See Message& operator<<(...) below for why. -void operator<<(const testing::internal::Secret&, int); - -namespace testing { - -// The Message class works like an ostream repeater. -// -// Typical usage: -// -// 1. You stream a bunch of values to a Message object. -// It will remember the text in a stringstream. -// 2. Then you stream the Message object to an ostream. -// This causes the text in the Message to be streamed -// to the ostream. -// -// For example; -// -// testing::Message foo; -// foo << 1 << " != " << 2; -// std::cout << foo; -// -// will print "1 != 2". -// -// Message is not intended to be inherited from. In particular, its -// destructor is not virtual. -// -// Note that stringstream behaves differently in gcc and in MSVC. You -// can stream a NULL char pointer to it in the former, but not in the -// latter (it causes an access violation if you do). The Message -// class hides this difference by treating a NULL char pointer as -// "(null)". -class GTEST_API_ Message { - private: - // The type of basic IO manipulators (endl, ends, and flush) for - // narrow streams. - typedef std::ostream& (*BasicNarrowIoManip)(std::ostream&); - - public: - // Constructs an empty Message. - Message(); - - // Copy constructor. - Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT - *ss_ << msg.GetString(); - } - - // Constructs a Message from a C-string. - explicit Message(const char* str) : ss_(new ::std::stringstream) { - *ss_ << str; - } - -#if GTEST_OS_SYMBIAN - // Streams a value (either a pointer or not) to this object. - template - inline Message& operator <<(const T& value) { - StreamHelper(typename internal::is_pointer::type(), value); - return *this; - } -#else - // Streams a non-pointer value to this object. - template - inline Message& operator <<(const T& val) { - // Some libraries overload << for STL containers. These - // overloads are defined in the global namespace instead of ::std. - // - // C++'s symbol lookup rule (i.e. Koenig lookup) says that these - // overloads are visible in either the std namespace or the global - // namespace, but not other namespaces, including the testing - // namespace which Google Test's Message class is in. - // - // To allow STL containers (and other types that has a << operator - // defined in the global namespace) to be used in Google Test - // assertions, testing::Message must access the custom << operator - // from the global namespace. With this using declaration, - // overloads of << defined in the global namespace and those - // visible via Koenig lookup are both exposed in this function. - using ::operator <<; - *ss_ << val; - return *this; - } - - // Streams a pointer value to this object. - // - // This function is an overload of the previous one. When you - // stream a pointer to a Message, this definition will be used as it - // is more specialized. (The C++ Standard, section - // [temp.func.order].) If you stream a non-pointer, then the - // previous definition will be used. - // - // The reason for this overload is that streaming a NULL pointer to - // ostream is undefined behavior. Depending on the compiler, you - // may get "0", "(nil)", "(null)", or an access violation. To - // ensure consistent result across compilers, we always treat NULL - // as "(null)". - template - inline Message& operator <<(T* const& pointer) { // NOLINT - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - return *this; - } -#endif // GTEST_OS_SYMBIAN - - // Since the basic IO manipulators are overloaded for both narrow - // and wide streams, we have to provide this specialized definition - // of operator <<, even though its body is the same as the - // templatized version above. Without this definition, streaming - // endl or other basic IO manipulators to Message will confuse the - // compiler. - Message& operator <<(BasicNarrowIoManip val) { - *ss_ << val; - return *this; - } - - // Instead of 1/0, we want to see true/false for bool values. - Message& operator <<(bool b) { - return *this << (b ? "true" : "false"); - } - - // These two overloads allow streaming a wide C string to a Message - // using the UTF-8 encoding. - Message& operator <<(const wchar_t* wide_c_str); - Message& operator <<(wchar_t* wide_c_str); - -#if GTEST_HAS_STD_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::std::wstring& wstr); -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_GLOBAL_WSTRING - // Converts the given wide string to a narrow string using the UTF-8 - // encoding, and streams the result to this Message object. - Message& operator <<(const ::wstring& wstr); -#endif // GTEST_HAS_GLOBAL_WSTRING - - // Gets the text streamed to this object so far as an std::string. - // Each '\0' character in the buffer is replaced with "\\0". - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - std::string GetString() const; - - private: - -#if GTEST_OS_SYMBIAN - // These are needed as the Nokia Symbian Compiler cannot decide between - // const T& and const T* in a function template. The Nokia compiler _can_ - // decide between class template specializations for T and T*, so a - // tr1::type_traits-like is_pointer works, and we can overload on that. - template - inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { - if (pointer == NULL) { - *ss_ << "(null)"; - } else { - *ss_ << pointer; - } - } - template - inline void StreamHelper(internal::false_type /*is_pointer*/, - const T& value) { - // See the comments in Message& operator <<(const T&) above for why - // we need this using statement. - using ::operator <<; - *ss_ << value; - } -#endif // GTEST_OS_SYMBIAN - - // We'll hold the text streamed to this object here. - const internal::scoped_ptr< ::std::stringstream> ss_; - - // We declare (but don't implement) this to prevent the compiler - // from implementing the assignment operator. - void operator=(const Message&); -}; - -// Streams a Message to an ostream. -inline std::ostream& operator <<(std::ostream& os, const Message& sb) { - return os << sb.GetString(); -} - -namespace internal { - -// Converts a streamable value to an std::string. A NULL pointer is -// converted to "(null)". When the input value is a ::string, -// ::std::string, ::wstring, or ::std::wstring object, each NUL -// character in it is replaced with "\\0". -template -std::string StreamableToString(const T& streamable) { - return (Message() << streamable).GetString(); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file declares the String class and functions used internally by -// Google Test. They are subject to change without notice. They should not used -// by code external to Google Test. -// -// This header file is #included by . -// It should not be #included by other files. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ - -#ifdef __BORLANDC__ -// string.h is not guaranteed to provide strcpy on C++ Builder. -# include -#endif - -#include -#include - - -namespace testing { -namespace internal { - -// String - an abstract class holding static string utilities. -class GTEST_API_ String { - public: - // Static utility methods - - // Clones a 0-terminated C string, allocating memory using new. The - // caller is responsible for deleting the return value using - // delete[]. Returns the cloned string, or NULL if the input is - // NULL. - // - // This is different from strdup() in string.h, which allocates - // memory using malloc(). - static const char* CloneCString(const char* c_str); - -#if GTEST_OS_WINDOWS_MOBILE - // Windows CE does not have the 'ANSI' versions of Win32 APIs. To be - // able to pass strings to Win32 APIs on CE we need to convert them - // to 'Unicode', UTF-16. - - // Creates a UTF-16 wide string from the given ANSI string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the wide string, or NULL if the - // input is NULL. - // - // The wide string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static LPCWSTR AnsiToUtf16(const char* c_str); - - // Creates an ANSI string from the given wide string, allocating - // memory using new. The caller is responsible for deleting the return - // value using delete[]. Returns the ANSI string, or NULL if the - // input is NULL. - // - // The returned string is created using the ANSI codepage (CP_ACP) to - // match the behaviour of the ANSI versions of Win32 calls and the - // C runtime. - static const char* Utf16ToAnsi(LPCWSTR utf16_str); -#endif - - // Compares two C strings. Returns true iff they have the same content. - // - // Unlike strcmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CStringEquals(const char* lhs, const char* rhs); - - // Converts a wide C string to a String using the UTF-8 encoding. - // NULL will be converted to "(null)". If an error occurred during - // the conversion, "(failed to convert from wide string)" is - // returned. - static std::string ShowWideCString(const wchar_t* wide_c_str); - - // Compares two wide C strings. Returns true iff they have the same - // content. - // - // Unlike wcscmp(), this function can handle NULL argument(s). A - // NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool WideCStringEquals(const wchar_t* lhs, const wchar_t* rhs); - - // Compares two C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike strcasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL C string, - // including the empty string. - static bool CaseInsensitiveCStringEquals(const char* lhs, - const char* rhs); - - // Compares two wide C strings, ignoring case. Returns true iff they - // have the same content. - // - // Unlike wcscasecmp(), this function can handle NULL argument(s). - // A NULL C string is considered different to any non-NULL wide C string, - // including the empty string. - // NB: The implementations on different platforms slightly differ. - // On windows, this method uses _wcsicmp which compares according to LC_CTYPE - // environment variable. On GNU platform this method uses wcscasecmp - // which compares according to LC_CTYPE category of the current locale. - // On MacOS X, it uses towlower, which also uses LC_CTYPE category of the - // current locale. - static bool CaseInsensitiveWideCStringEquals(const wchar_t* lhs, - const wchar_t* rhs); - - // Returns true iff the given string ends with the given suffix, ignoring - // case. Any string is considered to end with an empty suffix. - static bool EndsWithCaseInsensitive( - const std::string& str, const std::string& suffix); - - // Formats an int value as "%02d". - static std::string FormatIntWidth2(int value); // "%02d" for width == 2 - - // Formats an int value as "%X". - static std::string FormatHexInt(int value); - - // Formats a byte as "%02X". - static std::string FormatByte(unsigned char value); - - private: - String(); // Not meant to be instantiated. -}; // class String - -// Gets the content of the stringstream's buffer as an std::string. Each '\0' -// character in the buffer is replaced with "\\0". -GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: keith.ray@gmail.com (Keith Ray) -// -// Google Test filepath utilities -// -// This header file declares classes and functions used internally by -// Google Test. They are subject to change without notice. -// -// This file is #included in . -// Do not include this header file separately! - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ - - -namespace testing { -namespace internal { - -// FilePath - a class for file and directory pathname manipulation which -// handles platform-specific conventions (like the pathname separator). -// Used for helper functions for naming files in a directory for xml output. -// Except for Set methods, all methods are const or static, which provides an -// "immutable value object" -- useful for peace of mind. -// A FilePath with a value ending in a path separator ("like/this/") represents -// a directory, otherwise it is assumed to represent a file. In either case, -// it may or may not represent an actual file or directory in the file system. -// Names are NOT checked for syntax correctness -- no checking for illegal -// characters, malformed paths, etc. - -class GTEST_API_ FilePath { - public: - FilePath() : pathname_("") { } - FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } - - explicit FilePath(const std::string& pathname) : pathname_(pathname) { - Normalize(); - } - - FilePath& operator=(const FilePath& rhs) { - Set(rhs); - return *this; - } - - void Set(const FilePath& rhs) { - pathname_ = rhs.pathname_; - } - - const std::string& string() const { return pathname_; } - const char* c_str() const { return pathname_.c_str(); } - - // Returns the current working directory, or "" if unsuccessful. - static FilePath GetCurrentDir(); - - // Given directory = "dir", base_name = "test", number = 0, - // extension = "xml", returns "dir/test.xml". If number is greater - // than zero (e.g., 12), returns "dir/test_12.xml". - // On Windows platform, uses \ as the separator rather than /. - static FilePath MakeFileName(const FilePath& directory, - const FilePath& base_name, - int number, - const char* extension); - - // Given directory = "dir", relative_path = "test.xml", - // returns "dir/test.xml". - // On Windows, uses \ as the separator rather than /. - static FilePath ConcatPaths(const FilePath& directory, - const FilePath& relative_path); - - // Returns a pathname for a file that does not currently exist. The pathname - // will be directory/base_name.extension or - // directory/base_name_.extension if directory/base_name.extension - // already exists. The number will be incremented until a pathname is found - // that does not already exist. - // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. - // There could be a race condition if two or more processes are calling this - // function at the same time -- they could both pick the same filename. - static FilePath GenerateUniqueFileName(const FilePath& directory, - const FilePath& base_name, - const char* extension); - - // Returns true iff the path is "". - bool IsEmpty() const { return pathname_.empty(); } - - // If input name has a trailing separator character, removes it and returns - // the name, otherwise return the name string unmodified. - // On Windows platform, uses \ as the separator, other platforms use /. - FilePath RemoveTrailingPathSeparator() const; - - // Returns a copy of the FilePath with the directory part removed. - // Example: FilePath("path/to/file").RemoveDirectoryName() returns - // FilePath("file"). If there is no directory part ("just_a_file"), it returns - // the FilePath unmodified. If there is no file part ("just_a_dir/") it - // returns an empty FilePath (""). - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveDirectoryName() const; - - // RemoveFileName returns the directory path with the filename removed. - // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". - // If the FilePath is "a_file" or "/a_file", RemoveFileName returns - // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does - // not have a file, like "just/a/dir/", it returns the FilePath unmodified. - // On Windows platform, '\' is the path separator, otherwise it is '/'. - FilePath RemoveFileName() const; - - // Returns a copy of the FilePath with the case-insensitive extension removed. - // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns - // FilePath("dir/file"). If a case-insensitive extension is not - // found, returns a copy of the original FilePath. - FilePath RemoveExtension(const char* extension) const; - - // Creates directories so that path exists. Returns true if successful or if - // the directories already exist; returns false if unable to create - // directories for any reason. Will also return false if the FilePath does - // not represent a directory (that is, it doesn't end with a path separator). - bool CreateDirectoriesRecursively() const; - - // Create the directory so that path exists. Returns true if successful or - // if the directory already exists; returns false if unable to create the - // directory for any reason, including if the parent directory does not - // exist. Not named "CreateDirectory" because that's a macro on Windows. - bool CreateFolder() const; - - // Returns true if FilePath describes something in the file-system, - // either a file, directory, or whatever, and that something exists. - bool FileOrDirectoryExists() const; - - // Returns true if pathname describes a directory in the file-system - // that exists. - bool DirectoryExists() const; - - // Returns true if FilePath ends with a path separator, which indicates that - // it is intended to represent a directory. Returns false otherwise. - // This does NOT check that a directory (or file) actually exists. - bool IsDirectory() const; - - // Returns true if pathname describes a root directory. (Windows has one - // root directory per disk drive.) - bool IsRootDirectory() const; - - // Returns true if pathname describes an absolute path. - bool IsAbsolutePath() const; - - private: - // Replaces multiple consecutive separators with a single separator. - // For example, "bar///foo" becomes "bar/foo". Does not eliminate other - // redundancies that might be in a pathname involving "." or "..". - // - // A pathname with multiple consecutive separators may occur either through - // user error or as a result of some scripts or APIs that generate a pathname - // with a trailing separator. On other platforms the same API or script - // may NOT generate a pathname with a trailing "/". Then elsewhere that - // pathname may have another "/" and pathname components added to it, - // without checking for the separator already being there. - // The script language and operating system may allow paths like "foo//bar" - // but some of the functions in FilePath will not handle that correctly. In - // particular, RemoveTrailingPathSeparator() only removes one separator, and - // it is called in CreateDirectoriesRecursively() assuming that it will change - // a pathname from directory syntax (trailing separator) to filename syntax. - // - // On Windows this method also replaces the alternate path separator '/' with - // the primary path separator '\\', so that for example "bar\\/\\foo" becomes - // "bar\\foo". - - void Normalize(); - - // Returns a pointer to the last occurence of a valid path separator in - // the FilePath. On Windows, for example, both '/' and '\' are valid path - // separators. Returns NULL if no path separator was found. - const char* FindLastPathSeparator() const; - - std::string pathname_; -}; // class FilePath - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ -// This file was GENERATED by command: -// pump.py gtest-type-util.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - -// Type utilities needed for implementing typed and type-parameterized -// tests. This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently we support at most 50 types in a list, and at most 50 -// type-parameterized tests in one type-parameterized test case. -// Please contact googletestframework@googlegroups.com if you need -// more. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - - -// #ifdef __GNUC__ is too general here. It is possible to use gcc without using -// libstdc++ (which is where cxxabi.h comes from). -# if GTEST_HAS_CXXABI_H_ -# include -# elif defined(__HP_aCC) -# include -# endif // GTEST_HASH_CXXABI_H_ - -namespace testing { -namespace internal { - -// GetTypeName() returns a human-readable name of type T. -// NB: This function is also used in Google Mock, so don't move it inside of -// the typed-test-only section below. -template -std::string GetTypeName() { -# if GTEST_HAS_RTTI - - const char* const name = typeid(T).name(); -# if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) - int status = 0; - // gcc's implementation of typeid(T).name() mangles the type name, - // so we have to demangle it. -# if GTEST_HAS_CXXABI_H_ - using abi::__cxa_demangle; -# endif // GTEST_HAS_CXXABI_H_ - char* const readable_name = __cxa_demangle(name, 0, 0, &status); - const std::string name_str(status == 0 ? readable_name : name); - free(readable_name); - return name_str; -# else - return name; -# endif // GTEST_HAS_CXXABI_H_ || __HP_aCC - -# else - - return ""; - -# endif // GTEST_HAS_RTTI -} - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// AssertyTypeEq::type is defined iff T1 and T2 are the same -// type. This can be used as a compile-time assertion to ensure that -// two types are equal. - -template -struct AssertTypeEq; - -template -struct AssertTypeEq { - typedef bool type; -}; - -// A unique type used as the default value for the arguments of class -// template Types. This allows us to simulate variadic templates -// (e.g. Types, Type, and etc), which C++ doesn't -// support directly. -struct None {}; - -// The following family of struct and struct templates are used to -// represent type lists. In particular, TypesN -// represents a type list with N types (T1, T2, ..., and TN) in it. -// Except for Types0, every struct in the family has two member types: -// Head for the first type in the list, and Tail for the rest of the -// list. - -// The empty type list. -struct Types0 {}; - -// Type lists of length 1, 2, 3, and so on. - -template -struct Types1 { - typedef T1 Head; - typedef Types0 Tail; -}; -template -struct Types2 { - typedef T1 Head; - typedef Types1 Tail; -}; - -template -struct Types3 { - typedef T1 Head; - typedef Types2 Tail; -}; - -template -struct Types4 { - typedef T1 Head; - typedef Types3 Tail; -}; - -template -struct Types5 { - typedef T1 Head; - typedef Types4 Tail; -}; - -template -struct Types6 { - typedef T1 Head; - typedef Types5 Tail; -}; - -template -struct Types7 { - typedef T1 Head; - typedef Types6 Tail; -}; - -template -struct Types8 { - typedef T1 Head; - typedef Types7 Tail; -}; - -template -struct Types9 { - typedef T1 Head; - typedef Types8 Tail; -}; - -template -struct Types10 { - typedef T1 Head; - typedef Types9 Tail; -}; - -template -struct Types11 { - typedef T1 Head; - typedef Types10 Tail; -}; - -template -struct Types12 { - typedef T1 Head; - typedef Types11 Tail; -}; - -template -struct Types13 { - typedef T1 Head; - typedef Types12 Tail; -}; - -template -struct Types14 { - typedef T1 Head; - typedef Types13 Tail; -}; - -template -struct Types15 { - typedef T1 Head; - typedef Types14 Tail; -}; - -template -struct Types16 { - typedef T1 Head; - typedef Types15 Tail; -}; - -template -struct Types17 { - typedef T1 Head; - typedef Types16 Tail; -}; - -template -struct Types18 { - typedef T1 Head; - typedef Types17 Tail; -}; - -template -struct Types19 { - typedef T1 Head; - typedef Types18 Tail; -}; - -template -struct Types20 { - typedef T1 Head; - typedef Types19 Tail; -}; - -template -struct Types21 { - typedef T1 Head; - typedef Types20 Tail; -}; - -template -struct Types22 { - typedef T1 Head; - typedef Types21 Tail; -}; - -template -struct Types23 { - typedef T1 Head; - typedef Types22 Tail; -}; - -template -struct Types24 { - typedef T1 Head; - typedef Types23 Tail; -}; - -template -struct Types25 { - typedef T1 Head; - typedef Types24 Tail; -}; - -template -struct Types26 { - typedef T1 Head; - typedef Types25 Tail; -}; - -template -struct Types27 { - typedef T1 Head; - typedef Types26 Tail; -}; - -template -struct Types28 { - typedef T1 Head; - typedef Types27 Tail; -}; - -template -struct Types29 { - typedef T1 Head; - typedef Types28 Tail; -}; - -template -struct Types30 { - typedef T1 Head; - typedef Types29 Tail; -}; - -template -struct Types31 { - typedef T1 Head; - typedef Types30 Tail; -}; - -template -struct Types32 { - typedef T1 Head; - typedef Types31 Tail; -}; - -template -struct Types33 { - typedef T1 Head; - typedef Types32 Tail; -}; - -template -struct Types34 { - typedef T1 Head; - typedef Types33 Tail; -}; - -template -struct Types35 { - typedef T1 Head; - typedef Types34 Tail; -}; - -template -struct Types36 { - typedef T1 Head; - typedef Types35 Tail; -}; - -template -struct Types37 { - typedef T1 Head; - typedef Types36 Tail; -}; - -template -struct Types38 { - typedef T1 Head; - typedef Types37 Tail; -}; - -template -struct Types39 { - typedef T1 Head; - typedef Types38 Tail; -}; - -template -struct Types40 { - typedef T1 Head; - typedef Types39 Tail; -}; - -template -struct Types41 { - typedef T1 Head; - typedef Types40 Tail; -}; - -template -struct Types42 { - typedef T1 Head; - typedef Types41 Tail; -}; - -template -struct Types43 { - typedef T1 Head; - typedef Types42 Tail; -}; - -template -struct Types44 { - typedef T1 Head; - typedef Types43 Tail; -}; - -template -struct Types45 { - typedef T1 Head; - typedef Types44 Tail; -}; - -template -struct Types46 { - typedef T1 Head; - typedef Types45 Tail; -}; - -template -struct Types47 { - typedef T1 Head; - typedef Types46 Tail; -}; - -template -struct Types48 { - typedef T1 Head; - typedef Types47 Tail; -}; - -template -struct Types49 { - typedef T1 Head; - typedef Types48 Tail; -}; - -template -struct Types50 { - typedef T1 Head; - typedef Types49 Tail; -}; - - -} // namespace internal - -// We don't want to require the users to write TypesN<...> directly, -// as that would require them to count the length. Types<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Types -// will appear as Types in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Types, and Google Test will translate -// that to TypesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Types template. -template -struct Types { - typedef internal::Types50 type; -}; - -template <> -struct Types { - typedef internal::Types0 type; -}; -template -struct Types { - typedef internal::Types1 type; -}; -template -struct Types { - typedef internal::Types2 type; -}; -template -struct Types { - typedef internal::Types3 type; -}; -template -struct Types { - typedef internal::Types4 type; -}; -template -struct Types { - typedef internal::Types5 type; -}; -template -struct Types { - typedef internal::Types6 type; -}; -template -struct Types { - typedef internal::Types7 type; -}; -template -struct Types { - typedef internal::Types8 type; -}; -template -struct Types { - typedef internal::Types9 type; -}; -template -struct Types { - typedef internal::Types10 type; -}; -template -struct Types { - typedef internal::Types11 type; -}; -template -struct Types { - typedef internal::Types12 type; -}; -template -struct Types { - typedef internal::Types13 type; -}; -template -struct Types { - typedef internal::Types14 type; -}; -template -struct Types { - typedef internal::Types15 type; -}; -template -struct Types { - typedef internal::Types16 type; -}; -template -struct Types { - typedef internal::Types17 type; -}; -template -struct Types { - typedef internal::Types18 type; -}; -template -struct Types { - typedef internal::Types19 type; -}; -template -struct Types { - typedef internal::Types20 type; -}; -template -struct Types { - typedef internal::Types21 type; -}; -template -struct Types { - typedef internal::Types22 type; -}; -template -struct Types { - typedef internal::Types23 type; -}; -template -struct Types { - typedef internal::Types24 type; -}; -template -struct Types { - typedef internal::Types25 type; -}; -template -struct Types { - typedef internal::Types26 type; -}; -template -struct Types { - typedef internal::Types27 type; -}; -template -struct Types { - typedef internal::Types28 type; -}; -template -struct Types { - typedef internal::Types29 type; -}; -template -struct Types { - typedef internal::Types30 type; -}; -template -struct Types { - typedef internal::Types31 type; -}; -template -struct Types { - typedef internal::Types32 type; -}; -template -struct Types { - typedef internal::Types33 type; -}; -template -struct Types { - typedef internal::Types34 type; -}; -template -struct Types { - typedef internal::Types35 type; -}; -template -struct Types { - typedef internal::Types36 type; -}; -template -struct Types { - typedef internal::Types37 type; -}; -template -struct Types { - typedef internal::Types38 type; -}; -template -struct Types { - typedef internal::Types39 type; -}; -template -struct Types { - typedef internal::Types40 type; -}; -template -struct Types { - typedef internal::Types41 type; -}; -template -struct Types { - typedef internal::Types42 type; -}; -template -struct Types { - typedef internal::Types43 type; -}; -template -struct Types { - typedef internal::Types44 type; -}; -template -struct Types { - typedef internal::Types45 type; -}; -template -struct Types { - typedef internal::Types46 type; -}; -template -struct Types { - typedef internal::Types47 type; -}; -template -struct Types { - typedef internal::Types48 type; -}; -template -struct Types { - typedef internal::Types49 type; -}; - -namespace internal { - -# define GTEST_TEMPLATE_ template class - -// The template "selector" struct TemplateSel is used to -// represent Tmpl, which must be a class template with one type -// parameter, as a type. TemplateSel::Bind::type is defined -// as the type Tmpl. This allows us to actually instantiate the -// template "selected" by TemplateSel. -// -// This trick is necessary for simulating typedef for class templates, -// which C++ doesn't support directly. -template -struct TemplateSel { - template - struct Bind { - typedef Tmpl type; - }; -}; - -# define GTEST_BIND_(TmplSel, T) \ - TmplSel::template Bind::type - -// A unique struct template used as the default value for the -// arguments of class template Templates. This allows us to simulate -// variadic templates (e.g. Templates, Templates, -// and etc), which C++ doesn't support directly. -template -struct NoneT {}; - -// The following family of struct and struct templates are used to -// represent template lists. In particular, TemplatesN represents a list of N templates (T1, T2, ..., and TN). Except -// for Templates0, every struct in the family has two member types: -// Head for the selector of the first template in the list, and Tail -// for the rest of the list. - -// The empty template list. -struct Templates0 {}; - -// Template lists of length 1, 2, 3, and so on. - -template -struct Templates1 { - typedef TemplateSel Head; - typedef Templates0 Tail; -}; -template -struct Templates2 { - typedef TemplateSel Head; - typedef Templates1 Tail; -}; - -template -struct Templates3 { - typedef TemplateSel Head; - typedef Templates2 Tail; -}; - -template -struct Templates4 { - typedef TemplateSel Head; - typedef Templates3 Tail; -}; - -template -struct Templates5 { - typedef TemplateSel Head; - typedef Templates4 Tail; -}; - -template -struct Templates6 { - typedef TemplateSel Head; - typedef Templates5 Tail; -}; - -template -struct Templates7 { - typedef TemplateSel Head; - typedef Templates6 Tail; -}; - -template -struct Templates8 { - typedef TemplateSel Head; - typedef Templates7 Tail; -}; - -template -struct Templates9 { - typedef TemplateSel Head; - typedef Templates8 Tail; -}; - -template -struct Templates10 { - typedef TemplateSel Head; - typedef Templates9 Tail; -}; - -template -struct Templates11 { - typedef TemplateSel Head; - typedef Templates10 Tail; -}; - -template -struct Templates12 { - typedef TemplateSel Head; - typedef Templates11 Tail; -}; - -template -struct Templates13 { - typedef TemplateSel Head; - typedef Templates12 Tail; -}; - -template -struct Templates14 { - typedef TemplateSel Head; - typedef Templates13 Tail; -}; - -template -struct Templates15 { - typedef TemplateSel Head; - typedef Templates14 Tail; -}; - -template -struct Templates16 { - typedef TemplateSel Head; - typedef Templates15 Tail; -}; - -template -struct Templates17 { - typedef TemplateSel Head; - typedef Templates16 Tail; -}; - -template -struct Templates18 { - typedef TemplateSel Head; - typedef Templates17 Tail; -}; - -template -struct Templates19 { - typedef TemplateSel Head; - typedef Templates18 Tail; -}; - -template -struct Templates20 { - typedef TemplateSel Head; - typedef Templates19 Tail; -}; - -template -struct Templates21 { - typedef TemplateSel Head; - typedef Templates20 Tail; -}; - -template -struct Templates22 { - typedef TemplateSel Head; - typedef Templates21 Tail; -}; - -template -struct Templates23 { - typedef TemplateSel Head; - typedef Templates22 Tail; -}; - -template -struct Templates24 { - typedef TemplateSel Head; - typedef Templates23 Tail; -}; - -template -struct Templates25 { - typedef TemplateSel Head; - typedef Templates24 Tail; -}; - -template -struct Templates26 { - typedef TemplateSel Head; - typedef Templates25 Tail; -}; - -template -struct Templates27 { - typedef TemplateSel Head; - typedef Templates26 Tail; -}; - -template -struct Templates28 { - typedef TemplateSel Head; - typedef Templates27 Tail; -}; - -template -struct Templates29 { - typedef TemplateSel Head; - typedef Templates28 Tail; -}; - -template -struct Templates30 { - typedef TemplateSel Head; - typedef Templates29 Tail; -}; - -template -struct Templates31 { - typedef TemplateSel Head; - typedef Templates30 Tail; -}; - -template -struct Templates32 { - typedef TemplateSel Head; - typedef Templates31 Tail; -}; - -template -struct Templates33 { - typedef TemplateSel Head; - typedef Templates32 Tail; -}; - -template -struct Templates34 { - typedef TemplateSel Head; - typedef Templates33 Tail; -}; - -template -struct Templates35 { - typedef TemplateSel Head; - typedef Templates34 Tail; -}; - -template -struct Templates36 { - typedef TemplateSel Head; - typedef Templates35 Tail; -}; - -template -struct Templates37 { - typedef TemplateSel Head; - typedef Templates36 Tail; -}; - -template -struct Templates38 { - typedef TemplateSel Head; - typedef Templates37 Tail; -}; - -template -struct Templates39 { - typedef TemplateSel Head; - typedef Templates38 Tail; -}; - -template -struct Templates40 { - typedef TemplateSel Head; - typedef Templates39 Tail; -}; - -template -struct Templates41 { - typedef TemplateSel Head; - typedef Templates40 Tail; -}; - -template -struct Templates42 { - typedef TemplateSel Head; - typedef Templates41 Tail; -}; - -template -struct Templates43 { - typedef TemplateSel Head; - typedef Templates42 Tail; -}; - -template -struct Templates44 { - typedef TemplateSel Head; - typedef Templates43 Tail; -}; - -template -struct Templates45 { - typedef TemplateSel Head; - typedef Templates44 Tail; -}; - -template -struct Templates46 { - typedef TemplateSel Head; - typedef Templates45 Tail; -}; - -template -struct Templates47 { - typedef TemplateSel Head; - typedef Templates46 Tail; -}; - -template -struct Templates48 { - typedef TemplateSel Head; - typedef Templates47 Tail; -}; - -template -struct Templates49 { - typedef TemplateSel Head; - typedef Templates48 Tail; -}; - -template -struct Templates50 { - typedef TemplateSel Head; - typedef Templates49 Tail; -}; - - -// We don't want to require the users to write TemplatesN<...> directly, -// as that would require them to count the length. Templates<...> is much -// easier to write, but generates horrible messages when there is a -// compiler error, as gcc insists on printing out each template -// argument, even if it has the default value (this means Templates -// will appear as Templates in the compiler -// errors). -// -// Our solution is to combine the best part of the two approaches: a -// user would write Templates, and Google Test will translate -// that to TemplatesN internally to make error messages -// readable. The translation is done by the 'type' member of the -// Templates template. -template -struct Templates { - typedef Templates50 type; -}; - -template <> -struct Templates { - typedef Templates0 type; -}; -template -struct Templates { - typedef Templates1 type; -}; -template -struct Templates { - typedef Templates2 type; -}; -template -struct Templates { - typedef Templates3 type; -}; -template -struct Templates { - typedef Templates4 type; -}; -template -struct Templates { - typedef Templates5 type; -}; -template -struct Templates { - typedef Templates6 type; -}; -template -struct Templates { - typedef Templates7 type; -}; -template -struct Templates { - typedef Templates8 type; -}; -template -struct Templates { - typedef Templates9 type; -}; -template -struct Templates { - typedef Templates10 type; -}; -template -struct Templates { - typedef Templates11 type; -}; -template -struct Templates { - typedef Templates12 type; -}; -template -struct Templates { - typedef Templates13 type; -}; -template -struct Templates { - typedef Templates14 type; -}; -template -struct Templates { - typedef Templates15 type; -}; -template -struct Templates { - typedef Templates16 type; -}; -template -struct Templates { - typedef Templates17 type; -}; -template -struct Templates { - typedef Templates18 type; -}; -template -struct Templates { - typedef Templates19 type; -}; -template -struct Templates { - typedef Templates20 type; -}; -template -struct Templates { - typedef Templates21 type; -}; -template -struct Templates { - typedef Templates22 type; -}; -template -struct Templates { - typedef Templates23 type; -}; -template -struct Templates { - typedef Templates24 type; -}; -template -struct Templates { - typedef Templates25 type; -}; -template -struct Templates { - typedef Templates26 type; -}; -template -struct Templates { - typedef Templates27 type; -}; -template -struct Templates { - typedef Templates28 type; -}; -template -struct Templates { - typedef Templates29 type; -}; -template -struct Templates { - typedef Templates30 type; -}; -template -struct Templates { - typedef Templates31 type; -}; -template -struct Templates { - typedef Templates32 type; -}; -template -struct Templates { - typedef Templates33 type; -}; -template -struct Templates { - typedef Templates34 type; -}; -template -struct Templates { - typedef Templates35 type; -}; -template -struct Templates { - typedef Templates36 type; -}; -template -struct Templates { - typedef Templates37 type; -}; -template -struct Templates { - typedef Templates38 type; -}; -template -struct Templates { - typedef Templates39 type; -}; -template -struct Templates { - typedef Templates40 type; -}; -template -struct Templates { - typedef Templates41 type; -}; -template -struct Templates { - typedef Templates42 type; -}; -template -struct Templates { - typedef Templates43 type; -}; -template -struct Templates { - typedef Templates44 type; -}; -template -struct Templates { - typedef Templates45 type; -}; -template -struct Templates { - typedef Templates46 type; -}; -template -struct Templates { - typedef Templates47 type; -}; -template -struct Templates { - typedef Templates48 type; -}; -template -struct Templates { - typedef Templates49 type; -}; - -// The TypeList template makes it possible to use either a single type -// or a Types<...> list in TYPED_TEST_CASE() and -// INSTANTIATE_TYPED_TEST_CASE_P(). - -template -struct TypeList { - typedef Types1 type; -}; - -template -struct TypeList > { - typedef typename Types::type type; -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ - -// Due to C++ preprocessor weirdness, we need double indirection to -// concatenate two tokens when one of them is __LINE__. Writing -// -// foo ## __LINE__ -// -// will result in the token foo__LINE__, instead of foo followed by -// the current line number. For more details, see -// http://www.parashift.com/c++-faq-lite/misc-technical-issues.html#faq-39.6 -#define GTEST_CONCAT_TOKEN_(foo, bar) GTEST_CONCAT_TOKEN_IMPL_(foo, bar) -#define GTEST_CONCAT_TOKEN_IMPL_(foo, bar) foo ## bar - -class ProtocolMessage; -namespace proto2 { class Message; } - -namespace testing { - -// Forward declarations. - -class AssertionResult; // Result of an assertion. -class Message; // Represents a failure message. -class Test; // Represents a test. -class TestInfo; // Information about a test. -class TestPartResult; // Result of a test part. -class UnitTest; // A collection of test cases. - -template -::std::string PrintToString(const T& value); - -namespace internal { - -struct TraceInfo; // Information about a trace point. -class ScopedTrace; // Implements scoped trace. -class TestInfoImpl; // Opaque implementation of TestInfo -class UnitTestImpl; // Opaque implementation of UnitTest - -// How many times InitGoogleTest() has been called. -GTEST_API_ extern int g_init_gtest_count; - -// The text used in failure messages to indicate the start of the -// stack trace. -GTEST_API_ extern const char kStackTraceMarker[]; - -// Two overloaded helpers for checking at compile time whether an -// expression is a null pointer literal (i.e. NULL or any 0-valued -// compile-time integral constant). Their return values have -// different sizes, so we can use sizeof() to test which version is -// picked by the compiler. These helpers have no implementations, as -// we only need their signatures. -// -// Given IsNullLiteralHelper(x), the compiler will pick the first -// version if x can be implicitly converted to Secret*, and pick the -// second version otherwise. Since Secret is a secret and incomplete -// type, the only expression a user can write that has type Secret* is -// a null pointer literal. Therefore, we know that x is a null -// pointer literal if and only if the first version is picked by the -// compiler. -char IsNullLiteralHelper(Secret* p); -char (&IsNullLiteralHelper(...))[2]; // NOLINT - -// A compile-time bool constant that is true if and only if x is a -// null pointer literal (i.e. NULL or any 0-valued compile-time -// integral constant). -#ifdef GTEST_ELLIPSIS_NEEDS_POD_ -// We lose support for NULL detection where the compiler doesn't like -// passing non-POD classes through ellipsis (...). -# define GTEST_IS_NULL_LITERAL_(x) false -#else -# define GTEST_IS_NULL_LITERAL_(x) \ - (sizeof(::testing::internal::IsNullLiteralHelper(x)) == 1) -#endif // GTEST_ELLIPSIS_NEEDS_POD_ - -// Appends the user-supplied message to the Google-Test-generated message. -GTEST_API_ std::string AppendUserMessage( - const std::string& gtest_msg, const Message& user_msg); - -#if GTEST_HAS_EXCEPTIONS - -// This exception is thrown by (and only by) a failed Google Test -// assertion when GTEST_FLAG(throw_on_failure) is true (if exceptions -// are enabled). We derive it from std::runtime_error, which is for -// errors presumably detectable only at run time. Since -// std::runtime_error inherits from std::exception, many testing -// frameworks know how to extract and print the message inside it. -class GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { - public: - explicit GoogleTestFailureException(const TestPartResult& failure); -}; - -#endif // GTEST_HAS_EXCEPTIONS - -// A helper class for creating scoped traces in user programs. -class GTEST_API_ ScopedTrace { - public: - // The c'tor pushes the given source file location and message onto - // a trace stack maintained by Google Test. - ScopedTrace(const char* file, int line, const Message& message); - - // The d'tor pops the info pushed by the c'tor. - // - // Note that the d'tor is not virtual in order to be efficient. - // Don't inherit from ScopedTrace! - ~ScopedTrace(); - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedTrace); -} GTEST_ATTRIBUTE_UNUSED_; // A ScopedTrace object does its job in its - // c'tor and d'tor. Therefore it doesn't - // need to be used otherwise. - -// Constructs and returns the message for an equality assertion -// (e.g. ASSERT_EQ, EXPECT_STREQ, etc) failure. -// -// The first four parameters are the expressions used in the assertion -// and their values, as strings. For example, for ASSERT_EQ(foo, bar) -// where foo is 5 and bar is 6, we have: -// -// expected_expression: "foo" -// actual_expression: "bar" -// expected_value: "5" -// actual_value: "6" -// -// The ignoring_case parameter is true iff the assertion is a -// *_STRCASEEQ*. When it's true, the string " (ignoring case)" will -// be inserted into the message. -GTEST_API_ AssertionResult EqFailure(const char* expected_expression, - const char* actual_expression, - const std::string& expected_value, - const std::string& actual_value, - bool ignoring_case); - -// Constructs a failure message for Boolean assertions such as EXPECT_TRUE. -GTEST_API_ std::string GetBoolAssertionFailureMessage( - const AssertionResult& assertion_result, - const char* expression_text, - const char* actual_predicate_value, - const char* expected_predicate_value); - -// This template class represents an IEEE floating-point number -// (either single-precision or double-precision, depending on the -// template parameters). -// -// The purpose of this class is to do more sophisticated number -// comparison. (Due to round-off error, etc, it's very unlikely that -// two floating-points will be equal exactly. Hence a naive -// comparison by the == operation often doesn't work.) -// -// Format of IEEE floating-point: -// -// The most-significant bit being the leftmost, an IEEE -// floating-point looks like -// -// sign_bit exponent_bits fraction_bits -// -// Here, sign_bit is a single bit that designates the sign of the -// number. -// -// For float, there are 8 exponent bits and 23 fraction bits. -// -// For double, there are 11 exponent bits and 52 fraction bits. -// -// More details can be found at -// http://en.wikipedia.org/wiki/IEEE_floating-point_standard. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -template -class FloatingPoint { - public: - // Defines the unsigned integer type that has the same size as the - // floating point number. - typedef typename TypeWithSize::UInt Bits; - - // Constants. - - // # of bits in a number. - static const size_t kBitCount = 8*sizeof(RawType); - - // # of fraction bits in a number. - static const size_t kFractionBitCount = - std::numeric_limits::digits - 1; - - // # of exponent bits in a number. - static const size_t kExponentBitCount = kBitCount - 1 - kFractionBitCount; - - // The mask for the sign bit. - static const Bits kSignBitMask = static_cast(1) << (kBitCount - 1); - - // The mask for the fraction bits. - static const Bits kFractionBitMask = - ~static_cast(0) >> (kExponentBitCount + 1); - - // The mask for the exponent bits. - static const Bits kExponentBitMask = ~(kSignBitMask | kFractionBitMask); - - // How many ULP's (Units in the Last Place) we want to tolerate when - // comparing two numbers. The larger the value, the more error we - // allow. A 0 value means that two numbers must be exactly the same - // to be considered equal. - // - // The maximum error of a single floating-point operation is 0.5 - // units in the last place. On Intel CPU's, all floating-point - // calculations are done with 80-bit precision, while double has 64 - // bits. Therefore, 4 should be enough for ordinary use. - // - // See the following article for more details on ULP: - // http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ - static const size_t kMaxUlps = 4; - - // Constructs a FloatingPoint from a raw floating-point number. - // - // On an Intel CPU, passing a non-normalized NAN (Not a Number) - // around may change its bits, although the new value is guaranteed - // to be also a NAN. Therefore, don't expect this constructor to - // preserve the bits in x when x is a NAN. - explicit FloatingPoint(const RawType& x) { u_.value_ = x; } - - // Static methods - - // Reinterprets a bit pattern as a floating-point number. - // - // This function is needed to test the AlmostEquals() method. - static RawType ReinterpretBits(const Bits bits) { - FloatingPoint fp(0); - fp.u_.bits_ = bits; - return fp.u_.value_; - } - - // Returns the floating-point number that represent positive infinity. - static RawType Infinity() { - return ReinterpretBits(kExponentBitMask); - } - - // Returns the maximum representable finite floating-point number. - static RawType Max(); - - // Non-static methods - - // Returns the bits that represents this number. - const Bits &bits() const { return u_.bits_; } - - // Returns the exponent bits of this number. - Bits exponent_bits() const { return kExponentBitMask & u_.bits_; } - - // Returns the fraction bits of this number. - Bits fraction_bits() const { return kFractionBitMask & u_.bits_; } - - // Returns the sign bit of this number. - Bits sign_bit() const { return kSignBitMask & u_.bits_; } - - // Returns true iff this is NAN (not a number). - bool is_nan() const { - // It's a NAN if the exponent bits are all ones and the fraction - // bits are not entirely zeros. - return (exponent_bits() == kExponentBitMask) && (fraction_bits() != 0); - } - - // Returns true iff this number is at most kMaxUlps ULP's away from - // rhs. In particular, this function: - // - // - returns false if either number is (or both are) NAN. - // - treats really large numbers as almost equal to infinity. - // - thinks +0.0 and -0.0 are 0 DLP's apart. - bool AlmostEquals(const FloatingPoint& rhs) const { - // The IEEE standard says that any comparison operation involving - // a NAN must return false. - if (is_nan() || rhs.is_nan()) return false; - - return DistanceBetweenSignAndMagnitudeNumbers(u_.bits_, rhs.u_.bits_) - <= kMaxUlps; - } - - private: - // The data type used to store the actual floating-point number. - union FloatingPointUnion { - RawType value_; // The raw floating-point number. - Bits bits_; // The bits that represent the number. - }; - - // Converts an integer from the sign-and-magnitude representation to - // the biased representation. More precisely, let N be 2 to the - // power of (kBitCount - 1), an integer x is represented by the - // unsigned number x + N. - // - // For instance, - // - // -N + 1 (the most negative number representable using - // sign-and-magnitude) is represented by 1; - // 0 is represented by N; and - // N - 1 (the biggest number representable using - // sign-and-magnitude) is represented by 2N - 1. - // - // Read http://en.wikipedia.org/wiki/Signed_number_representations - // for more details on signed number representations. - static Bits SignAndMagnitudeToBiased(const Bits &sam) { - if (kSignBitMask & sam) { - // sam represents a negative number. - return ~sam + 1; - } else { - // sam represents a positive number. - return kSignBitMask | sam; - } - } - - // Given two numbers in the sign-and-magnitude representation, - // returns the distance between them as an unsigned number. - static Bits DistanceBetweenSignAndMagnitudeNumbers(const Bits &sam1, - const Bits &sam2) { - const Bits biased1 = SignAndMagnitudeToBiased(sam1); - const Bits biased2 = SignAndMagnitudeToBiased(sam2); - return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1); - } - - FloatingPointUnion u_; -}; - -// We cannot use std::numeric_limits::max() as it clashes with the max() -// macro defined by . -template <> -inline float FloatingPoint::Max() { return FLT_MAX; } -template <> -inline double FloatingPoint::Max() { return DBL_MAX; } - -// Typedefs the instances of the FloatingPoint template class that we -// care to use. -typedef FloatingPoint Float; -typedef FloatingPoint Double; - -// In order to catch the mistake of putting tests that use different -// test fixture classes in the same test case, we need to assign -// unique IDs to fixture classes and compare them. The TypeId type is -// used to hold such IDs. The user should treat TypeId as an opaque -// type: the only operation allowed on TypeId values is to compare -// them for equality using the == operator. -typedef const void* TypeId; - -template -class TypeIdHelper { - public: - // dummy_ must not have a const type. Otherwise an overly eager - // compiler (e.g. MSVC 7.1 & 8.0) may try to merge - // TypeIdHelper::dummy_ for different Ts as an "optimization". - static bool dummy_; -}; - -template -bool TypeIdHelper::dummy_ = false; - -// GetTypeId() returns the ID of type T. Different values will be -// returned for different types. Calling the function twice with the -// same type argument is guaranteed to return the same ID. -template -TypeId GetTypeId() { - // The compiler is required to allocate a different - // TypeIdHelper::dummy_ variable for each T used to instantiate - // the template. Therefore, the address of dummy_ is guaranteed to - // be unique. - return &(TypeIdHelper::dummy_); -} - -// Returns the type ID of ::testing::Test. Always call this instead -// of GetTypeId< ::testing::Test>() to get the type ID of -// ::testing::Test, as the latter may give the wrong result due to a -// suspected linker bug when compiling Google Test as a Mac OS X -// framework. -GTEST_API_ TypeId GetTestTypeId(); - -// Defines the abstract factory interface that creates instances -// of a Test object. -class TestFactoryBase { - public: - virtual ~TestFactoryBase() {} - - // Creates a test instance to run. The instance is both created and destroyed - // within TestInfoImpl::Run() - virtual Test* CreateTest() = 0; - - protected: - TestFactoryBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestFactoryBase); -}; - -// This class provides implementation of TeastFactoryBase interface. -// It is used in TEST and TEST_F macros. -template -class TestFactoryImpl : public TestFactoryBase { - public: - virtual Test* CreateTest() { return new TestClass; } -}; - -#if GTEST_OS_WINDOWS - -// Predicate-formatters for implementing the HRESULT checking macros -// {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED} -// We pass a long instead of HRESULT to avoid causing an -// include dependency for the HRESULT type. -GTEST_API_ AssertionResult IsHRESULTSuccess(const char* expr, - long hr); // NOLINT -GTEST_API_ AssertionResult IsHRESULTFailure(const char* expr, - long hr); // NOLINT - -#endif // GTEST_OS_WINDOWS - -// Types of SetUpTestCase() and TearDownTestCase() functions. -typedef void (*SetUpTestCaseFunc)(); -typedef void (*TearDownTestCaseFunc)(); - -// Creates a new TestInfo object and registers it with Google Test; -// returns the created object. -// -// Arguments: -// -// test_case_name: name of the test case -// name: name of the test -// type_param the name of the test's type parameter, or NULL if -// this is not a typed or a type-parameterized test. -// value_param text representation of the test's value parameter, -// or NULL if this is not a type-parameterized test. -// fixture_class_id: ID of the test fixture class -// set_up_tc: pointer to the function that sets up the test case -// tear_down_tc: pointer to the function that tears down the test case -// factory: pointer to the factory that creates a test object. -// The newly created TestInfo instance will assume -// ownership of the factory object. -GTEST_API_ TestInfo* MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - TypeId fixture_class_id, - SetUpTestCaseFunc set_up_tc, - TearDownTestCaseFunc tear_down_tc, - TestFactoryBase* factory); - -// If *pstr starts with the given prefix, modifies *pstr to be right -// past the prefix and returns true; otherwise leaves *pstr unchanged -// and returns false. None of pstr, *pstr, and prefix can be NULL. -GTEST_API_ bool SkipPrefix(const char* prefix, const char** pstr); - -#if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// State of the definition of a type-parameterized test case. -class GTEST_API_ TypedTestCasePState { - public: - TypedTestCasePState() : registered_(false) {} - - // Adds the given test name to defined_test_names_ and return true - // if the test case hasn't been registered; otherwise aborts the - // program. - bool AddTestName(const char* file, int line, const char* case_name, - const char* test_name) { - if (registered_) { - fprintf(stderr, "%s Test %s must be defined before " - "REGISTER_TYPED_TEST_CASE_P(%s, ...).\n", - FormatFileLocation(file, line).c_str(), test_name, case_name); - fflush(stderr); - posix::Abort(); - } - defined_test_names_.insert(test_name); - return true; - } - - // Verifies that registered_tests match the test names in - // defined_test_names_; returns registered_tests if successful, or - // aborts the program otherwise. - const char* VerifyRegisteredTestNames( - const char* file, int line, const char* registered_tests); - - private: - bool registered_; - ::std::set defined_test_names_; -}; - -// Skips to the first non-space char after the first comma in 'str'; -// returns NULL if no comma is found in 'str'. -inline const char* SkipComma(const char* str) { - const char* comma = strchr(str, ','); - if (comma == NULL) { - return NULL; - } - while (IsSpace(*(++comma))) {} - return comma; -} - -// Returns the prefix of 'str' before the first comma in it; returns -// the entire string if it contains no comma. -inline std::string GetPrefixUntilComma(const char* str) { - const char* comma = strchr(str, ','); - return comma == NULL ? str : std::string(str, comma); -} - -// TypeParameterizedTest::Register() -// registers a list of type-parameterized tests with Google Test. The -// return value is insignificant - we just need to return something -// such that we can call this function in a namespace scope. -// -// Implementation note: The GTEST_TEMPLATE_ macro declares a template -// template parameter. It's defined in gtest-type-util.h. -template -class TypeParameterizedTest { - public: - // 'index' is the index of the test in the type list 'Types' - // specified in INSTANTIATE_TYPED_TEST_CASE_P(Prefix, TestCase, - // Types). Valid values for 'index' are [0, N - 1] where N is the - // length of Types. - static bool Register(const char* prefix, const char* case_name, - const char* test_names, int index) { - typedef typename Types::Head Type; - typedef Fixture FixtureClass; - typedef typename GTEST_BIND_(TestSel, Type) TestClass; - - // First, registers the first type-parameterized test in the type - // list. - MakeAndRegisterTestInfo( - (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" - + StreamableToString(index)).c_str(), - GetPrefixUntilComma(test_names).c_str(), - GetTypeName().c_str(), - NULL, // No value parameter. - GetTypeId(), - TestClass::SetUpTestCase, - TestClass::TearDownTestCase, - new TestFactoryImpl); - - // Next, recurses (at compile time) with the tail of the type list. - return TypeParameterizedTest - ::Register(prefix, case_name, test_names, index + 1); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTest { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/, int /*index*/) { - return true; - } -}; - -// TypeParameterizedTestCase::Register() -// registers *all combinations* of 'Tests' and 'Types' with Google -// Test. The return value is insignificant - we just need to return -// something such that we can call this function in a namespace scope. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* prefix, const char* case_name, - const char* test_names) { - typedef typename Tests::Head Head; - - // First, register the first test in 'Test' for each type in 'Types'. - TypeParameterizedTest::Register( - prefix, case_name, test_names, 0); - - // Next, recurses (at compile time) with the tail of the test list. - return TypeParameterizedTestCase - ::Register(prefix, case_name, SkipComma(test_names)); - } -}; - -// The base case for the compile time recursion. -template -class TypeParameterizedTestCase { - public: - static bool Register(const char* /*prefix*/, const char* /*case_name*/, - const char* /*test_names*/) { - return true; - } -}; - -#endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P - -// Returns the current OS stack trace as an std::string. -// -// The maximum number of stack frames to be included is specified by -// the gtest_stack_trace_depth flag. The skip_count parameter -// specifies the number of top frames to be skipped, which doesn't -// count against the number of frames to be included. -// -// For example, if Foo() calls Bar(), which in turn calls -// GetCurrentOsStackTraceExceptTop(..., 1), Foo() will be included in -// the trace but Bar() and GetCurrentOsStackTraceExceptTop() won't. -GTEST_API_ std::string GetCurrentOsStackTraceExceptTop( - UnitTest* unit_test, int skip_count); - -// Helpers for suppressing warnings on unreachable code or constant -// condition. - -// Always returns true. -GTEST_API_ bool AlwaysTrue(); - -// Always returns false. -inline bool AlwaysFalse() { return !AlwaysTrue(); } - -// Helper for suppressing false warning from Clang on a const char* -// variable declared in a conditional expression always being NULL in -// the else branch. -struct GTEST_API_ ConstCharPtr { - ConstCharPtr(const char* str) : value(str) {} - operator bool() const { return true; } - const char* value; -}; - -// A simple Linear Congruential Generator for generating random -// numbers with a uniform distribution. Unlike rand() and srand(), it -// doesn't use global state (and therefore can't interfere with user -// code). Unlike rand_r(), it's portable. An LCG isn't very random, -// but it's good enough for our purposes. -class GTEST_API_ Random { - public: - static const UInt32 kMaxRange = 1u << 31; - - explicit Random(UInt32 seed) : state_(seed) {} - - void Reseed(UInt32 seed) { state_ = seed; } - - // Generates a random number from [0, range). Crashes if 'range' is - // 0 or greater than kMaxRange. - UInt32 Generate(UInt32 range); - - private: - UInt32 state_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(Random); -}; - -// Defining a variable of type CompileAssertTypesEqual will cause a -// compiler error iff T1 and T2 are different types. -template -struct CompileAssertTypesEqual; - -template -struct CompileAssertTypesEqual { -}; - -// Removes the reference from a type if it is a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::remove_reference, which is not widely available yet. -template -struct RemoveReference { typedef T type; }; // NOLINT -template -struct RemoveReference { typedef T type; }; // NOLINT - -// A handy wrapper around RemoveReference that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_REFERENCE_(T) \ - typename ::testing::internal::RemoveReference::type - -// Removes const from a type if it is a const type, otherwise leaves -// it unchanged. This is the same as tr1::remove_const, which is not -// widely available yet. -template -struct RemoveConst { typedef T type; }; // NOLINT -template -struct RemoveConst { typedef T type; }; // NOLINT - -// MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above -// definition to fail to remove the const in 'const int[3]' and 'const -// char[3][4]'. The following specialization works around the bug. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; - -#if defined(_MSC_VER) && _MSC_VER < 1400 -// This is the only specialization that allows VC++ 7.1 to remove const in -// 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC -// and thus needs to be conditionally compiled. -template -struct RemoveConst { - typedef typename RemoveConst::type type[N]; -}; -#endif - -// A handy wrapper around RemoveConst that works when the argument -// T depends on template parameters. -#define GTEST_REMOVE_CONST_(T) \ - typename ::testing::internal::RemoveConst::type - -// Turns const U&, U&, const U, and U all into U. -#define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ - GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) - -// Adds reference to a type if it is not a reference type, -// otherwise leaves it unchanged. This is the same as -// tr1::add_reference, which is not widely available yet. -template -struct AddReference { typedef T& type; }; // NOLINT -template -struct AddReference { typedef T& type; }; // NOLINT - -// A handy wrapper around AddReference that works when the argument T -// depends on template parameters. -#define GTEST_ADD_REFERENCE_(T) \ - typename ::testing::internal::AddReference::type - -// Adds a reference to const on top of T as necessary. For example, -// it transforms -// -// char ==> const char& -// const char ==> const char& -// char& ==> const char& -// const char& ==> const char& -// -// The argument T must depend on some template parameters. -#define GTEST_REFERENCE_TO_CONST_(T) \ - GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) - -// ImplicitlyConvertible::value is a compile-time bool -// constant that's true iff type From can be implicitly converted to -// type To. -template -class ImplicitlyConvertible { - private: - // We need the following helper functions only for their types. - // They have no implementations. - - // MakeFrom() is an expression whose type is From. We cannot simply - // use From(), as the type From may not have a public default - // constructor. - static From MakeFrom(); - - // These two functions are overloaded. Given an expression - // Helper(x), the compiler will pick the first version if x can be - // implicitly converted to type To; otherwise it will pick the - // second version. - // - // The first version returns a value of size 1, and the second - // version returns a value of size 2. Therefore, by checking the - // size of Helper(x), which can be done at compile time, we can tell - // which version of Helper() is used, and hence whether x can be - // implicitly converted to type To. - static char Helper(To); - static char (&Helper(...))[2]; // NOLINT - - // We have to put the 'public' section after the 'private' section, - // or MSVC refuses to compile the code. - public: - // MSVC warns about implicitly converting from double to int for - // possible loss of data, so we need to temporarily disable the - // warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4244) // Temporarily disables warning 4244. - - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -# pragma warning(pop) // Restores the warning state. -#elif defined(__BORLANDC__) - // C++Builder cannot use member overload resolution during template - // instantiation. The simplest workaround is to use its C++0x type traits - // functions (C++Builder 2009 and above only). - static const bool value = __is_convertible(From, To); -#else - static const bool value = - sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; -#endif // _MSV_VER -}; -template -const bool ImplicitlyConvertible::value; - -// IsAProtocolMessage::value is a compile-time bool constant that's -// true iff T is type ProtocolMessage, proto2::Message, or a subclass -// of those. -template -struct IsAProtocolMessage - : public bool_constant< - ImplicitlyConvertible::value || - ImplicitlyConvertible::value> { -}; - -// When the compiler sees expression IsContainerTest(0), if C is an -// STL-style container class, the first overload of IsContainerTest -// will be viable (since both C::iterator* and C::const_iterator* are -// valid types and NULL can be implicitly converted to them). It will -// be picked over the second overload as 'int' is a perfect match for -// the type of argument 0. If C::iterator or C::const_iterator is not -// a valid type, the first overload is not viable, and the second -// overload will be picked. Therefore, we can determine whether C is -// a container class by checking the type of IsContainerTest(0). -// The value of the expression is insignificant. -// -// Note that we look for both C::iterator and C::const_iterator. The -// reason is that C++ injects the name of a class as a member of the -// class itself (e.g. you can refer to class iterator as either -// 'iterator' or 'iterator::iterator'). If we look for C::iterator -// only, for example, we would mistakenly think that a class named -// iterator is an STL container. -// -// Also note that the simpler approach of overloading -// IsContainerTest(typename C::const_iterator*) and -// IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. -typedef int IsContainer; -template -IsContainer IsContainerTest(int /* dummy */, - typename C::iterator* /* it */ = NULL, - typename C::const_iterator* /* const_it */ = NULL) { - return 0; -} - -typedef char IsNotContainer; -template -IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } - -// EnableIf::type is void when 'Cond' is true, and -// undefined when 'Cond' is false. To use SFINAE to make a function -// overload only apply when a particular expression is true, add -// "typename EnableIf::type* = 0" as the last parameter. -template struct EnableIf; -template<> struct EnableIf { typedef void type; }; // NOLINT - -// Utilities for native arrays. - -// ArrayEq() compares two k-dimensional native arrays using the -// elements' operator==, where k can be any integer >= 0. When k is -// 0, ArrayEq() degenerates into comparing a single pair of values. - -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs); - -// This generic version is used when k is 0. -template -inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } - -// This overload is used when k >= 1. -template -inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { - return internal::ArrayEq(lhs, N, rhs); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous ArrayEq() function, arrays with different sizes would -// lead to different copies of the template code. -template -bool ArrayEq(const T* lhs, size_t size, const U* rhs) { - for (size_t i = 0; i != size; i++) { - if (!internal::ArrayEq(lhs[i], rhs[i])) - return false; - } - return true; -} - -// Finds the first element in the iterator range [begin, end) that -// equals elem. Element may be a native array type itself. -template -Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { - for (Iter it = begin; it != end; ++it) { - if (internal::ArrayEq(*it, elem)) - return it; - } - return end; -} - -// CopyArray() copies a k-dimensional native array using the elements' -// operator=, where k can be any integer >= 0. When k is 0, -// CopyArray() degenerates into copying a single value. - -template -void CopyArray(const T* from, size_t size, U* to); - -// This generic version is used when k is 0. -template -inline void CopyArray(const T& from, U* to) { *to = from; } - -// This overload is used when k >= 1. -template -inline void CopyArray(const T(&from)[N], U(*to)[N]) { - internal::CopyArray(from, N, *to); -} - -// This helper reduces code bloat. If we instead put its logic inside -// the previous CopyArray() function, arrays with different sizes -// would lead to different copies of the template code. -template -void CopyArray(const T* from, size_t size, U* to) { - for (size_t i = 0; i != size; i++) { - internal::CopyArray(from[i], to + i); - } -} - -// The relation between an NativeArray object (see below) and the -// native array it represents. -enum RelationToSource { - kReference, // The NativeArray references the native array. - kCopy // The NativeArray makes a copy of the native array and - // owns the copy. -}; - -// Adapts a native array to a read-only STL-style container. Instead -// of the complete STL container concept, this adaptor only implements -// members useful for Google Mock's container matchers. New members -// should be added as needed. To simplify the implementation, we only -// support Element being a raw type (i.e. having no top-level const or -// reference modifier). It's the client's responsibility to satisfy -// this requirement. Element can be an array type itself (hence -// multi-dimensional arrays are supported). -template -class NativeArray { - public: - // STL-style container typedefs. - typedef Element value_type; - typedef Element* iterator; - typedef const Element* const_iterator; - - // Constructs from a native array. - NativeArray(const Element* array, size_t count, RelationToSource relation) { - Init(array, count, relation); - } - - // Copy constructor. - NativeArray(const NativeArray& rhs) { - Init(rhs.array_, rhs.size_, rhs.relation_to_source_); - } - - ~NativeArray() { - // Ensures that the user doesn't instantiate NativeArray with a - // const or reference type. - static_cast(StaticAssertTypeEqHelper()); - if (relation_to_source_ == kCopy) - delete[] array_; - } - - // STL-style container methods. - size_t size() const { return size_; } - const_iterator begin() const { return array_; } - const_iterator end() const { return array_ + size_; } - bool operator==(const NativeArray& rhs) const { - return size() == rhs.size() && - ArrayEq(begin(), size(), rhs.begin()); - } - - private: - // Initializes this object; makes a copy of the input array if - // 'relation' is kCopy. - void Init(const Element* array, size_t a_size, RelationToSource relation) { - if (relation == kReference) { - array_ = array; - } else { - Element* const copy = new Element[a_size]; - CopyArray(array, a_size, copy); - array_ = copy; - } - size_ = a_size; - relation_to_source_ = relation; - } - - const Element* array_; - size_t size_; - RelationToSource relation_to_source_; - - GTEST_DISALLOW_ASSIGN_(NativeArray); -}; - -} // namespace internal -} // namespace testing - -#define GTEST_MESSAGE_AT_(file, line, message, result_type) \ - ::testing::internal::AssertHelper(result_type, file, line, message) \ - = ::testing::Message() - -#define GTEST_MESSAGE_(message, result_type) \ - GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) - -#define GTEST_FATAL_FAILURE_(message) \ - return GTEST_MESSAGE_(message, ::testing::TestPartResult::kFatalFailure) - -#define GTEST_NONFATAL_FAILURE_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kNonFatalFailure) - -#define GTEST_SUCCESS_(message) \ - GTEST_MESSAGE_(message, ::testing::TestPartResult::kSuccess) - -// Suppresses MSVC warnings 4072 (unreachable code) for the code following -// statement if it returns or throws (or doesn't return or throw in some -// situations). -#define GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) \ - if (::testing::internal::AlwaysTrue()) { statement; } - -#define GTEST_TEST_THROW_(statement, expected_exception, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::ConstCharPtr gtest_msg = "") { \ - bool gtest_caught_expected = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (expected_exception const&) { \ - gtest_caught_expected = true; \ - } \ - catch (...) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws a different type."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - if (!gtest_caught_expected) { \ - gtest_msg.value = \ - "Expected: " #statement " throws an exception of type " \ - #expected_exception ".\n Actual: it throws nothing."; \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testthrow_, __LINE__): \ - fail(gtest_msg.value) - -#define GTEST_TEST_NO_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ - fail("Expected: " #statement " doesn't throw an exception.\n" \ - " Actual: it throws.") - -#define GTEST_TEST_ANY_THROW_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - bool gtest_caught_any = false; \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } \ - catch (...) { \ - gtest_caught_any = true; \ - } \ - if (!gtest_caught_any) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ - fail("Expected: " #statement " throws an exception.\n" \ - " Actual: it doesn't.") - - -// Implements Boolean test assertions such as EXPECT_TRUE. expression can be -// either a boolean expression or an AssertionResult. text is a textual -// represenation of expression as it was passed into the EXPECT_TRUE. -#define GTEST_TEST_BOOLEAN_(expression, text, actual, expected, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar_ = \ - ::testing::AssertionResult(expression)) \ - ; \ - else \ - fail(::testing::internal::GetBoolAssertionFailureMessage(\ - gtest_ar_, text, #actual, #expected).c_str()) - -#define GTEST_TEST_NO_FATAL_FAILURE_(statement, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ - fail("Expected: " #statement " doesn't generate new fatal " \ - "failures in the current thread.\n" \ - " Actual: it does.") - -// Expands to the name of the class that implements the given test. -#define GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - test_case_name##_##test_name##_Test - -// Helper macro for defining tests. -#define GTEST_TEST_(test_case_name, test_name, parent_class, parent_id)\ -class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) : public parent_class {\ - public:\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {}\ - private:\ - virtual void TestBody();\ - static ::testing::TestInfo* const test_info_ GTEST_ATTRIBUTE_UNUSED_;\ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name));\ -};\ -\ -::testing::TestInfo* const GTEST_TEST_CLASS_NAME_(test_case_name, test_name)\ - ::test_info_ =\ - ::testing::internal::MakeAndRegisterTestInfo(\ - #test_case_name, #test_name, NULL, NULL, \ - (parent_id), \ - parent_class::SetUpTestCase, \ - parent_class::TearDownTestCase, \ - new ::testing::internal::TestFactoryImpl<\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>);\ -void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_INTERNAL_H_ -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines the public API for death tests. It is -// #included by gtest.h so a user doesn't need to include this -// directly. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ - -// Copyright 2005, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: wan@google.com (Zhanyong Wan), eefacm@gmail.com (Sean Mcafee) -// -// The Google C++ Testing Framework (Google Test) -// -// This header file defines internal utilities needed for implementing -// death tests. They are subject to change without notice. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ - - -#include - -namespace testing { -namespace internal { - -GTEST_DECLARE_string_(internal_run_death_test); - -// Names of the flags (needed for parsing Google Test flags). -const char kDeathTestStyleFlag[] = "death_test_style"; -const char kDeathTestUseFork[] = "death_test_use_fork"; -const char kInternalRunDeathTestFlag[] = "internal_run_death_test"; - -#if GTEST_HAS_DEATH_TEST - -// DeathTest is a class that hides much of the complexity of the -// GTEST_DEATH_TEST_ macro. It is abstract; its static Create method -// returns a concrete class that depends on the prevailing death test -// style, as defined by the --gtest_death_test_style and/or -// --gtest_internal_run_death_test flags. - -// In describing the results of death tests, these terms are used with -// the corresponding definitions: -// -// exit status: The integer exit information in the format specified -// by wait(2) -// exit code: The integer code passed to exit(3), _exit(2), or -// returned from main() -class GTEST_API_ DeathTest { - public: - // Create returns false if there was an error determining the - // appropriate action to take for the current death test; for example, - // if the gtest_death_test_style flag is set to an invalid value. - // The LastMessage method will return a more detailed message in that - // case. Otherwise, the DeathTest pointer pointed to by the "test" - // argument is set. If the death test should be skipped, the pointer - // is set to NULL; otherwise, it is set to the address of a new concrete - // DeathTest object that controls the execution of the current test. - static bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); - DeathTest(); - virtual ~DeathTest() { } - - // A helper class that aborts a death test when it's deleted. - class ReturnSentinel { - public: - explicit ReturnSentinel(DeathTest* test) : test_(test) { } - ~ReturnSentinel() { test_->Abort(TEST_ENCOUNTERED_RETURN_STATEMENT); } - private: - DeathTest* const test_; - GTEST_DISALLOW_COPY_AND_ASSIGN_(ReturnSentinel); - } GTEST_ATTRIBUTE_UNUSED_; - - // An enumeration of possible roles that may be taken when a death - // test is encountered. EXECUTE means that the death test logic should - // be executed immediately. OVERSEE means that the program should prepare - // the appropriate environment for a child process to execute the death - // test, then wait for it to complete. - enum TestRole { OVERSEE_TEST, EXECUTE_TEST }; - - // An enumeration of the three reasons that a test might be aborted. - enum AbortReason { - TEST_ENCOUNTERED_RETURN_STATEMENT, - TEST_THREW_EXCEPTION, - TEST_DID_NOT_DIE - }; - - // Assumes one of the above roles. - virtual TestRole AssumeRole() = 0; - - // Waits for the death test to finish and returns its status. - virtual int Wait() = 0; - - // Returns true if the death test passed; that is, the test process - // exited during the test, its exit status matches a user-supplied - // predicate, and its stderr output matches a user-supplied regular - // expression. - // The user-supplied predicate may be a macro expression rather - // than a function pointer or functor, or else Wait and Passed could - // be combined. - virtual bool Passed(bool exit_status_ok) = 0; - - // Signals that the death test did not die as expected. - virtual void Abort(AbortReason reason) = 0; - - // Returns a human-readable outcome message regarding the outcome of - // the last death test. - static const char* LastMessage(); - - static void set_last_death_test_message(const std::string& message); - - private: - // A string containing a description of the outcome of the last death test. - static std::string last_death_test_message_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(DeathTest); -}; - -// Factory interface for death tests. May be mocked out for testing. -class DeathTestFactory { - public: - virtual ~DeathTestFactory() { } - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test) = 0; -}; - -// A concrete DeathTestFactory implementation for normal use. -class DefaultDeathTestFactory : public DeathTestFactory { - public: - virtual bool Create(const char* statement, const RE* regex, - const char* file, int line, DeathTest** test); -}; - -// Returns true if exit_status describes a process that was terminated -// by a signal, or exited normally with a nonzero exit code. -GTEST_API_ bool ExitedUnsuccessfully(int exit_status); - -// Traps C++ exceptions escaping statement and reports them as test -// failures. Note that trapping SEH exceptions is not implemented here. -# if GTEST_HAS_EXCEPTIONS -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ - try { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } catch (const ::std::exception& gtest_exception) { \ - fprintf(\ - stderr, \ - "\n%s: Caught std::exception-derived exception escaping the " \ - "death test statement. Exception message: %s\n", \ - ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ - gtest_exception.what()); \ - fflush(stderr); \ - death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ - } catch (...) { \ - death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ - } - -# else -# define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) - -# endif - -// This macro is for implementing ASSERT_DEATH*, EXPECT_DEATH*, -// ASSERT_EXIT*, and EXPECT_EXIT*. -# define GTEST_DEATH_TEST_(statement, predicate, regex, fail) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - const ::testing::internal::RE& gtest_regex = (regex); \ - ::testing::internal::DeathTest* gtest_dt; \ - if (!::testing::internal::DeathTest::Create(#statement, >est_regex, \ - __FILE__, __LINE__, >est_dt)) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - if (gtest_dt != NULL) { \ - ::testing::internal::scoped_ptr< ::testing::internal::DeathTest> \ - gtest_dt_ptr(gtest_dt); \ - switch (gtest_dt->AssumeRole()) { \ - case ::testing::internal::DeathTest::OVERSEE_TEST: \ - if (!gtest_dt->Passed(predicate(gtest_dt->Wait()))) { \ - goto GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__); \ - } \ - break; \ - case ::testing::internal::DeathTest::EXECUTE_TEST: { \ - ::testing::internal::DeathTest::ReturnSentinel \ - gtest_sentinel(gtest_dt); \ - GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ - gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ - break; \ - } \ - default: \ - break; \ - } \ - } \ - } else \ - GTEST_CONCAT_TOKEN_(gtest_label_, __LINE__): \ - fail(::testing::internal::DeathTest::LastMessage()) -// The symbol "fail" here expands to something into which a message -// can be streamed. - -// This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in -// NDEBUG mode. In this case we need the statements to be executed, the regex is -// ignored, and the macro must accept a streamed message even though the message -// is never printed. -# define GTEST_EXECUTE_STATEMENT_(statement, regex) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - } else \ - ::testing::Message() - -// A class representing the parsed contents of the -// --gtest_internal_run_death_test flag, as it existed when -// RUN_ALL_TESTS was called. -class InternalRunDeathTestFlag { - public: - InternalRunDeathTestFlag(const std::string& a_file, - int a_line, - int an_index, - int a_write_fd) - : file_(a_file), line_(a_line), index_(an_index), - write_fd_(a_write_fd) {} - - ~InternalRunDeathTestFlag() { - if (write_fd_ >= 0) - posix::Close(write_fd_); - } - - const std::string& file() const { return file_; } - int line() const { return line_; } - int index() const { return index_; } - int write_fd() const { return write_fd_; } - - private: - std::string file_; - int line_; - int index_; - int write_fd_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(InternalRunDeathTestFlag); -}; - -// Returns a newly created InternalRunDeathTestFlag object with fields -// initialized from the GTEST_FLAG(internal_run_death_test) flag if -// the flag is specified; otherwise returns NULL. -InternalRunDeathTestFlag* ParseInternalRunDeathTestFlag(); - -#else // GTEST_HAS_DEATH_TEST - -// This macro is used for implementing macros such as -// EXPECT_DEATH_IF_SUPPORTED and ASSERT_DEATH_IF_SUPPORTED on systems where -// death tests are not supported. Those macros must compile on such systems -// iff EXPECT_DEATH and ASSERT_DEATH compile with the same parameters on -// systems that support death tests. This allows one to write such a macro -// on a system that does not support death tests and be sure that it will -// compile on a death-test supporting system. -// -// Parameters: -// statement - A statement that a macro such as EXPECT_DEATH would test -// for program termination. This macro has to make sure this -// statement is compiled but not executed, to ensure that -// EXPECT_DEATH_IF_SUPPORTED compiles with a certain -// parameter iff EXPECT_DEATH compiles with it. -// regex - A regex that a macro such as EXPECT_DEATH would use to test -// the output of statement. This parameter has to be -// compiled but not evaluated by this macro, to ensure that -// this macro only accepts expressions that a macro such as -// EXPECT_DEATH would accept. -// terminator - Must be an empty statement for EXPECT_DEATH_IF_SUPPORTED -// and a return statement for ASSERT_DEATH_IF_SUPPORTED. -// This ensures that ASSERT_DEATH_IF_SUPPORTED will not -// compile inside functions where ASSERT_DEATH doesn't -// compile. -// -// The branch that has an always false condition is used to ensure that -// statement and regex are compiled (and thus syntactically correct) but -// never executed. The unreachable code macro protects the terminator -// statement from generating an 'unreachable code' warning in case -// statement unconditionally returns or throws. The Message constructor at -// the end allows the syntax of streaming additional messages into the -// macro, for compilational compatibility with EXPECT_DEATH/ASSERT_DEATH. -# define GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, terminator) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (::testing::internal::AlwaysTrue()) { \ - GTEST_LOG_(WARNING) \ - << "Death tests are not supported on this platform.\n" \ - << "Statement '" #statement "' cannot be verified."; \ - } else if (::testing::internal::AlwaysFalse()) { \ - ::testing::internal::RE::PartialMatch(".*", (regex)); \ - GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ - terminator; \ - } else \ - ::testing::Message() - -#endif // GTEST_HAS_DEATH_TEST - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_DEATH_TEST_INTERNAL_H_ - -namespace testing { - -// This flag controls the style of death tests. Valid values are "threadsafe", -// meaning that the death test child process will re-execute the test binary -// from the start, running only a single death test, or "fast", -// meaning that the child process will execute the test logic immediately -// after forking. -GTEST_DECLARE_string_(death_test_style); - -#if GTEST_HAS_DEATH_TEST - -namespace internal { - -// Returns a Boolean value indicating whether the caller is currently -// executing in the context of the death test child process. Tools such as -// Valgrind heap checkers may need this to modify their behavior in death -// tests. IMPORTANT: This is an internal utility. Using it may break the -// implementation of death tests. User code MUST NOT use it. -GTEST_API_ bool InDeathTestChild(); - -} // namespace internal - -// The following macros are useful for writing death tests. - -// Here's what happens when an ASSERT_DEATH* or EXPECT_DEATH* is -// executed: -// -// 1. It generates a warning if there is more than one active -// thread. This is because it's safe to fork() or clone() only -// when there is a single thread. -// -// 2. The parent process clone()s a sub-process and runs the death -// test in it; the sub-process exits with code 0 at the end of the -// death test, if it hasn't exited already. -// -// 3. The parent process waits for the sub-process to terminate. -// -// 4. The parent process checks the exit code and error message of -// the sub-process. -// -// Examples: -// -// ASSERT_DEATH(server.SendMessage(56, "Hello"), "Invalid port number"); -// for (int i = 0; i < 5; i++) { -// EXPECT_DEATH(server.ProcessRequest(i), -// "Invalid request .* in ProcessRequest()") -// << "Failed to die on request " << i; -// } -// -// ASSERT_EXIT(server.ExitNow(), ::testing::ExitedWithCode(0), "Exiting"); -// -// bool KilledBySIGHUP(int exit_code) { -// return WIFSIGNALED(exit_code) && WTERMSIG(exit_code) == SIGHUP; -// } -// -// ASSERT_EXIT(client.HangUpServer(), KilledBySIGHUP, "Hanging up!"); -// -// On the regular expressions used in death tests: -// -// On POSIX-compliant systems (*nix), we use the library, -// which uses the POSIX extended regex syntax. -// -// On other platforms (e.g. Windows), we only support a simple regex -// syntax implemented as part of Google Test. This limited -// implementation should be enough most of the time when writing -// death tests; though it lacks many features you can find in PCRE -// or POSIX extended regex syntax. For example, we don't support -// union ("x|y"), grouping ("(xy)"), brackets ("[xy]"), and -// repetition count ("x{5,7}"), among others. -// -// Below is the syntax that we do support. We chose it to be a -// subset of both PCRE and POSIX extended regex, so it's easy to -// learn wherever you come from. In the following: 'A' denotes a -// literal character, period (.), or a single \\ escape sequence; -// 'x' and 'y' denote regular expressions; 'm' and 'n' are for -// natural numbers. -// -// c matches any literal character c -// \\d matches any decimal digit -// \\D matches any character that's not a decimal digit -// \\f matches \f -// \\n matches \n -// \\r matches \r -// \\s matches any ASCII whitespace, including \n -// \\S matches any character that's not a whitespace -// \\t matches \t -// \\v matches \v -// \\w matches any letter, _, or decimal digit -// \\W matches any character that \\w doesn't match -// \\c matches any literal character c, which must be a punctuation -// . matches any single character except \n -// A? matches 0 or 1 occurrences of A -// A* matches 0 or many occurrences of A -// A+ matches 1 or many occurrences of A -// ^ matches the beginning of a string (not that of each line) -// $ matches the end of a string (not that of each line) -// xy matches x followed by y -// -// If you accidentally use PCRE or POSIX extended regex features -// not implemented by us, you will get a run-time failure. In that -// case, please try to rewrite your regular expression within the -// above syntax. -// -// This implementation is *not* meant to be as highly tuned or robust -// as a compiled regex library, but should perform well enough for a -// death test, which already incurs significant overhead by launching -// a child process. -// -// Known caveats: -// -// A "threadsafe" style death test obtains the path to the test -// program from argv[0] and re-executes it in the sub-process. For -// simplicity, the current implementation doesn't search the PATH -// when launching the sub-process. This means that the user must -// invoke the test program via a path that contains at least one -// path separator (e.g. path/to/foo_test and -// /absolute/path/to/bar_test are fine, but foo_test is not). This -// is rarely a problem as people usually don't put the test binary -// directory in PATH. -// -// TODO(wan@google.com): make thread-safe death tests search the PATH. - -// Asserts that a given statement causes the program to exit, with an -// integer exit status that satisfies predicate, and emitting error output -// that matches regex. -# define ASSERT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_FATAL_FAILURE_) - -// Like ASSERT_EXIT, but continues on to successive tests in the -// test case, if any: -# define EXPECT_EXIT(statement, predicate, regex) \ - GTEST_DEATH_TEST_(statement, predicate, regex, GTEST_NONFATAL_FAILURE_) - -// Asserts that a given statement causes the program to exit, either by -// explicitly exiting with a nonzero exit code or being killed by a -// signal, and emitting error output that matches regex. -# define ASSERT_DEATH(statement, regex) \ - ASSERT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Like ASSERT_DEATH, but continues on to successive tests in the -// test case, if any: -# define EXPECT_DEATH(statement, regex) \ - EXPECT_EXIT(statement, ::testing::internal::ExitedUnsuccessfully, regex) - -// Two predicate classes that can be used in {ASSERT,EXPECT}_EXIT*: - -// Tests that an exit code describes a normal exit with a given exit code. -class GTEST_API_ ExitedWithCode { - public: - explicit ExitedWithCode(int exit_code); - bool operator()(int exit_status) const; - private: - // No implementation - assignment is unsupported. - void operator=(const ExitedWithCode& other); - - const int exit_code_; -}; - -# if !GTEST_OS_WINDOWS -// Tests that an exit code describes an exit due to termination by a -// given signal. -class GTEST_API_ KilledBySignal { - public: - explicit KilledBySignal(int signum); - bool operator()(int exit_status) const; - private: - const int signum_; -}; -# endif // !GTEST_OS_WINDOWS - -// EXPECT_DEBUG_DEATH asserts that the given statements die in debug mode. -// The death testing framework causes this to have interesting semantics, -// since the sideeffects of the call are only visible in opt mode, and not -// in debug mode. -// -// In practice, this can be used to test functions that utilize the -// LOG(DFATAL) macro using the following style: -// -// int DieInDebugOr12(int* sideeffect) { -// if (sideeffect) { -// *sideeffect = 12; -// } -// LOG(DFATAL) << "death"; -// return 12; -// } -// -// TEST(TestCase, TestDieOr12WorksInDgbAndOpt) { -// int sideeffect = 0; -// // Only asserts in dbg. -// EXPECT_DEBUG_DEATH(DieInDebugOr12(&sideeffect), "death"); -// -// #ifdef NDEBUG -// // opt-mode has sideeffect visible. -// EXPECT_EQ(12, sideeffect); -// #else -// // dbg-mode no visible sideeffect. -// EXPECT_EQ(0, sideeffect); -// #endif -// } -// -// This will assert that DieInDebugReturn12InOpt() crashes in debug -// mode, usually due to a DCHECK or LOG(DFATAL), but returns the -// appropriate fallback value (12 in this case) in opt mode. If you -// need to test that a function has appropriate side-effects in opt -// mode, include assertions against the side-effects. A general -// pattern for this is: -// -// EXPECT_DEBUG_DEATH({ -// // Side-effects here will have an effect after this statement in -// // opt mode, but none in debug mode. -// EXPECT_EQ(12, DieInDebugOr12(&sideeffect)); -// }, "death"); -// -# ifdef NDEBUG - -# define EXPECT_DEBUG_DEATH(statement, regex) \ - GTEST_EXECUTE_STATEMENT_(statement, regex) - -# define ASSERT_DEBUG_DEATH(statement, regex) \ - GTEST_EXECUTE_STATEMENT_(statement, regex) - -# else - -# define EXPECT_DEBUG_DEATH(statement, regex) \ - EXPECT_DEATH(statement, regex) - -# define ASSERT_DEBUG_DEATH(statement, regex) \ - ASSERT_DEATH(statement, regex) - -# endif // NDEBUG for EXPECT_DEBUG_DEATH -#endif // GTEST_HAS_DEATH_TEST - -// EXPECT_DEATH_IF_SUPPORTED(statement, regex) and -// ASSERT_DEATH_IF_SUPPORTED(statement, regex) expand to real death tests if -// death tests are supported; otherwise they just issue a warning. This is -// useful when you are combining death test assertions with normal test -// assertions in one test. -#if GTEST_HAS_DEATH_TEST -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - EXPECT_DEATH(statement, regex) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - ASSERT_DEATH(statement, regex) -#else -# define EXPECT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, ) -# define ASSERT_DEATH_IF_SUPPORTED(statement, regex) \ - GTEST_UNSUPPORTED_DEATH_TEST_(statement, regex, return) -#endif - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_DEATH_TEST_H_ -// This file was GENERATED by command: -// pump.py gtest-param-test.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: vladl@google.com (Vlad Losev) -// -// Macros and functions for implementing parameterized tests -// in Google C++ Testing Framework (Google Test) -// -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -#ifndef GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ - - -// Value-parameterized tests allow you to test your code with different -// parameters without writing multiple copies of the same test. -// -// Here is how you use value-parameterized tests: - -#if 0 - -// To write value-parameterized tests, first you should define a fixture -// class. It is usually derived from testing::TestWithParam (see below for -// another inheritance scheme that's sometimes useful in more complicated -// class hierarchies), where the type of your parameter values. -// TestWithParam is itself derived from testing::Test. T can be any -// copyable type. If it's a raw pointer, you are responsible for managing the -// lifespan of the pointed values. - -class FooTest : public ::testing::TestWithParam { - // You can implement all the usual class fixture members here. -}; - -// Then, use the TEST_P macro to define as many parameterized tests -// for this fixture as you want. The _P suffix is for "parameterized" -// or "pattern", whichever you prefer to think. - -TEST_P(FooTest, DoesBlah) { - // Inside a test, access the test parameter with the GetParam() method - // of the TestWithParam class: - EXPECT_TRUE(foo.Blah(GetParam())); - ... -} - -TEST_P(FooTest, HasBlahBlah) { - ... -} - -// Finally, you can use INSTANTIATE_TEST_CASE_P to instantiate the test -// case with any set of parameters you want. Google Test defines a number -// of functions for generating test parameters. They return what we call -// (surprise!) parameter generators. Here is a summary of them, which -// are all in the testing namespace: -// -// -// Range(begin, end [, step]) - Yields values {begin, begin+step, -// begin+step+step, ...}. The values do not -// include end. step defaults to 1. -// Values(v1, v2, ..., vN) - Yields values {v1, v2, ..., vN}. -// ValuesIn(container) - Yields values from a C-style array, an STL -// ValuesIn(begin,end) container, or an iterator range [begin, end). -// Bool() - Yields sequence {false, true}. -// Combine(g1, g2, ..., gN) - Yields all combinations (the Cartesian product -// for the math savvy) of the values generated -// by the N generators. -// -// For more details, see comments at the definitions of these functions below -// in this file. -// -// The following statement will instantiate tests from the FooTest test case -// each with parameter values "meeny", "miny", and "moe". - -INSTANTIATE_TEST_CASE_P(InstantiationName, - FooTest, - Values("meeny", "miny", "moe")); - -// To distinguish different instances of the pattern, (yes, you -// can instantiate it more then once) the first argument to the -// INSTANTIATE_TEST_CASE_P macro is a prefix that will be added to the -// actual test case name. Remember to pick unique prefixes for different -// instantiations. The tests from the instantiation above will have -// these names: -// -// * InstantiationName/FooTest.DoesBlah/0 for "meeny" -// * InstantiationName/FooTest.DoesBlah/1 for "miny" -// * InstantiationName/FooTest.DoesBlah/2 for "moe" -// * InstantiationName/FooTest.HasBlahBlah/0 for "meeny" -// * InstantiationName/FooTest.HasBlahBlah/1 for "miny" -// * InstantiationName/FooTest.HasBlahBlah/2 for "moe" -// -// You can use these names in --gtest_filter. -// -// This statement will instantiate all tests from FooTest again, each -// with parameter values "cat" and "dog": - -const char* pets[] = {"cat", "dog"}; -INSTANTIATE_TEST_CASE_P(AnotherInstantiationName, FooTest, ValuesIn(pets)); - -// The tests from the instantiation above will have these names: -// -// * AnotherInstantiationName/FooTest.DoesBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.DoesBlah/1 for "dog" -// * AnotherInstantiationName/FooTest.HasBlahBlah/0 for "cat" -// * AnotherInstantiationName/FooTest.HasBlahBlah/1 for "dog" -// -// Please note that INSTANTIATE_TEST_CASE_P will instantiate all tests -// in the given test case, whether their definitions come before or -// AFTER the INSTANTIATE_TEST_CASE_P statement. -// -// Please also note that generator expressions (including parameters to the -// generators) are evaluated in InitGoogleTest(), after main() has started. -// This allows the user on one hand, to adjust generator parameters in order -// to dynamically determine a set of tests to run and on the other hand, -// give the user a chance to inspect the generated tests with Google Test -// reflection API before RUN_ALL_TESTS() is executed. -// -// You can see samples/sample7_unittest.cc and samples/sample8_unittest.cc -// for more examples. -// -// In the future, we plan to publish the API for defining new parameter -// generators. But for now this interface remains part of the internal -// implementation and is subject to change. -// -// -// A parameterized test fixture must be derived from testing::Test and from -// testing::WithParamInterface, where T is the type of the parameter -// values. Inheriting from TestWithParam satisfies that requirement because -// TestWithParam inherits from both Test and WithParamInterface. In more -// complicated hierarchies, however, it is occasionally useful to inherit -// separately from Test and WithParamInterface. For example: - -class BaseTest : public ::testing::Test { - // You can inherit all the usual members for a non-parameterized test - // fixture here. -}; - -class DerivedTest : public BaseTest, public ::testing::WithParamInterface { - // The usual test fixture members go here too. -}; - -TEST_F(BaseTest, HasFoo) { - // This is an ordinary non-parameterized test. -} - -TEST_P(DerivedTest, DoesBlah) { - // GetParam works just the same here as if you inherit from TestWithParam. - EXPECT_TRUE(foo.Blah(GetParam())); -} - -#endif // 0 - - -#if !GTEST_OS_SYMBIAN -# include -#endif - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: vladl@google.com (Vlad Losev) - -// Type and function utilities for implementing parameterized tests. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ - -#include -#include -#include - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. -// Copyright 2003 Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Authors: Dan Egnor (egnor@google.com) -// -// A "smart" pointer type with reference tracking. Every pointer to a -// particular object is kept on a circular linked list. When the last pointer -// to an object is destroyed or reassigned, the object is deleted. -// -// Used properly, this deletes the object when the last reference goes away. -// There are several caveats: -// - Like all reference counting schemes, cycles lead to leaks. -// - Each smart pointer is actually two pointers (8 bytes instead of 4). -// - Every time a pointer is assigned, the entire list of pointers to that -// object is traversed. This class is therefore NOT SUITABLE when there -// will often be more than two or three pointers to a particular object. -// - References are only tracked as long as linked_ptr<> objects are copied. -// If a linked_ptr<> is converted to a raw pointer and back, BAD THINGS -// will happen (double deletion). -// -// A good use of this class is storing object references in STL containers. -// You can safely put linked_ptr<> in a vector<>. -// Other uses may not be as good. -// -// Note: If you use an incomplete type with linked_ptr<>, the class -// *containing* linked_ptr<> must have a constructor and destructor (even -// if they do nothing!). -// -// Bill Gibbons suggested we use something like this. -// -// Thread Safety: -// Unlike other linked_ptr implementations, in this implementation -// a linked_ptr object is thread-safe in the sense that: -// - it's safe to copy linked_ptr objects concurrently, -// - it's safe to copy *from* a linked_ptr and read its underlying -// raw pointer (e.g. via get()) concurrently, and -// - it's safe to write to two linked_ptrs that point to the same -// shared object concurrently. -// TODO(wan@google.com): rename this to safe_linked_ptr to avoid -// confusion with normal linked_ptr. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ - -#include -#include - - -namespace testing { -namespace internal { - -// Protects copying of all linked_ptr objects. -GTEST_API_ GTEST_DECLARE_STATIC_MUTEX_(g_linked_ptr_mutex); - -// This is used internally by all instances of linked_ptr<>. It needs to be -// a non-template class because different types of linked_ptr<> can refer to -// the same object (linked_ptr(obj) vs linked_ptr(obj)). -// So, it needs to be possible for different types of linked_ptr to participate -// in the same circular linked list, so we need a single class type here. -// -// DO NOT USE THIS CLASS DIRECTLY YOURSELF. Use linked_ptr. -class linked_ptr_internal { - public: - // Create a new circle that includes only this instance. - void join_new() { - next_ = this; - } - - // Many linked_ptr operations may change p.link_ for some linked_ptr - // variable p in the same circle as this object. Therefore we need - // to prevent two such operations from occurring concurrently. - // - // Note that different types of linked_ptr objects can coexist in a - // circle (e.g. linked_ptr, linked_ptr, and - // linked_ptr). Therefore we must use a single mutex to - // protect all linked_ptr objects. This can create serious - // contention in production code, but is acceptable in a testing - // framework. - - // Join an existing circle. - void join(linked_ptr_internal const* ptr) - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - linked_ptr_internal const* p = ptr; - while (p->next_ != ptr) p = p->next_; - p->next_ = this; - next_ = ptr; - } - - // Leave whatever circle we're part of. Returns true if we were the - // last member of the circle. Once this is done, you can join() another. - bool depart() - GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { - MutexLock lock(&g_linked_ptr_mutex); - - if (next_ == this) return true; - linked_ptr_internal const* p = next_; - while (p->next_ != this) p = p->next_; - p->next_ = next_; - return false; - } - - private: - mutable linked_ptr_internal const* next_; -}; - -template -class linked_ptr { - public: - typedef T element_type; - - // Take over ownership of a raw pointer. This should happen as soon as - // possible after the object is created. - explicit linked_ptr(T* ptr = NULL) { capture(ptr); } - ~linked_ptr() { depart(); } - - // Copy an existing linked_ptr<>, adding ourselves to the list of references. - template linked_ptr(linked_ptr const& ptr) { copy(&ptr); } - linked_ptr(linked_ptr const& ptr) { // NOLINT - assert(&ptr != this); - copy(&ptr); - } - - // Assignment releases the old value and acquires the new. - template linked_ptr& operator=(linked_ptr const& ptr) { - depart(); - copy(&ptr); - return *this; - } - - linked_ptr& operator=(linked_ptr const& ptr) { - if (&ptr != this) { - depart(); - copy(&ptr); - } - return *this; - } - - // Smart pointer members. - void reset(T* ptr = NULL) { - depart(); - capture(ptr); - } - T* get() const { return value_; } - T* operator->() const { return value_; } - T& operator*() const { return *value_; } - - bool operator==(T* p) const { return value_ == p; } - bool operator!=(T* p) const { return value_ != p; } - template - bool operator==(linked_ptr const& ptr) const { - return value_ == ptr.get(); - } - template - bool operator!=(linked_ptr const& ptr) const { - return value_ != ptr.get(); - } - - private: - template - friend class linked_ptr; - - T* value_; - linked_ptr_internal link_; - - void depart() { - if (link_.depart()) delete value_; - } - - void capture(T* ptr) { - value_ = ptr; - link_.join_new(); - } - - template void copy(linked_ptr const* ptr) { - value_ = ptr->get(); - if (value_) - link_.join(&ptr->link_); - else - link_.join_new(); - } -}; - -template inline -bool operator==(T* ptr, const linked_ptr& x) { - return ptr == x.get(); -} - -template inline -bool operator!=(T* ptr, const linked_ptr& x) { - return ptr != x.get(); -} - -// A function to convert T* into linked_ptr -// Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation -// for linked_ptr >(new FooBarBaz(arg)) -template -linked_ptr make_linked_ptr(T* ptr) { - return linked_ptr(ptr); -} - -} // namespace internal -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ -// Copyright 2007, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - -// Google Test - The Google C++ Testing Framework -// -// This file implements a universal value printer that can print a -// value of any type T: -// -// void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); -// -// A user can teach this function how to print a class type T by -// defining either operator<<() or PrintTo() in the namespace that -// defines T. More specifically, the FIRST defined function in the -// following list will be used (assuming T is defined in namespace -// foo): -// -// 1. foo::PrintTo(const T&, ostream*) -// 2. operator<<(ostream&, const T&) defined in either foo or the -// global namespace. -// -// If none of the above is defined, it will print the debug string of -// the value if it is a protocol buffer, or print the raw bytes in the -// value otherwise. -// -// To aid debugging: when T is a reference type, the address of the -// value is also printed; when T is a (const) char pointer, both the -// pointer value and the NUL-terminated string it points to are -// printed. -// -// We also provide some convenient wrappers: -// -// // Prints a value to a string. For a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// std::string ::testing::PrintToString(const T& value); -// -// // Prints a value tersely: for a reference type, the referenced -// // value (but not the address) is printed; for a (const or not) char -// // pointer, the NUL-terminated string (but not the pointer) is -// // printed. -// void ::testing::internal::UniversalTersePrint(const T& value, ostream*); -// -// // Prints value using the type inferred by the compiler. The difference -// // from UniversalTersePrint() is that this function prints both the -// // pointer and the NUL-terminated string for a (const or not) char pointer. -// void ::testing::internal::UniversalPrint(const T& value, ostream*); -// -// // Prints the fields of a tuple tersely to a string vector, one -// // element for each field. Tuple support must be enabled in -// // gtest-port.h. -// std::vector UniversalTersePrintTupleFieldsToStrings( -// const Tuple& value); -// -// Known limitation: -// -// The print primitives print the elements of an STL-style container -// using the compiler-inferred type of *iter where iter is a -// const_iterator of the container. When const_iterator is an input -// iterator but not a forward iterator, this inferred type may not -// match value_type, and the print output may be incorrect. In -// practice, this is rarely a problem as for most containers -// const_iterator is a forward iterator. We'll fix this if there's an -// actual need for it. Note that this fix cannot rely on value_type -// being defined as many user-defined container types don't have -// value_type. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ - -#include // NOLINT -#include -#include -#include -#include - -namespace testing { - -// Definitions in the 'internal' and 'internal2' name spaces are -// subject to change without notice. DO NOT USE THEM IN USER CODE! -namespace internal2 { - -// Prints the given number of bytes in the given object to the given -// ostream. -GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, - size_t count, - ::std::ostream* os); - -// For selecting which printer to use when a given type has neither << -// nor PrintTo(). -enum TypeKind { - kProtobuf, // a protobuf type - kConvertibleToInteger, // a type implicitly convertible to BiggestInt - // (e.g. a named or unnamed enum type) - kOtherType // anything else -}; - -// TypeWithoutFormatter::PrintValue(value, os) is called -// by the universal printer to print a value of type T when neither -// operator<< nor PrintTo() is defined for T, where kTypeKind is the -// "kind" of T as defined by enum TypeKind. -template -class TypeWithoutFormatter { - public: - // This default version is called when kTypeKind is kOtherType. - static void PrintValue(const T& value, ::std::ostream* os) { - PrintBytesInObjectTo(reinterpret_cast(&value), - sizeof(value), os); - } -}; - -// We print a protobuf using its ShortDebugString() when the string -// doesn't exceed this many characters; otherwise we print it using -// DebugString() for better readability. -const size_t kProtobufOneLinerMaxLength = 50; - -template -class TypeWithoutFormatter { - public: - static void PrintValue(const T& value, ::std::ostream* os) { - const ::testing::internal::string short_str = value.ShortDebugString(); - const ::testing::internal::string pretty_str = - short_str.length() <= kProtobufOneLinerMaxLength ? - short_str : ("\n" + value.DebugString()); - *os << ("<" + pretty_str + ">"); - } -}; - -template -class TypeWithoutFormatter { - public: - // Since T has no << operator or PrintTo() but can be implicitly - // converted to BiggestInt, we print it as a BiggestInt. - // - // Most likely T is an enum type (either named or unnamed), in which - // case printing it as an integer is the desired behavior. In case - // T is not an enum, printing it as an integer is the best we can do - // given that it has no user-defined printer. - static void PrintValue(const T& value, ::std::ostream* os) { - const internal::BiggestInt kBigInt = value; - *os << kBigInt; - } -}; - -// Prints the given value to the given ostream. If the value is a -// protocol message, its debug string is printed; if it's an enum or -// of a type implicitly convertible to BiggestInt, it's printed as an -// integer; otherwise the bytes in the value are printed. This is -// what UniversalPrinter::Print() does when it knows nothing about -// type T and T has neither << operator nor PrintTo(). -// -// A user can override this behavior for a class type Foo by defining -// a << operator in the namespace where Foo is defined. -// -// We put this operator in namespace 'internal2' instead of 'internal' -// to simplify the implementation, as much code in 'internal' needs to -// use << in STL, which would conflict with our own << were it defined -// in 'internal'. -// -// Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If -// we define it to take an std::ostream instead, we'll get an -// "ambiguous overloads" compiler error when trying to print a type -// Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether -// operator<<(std::ostream&, const T&) or -// operator<<(std::basic_stream, const Foo&) is more -// specific. -template -::std::basic_ostream& operator<<( - ::std::basic_ostream& os, const T& x) { - TypeWithoutFormatter::value ? kProtobuf : - internal::ImplicitlyConvertible::value ? - kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); - return os; -} - -} // namespace internal2 -} // namespace testing - -// This namespace MUST NOT BE NESTED IN ::testing, or the name look-up -// magic needed for implementing UniversalPrinter won't work. -namespace testing_internal { - -// Used to print a value that is not an STL-style container when the -// user doesn't define PrintTo() for it. -template -void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { - // With the following statement, during unqualified name lookup, - // testing::internal2::operator<< appears as if it was declared in - // the nearest enclosing namespace that contains both - // ::testing_internal and ::testing::internal2, i.e. the global - // namespace. For more details, refer to the C++ Standard section - // 7.3.4-1 [namespace.udir]. This allows us to fall back onto - // testing::internal2::operator<< in case T doesn't come with a << - // operator. - // - // We cannot write 'using ::testing::internal2::operator<<;', which - // gcc 3.3 fails to compile due to a compiler bug. - using namespace ::testing::internal2; // NOLINT - - // Assuming T is defined in namespace foo, in the next statement, - // the compiler will consider all of: - // - // 1. foo::operator<< (thanks to Koenig look-up), - // 2. ::operator<< (as the current namespace is enclosed in ::), - // 3. testing::internal2::operator<< (thanks to the using statement above). - // - // The operator<< whose type matches T best will be picked. - // - // We deliberately allow #2 to be a candidate, as sometimes it's - // impossible to define #1 (e.g. when foo is ::std, defining - // anything in it is undefined behavior unless you are a compiler - // vendor.). - *os << value; -} - -} // namespace testing_internal - -namespace testing { -namespace internal { - -// UniversalPrinter::Print(value, ostream_ptr) prints the given -// value to the given ostream. The caller must ensure that -// 'ostream_ptr' is not NULL, or the behavior is undefined. -// -// We define UniversalPrinter as a class template (as opposed to a -// function template), as we need to partially specialize it for -// reference types, which cannot be done with function templates. -template -class UniversalPrinter; - -template -void UniversalPrint(const T& value, ::std::ostream* os); - -// Used to print an STL-style container when the user doesn't define -// a PrintTo() for it. -template -void DefaultPrintTo(IsContainer /* dummy */, - false_type /* is not a pointer */, - const C& container, ::std::ostream* os) { - const size_t kMaxCount = 32; // The maximum number of elements to print. - *os << '{'; - size_t count = 0; - for (typename C::const_iterator it = container.begin(); - it != container.end(); ++it, ++count) { - if (count > 0) { - *os << ','; - if (count == kMaxCount) { // Enough has been printed. - *os << " ..."; - break; - } - } - *os << ' '; - // We cannot call PrintTo(*it, os) here as PrintTo() doesn't - // handle *it being a native array. - internal::UniversalPrint(*it, os); - } - - if (count > 0) { - *os << ' '; - } - *os << '}'; -} - -// Used to print a pointer that is neither a char pointer nor a member -// pointer, when the user doesn't define PrintTo() for it. (A member -// variable pointer or member function pointer doesn't really point to -// a location in the address space. Their representation is -// implementation-defined. Therefore they will be printed as raw -// bytes.) -template -void DefaultPrintTo(IsNotContainer /* dummy */, - true_type /* is a pointer */, - T* p, ::std::ostream* os) { - if (p == NULL) { - *os << "NULL"; - } else { - // C++ doesn't allow casting from a function pointer to any object - // pointer. - // - // IsTrue() silences warnings: "Condition is always true", - // "unreachable code". - if (IsTrue(ImplicitlyConvertible::value)) { - // T is not a function type. We just call << to print p, - // relying on ADL to pick up user-defined << for their pointer - // types, if any. - *os << p; - } else { - // T is a function type, so '*os << p' doesn't do what we want - // (it just prints p as bool). We want to print p as a const - // void*. However, we cannot cast it to const void* directly, - // even using reinterpret_cast, as earlier versions of gcc - // (e.g. 3.4.5) cannot compile the cast when p is a function - // pointer. Casting to UInt64 first solves the problem. - *os << reinterpret_cast( - reinterpret_cast(p)); - } - } -} - -// Used to print a non-container, non-pointer value when the user -// doesn't define PrintTo() for it. -template -void DefaultPrintTo(IsNotContainer /* dummy */, - false_type /* is not a pointer */, - const T& value, ::std::ostream* os) { - ::testing_internal::DefaultPrintNonContainerTo(value, os); -} - -// Prints the given value using the << operator if it has one; -// otherwise prints the bytes in it. This is what -// UniversalPrinter::Print() does when PrintTo() is not specialized -// or overloaded for type T. -// -// A user can override this behavior for a class type Foo by defining -// an overload of PrintTo() in the namespace where Foo is defined. We -// give the user this option as sometimes defining a << operator for -// Foo is not desirable (e.g. the coding style may prevent doing it, -// or there is already a << operator but it doesn't do what the user -// wants). -template -void PrintTo(const T& value, ::std::ostream* os) { - // DefaultPrintTo() is overloaded. The type of its first two - // arguments determine which version will be picked. If T is an - // STL-style container, the version for container will be called; if - // T is a pointer, the pointer version will be called; otherwise the - // generic version will be called. - // - // Note that we check for container types here, prior to we check - // for protocol message types in our operator<<. The rationale is: - // - // For protocol messages, we want to give people a chance to - // override Google Mock's format by defining a PrintTo() or - // operator<<. For STL containers, other formats can be - // incompatible with Google Mock's format for the container - // elements; therefore we check for container types here to ensure - // that our format is used. - // - // The second argument of DefaultPrintTo() is needed to bypass a bug - // in Symbian's C++ compiler that prevents it from picking the right - // overload between: - // - // PrintTo(const T& x, ...); - // PrintTo(T* x, ...); - DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); -} - -// The following list of PrintTo() overloads tells -// UniversalPrinter::Print() how to print standard types (built-in -// types, strings, plain arrays, and pointers). - -// Overloads for various char types. -GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); -GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); -inline void PrintTo(char c, ::std::ostream* os) { - // When printing a plain char, we always treat it as unsigned. This - // way, the output won't be affected by whether the compiler thinks - // char is signed or not. - PrintTo(static_cast(c), os); -} - -// Overloads for other simple built-in types. -inline void PrintTo(bool x, ::std::ostream* os) { - *os << (x ? "true" : "false"); -} - -// Overload for wchar_t type. -// Prints a wchar_t as a symbol if it is printable or as its internal -// code otherwise and also as its decimal code (except for L'\0'). -// The L'\0' char is printed as "L'\\0'". The decimal code is printed -// as signed integer when wchar_t is implemented by the compiler -// as a signed type and is printed as an unsigned integer when wchar_t -// is implemented as an unsigned type. -GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); - -// Overloads for C strings. -GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); -inline void PrintTo(char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} - -// signed/unsigned char is often used for representing binary data, so -// we print pointers to it as void* to be safe. -inline void PrintTo(const signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(signed char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(const unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -inline void PrintTo(unsigned char* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} - -// MSVC can be configured to define wchar_t as a typedef of unsigned -// short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native -// type. When wchar_t is a typedef, defining an overload for const -// wchar_t* would cause unsigned short* be printed as a wide string, -// possibly causing invalid memory accesses. -#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) -// Overloads for wide C strings -GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); -inline void PrintTo(wchar_t* s, ::std::ostream* os) { - PrintTo(ImplicitCast_(s), os); -} -#endif - -// Overload for C arrays. Multi-dimensional arrays are printed -// properly. - -// Prints the given number of elements in an array, without printing -// the curly braces. -template -void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { - UniversalPrint(a[0], os); - for (size_t i = 1; i != count; i++) { - *os << ", "; - UniversalPrint(a[i], os); - } -} - -// Overloads for ::string and ::std::string. -#if GTEST_HAS_GLOBAL_STRING -GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); -inline void PrintTo(const ::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_STRING - -GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); -inline void PrintTo(const ::std::string& s, ::std::ostream* os) { - PrintStringTo(s, os); -} - -// Overloads for ::wstring and ::std::wstring. -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_GLOBAL_WSTRING - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); -inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { - PrintWideStringTo(s, os); -} -#endif // GTEST_HAS_STD_WSTRING - -#if GTEST_HAS_TR1_TUPLE -// Overload for ::std::tr1::tuple. Needed for printing function arguments, -// which are packed as tuples. - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os); - -// Overloaded PrintTo() for tuples of various arities. We support -// tuples of up-to 10 fields. The following implementation works -// regardless of whether tr1::tuple is implemented using the -// non-standard variadic template feature or not. - -inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo(const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} - -template -void PrintTo( - const ::std::tr1::tuple& t, - ::std::ostream* os) { - PrintTupleTo(t, os); -} -#endif // GTEST_HAS_TR1_TUPLE - -// Overload for std::pair. -template -void PrintTo(const ::std::pair& value, ::std::ostream* os) { - *os << '('; - // We cannot use UniversalPrint(value.first, os) here, as T1 may be - // a reference type. The same for printing value.second. - UniversalPrinter::Print(value.first, os); - *os << ", "; - UniversalPrinter::Print(value.second, os); - *os << ')'; -} - -// Implements printing a non-reference type T by letting the compiler -// pick the right overload of PrintTo() for T. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER - - // Note: we deliberately don't call this PrintTo(), as that name - // conflicts with ::testing::internal::PrintTo in the body of the - // function. - static void Print(const T& value, ::std::ostream* os) { - // By default, ::testing::internal::PrintTo() is used for printing - // the value. - // - // Thanks to Koenig look-up, if T is a class and has its own - // PrintTo() function defined in its namespace, that function will - // be visible here. Since it is more specific than the generic ones - // in ::testing::internal, it will be picked by the compiler in the - // following statement - exactly what we want. - PrintTo(value, os); - } - -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER -}; - -// UniversalPrintArray(begin, len, os) prints an array of 'len' -// elements, starting at address 'begin'. -template -void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { - if (len == 0) { - *os << "{}"; - } else { - *os << "{ "; - const size_t kThreshold = 18; - const size_t kChunkSize = 8; - // If the array has more than kThreshold elements, we'll have to - // omit some details by printing only the first and the last - // kChunkSize elements. - // TODO(wan@google.com): let the user control the threshold using a flag. - if (len <= kThreshold) { - PrintRawArrayTo(begin, len, os); - } else { - PrintRawArrayTo(begin, kChunkSize, os); - *os << ", ..., "; - PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); - } - *os << " }"; - } -} -// This overload prints a (const) char array compactly. -GTEST_API_ void UniversalPrintArray( - const char* begin, size_t len, ::std::ostream* os); - -// This overload prints a (const) wchar_t array compactly. -GTEST_API_ void UniversalPrintArray( - const wchar_t* begin, size_t len, ::std::ostream* os); - -// Implements printing an array type T[N]. -template -class UniversalPrinter { - public: - // Prints the given array, omitting some elements when there are too - // many. - static void Print(const T (&a)[N], ::std::ostream* os) { - UniversalPrintArray(a, N, os); - } -}; - -// Implements printing a reference type T&. -template -class UniversalPrinter { - public: - // MSVC warns about adding const to a function type, so we want to - // disable the warning. -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4180) // Temporarily disables warning 4180. -#endif // _MSC_VER - - static void Print(const T& value, ::std::ostream* os) { - // Prints the address of the value. We use reinterpret_cast here - // as static_cast doesn't compile when T is a function type. - *os << "@" << reinterpret_cast(&value) << " "; - - // Then prints the value itself. - UniversalPrint(value, os); - } - -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif // _MSC_VER -}; - -// Prints a value tersely: for a reference type, the referenced value -// (but not the address) is printed; for a (const) char pointer, the -// NUL-terminated string (but not the pointer) is printed. - -template -class UniversalTersePrinter { - public: - static void Print(const T& value, ::std::ostream* os) { - UniversalPrint(value, os); - } -}; -template -class UniversalTersePrinter { - public: - static void Print(const T& value, ::std::ostream* os) { - UniversalPrint(value, os); - } -}; -template -class UniversalTersePrinter { - public: - static void Print(const T (&value)[N], ::std::ostream* os) { - UniversalPrinter::Print(value, os); - } -}; -template <> -class UniversalTersePrinter { - public: - static void Print(const char* str, ::std::ostream* os) { - if (str == NULL) { - *os << "NULL"; - } else { - UniversalPrint(string(str), os); - } - } -}; -template <> -class UniversalTersePrinter { - public: - static void Print(char* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); - } -}; - -#if GTEST_HAS_STD_WSTRING -template <> -class UniversalTersePrinter { - public: - static void Print(const wchar_t* str, ::std::ostream* os) { - if (str == NULL) { - *os << "NULL"; - } else { - UniversalPrint(::std::wstring(str), os); - } - } -}; -#endif - -template <> -class UniversalTersePrinter { - public: - static void Print(wchar_t* str, ::std::ostream* os) { - UniversalTersePrinter::Print(str, os); - } -}; - -template -void UniversalTersePrint(const T& value, ::std::ostream* os) { - UniversalTersePrinter::Print(value, os); -} - -// Prints a value using the type inferred by the compiler. The -// difference between this and UniversalTersePrint() is that for a -// (const) char pointer, this prints both the pointer and the -// NUL-terminated string. -template -void UniversalPrint(const T& value, ::std::ostream* os) { - // A workarond for the bug in VC++ 7.1 that prevents us from instantiating - // UniversalPrinter with T directly. - typedef T T1; - UniversalPrinter::Print(value, os); -} - -#if GTEST_HAS_TR1_TUPLE -typedef ::std::vector Strings; - -// This helper template allows PrintTo() for tuples and -// UniversalTersePrintTupleFieldsToStrings() to be defined by -// induction on the number of tuple fields. The idea is that -// TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N -// fields in tuple t, and can be defined in terms of -// TuplePrefixPrinter. - -// The inductive case. -template -struct TuplePrefixPrinter { - // Prints the first N fields of a tuple. - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - TuplePrefixPrinter::PrintPrefixTo(t, os); - *os << ", "; - UniversalPrinter::type> - ::Print(::std::tr1::get(t), os); - } - - // Tersely prints the first N fields of a tuple to a string vector, - // one element for each field. - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Base cases. -template <> -struct TuplePrefixPrinter<0> { - template - static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} - - template - static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} -}; -// We have to specialize the entire TuplePrefixPrinter<> class -// template here, even though the definition of -// TersePrintPrefixToStrings() is the same as the generic version, as -// Embarcadero (formerly CodeGear, formerly Borland) C++ doesn't -// support specializing a method template of a class template. -template <> -struct TuplePrefixPrinter<1> { - template - static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { - UniversalPrinter::type>:: - Print(::std::tr1::get<0>(t), os); - } - - template - static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { - ::std::stringstream ss; - UniversalTersePrint(::std::tr1::get<0>(t), &ss); - strings->push_back(ss.str()); - } -}; - -// Helper function for printing a tuple. T must be instantiated with -// a tuple type. -template -void PrintTupleTo(const T& t, ::std::ostream* os) { - *os << "("; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - PrintPrefixTo(t, os); - *os << ")"; -} - -// Prints the fields of a tuple tersely to a string vector, one -// element for each field. See the comment before -// UniversalTersePrint() for how we define "tersely". -template -Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { - Strings result; - TuplePrefixPrinter< ::std::tr1::tuple_size::value>:: - TersePrintPrefixToStrings(value, &result); - return result; -} -#endif // GTEST_HAS_TR1_TUPLE - -} // namespace internal - -template -::std::string PrintToString(const T& value) { - ::std::stringstream ss; - internal::UniversalTersePrinter::Print(value, &ss); - return ss.str(); -} - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ - -#if GTEST_HAS_PARAM_TEST - -namespace testing { -namespace internal { - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Outputs a message explaining invalid registration of different -// fixture class for the same test case. This may happen when -// TEST_P macro is used to define two tests with the same name -// but in different namespaces. -GTEST_API_ void ReportInvalidTestCaseType(const char* test_case_name, - const char* file, int line); - -template class ParamGeneratorInterface; -template class ParamGenerator; - -// Interface for iterating over elements provided by an implementation -// of ParamGeneratorInterface. -template -class ParamIteratorInterface { - public: - virtual ~ParamIteratorInterface() {} - // A pointer to the base generator instance. - // Used only for the purposes of iterator comparison - // to make sure that two iterators belong to the same generator. - virtual const ParamGeneratorInterface* BaseGenerator() const = 0; - // Advances iterator to point to the next element - // provided by the generator. The caller is responsible - // for not calling Advance() on an iterator equal to - // BaseGenerator()->End(). - virtual void Advance() = 0; - // Clones the iterator object. Used for implementing copy semantics - // of ParamIterator. - virtual ParamIteratorInterface* Clone() const = 0; - // Dereferences the current iterator and provides (read-only) access - // to the pointed value. It is the caller's responsibility not to call - // Current() on an iterator equal to BaseGenerator()->End(). - // Used for implementing ParamGenerator::operator*(). - virtual const T* Current() const = 0; - // Determines whether the given iterator and other point to the same - // element in the sequence generated by the generator. - // Used for implementing ParamGenerator::operator==(). - virtual bool Equals(const ParamIteratorInterface& other) const = 0; -}; - -// Class iterating over elements provided by an implementation of -// ParamGeneratorInterface. It wraps ParamIteratorInterface -// and implements the const forward iterator concept. -template -class ParamIterator { - public: - typedef T value_type; - typedef const T& reference; - typedef ptrdiff_t difference_type; - - // ParamIterator assumes ownership of the impl_ pointer. - ParamIterator(const ParamIterator& other) : impl_(other.impl_->Clone()) {} - ParamIterator& operator=(const ParamIterator& other) { - if (this != &other) - impl_.reset(other.impl_->Clone()); - return *this; - } - - const T& operator*() const { return *impl_->Current(); } - const T* operator->() const { return impl_->Current(); } - // Prefix version of operator++. - ParamIterator& operator++() { - impl_->Advance(); - return *this; - } - // Postfix version of operator++. - ParamIterator operator++(int /*unused*/) { - ParamIteratorInterface* clone = impl_->Clone(); - impl_->Advance(); - return ParamIterator(clone); - } - bool operator==(const ParamIterator& other) const { - return impl_.get() == other.impl_.get() || impl_->Equals(*other.impl_); - } - bool operator!=(const ParamIterator& other) const { - return !(*this == other); - } - - private: - friend class ParamGenerator; - explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} - scoped_ptr > impl_; -}; - -// ParamGeneratorInterface is the binary interface to access generators -// defined in other translation units. -template -class ParamGeneratorInterface { - public: - typedef T ParamType; - - virtual ~ParamGeneratorInterface() {} - - // Generator interface definition - virtual ParamIteratorInterface* Begin() const = 0; - virtual ParamIteratorInterface* End() const = 0; -}; - -// Wraps ParamGeneratorInterface and provides general generator syntax -// compatible with the STL Container concept. -// This class implements copy initialization semantics and the contained -// ParamGeneratorInterface instance is shared among all copies -// of the original object. This is possible because that instance is immutable. -template -class ParamGenerator { - public: - typedef ParamIterator iterator; - - explicit ParamGenerator(ParamGeneratorInterface* impl) : impl_(impl) {} - ParamGenerator(const ParamGenerator& other) : impl_(other.impl_) {} - - ParamGenerator& operator=(const ParamGenerator& other) { - impl_ = other.impl_; - return *this; - } - - iterator begin() const { return iterator(impl_->Begin()); } - iterator end() const { return iterator(impl_->End()); } - - private: - linked_ptr > impl_; -}; - -// Generates values from a range of two comparable values. Can be used to -// generate sequences of user-defined types that implement operator+() and -// operator<(). -// This class is used in the Range() function. -template -class RangeGenerator : public ParamGeneratorInterface { - public: - RangeGenerator(T begin, T end, IncrementT step) - : begin_(begin), end_(end), - step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} - virtual ~RangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, begin_, 0, step_); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, end_, end_index_, step_); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, T value, int index, - IncrementT step) - : base_(base), value_(value), index_(index), step_(step) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - value_ = value_ + step_; - index_++; - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const T* Current() const { return &value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const int other_index = - CheckedDowncastToActualType(&other)->index_; - return index_ == other_index; - } - - private: - Iterator(const Iterator& other) - : ParamIteratorInterface(), - base_(other.base_), value_(other.value_), index_(other.index_), - step_(other.step_) {} - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - T value_; - int index_; - const IncrementT step_; - }; // class RangeGenerator::Iterator - - static int CalculateEndIndex(const T& begin, - const T& end, - const IncrementT& step) { - int end_index = 0; - for (T i = begin; i < end; i = i + step) - end_index++; - return end_index; - } - - // No implementation - assignment is unsupported. - void operator=(const RangeGenerator& other); - - const T begin_; - const T end_; - const IncrementT step_; - // The index for the end() iterator. All the elements in the generated - // sequence are indexed (0-based) to aid iterator comparison. - const int end_index_; -}; // class RangeGenerator - - -// Generates values from a pair of STL-style iterators. Used in the -// ValuesIn() function. The elements are copied from the source range -// since the source can be located on the stack, and the generator -// is likely to persist beyond that stack frame. -template -class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { - public: - template - ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) - : container_(begin, end) {} - virtual ~ValuesInIteratorRangeGenerator() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, container_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, container_.end()); - } - - private: - typedef typename ::std::vector ContainerType; - - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - typename ContainerType::const_iterator iterator) - : base_(base), iterator_(iterator) {} - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - virtual void Advance() { - ++iterator_; - value_.reset(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - // We need to use cached value referenced by iterator_ because *iterator_ - // can return a temporary object (and of type other then T), so just - // having "return &*iterator_;" doesn't work. - // value_ is updated here and not in Advance() because Advance() - // can advance iterator_ beyond the end of the range, and we cannot - // detect that fact. The client code, on the other hand, is - // responsible for not calling Current() on an out-of-range iterator. - virtual const T* Current() const { - if (value_.get() == NULL) - value_.reset(new T(*iterator_)); - return value_.get(); - } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - return iterator_ == - CheckedDowncastToActualType(&other)->iterator_; - } - - private: - Iterator(const Iterator& other) - // The explicit constructor call suppresses a false warning - // emitted by gcc when supplied with the -Wextra option. - : ParamIteratorInterface(), - base_(other.base_), - iterator_(other.iterator_) {} - - const ParamGeneratorInterface* const base_; - typename ContainerType::const_iterator iterator_; - // A cached value of *iterator_. We keep it here to allow access by - // pointer in the wrapping iterator's operator->(). - // value_ needs to be mutable to be accessed in Current(). - // Use of scoped_ptr helps manage cached value's lifetime, - // which is bound by the lifespan of the iterator itself. - mutable scoped_ptr value_; - }; // class ValuesInIteratorRangeGenerator::Iterator - - // No implementation - assignment is unsupported. - void operator=(const ValuesInIteratorRangeGenerator& other); - - const ContainerType container_; -}; // class ValuesInIteratorRangeGenerator - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Stores a parameter value and later creates tests parameterized with that -// value. -template -class ParameterizedTestFactory : public TestFactoryBase { - public: - typedef typename TestClass::ParamType ParamType; - explicit ParameterizedTestFactory(ParamType parameter) : - parameter_(parameter) {} - virtual Test* CreateTest() { - TestClass::SetParam(¶meter_); - return new TestClass(); - } - - private: - const ParamType parameter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactoryBase is a base class for meta-factories that create -// test factories for passing into MakeAndRegisterTestInfo function. -template -class TestMetaFactoryBase { - public: - virtual ~TestMetaFactoryBase() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) = 0; -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// TestMetaFactory creates test factories for passing into -// MakeAndRegisterTestInfo function. Since MakeAndRegisterTestInfo receives -// ownership of test factory pointer, same factory object cannot be passed -// into that method twice. But ParameterizedTestCaseInfo is going to call -// it for each Test/Parameter value combination. Thus it needs meta factory -// creator class. -template -class TestMetaFactory - : public TestMetaFactoryBase { - public: - typedef typename TestCase::ParamType ParamType; - - TestMetaFactory() {} - - virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { - return new ParameterizedTestFactory(parameter); - } - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestMetaFactory); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfoBase is a generic interface -// to ParameterizedTestCaseInfo classes. ParameterizedTestCaseInfoBase -// accumulates test information provided by TEST_P macro invocations -// and generators provided by INSTANTIATE_TEST_CASE_P macro invocations -// and uses that information to register all resulting test instances -// in RegisterTests method. The ParameterizeTestCaseRegistry class holds -// a collection of pointers to the ParameterizedTestCaseInfo objects -// and calls RegisterTests() on each of them when asked. -class ParameterizedTestCaseInfoBase { - public: - virtual ~ParameterizedTestCaseInfoBase() {} - - // Base part of test case name for display purposes. - virtual const string& GetTestCaseName() const = 0; - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const = 0; - // UnitTest class invokes this method to register tests in this - // test case right before running them in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - virtual void RegisterTests() = 0; - - protected: - ParameterizedTestCaseInfoBase() {} - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfoBase); -}; - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseInfo accumulates tests obtained from TEST_P -// macro invocations for a particular test case and generators -// obtained from INSTANTIATE_TEST_CASE_P macro invocations for that -// test case. It registers tests with all values generated by all -// generators when asked. -template -class ParameterizedTestCaseInfo : public ParameterizedTestCaseInfoBase { - public: - // ParamType and GeneratorCreationFunc are private types but are required - // for declarations of public methods AddTestPattern() and - // AddTestCaseInstantiation(). - typedef typename TestCase::ParamType ParamType; - // A function that returns an instance of appropriate generator type. - typedef ParamGenerator(GeneratorCreationFunc)(); - - explicit ParameterizedTestCaseInfo(const char* name) - : test_case_name_(name) {} - - // Test case base name for display purposes. - virtual const string& GetTestCaseName() const { return test_case_name_; } - // Test case id to verify identity. - virtual TypeId GetTestCaseTypeId() const { return GetTypeId(); } - // TEST_P macro uses AddTestPattern() to record information - // about a single test in a LocalTestInfo structure. - // test_case_name is the base name of the test case (without invocation - // prefix). test_base_name is the name of an individual test without - // parameter index. For the test SequenceA/FooTest.DoBar/1 FooTest is - // test case base name and DoBar is test base name. - void AddTestPattern(const char* test_case_name, - const char* test_base_name, - TestMetaFactoryBase* meta_factory) { - tests_.push_back(linked_ptr(new TestInfo(test_case_name, - test_base_name, - meta_factory))); - } - // INSTANTIATE_TEST_CASE_P macro uses AddGenerator() to record information - // about a generator. - int AddTestCaseInstantiation(const string& instantiation_name, - GeneratorCreationFunc* func, - const char* /* file */, - int /* line */) { - instantiations_.push_back(::std::make_pair(instantiation_name, func)); - return 0; // Return value used only to run this method in namespace scope. - } - // UnitTest class invokes this method to register tests in this test case - // test cases right before running tests in RUN_ALL_TESTS macro. - // This method should not be called more then once on any single - // instance of a ParameterizedTestCaseInfoBase derived class. - // UnitTest has a guard to prevent from calling this method more then once. - virtual void RegisterTests() { - for (typename TestInfoContainer::iterator test_it = tests_.begin(); - test_it != tests_.end(); ++test_it) { - linked_ptr test_info = *test_it; - for (typename InstantiationContainer::iterator gen_it = - instantiations_.begin(); gen_it != instantiations_.end(); - ++gen_it) { - const string& instantiation_name = gen_it->first; - ParamGenerator generator((*gen_it->second)()); - - string test_case_name; - if ( !instantiation_name.empty() ) - test_case_name = instantiation_name + "/"; - test_case_name += test_info->test_case_base_name; - - int i = 0; - for (typename ParamGenerator::iterator param_it = - generator.begin(); - param_it != generator.end(); ++param_it, ++i) { - Message test_name_stream; - test_name_stream << test_info->test_base_name << "/" << i; - MakeAndRegisterTestInfo( - test_case_name.c_str(), - test_name_stream.GetString().c_str(), - NULL, // No type parameter. - PrintToString(*param_it).c_str(), - GetTestCaseTypeId(), - TestCase::SetUpTestCase, - TestCase::TearDownTestCase, - test_info->test_meta_factory->CreateTestFactory(*param_it)); - } // for param_it - } // for gen_it - } // for test_it - } // RegisterTests - - private: - // LocalTestInfo structure keeps information about a single test registered - // with TEST_P macro. - struct TestInfo { - TestInfo(const char* a_test_case_base_name, - const char* a_test_base_name, - TestMetaFactoryBase* a_test_meta_factory) : - test_case_base_name(a_test_case_base_name), - test_base_name(a_test_base_name), - test_meta_factory(a_test_meta_factory) {} - - const string test_case_base_name; - const string test_base_name; - const scoped_ptr > test_meta_factory; - }; - typedef ::std::vector > TestInfoContainer; - // Keeps pairs of - // received from INSTANTIATE_TEST_CASE_P macros. - typedef ::std::vector > - InstantiationContainer; - - const string test_case_name_; - TestInfoContainer tests_; - InstantiationContainer instantiations_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseInfo); -}; // class ParameterizedTestCaseInfo - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// ParameterizedTestCaseRegistry contains a map of ParameterizedTestCaseInfoBase -// classes accessed by test case names. TEST_P and INSTANTIATE_TEST_CASE_P -// macros use it to locate their corresponding ParameterizedTestCaseInfo -// descriptors. -class ParameterizedTestCaseRegistry { - public: - ParameterizedTestCaseRegistry() {} - ~ParameterizedTestCaseRegistry() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - delete *it; - } - } - - // Looks up or creates and returns a structure containing information about - // tests and instantiations of a particular test case. - template - ParameterizedTestCaseInfo* GetTestCasePatternHolder( - const char* test_case_name, - const char* file, - int line) { - ParameterizedTestCaseInfo* typed_test_info = NULL; - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - if ((*it)->GetTestCaseName() == test_case_name) { - if ((*it)->GetTestCaseTypeId() != GetTypeId()) { - // Complain about incorrect usage of Google Test facilities - // and terminate the program since we cannot guaranty correct - // test case setup and tear-down in this case. - ReportInvalidTestCaseType(test_case_name, file, line); - posix::Abort(); - } else { - // At this point we are sure that the object we found is of the same - // type we are looking for, so we downcast it to that type - // without further checks. - typed_test_info = CheckedDowncastToActualType< - ParameterizedTestCaseInfo >(*it); - } - break; - } - } - if (typed_test_info == NULL) { - typed_test_info = new ParameterizedTestCaseInfo(test_case_name); - test_case_infos_.push_back(typed_test_info); - } - return typed_test_info; - } - void RegisterTests() { - for (TestCaseInfoContainer::iterator it = test_case_infos_.begin(); - it != test_case_infos_.end(); ++it) { - (*it)->RegisterTests(); - } - } - - private: - typedef ::std::vector TestCaseInfoContainer; - - TestCaseInfoContainer test_case_infos_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(ParameterizedTestCaseRegistry); -}; - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_H_ -// This file was GENERATED by command: -// pump.py gtest-param-util-generated.h.pump -// DO NOT EDIT BY HAND!!! - -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: vladl@google.com (Vlad Losev) - -// Type and function utilities for implementing parameterized tests. -// This file is generated by a SCRIPT. DO NOT EDIT BY HAND! -// -// Currently Google Test supports at most 50 arguments in Values, -// and at most 10 arguments in Combine. Please contact -// googletestframework@googlegroups.com if you need more. -// Please note that the number of arguments to Combine is limited -// by the maximum arity of the implementation of tr1::tuple which is -// currently set at 10. - -#ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ -#define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -// scripts/fuse_gtest.py depends on gtest's own header being #included -// *unconditionally*. Therefore these #includes cannot be moved -// inside #if GTEST_HAS_PARAM_TEST. - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Forward declarations of ValuesIn(), which is implemented in -// include/gtest/gtest-param-test.h. -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end); - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]); - -template -internal::ParamGenerator ValuesIn( - const Container& container); - -namespace internal { - -// Used in the Values() function to provide polymorphic capabilities. -template -class ValueArray1 { - public: - explicit ValueArray1(T1 v1) : v1_(v1) {} - - template - operator ParamGenerator() const { return ValuesIn(&v1_, &v1_ + 1); } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray1& other); - - const T1 v1_; -}; - -template -class ValueArray2 { - public: - ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray2& other); - - const T1 v1_; - const T2 v2_; -}; - -template -class ValueArray3 { - public: - ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray3& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; -}; - -template -class ValueArray4 { - public: - ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray4& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; -}; - -template -class ValueArray5 { - public: - ValueArray5(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray5& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; -}; - -template -class ValueArray6 { - public: - ValueArray6(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray6& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; -}; - -template -class ValueArray7 { - public: - ValueArray7(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray7& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; -}; - -template -class ValueArray8 { - public: - ValueArray8(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray8& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; -}; - -template -class ValueArray9 { - public: - ValueArray9(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray9& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; -}; - -template -class ValueArray10 { - public: - ValueArray10(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray10& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; -}; - -template -class ValueArray11 { - public: - ValueArray11(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray11& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; -}; - -template -class ValueArray12 { - public: - ValueArray12(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray12& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; -}; - -template -class ValueArray13 { - public: - ValueArray13(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray13& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; -}; - -template -class ValueArray14 { - public: - ValueArray14(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray14& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; -}; - -template -class ValueArray15 { - public: - ValueArray15(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray15& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; -}; - -template -class ValueArray16 { - public: - ValueArray16(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray16& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; -}; - -template -class ValueArray17 { - public: - ValueArray17(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray17& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; -}; - -template -class ValueArray18 { - public: - ValueArray18(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray18& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; -}; - -template -class ValueArray19 { - public: - ValueArray19(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray19& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; -}; - -template -class ValueArray20 { - public: - ValueArray20(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray20& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; -}; - -template -class ValueArray21 { - public: - ValueArray21(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray21& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; -}; - -template -class ValueArray22 { - public: - ValueArray22(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray22& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; -}; - -template -class ValueArray23 { - public: - ValueArray23(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray23& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; -}; - -template -class ValueArray24 { - public: - ValueArray24(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray24& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; -}; - -template -class ValueArray25 { - public: - ValueArray25(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray25& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; -}; - -template -class ValueArray26 { - public: - ValueArray26(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray26& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; -}; - -template -class ValueArray27 { - public: - ValueArray27(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray27& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; -}; - -template -class ValueArray28 { - public: - ValueArray28(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray28& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; -}; - -template -class ValueArray29 { - public: - ValueArray29(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray29& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; -}; - -template -class ValueArray30 { - public: - ValueArray30(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray30& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; -}; - -template -class ValueArray31 { - public: - ValueArray31(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray31& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; -}; - -template -class ValueArray32 { - public: - ValueArray32(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray32& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; -}; - -template -class ValueArray33 { - public: - ValueArray33(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray33& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; -}; - -template -class ValueArray34 { - public: - ValueArray34(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray34& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; -}; - -template -class ValueArray35 { - public: - ValueArray35(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray35& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; -}; - -template -class ValueArray36 { - public: - ValueArray36(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray36& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; -}; - -template -class ValueArray37 { - public: - ValueArray37(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray37& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; -}; - -template -class ValueArray38 { - public: - ValueArray38(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray38& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; -}; - -template -class ValueArray39 { - public: - ValueArray39(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray39& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; -}; - -template -class ValueArray40 { - public: - ValueArray40(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray40& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; -}; - -template -class ValueArray41 { - public: - ValueArray41(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray41& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; -}; - -template -class ValueArray42 { - public: - ValueArray42(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray42& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; -}; - -template -class ValueArray43 { - public: - ValueArray43(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), - v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), - v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), - v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), - v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), - v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), - v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray43& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; -}; - -template -class ValueArray44 { - public: - ValueArray44(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), - v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), - v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), v18_(v18), - v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), v24_(v24), - v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), v30_(v30), - v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), v36_(v36), - v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), v42_(v42), - v43_(v43), v44_(v44) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray44& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; -}; - -template -class ValueArray45 { - public: - ValueArray45(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), - v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), v11_(v11), - v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), v17_(v17), - v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), v23_(v23), - v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), v29_(v29), - v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), v35_(v35), - v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), v41_(v41), - v42_(v42), v43_(v43), v44_(v44), v45_(v45) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray45& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; -}; - -template -class ValueArray46 { - public: - ValueArray46(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) : v1_(v1), v2_(v2), v3_(v3), - v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray46& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; -}; - -template -class ValueArray47 { - public: - ValueArray47(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) : v1_(v1), v2_(v2), - v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), v10_(v10), - v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), v16_(v16), - v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), v22_(v22), - v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), v28_(v28), - v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), v34_(v34), - v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), v40_(v40), - v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), v46_(v46), - v47_(v47) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray47& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; -}; - -template -class ValueArray48 { - public: - ValueArray48(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48) : v1_(v1), - v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), v8_(v8), v9_(v9), - v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), v15_(v15), - v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), v21_(v21), - v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), v27_(v27), - v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), v33_(v33), - v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), v39_(v39), - v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), v45_(v45), - v46_(v46), v47_(v47), v48_(v48) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray48& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; -}; - -template -class ValueArray49 { - public: - ValueArray49(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, - T49 v49) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray49& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; -}; - -template -class ValueArray50 { - public: - ValueArray50(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, T48 v48, T49 v49, - T50 v50) : v1_(v1), v2_(v2), v3_(v3), v4_(v4), v5_(v5), v6_(v6), v7_(v7), - v8_(v8), v9_(v9), v10_(v10), v11_(v11), v12_(v12), v13_(v13), v14_(v14), - v15_(v15), v16_(v16), v17_(v17), v18_(v18), v19_(v19), v20_(v20), - v21_(v21), v22_(v22), v23_(v23), v24_(v24), v25_(v25), v26_(v26), - v27_(v27), v28_(v28), v29_(v29), v30_(v30), v31_(v31), v32_(v32), - v33_(v33), v34_(v34), v35_(v35), v36_(v36), v37_(v37), v38_(v38), - v39_(v39), v40_(v40), v41_(v41), v42_(v42), v43_(v43), v44_(v44), - v45_(v45), v46_(v46), v47_(v47), v48_(v48), v49_(v49), v50_(v50) {} - - template - operator ParamGenerator() const { - const T array[] = {static_cast(v1_), static_cast(v2_), - static_cast(v3_), static_cast(v4_), static_cast(v5_), - static_cast(v6_), static_cast(v7_), static_cast(v8_), - static_cast(v9_), static_cast(v10_), static_cast(v11_), - static_cast(v12_), static_cast(v13_), static_cast(v14_), - static_cast(v15_), static_cast(v16_), static_cast(v17_), - static_cast(v18_), static_cast(v19_), static_cast(v20_), - static_cast(v21_), static_cast(v22_), static_cast(v23_), - static_cast(v24_), static_cast(v25_), static_cast(v26_), - static_cast(v27_), static_cast(v28_), static_cast(v29_), - static_cast(v30_), static_cast(v31_), static_cast(v32_), - static_cast(v33_), static_cast(v34_), static_cast(v35_), - static_cast(v36_), static_cast(v37_), static_cast(v38_), - static_cast(v39_), static_cast(v40_), static_cast(v41_), - static_cast(v42_), static_cast(v43_), static_cast(v44_), - static_cast(v45_), static_cast(v46_), static_cast(v47_), - static_cast(v48_), static_cast(v49_), static_cast(v50_)}; - return ValuesIn(array); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const ValueArray50& other); - - const T1 v1_; - const T2 v2_; - const T3 v3_; - const T4 v4_; - const T5 v5_; - const T6 v6_; - const T7 v7_; - const T8 v8_; - const T9 v9_; - const T10 v10_; - const T11 v11_; - const T12 v12_; - const T13 v13_; - const T14 v14_; - const T15 v15_; - const T16 v16_; - const T17 v17_; - const T18 v18_; - const T19 v19_; - const T20 v20_; - const T21 v21_; - const T22 v22_; - const T23 v23_; - const T24 v24_; - const T25 v25_; - const T26 v26_; - const T27 v27_; - const T28 v28_; - const T29 v29_; - const T30 v30_; - const T31 v31_; - const T32 v32_; - const T33 v33_; - const T34 v34_; - const T35 v35_; - const T36 v36_; - const T37 v37_; - const T38 v38_; - const T39 v39_; - const T40 v40_; - const T41 v41_; - const T42 v42_; - const T43 v43_; - const T44 v44_; - const T45 v45_; - const T46 v46_; - const T47 v47_; - const T48 v48_; - const T49 v49_; - const T50 v50_; -}; - -# if GTEST_HAS_COMBINE -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Generates values from the Cartesian product of values produced -// by the argument generators. -// -template -class CartesianProductGenerator2 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator2(const ParamGenerator& g1, - const ParamGenerator& g2) - : g1_(g1), g2_(g2) {} - virtual ~CartesianProductGenerator2() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current2_; - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - ParamType current_value_; - }; // class CartesianProductGenerator2::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator2& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; -}; // class CartesianProductGenerator2 - - -template -class CartesianProductGenerator3 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator3(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - virtual ~CartesianProductGenerator3() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current3_; - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - ParamType current_value_; - }; // class CartesianProductGenerator3::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator3& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; -}; // class CartesianProductGenerator3 - - -template -class CartesianProductGenerator4 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator4(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - virtual ~CartesianProductGenerator4() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current4_; - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - ParamType current_value_; - }; // class CartesianProductGenerator4::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator4& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; -}; // class CartesianProductGenerator4 - - -template -class CartesianProductGenerator5 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator5(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - virtual ~CartesianProductGenerator5() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current5_; - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - ParamType current_value_; - }; // class CartesianProductGenerator5::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator5& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; -}; // class CartesianProductGenerator5 - - -template -class CartesianProductGenerator6 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator6(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - virtual ~CartesianProductGenerator6() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current6_; - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - ParamType current_value_; - }; // class CartesianProductGenerator6::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator6& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; -}; // class CartesianProductGenerator6 - - -template -class CartesianProductGenerator7 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator7(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - virtual ~CartesianProductGenerator7() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current7_; - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - ParamType current_value_; - }; // class CartesianProductGenerator7::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator7& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; -}; // class CartesianProductGenerator7 - - -template -class CartesianProductGenerator8 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator8(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - virtual ~CartesianProductGenerator8() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current8_; - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - ParamType current_value_; - }; // class CartesianProductGenerator8::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator8& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; -}; // class CartesianProductGenerator8 - - -template -class CartesianProductGenerator9 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator9(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - virtual ~CartesianProductGenerator9() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current9_; - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - ParamType current_value_; - }; // class CartesianProductGenerator9::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator9& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; -}; // class CartesianProductGenerator9 - - -template -class CartesianProductGenerator10 - : public ParamGeneratorInterface< ::std::tr1::tuple > { - public: - typedef ::std::tr1::tuple ParamType; - - CartesianProductGenerator10(const ParamGenerator& g1, - const ParamGenerator& g2, const ParamGenerator& g3, - const ParamGenerator& g4, const ParamGenerator& g5, - const ParamGenerator& g6, const ParamGenerator& g7, - const ParamGenerator& g8, const ParamGenerator& g9, - const ParamGenerator& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - virtual ~CartesianProductGenerator10() {} - - virtual ParamIteratorInterface* Begin() const { - return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, - g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin(), g6_, g6_.begin(), g7_, - g7_.begin(), g8_, g8_.begin(), g9_, g9_.begin(), g10_, g10_.begin()); - } - virtual ParamIteratorInterface* End() const { - return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), - g4_, g4_.end(), g5_, g5_.end(), g6_, g6_.end(), g7_, g7_.end(), g8_, - g8_.end(), g9_, g9_.end(), g10_, g10_.end()); - } - - private: - class Iterator : public ParamIteratorInterface { - public: - Iterator(const ParamGeneratorInterface* base, - const ParamGenerator& g1, - const typename ParamGenerator::iterator& current1, - const ParamGenerator& g2, - const typename ParamGenerator::iterator& current2, - const ParamGenerator& g3, - const typename ParamGenerator::iterator& current3, - const ParamGenerator& g4, - const typename ParamGenerator::iterator& current4, - const ParamGenerator& g5, - const typename ParamGenerator::iterator& current5, - const ParamGenerator& g6, - const typename ParamGenerator::iterator& current6, - const ParamGenerator& g7, - const typename ParamGenerator::iterator& current7, - const ParamGenerator& g8, - const typename ParamGenerator::iterator& current8, - const ParamGenerator& g9, - const typename ParamGenerator::iterator& current9, - const ParamGenerator& g10, - const typename ParamGenerator::iterator& current10) - : base_(base), - begin1_(g1.begin()), end1_(g1.end()), current1_(current1), - begin2_(g2.begin()), end2_(g2.end()), current2_(current2), - begin3_(g3.begin()), end3_(g3.end()), current3_(current3), - begin4_(g4.begin()), end4_(g4.end()), current4_(current4), - begin5_(g5.begin()), end5_(g5.end()), current5_(current5), - begin6_(g6.begin()), end6_(g6.end()), current6_(current6), - begin7_(g7.begin()), end7_(g7.end()), current7_(current7), - begin8_(g8.begin()), end8_(g8.end()), current8_(current8), - begin9_(g9.begin()), end9_(g9.end()), current9_(current9), - begin10_(g10.begin()), end10_(g10.end()), current10_(current10) { - ComputeCurrentValue(); - } - virtual ~Iterator() {} - - virtual const ParamGeneratorInterface* BaseGenerator() const { - return base_; - } - // Advance should not be called on beyond-of-range iterators - // so no component iterators must be beyond end of range, either. - virtual void Advance() { - assert(!AtEnd()); - ++current10_; - if (current10_ == end10_) { - current10_ = begin10_; - ++current9_; - } - if (current9_ == end9_) { - current9_ = begin9_; - ++current8_; - } - if (current8_ == end8_) { - current8_ = begin8_; - ++current7_; - } - if (current7_ == end7_) { - current7_ = begin7_; - ++current6_; - } - if (current6_ == end6_) { - current6_ = begin6_; - ++current5_; - } - if (current5_ == end5_) { - current5_ = begin5_; - ++current4_; - } - if (current4_ == end4_) { - current4_ = begin4_; - ++current3_; - } - if (current3_ == end3_) { - current3_ = begin3_; - ++current2_; - } - if (current2_ == end2_) { - current2_ = begin2_; - ++current1_; - } - ComputeCurrentValue(); - } - virtual ParamIteratorInterface* Clone() const { - return new Iterator(*this); - } - virtual const ParamType* Current() const { return ¤t_value_; } - virtual bool Equals(const ParamIteratorInterface& other) const { - // Having the same base generator guarantees that the other - // iterator is of the same type and we can downcast. - GTEST_CHECK_(BaseGenerator() == other.BaseGenerator()) - << "The program attempted to compare iterators " - << "from different generators." << std::endl; - const Iterator* typed_other = - CheckedDowncastToActualType(&other); - // We must report iterators equal if they both point beyond their - // respective ranges. That can happen in a variety of fashions, - // so we have to consult AtEnd(). - return (AtEnd() && typed_other->AtEnd()) || - ( - current1_ == typed_other->current1_ && - current2_ == typed_other->current2_ && - current3_ == typed_other->current3_ && - current4_ == typed_other->current4_ && - current5_ == typed_other->current5_ && - current6_ == typed_other->current6_ && - current7_ == typed_other->current7_ && - current8_ == typed_other->current8_ && - current9_ == typed_other->current9_ && - current10_ == typed_other->current10_); - } - - private: - Iterator(const Iterator& other) - : base_(other.base_), - begin1_(other.begin1_), - end1_(other.end1_), - current1_(other.current1_), - begin2_(other.begin2_), - end2_(other.end2_), - current2_(other.current2_), - begin3_(other.begin3_), - end3_(other.end3_), - current3_(other.current3_), - begin4_(other.begin4_), - end4_(other.end4_), - current4_(other.current4_), - begin5_(other.begin5_), - end5_(other.end5_), - current5_(other.current5_), - begin6_(other.begin6_), - end6_(other.end6_), - current6_(other.current6_), - begin7_(other.begin7_), - end7_(other.end7_), - current7_(other.current7_), - begin8_(other.begin8_), - end8_(other.end8_), - current8_(other.current8_), - begin9_(other.begin9_), - end9_(other.end9_), - current9_(other.current9_), - begin10_(other.begin10_), - end10_(other.end10_), - current10_(other.current10_) { - ComputeCurrentValue(); - } - - void ComputeCurrentValue() { - if (!AtEnd()) - current_value_ = ParamType(*current1_, *current2_, *current3_, - *current4_, *current5_, *current6_, *current7_, *current8_, - *current9_, *current10_); - } - bool AtEnd() const { - // We must report iterator past the end of the range when either of the - // component iterators has reached the end of its range. - return - current1_ == end1_ || - current2_ == end2_ || - current3_ == end3_ || - current4_ == end4_ || - current5_ == end5_ || - current6_ == end6_ || - current7_ == end7_ || - current8_ == end8_ || - current9_ == end9_ || - current10_ == end10_; - } - - // No implementation - assignment is unsupported. - void operator=(const Iterator& other); - - const ParamGeneratorInterface* const base_; - // begin[i]_ and end[i]_ define the i-th range that Iterator traverses. - // current[i]_ is the actual traversing iterator. - const typename ParamGenerator::iterator begin1_; - const typename ParamGenerator::iterator end1_; - typename ParamGenerator::iterator current1_; - const typename ParamGenerator::iterator begin2_; - const typename ParamGenerator::iterator end2_; - typename ParamGenerator::iterator current2_; - const typename ParamGenerator::iterator begin3_; - const typename ParamGenerator::iterator end3_; - typename ParamGenerator::iterator current3_; - const typename ParamGenerator::iterator begin4_; - const typename ParamGenerator::iterator end4_; - typename ParamGenerator::iterator current4_; - const typename ParamGenerator::iterator begin5_; - const typename ParamGenerator::iterator end5_; - typename ParamGenerator::iterator current5_; - const typename ParamGenerator::iterator begin6_; - const typename ParamGenerator::iterator end6_; - typename ParamGenerator::iterator current6_; - const typename ParamGenerator::iterator begin7_; - const typename ParamGenerator::iterator end7_; - typename ParamGenerator::iterator current7_; - const typename ParamGenerator::iterator begin8_; - const typename ParamGenerator::iterator end8_; - typename ParamGenerator::iterator current8_; - const typename ParamGenerator::iterator begin9_; - const typename ParamGenerator::iterator end9_; - typename ParamGenerator::iterator current9_; - const typename ParamGenerator::iterator begin10_; - const typename ParamGenerator::iterator end10_; - typename ParamGenerator::iterator current10_; - ParamType current_value_; - }; // class CartesianProductGenerator10::Iterator - - // No implementation - assignment is unsupported. - void operator=(const CartesianProductGenerator10& other); - - const ParamGenerator g1_; - const ParamGenerator g2_; - const ParamGenerator g3_; - const ParamGenerator g4_; - const ParamGenerator g5_; - const ParamGenerator g6_; - const ParamGenerator g7_; - const ParamGenerator g8_; - const ParamGenerator g9_; - const ParamGenerator g10_; -}; // class CartesianProductGenerator10 - - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Helper classes providing Combine() with polymorphic features. They allow -// casting CartesianProductGeneratorN to ParamGenerator if T is -// convertible to U. -// -template -class CartesianProductHolder2 { - public: -CartesianProductHolder2(const Generator1& g1, const Generator2& g2) - : g1_(g1), g2_(g2) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator2( - static_cast >(g1_), - static_cast >(g2_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder2& other); - - const Generator1 g1_; - const Generator2 g2_; -}; // class CartesianProductHolder2 - -template -class CartesianProductHolder3 { - public: -CartesianProductHolder3(const Generator1& g1, const Generator2& g2, - const Generator3& g3) - : g1_(g1), g2_(g2), g3_(g3) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator3( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder3& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; -}; // class CartesianProductHolder3 - -template -class CartesianProductHolder4 { - public: -CartesianProductHolder4(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator4( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder4& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; -}; // class CartesianProductHolder4 - -template -class CartesianProductHolder5 { - public: -CartesianProductHolder5(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator5( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder5& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; -}; // class CartesianProductHolder5 - -template -class CartesianProductHolder6 { - public: -CartesianProductHolder6(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator6( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder6& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; -}; // class CartesianProductHolder6 - -template -class CartesianProductHolder7 { - public: -CartesianProductHolder7(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator7( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder7& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; -}; // class CartesianProductHolder7 - -template -class CartesianProductHolder8 { - public: -CartesianProductHolder8(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), - g8_(g8) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator8( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder8& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; -}; // class CartesianProductHolder8 - -template -class CartesianProductHolder9 { - public: -CartesianProductHolder9(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator9( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder9& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; -}; // class CartesianProductHolder9 - -template -class CartesianProductHolder10 { - public: -CartesianProductHolder10(const Generator1& g1, const Generator2& g2, - const Generator3& g3, const Generator4& g4, const Generator5& g5, - const Generator6& g6, const Generator7& g7, const Generator8& g8, - const Generator9& g9, const Generator10& g10) - : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), - g9_(g9), g10_(g10) {} - template - operator ParamGenerator< ::std::tr1::tuple >() const { - return ParamGenerator< ::std::tr1::tuple >( - new CartesianProductGenerator10( - static_cast >(g1_), - static_cast >(g2_), - static_cast >(g3_), - static_cast >(g4_), - static_cast >(g5_), - static_cast >(g6_), - static_cast >(g7_), - static_cast >(g8_), - static_cast >(g9_), - static_cast >(g10_))); - } - - private: - // No implementation - assignment is unsupported. - void operator=(const CartesianProductHolder10& other); - - const Generator1 g1_; - const Generator2 g2_; - const Generator3 g3_; - const Generator4 g4_; - const Generator5 g5_; - const Generator6 g6_; - const Generator7 g7_; - const Generator8 g8_; - const Generator9 g9_; - const Generator10 g10_; -}; // class CartesianProductHolder10 - -# endif // GTEST_HAS_COMBINE - -} // namespace internal -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PARAM_UTIL_GENERATED_H_ - -#if GTEST_HAS_PARAM_TEST - -namespace testing { - -// Functions producing parameter generators. -// -// Google Test uses these generators to produce parameters for value- -// parameterized tests. When a parameterized test case is instantiated -// with a particular generator, Google Test creates and runs tests -// for each element in the sequence produced by the generator. -// -// In the following sample, tests from test case FooTest are instantiated -// each three times with parameter values 3, 5, and 8: -// -// class FooTest : public TestWithParam { ... }; -// -// TEST_P(FooTest, TestThis) { -// } -// TEST_P(FooTest, TestThat) { -// } -// INSTANTIATE_TEST_CASE_P(TestSequence, FooTest, Values(3, 5, 8)); -// - -// Range() returns generators providing sequences of values in a range. -// -// Synopsis: -// Range(start, end) -// - returns a generator producing a sequence of values {start, start+1, -// start+2, ..., }. -// Range(start, end, step) -// - returns a generator producing a sequence of values {start, start+step, -// start+step+step, ..., }. -// Notes: -// * The generated sequences never include end. For example, Range(1, 5) -// returns a generator producing a sequence {1, 2, 3, 4}. Range(1, 9, 2) -// returns a generator producing {1, 3, 5, 7}. -// * start and end must have the same type. That type may be any integral or -// floating-point type or a user defined type satisfying these conditions: -// * It must be assignable (have operator=() defined). -// * It must have operator+() (operator+(int-compatible type) for -// two-operand version). -// * It must have operator<() defined. -// Elements in the resulting sequences will also have that type. -// * Condition start < end must be satisfied in order for resulting sequences -// to contain any elements. -// -template -internal::ParamGenerator Range(T start, T end, IncrementT step) { - return internal::ParamGenerator( - new internal::RangeGenerator(start, end, step)); -} - -template -internal::ParamGenerator Range(T start, T end) { - return Range(start, end, 1); -} - -// ValuesIn() function allows generation of tests with parameters coming from -// a container. -// -// Synopsis: -// ValuesIn(const T (&array)[N]) -// - returns a generator producing sequences with elements from -// a C-style array. -// ValuesIn(const Container& container) -// - returns a generator producing sequences with elements from -// an STL-style container. -// ValuesIn(Iterator begin, Iterator end) -// - returns a generator producing sequences with elements from -// a range [begin, end) defined by a pair of STL-style iterators. These -// iterators can also be plain C pointers. -// -// Please note that ValuesIn copies the values from the containers -// passed in and keeps them to generate tests in RUN_ALL_TESTS(). -// -// Examples: -// -// This instantiates tests from test case StringTest -// each with C-string values of "foo", "bar", and "baz": -// -// const char* strings[] = {"foo", "bar", "baz"}; -// INSTANTIATE_TEST_CASE_P(StringSequence, SrtingTest, ValuesIn(strings)); -// -// This instantiates tests from test case StlStringTest -// each with STL strings with values "a" and "b": -// -// ::std::vector< ::std::string> GetParameterStrings() { -// ::std::vector< ::std::string> v; -// v.push_back("a"); -// v.push_back("b"); -// return v; -// } -// -// INSTANTIATE_TEST_CASE_P(CharSequence, -// StlStringTest, -// ValuesIn(GetParameterStrings())); -// -// -// This will also instantiate tests from CharTest -// each with parameter values 'a' and 'b': -// -// ::std::list GetParameterChars() { -// ::std::list list; -// list.push_back('a'); -// list.push_back('b'); -// return list; -// } -// ::std::list l = GetParameterChars(); -// INSTANTIATE_TEST_CASE_P(CharSequence2, -// CharTest, -// ValuesIn(l.begin(), l.end())); -// -template -internal::ParamGenerator< - typename ::testing::internal::IteratorTraits::value_type> -ValuesIn(ForwardIterator begin, ForwardIterator end) { - typedef typename ::testing::internal::IteratorTraits - ::value_type ParamType; - return internal::ParamGenerator( - new internal::ValuesInIteratorRangeGenerator(begin, end)); -} - -template -internal::ParamGenerator ValuesIn(const T (&array)[N]) { - return ValuesIn(array, array + N); -} - -template -internal::ParamGenerator ValuesIn( - const Container& container) { - return ValuesIn(container.begin(), container.end()); -} - -// Values() allows generating tests from explicitly specified list of -// parameters. -// -// Synopsis: -// Values(T v1, T v2, ..., T vN) -// - returns a generator producing sequences with elements v1, v2, ..., vN. -// -// For example, this instantiates tests from test case BarTest each -// with values "one", "two", and "three": -// -// INSTANTIATE_TEST_CASE_P(NumSequence, BarTest, Values("one", "two", "three")); -// -// This instantiates tests from test case BazTest each with values 1, 2, 3.5. -// The exact type of values will depend on the type of parameter in BazTest. -// -// INSTANTIATE_TEST_CASE_P(FloatingNumbers, BazTest, Values(1, 2, 3.5)); -// -// Currently, Values() supports from 1 to 50 parameters. -// -template -internal::ValueArray1 Values(T1 v1) { - return internal::ValueArray1(v1); -} - -template -internal::ValueArray2 Values(T1 v1, T2 v2) { - return internal::ValueArray2(v1, v2); -} - -template -internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { - return internal::ValueArray3(v1, v2, v3); -} - -template -internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { - return internal::ValueArray4(v1, v2, v3, v4); -} - -template -internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5) { - return internal::ValueArray5(v1, v2, v3, v4, v5); -} - -template -internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6) { - return internal::ValueArray6(v1, v2, v3, v4, v5, v6); -} - -template -internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7) { - return internal::ValueArray7(v1, v2, v3, v4, v5, - v6, v7); -} - -template -internal::ValueArray8 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { - return internal::ValueArray8(v1, v2, v3, v4, - v5, v6, v7, v8); -} - -template -internal::ValueArray9 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { - return internal::ValueArray9(v1, v2, v3, - v4, v5, v6, v7, v8, v9); -} - -template -internal::ValueArray10 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { - return internal::ValueArray10(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10); -} - -template -internal::ValueArray11 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11) { - return internal::ValueArray11(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); -} - -template -internal::ValueArray12 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12) { - return internal::ValueArray12(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); -} - -template -internal::ValueArray13 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13) { - return internal::ValueArray13(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); -} - -template -internal::ValueArray14 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14) { - return internal::ValueArray14(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14); -} - -template -internal::ValueArray15 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15) { - return internal::ValueArray15(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15); -} - -template -internal::ValueArray16 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16) { - return internal::ValueArray16(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16); -} - -template -internal::ValueArray17 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17) { - return internal::ValueArray17(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17); -} - -template -internal::ValueArray18 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18) { - return internal::ValueArray18(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18); -} - -template -internal::ValueArray19 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19) { - return internal::ValueArray19(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); -} - -template -internal::ValueArray20 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20) { - return internal::ValueArray20(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); -} - -template -internal::ValueArray21 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21) { - return internal::ValueArray21(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); -} - -template -internal::ValueArray22 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22) { - return internal::ValueArray22(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22); -} - -template -internal::ValueArray23 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23) { - return internal::ValueArray23(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23); -} - -template -internal::ValueArray24 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24) { - return internal::ValueArray24(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24); -} - -template -internal::ValueArray25 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25) { - return internal::ValueArray25(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25); -} - -template -internal::ValueArray26 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26) { - return internal::ValueArray26(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26); -} - -template -internal::ValueArray27 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27) { - return internal::ValueArray27(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27); -} - -template -internal::ValueArray28 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28) { - return internal::ValueArray28(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28); -} - -template -internal::ValueArray29 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29) { - return internal::ValueArray29(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29); -} - -template -internal::ValueArray30 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30) { - return internal::ValueArray30(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30); -} - -template -internal::ValueArray31 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31) { - return internal::ValueArray31(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31); -} - -template -internal::ValueArray32 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32) { - return internal::ValueArray32(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32); -} - -template -internal::ValueArray33 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33) { - return internal::ValueArray33(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33); -} - -template -internal::ValueArray34 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34) { - return internal::ValueArray34(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34); -} - -template -internal::ValueArray35 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35) { - return internal::ValueArray35(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35); -} - -template -internal::ValueArray36 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36) { - return internal::ValueArray36(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36); -} - -template -internal::ValueArray37 Values(T1 v1, T2 v2, T3 v3, - T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37) { - return internal::ValueArray37(v1, v2, v3, - v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37); -} - -template -internal::ValueArray38 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38) { - return internal::ValueArray38(v1, v2, - v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, - v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, - v33, v34, v35, v36, v37, v38); -} - -template -internal::ValueArray39 Values(T1 v1, T2 v2, - T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, - T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, - T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, - T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, - T37 v37, T38 v38, T39 v39) { - return internal::ValueArray39(v1, - v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, - v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, - v32, v33, v34, v35, v36, v37, v38, v39); -} - -template -internal::ValueArray40 Values(T1 v1, - T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, - T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, - T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, - T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, - T36 v36, T37 v37, T38 v38, T39 v39, T40 v40) { - return internal::ValueArray40(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, - v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, - v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40); -} - -template -internal::ValueArray41 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41) { - return internal::ValueArray41(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, - v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, v28, - v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41); -} - -template -internal::ValueArray42 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42) { - return internal::ValueArray42(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, - v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, v27, - v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, v41, - v42); -} - -template -internal::ValueArray43 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43) { - return internal::ValueArray43(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, - v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, v26, - v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, v40, - v41, v42, v43); -} - -template -internal::ValueArray44 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, - T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, T17 v17, - T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, T25 v25, - T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, T33 v33, - T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, T41 v41, - T42 v42, T43 v43, T44 v44) { - return internal::ValueArray44(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, - v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, v25, - v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, v39, - v40, v41, v42, v43, v44); -} - -template -internal::ValueArray45 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, - T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, T16 v16, - T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, T24 v24, - T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, T32 v32, - T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, T40 v40, - T41 v41, T42 v42, T43 v43, T44 v44, T45 v45) { - return internal::ValueArray45(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, - v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, v24, - v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, v38, - v39, v40, v41, v42, v43, v44, v45); -} - -template -internal::ValueArray46 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46) { - return internal::ValueArray46(v1, v2, v3, v4, v5, v6, v7, v8, v9, - v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46); -} - -template -internal::ValueArray47 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, - T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47) { - return internal::ValueArray47(v1, v2, v3, v4, v5, v6, v7, v8, - v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23, - v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, v37, - v38, v39, v40, v41, v42, v43, v44, v45, v46, v47); -} - -template -internal::ValueArray48 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, - T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, T15 v15, - T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, T23 v23, - T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, T31 v31, - T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, T39 v39, - T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, T47 v47, - T48 v48) { - return internal::ValueArray48(v1, v2, v3, v4, v5, v6, v7, - v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, - v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, v36, - v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48); -} - -template -internal::ValueArray49 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, - T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, T14 v14, - T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, T22 v22, - T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, T30 v30, - T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, T38 v38, - T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, T46 v46, - T47 v47, T48 v48, T49 v49) { - return internal::ValueArray49(v1, v2, v3, v4, v5, v6, - v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, - v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, v34, v35, - v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, v48, v49); -} - -template -internal::ValueArray50 Values(T1 v1, T2 v2, T3 v3, T4 v4, - T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10, T11 v11, T12 v12, T13 v13, - T14 v14, T15 v15, T16 v16, T17 v17, T18 v18, T19 v19, T20 v20, T21 v21, - T22 v22, T23 v23, T24 v24, T25 v25, T26 v26, T27 v27, T28 v28, T29 v29, - T30 v30, T31 v31, T32 v32, T33 v33, T34 v34, T35 v35, T36 v36, T37 v37, - T38 v38, T39 v39, T40 v40, T41 v41, T42 v42, T43 v43, T44 v44, T45 v45, - T46 v46, T47 v47, T48 v48, T49 v49, T50 v50) { - return internal::ValueArray50(v1, v2, v3, v4, - v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, - v20, v21, v22, v23, v24, v25, v26, v27, v28, v29, v30, v31, v32, v33, - v34, v35, v36, v37, v38, v39, v40, v41, v42, v43, v44, v45, v46, v47, - v48, v49, v50); -} - -// Bool() allows generating tests with parameters in a set of (false, true). -// -// Synopsis: -// Bool() -// - returns a generator producing sequences with elements {false, true}. -// -// It is useful when testing code that depends on Boolean flags. Combinations -// of multiple flags can be tested when several Bool()'s are combined using -// Combine() function. -// -// In the following example all tests in the test case FlagDependentTest -// will be instantiated twice with parameters false and true. -// -// class FlagDependentTest : public testing::TestWithParam { -// virtual void SetUp() { -// external_flag = GetParam(); -// } -// } -// INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); -// -inline internal::ParamGenerator Bool() { - return Values(false, true); -} - -# if GTEST_HAS_COMBINE -// Combine() allows the user to combine two or more sequences to produce -// values of a Cartesian product of those sequences' elements. -// -// Synopsis: -// Combine(gen1, gen2, ..., genN) -// - returns a generator producing sequences with elements coming from -// the Cartesian product of elements from the sequences generated by -// gen1, gen2, ..., genN. The sequence elements will have a type of -// tuple where T1, T2, ..., TN are the types -// of elements from sequences produces by gen1, gen2, ..., genN. -// -// Combine can have up to 10 arguments. This number is currently limited -// by the maximum number of elements in the tuple implementation used by Google -// Test. -// -// Example: -// -// This will instantiate tests in test case AnimalTest each one with -// the parameter values tuple("cat", BLACK), tuple("cat", WHITE), -// tuple("dog", BLACK), and tuple("dog", WHITE): -// -// enum Color { BLACK, GRAY, WHITE }; -// class AnimalTest -// : public testing::TestWithParam > {...}; -// -// TEST_P(AnimalTest, AnimalLooksNice) {...} -// -// INSTANTIATE_TEST_CASE_P(AnimalVariations, AnimalTest, -// Combine(Values("cat", "dog"), -// Values(BLACK, WHITE))); -// -// This will instantiate tests in FlagDependentTest with all variations of two -// Boolean flags: -// -// class FlagDependentTest -// : public testing::TestWithParam > { -// virtual void SetUp() { -// // Assigns external_flag_1 and external_flag_2 values from the tuple. -// tie(external_flag_1, external_flag_2) = GetParam(); -// } -// }; -// -// TEST_P(FlagDependentTest, TestFeature1) { -// // Test your code using external_flag_1 and external_flag_2 here. -// } -// INSTANTIATE_TEST_CASE_P(TwoBoolSequence, FlagDependentTest, -// Combine(Bool(), Bool())); -// -template -internal::CartesianProductHolder2 Combine( - const Generator1& g1, const Generator2& g2) { - return internal::CartesianProductHolder2( - g1, g2); -} - -template -internal::CartesianProductHolder3 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3) { - return internal::CartesianProductHolder3( - g1, g2, g3); -} - -template -internal::CartesianProductHolder4 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4) { - return internal::CartesianProductHolder4( - g1, g2, g3, g4); -} - -template -internal::CartesianProductHolder5 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5) { - return internal::CartesianProductHolder5( - g1, g2, g3, g4, g5); -} - -template -internal::CartesianProductHolder6 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6) { - return internal::CartesianProductHolder6( - g1, g2, g3, g4, g5, g6); -} - -template -internal::CartesianProductHolder7 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7) { - return internal::CartesianProductHolder7( - g1, g2, g3, g4, g5, g6, g7); -} - -template -internal::CartesianProductHolder8 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8) { - return internal::CartesianProductHolder8( - g1, g2, g3, g4, g5, g6, g7, g8); -} - -template -internal::CartesianProductHolder9 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9) { - return internal::CartesianProductHolder9( - g1, g2, g3, g4, g5, g6, g7, g8, g9); -} - -template -internal::CartesianProductHolder10 Combine( - const Generator1& g1, const Generator2& g2, const Generator3& g3, - const Generator4& g4, const Generator5& g5, const Generator6& g6, - const Generator7& g7, const Generator8& g8, const Generator9& g9, - const Generator10& g10) { - return internal::CartesianProductHolder10( - g1, g2, g3, g4, g5, g6, g7, g8, g9, g10); -} -# endif // GTEST_HAS_COMBINE - - - -# define TEST_P(test_case_name, test_name) \ - class GTEST_TEST_CLASS_NAME_(test_case_name, test_name) \ - : public test_case_name { \ - public: \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)() {} \ - virtual void TestBody(); \ - private: \ - static int AddToRegistry() { \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestPattern(\ - #test_case_name, \ - #test_name, \ - new ::testing::internal::TestMetaFactory< \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)>()); \ - return 0; \ - } \ - static int gtest_registering_dummy_; \ - GTEST_DISALLOW_COPY_AND_ASSIGN_(\ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)); \ - }; \ - int GTEST_TEST_CLASS_NAME_(test_case_name, \ - test_name)::gtest_registering_dummy_ = \ - GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::AddToRegistry(); \ - void GTEST_TEST_CLASS_NAME_(test_case_name, test_name)::TestBody() - -# define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator) \ - ::testing::internal::ParamGenerator \ - gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ - int gtest_##prefix##test_case_name##_dummy_ = \ - ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ - GetTestCasePatternHolder(\ - #test_case_name, __FILE__, __LINE__)->AddTestCaseInstantiation(\ - #prefix, \ - >est_##prefix##test_case_name##_EvalGenerator_, \ - __FILE__, __LINE__) - -} // namespace testing - -#endif // GTEST_HAS_PARAM_TEST - -#endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ -// Copyright 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) -// -// Google C++ Testing Framework definitions useful in production code. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PROD_H_ - -// When you need to test the private or protected members of a class, -// use the FRIEND_TEST macro to declare your tests as friends of the -// class. For example: -// -// class MyClass { -// private: -// void MyMethod(); -// FRIEND_TEST(MyClassTest, MyMethod); -// }; -// -// class MyClassTest : public testing::Test { -// // ... -// }; -// -// TEST_F(MyClassTest, MyMethod) { -// // Can call MyClass::MyMethod() here. -// } - -#define FRIEND_TEST(test_case_name, test_name)\ -friend class test_case_name##_##test_name##_Test - -#endif // GTEST_INCLUDE_GTEST_GTEST_PROD_H_ -// Copyright 2008, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: mheule@google.com (Markus Heule) -// - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ - -#include -#include - -namespace testing { - -// A copyable object representing the result of a test part (i.e. an -// assertion or an explicit FAIL(), ADD_FAILURE(), or SUCCESS()). -// -// Don't inherit from TestPartResult as its destructor is not virtual. -class GTEST_API_ TestPartResult { - public: - // The possible outcomes of a test part (i.e. an assertion or an - // explicit SUCCEED(), FAIL(), or ADD_FAILURE()). - enum Type { - kSuccess, // Succeeded. - kNonFatalFailure, // Failed but the test can continue. - kFatalFailure // Failed and the test should be terminated. - }; - - // C'tor. TestPartResult does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestPartResult object. - TestPartResult(Type a_type, - const char* a_file_name, - int a_line_number, - const char* a_message) - : type_(a_type), - file_name_(a_file_name == NULL ? "" : a_file_name), - line_number_(a_line_number), - summary_(ExtractSummary(a_message)), - message_(a_message) { - } - - // Gets the outcome of the test part. - Type type() const { return type_; } - - // Gets the name of the source file where the test part took place, or - // NULL if it's unknown. - const char* file_name() const { - return file_name_.empty() ? NULL : file_name_.c_str(); - } - - // Gets the line in the source file where the test part took place, - // or -1 if it's unknown. - int line_number() const { return line_number_; } - - // Gets the summary of the failure message. - const char* summary() const { return summary_.c_str(); } - - // Gets the message associated with the test part. - const char* message() const { return message_.c_str(); } - - // Returns true iff the test part passed. - bool passed() const { return type_ == kSuccess; } - - // Returns true iff the test part failed. - bool failed() const { return type_ != kSuccess; } - - // Returns true iff the test part non-fatally failed. - bool nonfatally_failed() const { return type_ == kNonFatalFailure; } - - // Returns true iff the test part fatally failed. - bool fatally_failed() const { return type_ == kFatalFailure; } - - private: - Type type_; - - // Gets the summary of the failure message by omitting the stack - // trace in it. - static std::string ExtractSummary(const char* message); - - // The name of the source file where the test part took place, or - // "" if the source file is unknown. - std::string file_name_; - // The line in the source file where the test part took place, or -1 - // if the line number is unknown. - int line_number_; - std::string summary_; // The test failure summary. - std::string message_; // The test failure message. -}; - -// Prints a TestPartResult object. -std::ostream& operator<<(std::ostream& os, const TestPartResult& result); - -// An array of TestPartResult objects. -// -// Don't inherit from TestPartResultArray as its destructor is not -// virtual. -class GTEST_API_ TestPartResultArray { - public: - TestPartResultArray() {} - - // Appends the given TestPartResult to the array. - void Append(const TestPartResult& result); - - // Returns the TestPartResult at the given index (0-based). - const TestPartResult& GetTestPartResult(int index) const; - - // Returns the number of TestPartResult objects in the array. - int size() const; - - private: - std::vector array_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestPartResultArray); -}; - -// This interface knows how to report a test part result. -class TestPartResultReporterInterface { - public: - virtual ~TestPartResultReporterInterface() {} - - virtual void ReportTestPartResult(const TestPartResult& result) = 0; -}; - -namespace internal { - -// This helper class is used by {ASSERT|EXPECT}_NO_FATAL_FAILURE to check if a -// statement generates new fatal failures. To do so it registers itself as the -// current test part result reporter. Besides checking if fatal failures were -// reported, it only delegates the reporting to the former result reporter. -// The original result reporter is restored in the destructor. -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -class GTEST_API_ HasNewFatalFailureHelper - : public TestPartResultReporterInterface { - public: - HasNewFatalFailureHelper(); - virtual ~HasNewFatalFailureHelper(); - virtual void ReportTestPartResult(const TestPartResult& result); - bool has_new_fatal_failure() const { return has_new_fatal_failure_; } - private: - bool has_new_fatal_failure_; - TestPartResultReporterInterface* original_reporter_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(HasNewFatalFailureHelper); -}; - -} // namespace internal - -} // namespace testing - -#endif // GTEST_INCLUDE_GTEST_GTEST_TEST_PART_H_ -// Copyright 2008 Google Inc. -// All Rights Reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. -// -// Author: wan@google.com (Zhanyong Wan) - -#ifndef GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ -#define GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - -// This header implements typed tests and type-parameterized tests. - -// Typed (aka type-driven) tests repeat the same test for types in a -// list. You must know which types you want to test with when writing -// typed tests. Here's how you do it: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - public: - ... - typedef std::list List; - static T shared_; - T value_; -}; - -// Next, associate a list of types with the test case, which will be -// repeated for each type in the list. The typedef is necessary for -// the macro to parse correctly. -typedef testing::Types MyTypes; -TYPED_TEST_CASE(FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// TYPED_TEST_CASE(FooTest, int); - -// Then, use TYPED_TEST() instead of TEST_F() to define as many typed -// tests for this test case as you want. -TYPED_TEST(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - // Since we are inside a derived class template, C++ requires use to - // visit the members of FooTest via 'this'. - TypeParam n = this->value_; - - // To visit static members of the fixture, add the TestFixture:: - // prefix. - n += TestFixture::shared_; - - // To refer to typedefs in the fixture, add the "typename - // TestFixture::" prefix. - typename TestFixture::List values; - values.push_back(n); - ... -} - -TYPED_TEST(FooTest, HasPropertyA) { ... } - -#endif // 0 - -// Type-parameterized tests are abstract test patterns parameterized -// by a type. Compared with typed tests, type-parameterized tests -// allow you to define the test pattern without knowing what the type -// parameters are. The defined pattern can be instantiated with -// different types any number of times, in any number of translation -// units. -// -// If you are designing an interface or concept, you can define a -// suite of type-parameterized tests to verify properties that any -// valid implementation of the interface/concept should have. Then, -// each implementation can easily instantiate the test suite to verify -// that it conforms to the requirements, without having to write -// similar tests repeatedly. Here's an example: - -#if 0 - -// First, define a fixture class template. It should be parameterized -// by a type. Remember to derive it from testing::Test. -template -class FooTest : public testing::Test { - ... -}; - -// Next, declare that you will define a type-parameterized test case -// (the _P suffix is for "parameterized" or "pattern", whichever you -// prefer): -TYPED_TEST_CASE_P(FooTest); - -// Then, use TYPED_TEST_P() to define as many type-parameterized tests -// for this type-parameterized test case as you want. -TYPED_TEST_P(FooTest, DoesBlah) { - // Inside a test, refer to TypeParam to get the type parameter. - TypeParam n = 0; - ... -} - -TYPED_TEST_P(FooTest, HasPropertyA) { ... } - -// Now the tricky part: you need to register all test patterns before -// you can instantiate them. The first argument of the macro is the -// test case name; the rest are the names of the tests in this test -// case. -REGISTER_TYPED_TEST_CASE_P(FooTest, - DoesBlah, HasPropertyA); - -// Finally, you are free to instantiate the pattern with the types you -// want. If you put the above code in a header file, you can #include -// it in multiple C++ source files and instantiate it multiple times. -// -// To distinguish different instances of the pattern, the first -// argument to the INSTANTIATE_* macro is a prefix that will be added -// to the actual test case name. Remember to pick unique prefixes for -// different instances. -typedef testing::Types MyTypes; -INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); - -// If the type list contains only one type, you can write that type -// directly without Types<...>: -// INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); - -#endif // 0 - - -// Implements typed tests. - -#if GTEST_HAS_TYPED_TEST - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the typedef for the type parameters of the -// given test case. -# define GTEST_TYPE_PARAMS_(TestCaseName) gtest_type_params_##TestCaseName##_ - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define TYPED_TEST_CASE(CaseName, Types) \ - typedef ::testing::internal::TypeList< Types >::type \ - GTEST_TYPE_PARAMS_(CaseName) - -# define TYPED_TEST(CaseName, TestName) \ - template \ - class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ - : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTest< \ - CaseName, \ - ::testing::internal::TemplateSel< \ - GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ - GTEST_TYPE_PARAMS_(CaseName)>::Register(\ - "", #CaseName, #TestName, 0); \ - template \ - void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::TestBody() - -#endif // GTEST_HAS_TYPED_TEST - -// Implements type-parameterized tests. - -#if GTEST_HAS_TYPED_TEST_P - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the namespace name that the type-parameterized tests for -// the given type-parameterized test case are defined in. The exact -// name of the namespace is subject to change without notice. -# define GTEST_CASE_NAMESPACE_(TestCaseName) \ - gtest_case_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// -// Expands to the name of the variable used to remember the names of -// the defined tests in the given test case. -# define GTEST_TYPED_TEST_CASE_P_STATE_(TestCaseName) \ - gtest_typed_test_case_p_state_##TestCaseName##_ - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE DIRECTLY. -// -// Expands to the name of the variable used to remember the names of -// the registered tests in the given test case. -# define GTEST_REGISTERED_TEST_NAMES_(TestCaseName) \ - gtest_registered_test_names_##TestCaseName##_ - -// The variables defined in the type-parameterized test macros are -// static as typically these macros are used in a .h file that can be -// #included in multiple translation units linked together. -# define TYPED_TEST_CASE_P(CaseName) \ - static ::testing::internal::TypedTestCasePState \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName) - -# define TYPED_TEST_P(CaseName, TestName) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - template \ - class TestName : public CaseName { \ - private: \ - typedef CaseName TestFixture; \ - typedef gtest_TypeParam_ TypeParam; \ - virtual void TestBody(); \ - }; \ - static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ - __FILE__, __LINE__, #CaseName, #TestName); \ - } \ - template \ - void GTEST_CASE_NAMESPACE_(CaseName)::TestName::TestBody() - -# define REGISTER_TYPED_TEST_CASE_P(CaseName, ...) \ - namespace GTEST_CASE_NAMESPACE_(CaseName) { \ - typedef ::testing::internal::Templates<__VA_ARGS__>::type gtest_AllTests_; \ - } \ - static const char* const GTEST_REGISTERED_TEST_NAMES_(CaseName) = \ - GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).VerifyRegisteredTestNames(\ - __FILE__, __LINE__, #__VA_ARGS__) - -// The 'Types' template argument below must have spaces around it -// since some compilers may choke on '>>' when passing a template -// instance (e.g. Types) -# define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ - bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ - ::testing::internal::TypeParameterizedTestCase::type>::Register(\ - #Prefix, #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) - -#endif // GTEST_HAS_TYPED_TEST_P - -#endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ - -// Depending on the platform, different string classes are available. -// On Linux, in addition to ::std::string, Google also makes use of -// class ::string, which has the same interface as ::std::string, but -// has a different implementation. -// -// The user can define GTEST_HAS_GLOBAL_STRING to 1 to indicate that -// ::string is available AND is a distinct type to ::std::string, or -// define it to 0 to indicate otherwise. -// -// If the user's ::std::string and ::string are the same class due to -// aliasing, he should define GTEST_HAS_GLOBAL_STRING to 0. -// -// If the user doesn't define GTEST_HAS_GLOBAL_STRING, it is defined -// heuristically. - -namespace testing { - -// Declares the flags. - -// This flag temporary enables the disabled tests. -GTEST_DECLARE_bool_(also_run_disabled_tests); - -// This flag brings the debugger on an assertion failure. -GTEST_DECLARE_bool_(break_on_failure); - -// This flag controls whether Google Test catches all test-thrown exceptions -// and logs them as failures. -GTEST_DECLARE_bool_(catch_exceptions); - -// This flag enables using colors in terminal output. Available values are -// "yes" to enable colors, "no" (disable colors), or "auto" (the default) -// to let Google Test decide. -GTEST_DECLARE_string_(color); - -// This flag sets up the filter to select by name using a glob pattern -// the tests to run. If the filter is not given all tests are executed. -GTEST_DECLARE_string_(filter); - -// This flag causes the Google Test to list tests. None of the tests listed -// are actually run if the flag is provided. -GTEST_DECLARE_bool_(list_tests); - -// This flag controls whether Google Test emits a detailed XML report to a file -// in addition to its normal textual output. -GTEST_DECLARE_string_(output); - -// This flags control whether Google Test prints the elapsed time for each -// test. -GTEST_DECLARE_bool_(print_time); - -// This flag specifies the random number seed. -GTEST_DECLARE_int32_(random_seed); - -// This flag sets how many times the tests are repeated. The default value -// is 1. If the value is -1 the tests are repeating forever. -GTEST_DECLARE_int32_(repeat); - -// This flag controls whether Google Test includes Google Test internal -// stack frames in failure stack traces. -GTEST_DECLARE_bool_(show_internal_stack_frames); - -// When this flag is specified, tests' order is randomized on every iteration. -GTEST_DECLARE_bool_(shuffle); - -// This flag specifies the maximum number of stack frames to be -// printed in a failure message. -GTEST_DECLARE_int32_(stack_trace_depth); - -// When this flag is specified, a failed assertion will throw an -// exception if exceptions are enabled, or exit the program with a -// non-zero code otherwise. -GTEST_DECLARE_bool_(throw_on_failure); - -// When this flag is set with a "host:port" string, on supported -// platforms test results are streamed to the specified port on -// the specified host machine. -GTEST_DECLARE_string_(stream_result_to); - -// The upper limit for valid stack trace depths. -const int kMaxStackTraceDepth = 100; - -namespace internal { - -class AssertHelper; -class DefaultGlobalTestPartResultReporter; -class ExecDeathTest; -class NoExecDeathTest; -class FinalSuccessChecker; -class GTestFlagSaver; -class StreamingListenerTest; -class TestResultAccessor; -class TestEventListenersAccessor; -class TestEventRepeater; -class UnitTestRecordPropertyTestHelper; -class WindowsDeathTest; -class UnitTestImpl* GetUnitTestImpl(); -void ReportFailureInUnknownLocation(TestPartResult::Type result_type, - const std::string& message); - -} // namespace internal - -// The friend relationship of some of these classes is cyclic. -// If we don't forward declare them the compiler might confuse the classes -// in friendship clauses with same named classes on the scope. -class Test; -class TestCase; -class TestInfo; -class UnitTest; - -// A class for indicating whether an assertion was successful. When -// the assertion wasn't successful, the AssertionResult object -// remembers a non-empty message that describes how it failed. -// -// To create an instance of this class, use one of the factory functions -// (AssertionSuccess() and AssertionFailure()). -// -// This class is useful for two purposes: -// 1. Defining predicate functions to be used with Boolean test assertions -// EXPECT_TRUE/EXPECT_FALSE and their ASSERT_ counterparts -// 2. Defining predicate-format functions to be -// used with predicate assertions (ASSERT_PRED_FORMAT*, etc). -// -// For example, if you define IsEven predicate: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then the failed expectation EXPECT_TRUE(IsEven(Fib(5))) -// will print the message -// -// Value of: IsEven(Fib(5)) -// Actual: false (5 is odd) -// Expected: true -// -// instead of a more opaque -// -// Value of: IsEven(Fib(5)) -// Actual: false -// Expected: true -// -// in case IsEven is a simple Boolean predicate. -// -// If you expect your predicate to be reused and want to support informative -// messages in EXPECT_FALSE and ASSERT_FALSE (negative assertions show up -// about half as often as positive ones in our tests), supply messages for -// both success and failure cases: -// -// testing::AssertionResult IsEven(int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess() << n << " is even"; -// else -// return testing::AssertionFailure() << n << " is odd"; -// } -// -// Then a statement EXPECT_FALSE(IsEven(Fib(6))) will print -// -// Value of: IsEven(Fib(6)) -// Actual: true (8 is even) -// Expected: false -// -// NB: Predicates that support negative Boolean assertions have reduced -// performance in positive ones so be careful not to use them in tests -// that have lots (tens of thousands) of positive Boolean assertions. -// -// To use this class with EXPECT_PRED_FORMAT assertions such as: -// -// // Verifies that Foo() returns an even number. -// EXPECT_PRED_FORMAT1(IsEven, Foo()); -// -// you need to define: -// -// testing::AssertionResult IsEven(const char* expr, int n) { -// if ((n % 2) == 0) -// return testing::AssertionSuccess(); -// else -// return testing::AssertionFailure() -// << "Expected: " << expr << " is even\n Actual: it's " << n; -// } -// -// If Foo() returns 5, you will see the following message: -// -// Expected: Foo() is even -// Actual: it's 5 -// -class GTEST_API_ AssertionResult { - public: - // Copy constructor. - // Used in EXPECT_TRUE/FALSE(assertion_result). - AssertionResult(const AssertionResult& other); - // Used in the EXPECT_TRUE/FALSE(bool_expression). - explicit AssertionResult(bool success) : success_(success) {} - - // Returns true iff the assertion succeeded. - operator bool() const { return success_; } // NOLINT - - // Returns the assertion's negation. Used with EXPECT/ASSERT_FALSE. - AssertionResult operator!() const; - - // Returns the text streamed into this AssertionResult. Test assertions - // use it when they fail (i.e., the predicate's outcome doesn't match the - // assertion's expectation). When nothing has been streamed into the - // object, returns an empty string. - const char* message() const { - return message_.get() != NULL ? message_->c_str() : ""; - } - // TODO(vladl@google.com): Remove this after making sure no clients use it. - // Deprecated; please use message() instead. - const char* failure_message() const { return message(); } - - // Streams a custom failure message into this object. - template AssertionResult& operator<<(const T& value) { - AppendMessage(Message() << value); - return *this; - } - - // Allows streaming basic output manipulators such as endl or flush into - // this object. - AssertionResult& operator<<( - ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { - AppendMessage(Message() << basic_manipulator); - return *this; - } - - private: - // Appends the contents of message to message_. - void AppendMessage(const Message& a_message) { - if (message_.get() == NULL) - message_.reset(new ::std::string); - message_->append(a_message.GetString().c_str()); - } - - // Stores result of the assertion predicate. - bool success_; - // Stores the message describing the condition in case the expectation - // construct is not satisfied with the predicate's outcome. - // Referenced via a pointer to avoid taking too much stack frame space - // with test assertions. - internal::scoped_ptr< ::std::string> message_; - - GTEST_DISALLOW_ASSIGN_(AssertionResult); -}; - -// Makes a successful assertion result. -GTEST_API_ AssertionResult AssertionSuccess(); - -// Makes a failed assertion result. -GTEST_API_ AssertionResult AssertionFailure(); - -// Makes a failed assertion result with the given failure message. -// Deprecated; use AssertionFailure() << msg. -GTEST_API_ AssertionResult AssertionFailure(const Message& msg); - -// The abstract class that all tests inherit from. -// -// In Google Test, a unit test program contains one or many TestCases, and -// each TestCase contains one or many Tests. -// -// When you define a test using the TEST macro, you don't need to -// explicitly derive from Test - the TEST macro automatically does -// this for you. -// -// The only time you derive from Test is when defining a test fixture -// to be used a TEST_F. For example: -// -// class FooTest : public testing::Test { -// protected: -// virtual void SetUp() { ... } -// virtual void TearDown() { ... } -// ... -// }; -// -// TEST_F(FooTest, Bar) { ... } -// TEST_F(FooTest, Baz) { ... } -// -// Test is not copyable. -class GTEST_API_ Test { - public: - friend class TestInfo; - - // Defines types for pointers to functions that set up and tear down - // a test case. - typedef internal::SetUpTestCaseFunc SetUpTestCaseFunc; - typedef internal::TearDownTestCaseFunc TearDownTestCaseFunc; - - // The d'tor is virtual as we intend to inherit from Test. - virtual ~Test(); - - // Sets up the stuff shared by all tests in this test case. - // - // Google Test will call Foo::SetUpTestCase() before running the first - // test in test case Foo. Hence a sub-class can define its own - // SetUpTestCase() method to shadow the one defined in the super - // class. - static void SetUpTestCase() {} - - // Tears down the stuff shared by all tests in this test case. - // - // Google Test will call Foo::TearDownTestCase() after running the last - // test in test case Foo. Hence a sub-class can define its own - // TearDownTestCase() method to shadow the one defined in the super - // class. - static void TearDownTestCase() {} - - // Returns true iff the current test has a fatal failure. - static bool HasFatalFailure(); - - // Returns true iff the current test has a non-fatal failure. - static bool HasNonfatalFailure(); - - // Returns true iff the current test has a (either fatal or - // non-fatal) failure. - static bool HasFailure() { return HasFatalFailure() || HasNonfatalFailure(); } - - // Logs a property for the current test, test case, or for the entire - // invocation of the test program when used outside of the context of a - // test case. Only the last value for a given key is remembered. These - // are public static so they can be called from utility functions that are - // not members of the test fixture. Calls to RecordProperty made during - // lifespan of the test (from the moment its constructor starts to the - // moment its destructor finishes) will be output in XML as attributes of - // the element. Properties recorded from fixture's - // SetUpTestCase or TearDownTestCase are logged as attributes of the - // corresponding element. Calls to RecordProperty made in the - // global context (before or after invocation of RUN_ALL_TESTS and from - // SetUp/TearDown method of Environment objects registered with Google - // Test) will be output as attributes of the element. - static void RecordProperty(const std::string& key, const std::string& value); - static void RecordProperty(const std::string& key, int value); - - protected: - // Creates a Test object. - Test(); - - // Sets up the test fixture. - virtual void SetUp(); - - // Tears down the test fixture. - virtual void TearDown(); - - private: - // Returns true iff the current test has the same fixture class as - // the first test in the current test case. - static bool HasSameFixtureClass(); - - // Runs the test after the test fixture has been set up. - // - // A sub-class must implement this to define the test logic. - // - // DO NOT OVERRIDE THIS FUNCTION DIRECTLY IN A USER PROGRAM. - // Instead, use the TEST or TEST_F macro. - virtual void TestBody() = 0; - - // Sets up, executes, and tears down the test. - void Run(); - - // Deletes self. We deliberately pick an unusual name for this - // internal method to avoid clashing with names used in user TESTs. - void DeleteSelf_() { delete this; } - - // Uses a GTestFlagSaver to save and restore all Google Test flags. - const internal::GTestFlagSaver* const gtest_flag_saver_; - - // Often a user mis-spells SetUp() as Setup() and spends a long time - // wondering why it is never called by Google Test. The declaration of - // the following method is solely for catching such an error at - // compile time: - // - // - The return type is deliberately chosen to be not void, so it - // will be a conflict if a user declares void Setup() in his test - // fixture. - // - // - This method is private, so it will be another compiler error - // if a user calls it from his test fixture. - // - // DO NOT OVERRIDE THIS FUNCTION. - // - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } - - // We disallow copying Tests. - GTEST_DISALLOW_COPY_AND_ASSIGN_(Test); -}; - -typedef internal::TimeInMillis TimeInMillis; - -// A copyable object representing a user specified test property which can be -// output as a key/value string pair. -// -// Don't inherit from TestProperty as its destructor is not virtual. -class TestProperty { - public: - // C'tor. TestProperty does NOT have a default constructor. - // Always use this constructor (with parameters) to create a - // TestProperty object. - TestProperty(const std::string& a_key, const std::string& a_value) : - key_(a_key), value_(a_value) { - } - - // Gets the user supplied key. - const char* key() const { - return key_.c_str(); - } - - // Gets the user supplied value. - const char* value() const { - return value_.c_str(); - } - - // Sets a new value, overriding the one supplied in the constructor. - void SetValue(const std::string& new_value) { - value_ = new_value; - } - - private: - // The key supplied by the user. - std::string key_; - // The value supplied by the user. - std::string value_; -}; - -// The result of a single Test. This includes a list of -// TestPartResults, a list of TestProperties, a count of how many -// death tests there are in the Test, and how much time it took to run -// the Test. -// -// TestResult is not copyable. -class GTEST_API_ TestResult { - public: - // Creates an empty TestResult. - TestResult(); - - // D'tor. Do not inherit from TestResult. - ~TestResult(); - - // Gets the number of all test parts. This is the sum of the number - // of successful test parts and the number of failed test parts. - int total_part_count() const; - - // Returns the number of the test properties. - int test_property_count() const; - - // Returns true iff the test passed (i.e. no test part failed). - bool Passed() const { return !Failed(); } - - // Returns true iff the test failed. - bool Failed() const; - - // Returns true iff the test fatally failed. - bool HasFatalFailure() const; - - // Returns true iff the test has a non-fatal failure. - bool HasNonfatalFailure() const; - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test part result among all the results. i can range - // from 0 to test_property_count() - 1. If i is not in that range, aborts - // the program. - const TestPartResult& GetTestPartResult(int i) const; - - // Returns the i-th test property. i can range from 0 to - // test_property_count() - 1. If i is not in that range, aborts the - // program. - const TestProperty& GetTestProperty(int i) const; - - private: - friend class TestInfo; - friend class TestCase; - friend class UnitTest; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::ExecDeathTest; - friend class internal::TestResultAccessor; - friend class internal::UnitTestImpl; - friend class internal::WindowsDeathTest; - - // Gets the vector of TestPartResults. - const std::vector& test_part_results() const { - return test_part_results_; - } - - // Gets the vector of TestProperties. - const std::vector& test_properties() const { - return test_properties_; - } - - // Sets the elapsed time. - void set_elapsed_time(TimeInMillis elapsed) { elapsed_time_ = elapsed; } - - // Adds a test property to the list. The property is validated and may add - // a non-fatal failure if invalid (e.g., if it conflicts with reserved - // key names). If a property is already recorded for the same key, the - // value will be updated, rather than storing multiple values for the same - // key. xml_element specifies the element for which the property is being - // recorded and is used for validation. - void RecordProperty(const std::string& xml_element, - const TestProperty& test_property); - - // Adds a failure if the key is a reserved attribute of Google Test - // testcase tags. Returns true if the property is valid. - // TODO(russr): Validate attribute names are legal and human readable. - static bool ValidateTestProperty(const std::string& xml_element, - const TestProperty& test_property); - - // Adds a test part result to the list. - void AddTestPartResult(const TestPartResult& test_part_result); - - // Returns the death test count. - int death_test_count() const { return death_test_count_; } - - // Increments the death test count, returning the new count. - int increment_death_test_count() { return ++death_test_count_; } - - // Clears the test part results. - void ClearTestPartResults(); - - // Clears the object. - void Clear(); - - // Protects mutable state of the property vector and of owned - // properties, whose values may be updated. - internal::Mutex test_properites_mutex_; - - // The vector of TestPartResults - std::vector test_part_results_; - // The vector of TestProperties - std::vector test_properties_; - // Running count of death tests. - int death_test_count_; - // The elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - - // We disallow copying TestResult. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestResult); -}; // class TestResult - -// A TestInfo object stores the following information about a test: -// -// Test case name -// Test name -// Whether the test should be run -// A function pointer that creates the test object when invoked -// Test result -// -// The constructor of TestInfo registers itself with the UnitTest -// singleton such that the RUN_ALL_TESTS() macro knows which tests to -// run. -class GTEST_API_ TestInfo { - public: - // Destructs a TestInfo object. This function is not virtual, so - // don't inherit from TestInfo. - ~TestInfo(); - - // Returns the test case name. - const char* test_case_name() const { return test_case_name_.c_str(); } - - // Returns the test name. - const char* name() const { return name_.c_str(); } - - // Returns the name of the parameter type, or NULL if this is not a typed - // or a type-parameterized test. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; - } - - // Returns the text representation of the value parameter, or NULL if this - // is not a value-parameterized test. - const char* value_param() const { - if (value_param_.get() != NULL) - return value_param_->c_str(); - return NULL; - } - - // Returns true if this test should run, that is if the test is not - // disabled (or it is disabled but the also_run_disabled_tests flag has - // been specified) and its full name matches the user-specified filter. - // - // Google Test allows the user to filter the tests by their full names. - // The full name of a test Bar in test case Foo is defined as - // "Foo.Bar". Only the tests that match the filter will run. - // - // A filter is a colon-separated list of glob (not regex) patterns, - // optionally followed by a '-' and a colon-separated list of - // negative patterns (tests to exclude). A test is run if it - // matches one of the positive patterns and does not match any of - // the negative patterns. - // - // For example, *A*:Foo.* is a filter that matches any string that - // contains the character 'A' or starts with "Foo.". - bool should_run() const { return should_run_; } - - // Returns true iff this test will appear in the XML report. - bool is_reportable() const { - // For now, the XML report includes all tests matching the filter. - // In the future, we may trim tests that are excluded because of - // sharding. - return matches_filter_; - } - - // Returns the result of the test. - const TestResult* result() const { return &result_; } - - private: -#if GTEST_HAS_DEATH_TEST - friend class internal::DefaultDeathTestFactory; -#endif // GTEST_HAS_DEATH_TEST - friend class Test; - friend class TestCase; - friend class internal::UnitTestImpl; - friend class internal::StreamingListenerTest; - friend TestInfo* internal::MakeAndRegisterTestInfo( - const char* test_case_name, - const char* name, - const char* type_param, - const char* value_param, - internal::TypeId fixture_class_id, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc, - internal::TestFactoryBase* factory); - - // Constructs a TestInfo object. The newly constructed instance assumes - // ownership of the factory object. - TestInfo(const std::string& test_case_name, - const std::string& name, - const char* a_type_param, // NULL if not a type-parameterized test - const char* a_value_param, // NULL if not a value-parameterized test - internal::TypeId fixture_class_id, - internal::TestFactoryBase* factory); - - // Increments the number of death tests encountered in this test so - // far. - int increment_death_test_count() { - return result_.increment_death_test_count(); - } - - // Creates the test object, runs it, records its result, and then - // deletes it. - void Run(); - - static void ClearTestResult(TestInfo* test_info) { - test_info->result_.Clear(); - } - - // These fields are immutable properties of the test. - const std::string test_case_name_; // Test case name - const std::string name_; // Test name - // Name of the parameter type, or NULL if this is not a typed or a - // type-parameterized test. - const internal::scoped_ptr type_param_; - // Text representation of the value parameter, or NULL if this is not a - // value-parameterized test. - const internal::scoped_ptr value_param_; - const internal::TypeId fixture_class_id_; // ID of the test fixture class - bool should_run_; // True iff this test should run - bool is_disabled_; // True iff this test is disabled - bool matches_filter_; // True if this test matches the - // user-specified filter. - internal::TestFactoryBase* const factory_; // The factory that creates - // the test object - - // This field is mutable and needs to be reset before running the - // test for the second time. - TestResult result_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo); -}; - -// A test case, which consists of a vector of TestInfos. -// -// TestCase is not copyable. -class GTEST_API_ TestCase { - public: - // Creates a TestCase with the given name. - // - // TestCase does NOT have a default constructor. Always use this - // constructor to create a TestCase object. - // - // Arguments: - // - // name: name of the test case - // a_type_param: the name of the test's type parameter, or NULL if - // this is not a type-parameterized test. - // set_up_tc: pointer to the function that sets up the test case - // tear_down_tc: pointer to the function that tears down the test case - TestCase(const char* name, const char* a_type_param, - Test::SetUpTestCaseFunc set_up_tc, - Test::TearDownTestCaseFunc tear_down_tc); - - // Destructor of TestCase. - virtual ~TestCase(); - - // Gets the name of the TestCase. - const char* name() const { return name_.c_str(); } - - // Returns the name of the parameter type, or NULL if this is not a - // type-parameterized test case. - const char* type_param() const { - if (type_param_.get() != NULL) - return type_param_->c_str(); - return NULL; - } - - // Returns true if any test in this test case should run. - bool should_run() const { return should_run_; } - - // Gets the number of successful tests in this test case. - int successful_test_count() const; - - // Gets the number of failed tests in this test case. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests in this test case. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Get the number of tests in this test case that should run. - int test_to_run_count() const; - - // Gets the number of all tests in this test case. - int total_test_count() const; - - // Returns true iff the test case passed. - bool Passed() const { return !Failed(); } - - // Returns true iff the test case failed. - bool Failed() const { return failed_test_count() > 0; } - - // Returns the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const { return elapsed_time_; } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - const TestInfo* GetTestInfo(int i) const; - - // Returns the TestResult that holds test properties recorded during - // execution of SetUpTestCase and TearDownTestCase. - const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } - - private: - friend class Test; - friend class internal::UnitTestImpl; - - // Gets the (mutable) vector of TestInfos in this TestCase. - std::vector& test_info_list() { return test_info_list_; } - - // Gets the (immutable) vector of TestInfos in this TestCase. - const std::vector& test_info_list() const { - return test_info_list_; - } - - // Returns the i-th test among all the tests. i can range from 0 to - // total_test_count() - 1. If i is not in that range, returns NULL. - TestInfo* GetMutableTestInfo(int i); - - // Sets the should_run member. - void set_should_run(bool should) { should_run_ = should; } - - // Adds a TestInfo to this test case. Will delete the TestInfo upon - // destruction of the TestCase object. - void AddTestInfo(TestInfo * test_info); - - // Clears the results of all tests in this test case. - void ClearResult(); - - // Clears the results of all tests in the given test case. - static void ClearTestCaseResult(TestCase* test_case) { - test_case->ClearResult(); - } - - // Runs every test in this TestCase. - void Run(); - - // Runs SetUpTestCase() for this TestCase. This wrapper is needed - // for catching exceptions thrown from SetUpTestCase(). - void RunSetUpTestCase() { (*set_up_tc_)(); } - - // Runs TearDownTestCase() for this TestCase. This wrapper is - // needed for catching exceptions thrown from TearDownTestCase(). - void RunTearDownTestCase() { (*tear_down_tc_)(); } - - // Returns true iff test passed. - static bool TestPassed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Passed(); - } - - // Returns true iff test failed. - static bool TestFailed(const TestInfo* test_info) { - return test_info->should_run() && test_info->result()->Failed(); - } - - // Returns true iff the test is disabled and will be reported in the XML - // report. - static bool TestReportableDisabled(const TestInfo* test_info) { - return test_info->is_reportable() && test_info->is_disabled_; - } - - // Returns true iff test is disabled. - static bool TestDisabled(const TestInfo* test_info) { - return test_info->is_disabled_; - } - - // Returns true iff this test will appear in the XML report. - static bool TestReportable(const TestInfo* test_info) { - return test_info->is_reportable(); - } - - // Returns true if the given test should run. - static bool ShouldRunTest(const TestInfo* test_info) { - return test_info->should_run(); - } - - // Shuffles the tests in this test case. - void ShuffleTests(internal::Random* random); - - // Restores the test order to before the first shuffle. - void UnshuffleTests(); - - // Name of the test case. - std::string name_; - // Name of the parameter type, or NULL if this is not a typed or a - // type-parameterized test. - const internal::scoped_ptr type_param_; - // The vector of TestInfos in their original order. It owns the - // elements in the vector. - std::vector test_info_list_; - // Provides a level of indirection for the test list to allow easy - // shuffling and restoring the test order. The i-th element in this - // vector is the index of the i-th test in the shuffled test list. - std::vector test_indices_; - // Pointer to the function that sets up the test case. - Test::SetUpTestCaseFunc set_up_tc_; - // Pointer to the function that tears down the test case. - Test::TearDownTestCaseFunc tear_down_tc_; - // True iff any test in this test case should run. - bool should_run_; - // Elapsed time, in milliseconds. - TimeInMillis elapsed_time_; - // Holds test properties recorded during execution of SetUpTestCase and - // TearDownTestCase. - TestResult ad_hoc_test_result_; - - // We disallow copying TestCases. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); -}; - -// An Environment object is capable of setting up and tearing down an -// environment. The user should subclass this to define his own -// environment(s). -// -// An Environment object does the set-up and tear-down in virtual -// methods SetUp() and TearDown() instead of the constructor and the -// destructor, as: -// -// 1. You cannot safely throw from a destructor. This is a problem -// as in some cases Google Test is used where exceptions are enabled, and -// we may want to implement ASSERT_* using exceptions where they are -// available. -// 2. You cannot use ASSERT_* directly in a constructor or -// destructor. -class Environment { - public: - // The d'tor is virtual as we need to subclass Environment. - virtual ~Environment() {} - - // Override this to define how to set up the environment. - virtual void SetUp() {} - - // Override this to define how to tear down the environment. - virtual void TearDown() {} - private: - // If you see an error about overriding the following function or - // about it being private, you have mis-spelled SetUp() as Setup(). - struct Setup_should_be_spelled_SetUp {}; - virtual Setup_should_be_spelled_SetUp* Setup() { return NULL; } -}; - -// The interface for tracing execution of tests. The methods are organized in -// the order the corresponding events are fired. -class TestEventListener { - public: - virtual ~TestEventListener() {} - - // Fired before any test activity starts. - virtual void OnTestProgramStart(const UnitTest& unit_test) = 0; - - // Fired before each iteration of tests starts. There may be more than - // one iteration if GTEST_FLAG(repeat) is set. iteration is the iteration - // index, starting from 0. - virtual void OnTestIterationStart(const UnitTest& unit_test, - int iteration) = 0; - - // Fired before environment set-up for each iteration of tests starts. - virtual void OnEnvironmentsSetUpStart(const UnitTest& unit_test) = 0; - - // Fired after environment set-up for each iteration of tests ends. - virtual void OnEnvironmentsSetUpEnd(const UnitTest& unit_test) = 0; - - // Fired before the test case starts. - virtual void OnTestCaseStart(const TestCase& test_case) = 0; - - // Fired before the test starts. - virtual void OnTestStart(const TestInfo& test_info) = 0; - - // Fired after a failed assertion or a SUCCEED() invocation. - virtual void OnTestPartResult(const TestPartResult& test_part_result) = 0; - - // Fired after the test ends. - virtual void OnTestEnd(const TestInfo& test_info) = 0; - - // Fired after the test case ends. - virtual void OnTestCaseEnd(const TestCase& test_case) = 0; - - // Fired before environment tear-down for each iteration of tests starts. - virtual void OnEnvironmentsTearDownStart(const UnitTest& unit_test) = 0; - - // Fired after environment tear-down for each iteration of tests ends. - virtual void OnEnvironmentsTearDownEnd(const UnitTest& unit_test) = 0; - - // Fired after each iteration of tests finishes. - virtual void OnTestIterationEnd(const UnitTest& unit_test, - int iteration) = 0; - - // Fired after all test activities have ended. - virtual void OnTestProgramEnd(const UnitTest& unit_test) = 0; -}; - -// The convenience class for users who need to override just one or two -// methods and are not concerned that a possible change to a signature of -// the methods they override will not be caught during the build. For -// comments about each method please see the definition of TestEventListener -// above. -class EmptyTestEventListener : public TestEventListener { - public: - virtual void OnTestProgramStart(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationStart(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnEnvironmentsSetUpStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsSetUpEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestCaseStart(const TestCase& /*test_case*/) {} - virtual void OnTestStart(const TestInfo& /*test_info*/) {} - virtual void OnTestPartResult(const TestPartResult& /*test_part_result*/) {} - virtual void OnTestEnd(const TestInfo& /*test_info*/) {} - virtual void OnTestCaseEnd(const TestCase& /*test_case*/) {} - virtual void OnEnvironmentsTearDownStart(const UnitTest& /*unit_test*/) {} - virtual void OnEnvironmentsTearDownEnd(const UnitTest& /*unit_test*/) {} - virtual void OnTestIterationEnd(const UnitTest& /*unit_test*/, - int /*iteration*/) {} - virtual void OnTestProgramEnd(const UnitTest& /*unit_test*/) {} -}; - -// TestEventListeners lets users add listeners to track events in Google Test. -class GTEST_API_ TestEventListeners { - public: - TestEventListeners(); - ~TestEventListeners(); - - // Appends an event listener to the end of the list. Google Test assumes - // the ownership of the listener (i.e. it will delete the listener when - // the test program finishes). - void Append(TestEventListener* listener); - - // Removes the given event listener from the list and returns it. It then - // becomes the caller's responsibility to delete the listener. Returns - // NULL if the listener is not found in the list. - TestEventListener* Release(TestEventListener* listener); - - // Returns the standard listener responsible for the default console - // output. Can be removed from the listeners list to shut down default - // console output. Note that removing this object from the listener list - // with Release transfers its ownership to the caller and makes this - // function return NULL the next time. - TestEventListener* default_result_printer() const { - return default_result_printer_; - } - - // Returns the standard listener responsible for the default XML output - // controlled by the --gtest_output=xml flag. Can be removed from the - // listeners list by users who want to shut down the default XML output - // controlled by this flag and substitute it with custom one. Note that - // removing this object from the listener list with Release transfers its - // ownership to the caller and makes this function return NULL the next - // time. - TestEventListener* default_xml_generator() const { - return default_xml_generator_; - } - - private: - friend class TestCase; - friend class TestInfo; - friend class internal::DefaultGlobalTestPartResultReporter; - friend class internal::NoExecDeathTest; - friend class internal::TestEventListenersAccessor; - friend class internal::UnitTestImpl; - - // Returns repeater that broadcasts the TestEventListener events to all - // subscribers. - TestEventListener* repeater(); - - // Sets the default_result_printer attribute to the provided listener. - // The listener is also added to the listener list and previous - // default_result_printer is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultResultPrinter(TestEventListener* listener); - - // Sets the default_xml_generator attribute to the provided listener. The - // listener is also added to the listener list and previous - // default_xml_generator is removed from it and deleted. The listener can - // also be NULL in which case it will not be added to the list. Does - // nothing if the previous and the current listener objects are the same. - void SetDefaultXmlGenerator(TestEventListener* listener); - - // Controls whether events will be forwarded by the repeater to the - // listeners in the list. - bool EventForwardingEnabled() const; - void SuppressEventForwarding(); - - // The actual list of listeners. - internal::TestEventRepeater* repeater_; - // Listener responsible for the standard result output. - TestEventListener* default_result_printer_; - // Listener responsible for the creation of the XML output file. - TestEventListener* default_xml_generator_; - - // We disallow copying TestEventListeners. - GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventListeners); -}; - -// A UnitTest consists of a vector of TestCases. -// -// This is a singleton class. The only instance of UnitTest is -// created when UnitTest::GetInstance() is first called. This -// instance is never deleted. -// -// UnitTest is not copyable. -// -// This class is thread-safe as long as the methods are called -// according to their specification. -class GTEST_API_ UnitTest { - public: - // Gets the singleton UnitTest object. The first time this method - // is called, a UnitTest object is constructed and returned. - // Consecutive calls will return the same object. - static UnitTest* GetInstance(); - - // Runs all tests in this UnitTest object and prints the result. - // Returns 0 if successful, or 1 otherwise. - // - // This method can only be called from the main thread. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - int Run() GTEST_MUST_USE_RESULT_; - - // Returns the working directory when the first TEST() or TEST_F() - // was executed. The UnitTest object owns the string. - const char* original_working_dir() const; - - // Returns the TestCase object for the test that's currently running, - // or NULL if no test is running. - const TestCase* current_test_case() const - GTEST_LOCK_EXCLUDED_(mutex_); - - // Returns the TestInfo object for the test that's currently running, - // or NULL if no test is running. - const TestInfo* current_test_info() const - GTEST_LOCK_EXCLUDED_(mutex_); - - // Returns the random seed used at the start of the current test run. - int random_seed() const; - -#if GTEST_HAS_PARAM_TEST - // Returns the ParameterizedTestCaseRegistry object used to keep track of - // value-parameterized tests and instantiate and register them. - // - // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - internal::ParameterizedTestCaseRegistry& parameterized_test_registry() - GTEST_LOCK_EXCLUDED_(mutex_); -#endif // GTEST_HAS_PARAM_TEST - - // Gets the number of successful test cases. - int successful_test_case_count() const; - - // Gets the number of failed test cases. - int failed_test_case_count() const; - - // Gets the number of all test cases. - int total_test_case_count() const; - - // Gets the number of all test cases that contain at least one test - // that should run. - int test_case_to_run_count() const; - - // Gets the number of successful tests. - int successful_test_count() const; - - // Gets the number of failed tests. - int failed_test_count() const; - - // Gets the number of disabled tests that will be reported in the XML report. - int reportable_disabled_test_count() const; - - // Gets the number of disabled tests. - int disabled_test_count() const; - - // Gets the number of tests to be printed in the XML report. - int reportable_test_count() const; - - // Gets the number of all tests. - int total_test_count() const; - - // Gets the number of tests that should run. - int test_to_run_count() const; - - // Gets the time of the test program start, in ms from the start of the - // UNIX epoch. - TimeInMillis start_timestamp() const; - - // Gets the elapsed time, in milliseconds. - TimeInMillis elapsed_time() const; - - // Returns true iff the unit test passed (i.e. all test cases passed). - bool Passed() const; - - // Returns true iff the unit test failed (i.e. some test case failed - // or something outside of all tests failed). - bool Failed() const; - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - const TestCase* GetTestCase(int i) const; - - // Returns the TestResult containing information on test failures and - // properties logged outside of individual test cases. - const TestResult& ad_hoc_test_result() const; - - // Returns the list of event listeners that can be used to track events - // inside Google Test. - TestEventListeners& listeners(); - - private: - // Registers and returns a global test environment. When a test - // program is run, all global test environments will be set-up in - // the order they were registered. After all tests in the program - // have finished, all global test environments will be torn-down in - // the *reverse* order they were registered. - // - // The UnitTest object takes ownership of the given environment. - // - // This method can only be called from the main thread. - Environment* AddEnvironment(Environment* env); - - // Adds a TestPartResult to the current TestResult object. All - // Google Test assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) - // eventually call this to report their results. The user code - // should use the assertion macros instead of calling this directly. - void AddTestPartResult(TestPartResult::Type result_type, - const char* file_name, - int line_number, - const std::string& message, - const std::string& os_stack_trace) - GTEST_LOCK_EXCLUDED_(mutex_); - - // Adds a TestProperty to the current TestResult object when invoked from - // inside a test, to current TestCase's ad_hoc_test_result_ when invoked - // from SetUpTestCase or TearDownTestCase, or to the global property set - // when invoked elsewhere. If the result already contains a property with - // the same key, the value will be updated. - void RecordProperty(const std::string& key, const std::string& value); - - // Gets the i-th test case among all the test cases. i can range from 0 to - // total_test_case_count() - 1. If i is not in that range, returns NULL. - TestCase* GetMutableTestCase(int i); - - // Accessors for the implementation object. - internal::UnitTestImpl* impl() { return impl_; } - const internal::UnitTestImpl* impl() const { return impl_; } - - // These classes and funcions are friends as they need to access private - // members of UnitTest. - friend class Test; - friend class internal::AssertHelper; - friend class internal::ScopedTrace; - friend class internal::StreamingListenerTest; - friend class internal::UnitTestRecordPropertyTestHelper; - friend Environment* AddGlobalTestEnvironment(Environment* env); - friend internal::UnitTestImpl* internal::GetUnitTestImpl(); - friend void internal::ReportFailureInUnknownLocation( - TestPartResult::Type result_type, - const std::string& message); - - // Creates an empty UnitTest. - UnitTest(); - - // D'tor - virtual ~UnitTest(); - - // Pushes a trace defined by SCOPED_TRACE() on to the per-thread - // Google Test trace stack. - void PushGTestTrace(const internal::TraceInfo& trace) - GTEST_LOCK_EXCLUDED_(mutex_); - - // Pops a trace from the per-thread Google Test trace stack. - void PopGTestTrace() - GTEST_LOCK_EXCLUDED_(mutex_); - - // Protects mutable state in *impl_. This is mutable as some const - // methods need to lock it too. - mutable internal::Mutex mutex_; - - // Opaque implementation object. This field is never changed once - // the object is constructed. We don't mark it as const here, as - // doing so will cause a warning in the constructor of UnitTest. - // Mutable state in *impl_ is protected by mutex_. - internal::UnitTestImpl* impl_; - - // We disallow copying UnitTest. - GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTest); -}; - -// A convenient wrapper for adding an environment for the test -// program. -// -// You should call this before RUN_ALL_TESTS() is called, probably in -// main(). If you use gtest_main, you need to call this before main() -// starts for it to take effect. For example, you can define a global -// variable like this: -// -// testing::Environment* const foo_env = -// testing::AddGlobalTestEnvironment(new FooEnvironment); -// -// However, we strongly recommend you to write your own main() and -// call AddGlobalTestEnvironment() there, as relying on initialization -// of global variables makes the code harder to read and may cause -// problems when you register multiple environments from different -// translation units and the environments have dependencies among them -// (remember that the compiler doesn't guarantee the order in which -// global variables from different translation units are initialized). -inline Environment* AddGlobalTestEnvironment(Environment* env) { - return UnitTest::GetInstance()->AddEnvironment(env); -} - -// Initializes Google Test. This must be called before calling -// RUN_ALL_TESTS(). In particular, it parses a command line for the -// flags that Google Test recognizes. Whenever a Google Test flag is -// seen, it is removed from argv, and *argc is decremented. -// -// No value is returned. Instead, the Google Test flag variables are -// updated. -// -// Calling the function for the second time has no user-visible effect. -GTEST_API_ void InitGoogleTest(int* argc, char** argv); - -// This overloaded version can be used in Windows programs compiled in -// UNICODE mode. -GTEST_API_ void InitGoogleTest(int* argc, wchar_t** argv); - -namespace internal { - -// FormatForComparison::Format(value) formats a -// value of type ToPrint that is an operand of a comparison assertion -// (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in -// the comparison, and is used to help determine the best way to -// format the value. In particular, when the value is a C string -// (char pointer) and the other operand is an STL string object, we -// want to format the C string as a string, since we know it is -// compared by value with the string object. If the value is a char -// pointer but the other operand is not an STL string object, we don't -// know whether the pointer is supposed to point to a NUL-terminated -// string, and thus want to print it as a pointer to be safe. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// The default case. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint& value) { - return ::testing::PrintToString(value); - } -}; - -// Array. -template -class FormatForComparison { - public: - static ::std::string Format(const ToPrint* value) { - return FormatForComparison::Format(value); - } -}; - -// By default, print C string as pointers to be safe, as we don't know -// whether they actually point to a NUL-terminated string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ - template \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(static_cast(value)); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); -GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ - -// If a C string is compared with an STL string object, we know it's meant -// to point to a NUL-terminated string, and thus can print it as a string. - -#define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ - template <> \ - class FormatForComparison { \ - public: \ - static ::std::string Format(CharType* value) { \ - return ::testing::PrintToString(value); \ - } \ - } - -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); - -#if GTEST_HAS_GLOBAL_STRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); -#endif - -#if GTEST_HAS_GLOBAL_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); -#endif - -#if GTEST_HAS_STD_WSTRING -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); -GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); -#endif - -#undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ - -// Formats a comparison assertion (e.g. ASSERT_EQ, EXPECT_LT, and etc) -// operand to be used in a failure message. The type (but not value) -// of the other operand may affect the format. This allows us to -// print a char* as a raw pointer when it is compared against another -// char* or void*, and print it as a C string when it is compared -// against an std::string object, for example. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -std::string FormatForComparisonFailureMessage( - const T1& value, const T2& /* other_operand */) { - return FormatForComparison::Format(value); -} - -// The helper function for {ASSERT|EXPECT}_EQ. -template -AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { -#ifdef _MSC_VER -# pragma warning(push) // Saves the current warning state. -# pragma warning(disable:4389) // Temporarily disables warning on - // signed/unsigned mismatch. -#endif - - if (expected == actual) { - return AssertionSuccess(); - } - -#ifdef _MSC_VER -# pragma warning(pop) // Restores the warning state. -#endif - - return EqFailure(expected_expression, - actual_expression, - FormatForComparisonFailureMessage(expected, actual), - FormatForComparisonFailureMessage(actual, expected), - false); -} - -// With this overloaded version, we allow anonymous enums to be used -// in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous enums -// can be implicitly cast to BiggestInt. -GTEST_API_ AssertionResult CmpHelperEQ(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual); - -// The helper class for {ASSERT|EXPECT}_EQ. The template argument -// lhs_is_null_literal is true iff the first argument to ASSERT_EQ() -// is a null pointer literal. The following default implementation is -// for lhs_is_null_literal being false. -template -class EqHelper { - public: - // This templatized version is for the general case. - template - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // With this overloaded version, we allow anonymous enums to be used - // in {ASSERT|EXPECT}_EQ when compiled with gcc 4, as anonymous - // enums can be implicitly cast to BiggestInt. - // - // Even though its body looks the same as the above version, we - // cannot merge the two, as it will make anonymous enums unhappy. - static AssertionResult Compare(const char* expected_expression, - const char* actual_expression, - BiggestInt expected, - BiggestInt actual) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } -}; - -// This specialization is used when the first argument to ASSERT_EQ() -// is a null pointer literal, like NULL, false, or 0. -template <> -class EqHelper { - public: - // We define two overloaded versions of Compare(). The first - // version will be picked when the second argument to ASSERT_EQ() is - // NOT a pointer, e.g. ASSERT_EQ(0, AnIntFunction()) or - // EXPECT_EQ(false, a_bool). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - const T1& expected, - const T2& actual, - // The following line prevents this overload from being considered if T2 - // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) - // expands to Compare("", "", NULL, my_ptr), which requires a conversion - // to match the Secret* in the other overload, which would otherwise make - // this template match better. - typename EnableIf::value>::type* = 0) { - return CmpHelperEQ(expected_expression, actual_expression, expected, - actual); - } - - // This version will be picked when the second argument to ASSERT_EQ() is a - // pointer, e.g. ASSERT_EQ(NULL, a_pointer). - template - static AssertionResult Compare( - const char* expected_expression, - const char* actual_expression, - // We used to have a second template parameter instead of Secret*. That - // template parameter would deduce to 'long', making this a better match - // than the first overload even without the first overload's EnableIf. - // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to - // non-pointer argument" (even a deduced integral argument), so the old - // implementation caused warnings in user code. - Secret* /* expected (NULL) */, - T* actual) { - // We already know that 'expected' is a null pointer. - return CmpHelperEQ(expected_expression, actual_expression, - static_cast(NULL), actual); - } -}; - -// A macro for implementing the helper functions needed to implement -// ASSERT_?? and EXPECT_??. It is here just to avoid copy-and-paste -// of similar code. -// -// For each templatized helper function, we also define an overloaded -// version for BiggestInt in order to reduce code bloat and allow -// anonymous enums to be used with {ASSERT|EXPECT}_?? when compiled -// with gcc 4. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -#define GTEST_IMPL_CMP_HELPER_(op_name, op)\ -template \ -AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ - const T1& val1, const T2& val2) {\ - if (val1 op val2) {\ - return AssertionSuccess();\ - } else {\ - return AssertionFailure() \ - << "Expected: (" << expr1 << ") " #op " (" << expr2\ - << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ - << " vs " << FormatForComparisonFailureMessage(val2, val1);\ - }\ -}\ -GTEST_API_ AssertionResult CmpHelper##op_name(\ - const char* expr1, const char* expr2, BiggestInt val1, BiggestInt val2) - -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. - -// Implements the helper function for {ASSERT|EXPECT}_NE -GTEST_IMPL_CMP_HELPER_(NE, !=); -// Implements the helper function for {ASSERT|EXPECT}_LE -GTEST_IMPL_CMP_HELPER_(LE, <=); -// Implements the helper function for {ASSERT|EXPECT}_LT -GTEST_IMPL_CMP_HELPER_(LT, <); -// Implements the helper function for {ASSERT|EXPECT}_GE -GTEST_IMPL_CMP_HELPER_(GE, >=); -// Implements the helper function for {ASSERT|EXPECT}_GT -GTEST_IMPL_CMP_HELPER_(GT, >); - -#undef GTEST_IMPL_CMP_HELPER_ - -// The helper function for {ASSERT|EXPECT}_STREQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRCASEEQ. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* expected_expression, - const char* actual_expression, - const char* expected, - const char* actual); - -// The helper function for {ASSERT|EXPECT}_STRNE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - -// The helper function for {ASSERT|EXPECT}_STRCASENE. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRCASENE(const char* s1_expression, - const char* s2_expression, - const char* s1, - const char* s2); - - -// Helper function for *_STREQ on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTREQ(const char* expected_expression, - const char* actual_expression, - const wchar_t* expected, - const wchar_t* actual); - -// Helper function for *_STRNE on wide strings. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult CmpHelperSTRNE(const char* s1_expression, - const char* s2_expression, - const wchar_t* s1, - const wchar_t* s2); - -} // namespace internal - -// IsSubstring() and IsNotSubstring() are intended to be used as the -// first argument to {EXPECT,ASSERT}_PRED_FORMAT2(), not by -// themselves. They check whether needle is a substring of haystack -// (NULL is considered a substring of itself only), and return an -// appropriate error message when they fail. -// -// The {needle,haystack}_expr arguments are the stringified -// expressions that generated the two real arguments. -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const char* needle, const char* haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const wchar_t* needle, const wchar_t* haystack); -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::string& needle, const ::std::string& haystack); - -#if GTEST_HAS_STD_WSTRING -GTEST_API_ AssertionResult IsSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -GTEST_API_ AssertionResult IsNotSubstring( - const char* needle_expr, const char* haystack_expr, - const ::std::wstring& needle, const ::std::wstring& haystack); -#endif // GTEST_HAS_STD_WSTRING - -namespace internal { - -// Helper template function for comparing floating-points. -// -// Template parameter: -// -// RawType: the raw floating-point type (either float or double) -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -template -AssertionResult CmpHelperFloatingPointEQ(const char* expected_expression, - const char* actual_expression, - RawType expected, - RawType actual) { - const FloatingPoint lhs(expected), rhs(actual); - - if (lhs.AlmostEquals(rhs)) { - return AssertionSuccess(); - } - - ::std::stringstream expected_ss; - expected_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << expected; - - ::std::stringstream actual_ss; - actual_ss << std::setprecision(std::numeric_limits::digits10 + 2) - << actual; - - return EqFailure(expected_expression, - actual_expression, - StringStreamToString(&expected_ss), - StringStreamToString(&actual_ss), - false); -} - -// Helper function for implementing ASSERT_NEAR. -// -// INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. -GTEST_API_ AssertionResult DoubleNearPredFormat(const char* expr1, - const char* expr2, - const char* abs_error_expr, - double val1, - double val2, - double abs_error); - -// INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. -// A class that enables one to stream messages to assertion macros -class GTEST_API_ AssertHelper { - public: - // Constructor. - AssertHelper(TestPartResult::Type type, - const char* file, - int line, - const char* message); - ~AssertHelper(); - - // Message assignment is a semantic trick to enable assertion - // streaming; see the GTEST_MESSAGE_ macro below. - void operator=(const Message& message) const; - - private: - // We put our data in a struct so that the size of the AssertHelper class can - // be as small as possible. This is important because gcc is incapable of - // re-using stack space even for temporary variables, so every EXPECT_EQ - // reserves stack space for another AssertHelper. - struct AssertHelperData { - AssertHelperData(TestPartResult::Type t, - const char* srcfile, - int line_num, - const char* msg) - : type(t), file(srcfile), line(line_num), message(msg) { } - - TestPartResult::Type const type; - const char* const file; - int const line; - std::string const message; - - private: - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelperData); - }; - - AssertHelperData* const data_; - - GTEST_DISALLOW_COPY_AND_ASSIGN_(AssertHelper); -}; - -} // namespace internal - -#if GTEST_HAS_PARAM_TEST -// The pure interface class that all value-parameterized tests inherit from. -// A value-parameterized class must inherit from both ::testing::Test and -// ::testing::WithParamInterface. In most cases that just means inheriting -// from ::testing::TestWithParam, but more complicated test hierarchies -// may need to inherit from Test and WithParamInterface at different levels. -// -// This interface has support for accessing the test parameter value via -// the GetParam() method. -// -// Use it with one of the parameter generator defining functions, like Range(), -// Values(), ValuesIn(), Bool(), and Combine(). -// -// class FooTest : public ::testing::TestWithParam { -// protected: -// FooTest() { -// // Can use GetParam() here. -// } -// virtual ~FooTest() { -// // Can use GetParam() here. -// } -// virtual void SetUp() { -// // Can use GetParam() here. -// } -// virtual void TearDown { -// // Can use GetParam() here. -// } -// }; -// TEST_P(FooTest, DoesBar) { -// // Can use GetParam() method here. -// Foo foo; -// ASSERT_TRUE(foo.DoesBar(GetParam())); -// } -// INSTANTIATE_TEST_CASE_P(OneToTenRange, FooTest, ::testing::Range(1, 10)); - -template -class WithParamInterface { - public: - typedef T ParamType; - virtual ~WithParamInterface() {} - - // The current parameter value. Is also available in the test fixture's - // constructor. This member function is non-static, even though it only - // references static data, to reduce the opportunity for incorrect uses - // like writing 'WithParamInterface::GetParam()' for a test that - // uses a fixture whose parameter type is int. - const ParamType& GetParam() const { - GTEST_CHECK_(parameter_ != NULL) - << "GetParam() can only be called inside a value-parameterized test " - << "-- did you intend to write TEST_P instead of TEST_F?"; - return *parameter_; - } - - private: - // Sets parameter value. The caller is responsible for making sure the value - // remains alive and unchanged throughout the current test. - static void SetParam(const ParamType* parameter) { - parameter_ = parameter; - } - - // Static value used for accessing parameter during a test lifetime. - static const ParamType* parameter_; - - // TestClass must be a subclass of WithParamInterface and Test. - template friend class internal::ParameterizedTestFactory; -}; - -template -const T* WithParamInterface::parameter_ = NULL; - -// Most value-parameterized classes can ignore the existence of -// WithParamInterface, and can just inherit from ::testing::TestWithParam. - -template -class TestWithParam : public Test, public WithParamInterface { -}; - -#endif // GTEST_HAS_PARAM_TEST - -// Macros for indicating success/failure in test code. - -// ADD_FAILURE unconditionally adds a failure to the current test. -// SUCCEED generates a success - it doesn't automatically make the -// current test successful, as a test is only successful when it has -// no failure. -// -// EXPECT_* verifies that a certain condition is satisfied. If not, -// it behaves like ADD_FAILURE. In particular: -// -// EXPECT_TRUE verifies that a Boolean condition is true. -// EXPECT_FALSE verifies that a Boolean condition is false. -// -// FAIL and ASSERT_* are similar to ADD_FAILURE and EXPECT_*, except -// that they will also abort the current function on failure. People -// usually want the fail-fast behavior of FAIL and ASSERT_*, but those -// writing data-driven tests often find themselves using ADD_FAILURE -// and EXPECT_* more. - -// Generates a nonfatal failure with a generic message. -#define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") - -// Generates a nonfatal failure at the given source file location with -// a generic message. -#define ADD_FAILURE_AT(file, line) \ - GTEST_MESSAGE_AT_(file, line, "Failed", \ - ::testing::TestPartResult::kNonFatalFailure) - -// Generates a fatal failure with a generic message. -#define GTEST_FAIL() GTEST_FATAL_FAILURE_("Failed") - -// Define this macro to 1 to omit the definition of FAIL(), which is a -// generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_FAIL -# define FAIL() GTEST_FAIL() -#endif - -// Generates a success with a generic message. -#define GTEST_SUCCEED() GTEST_SUCCESS_("Succeeded") - -// Define this macro to 1 to omit the definition of SUCCEED(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_SUCCEED -# define SUCCEED() GTEST_SUCCEED() -#endif - -// Macros for testing exceptions. -// -// * {ASSERT|EXPECT}_THROW(statement, expected_exception): -// Tests that the statement throws the expected exception. -// * {ASSERT|EXPECT}_NO_THROW(statement): -// Tests that the statement doesn't throw any exception. -// * {ASSERT|EXPECT}_ANY_THROW(statement): -// Tests that the statement throws an exception. - -#define EXPECT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_NONFATAL_FAILURE_) -#define EXPECT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define EXPECT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_NONFATAL_FAILURE_) -#define ASSERT_THROW(statement, expected_exception) \ - GTEST_TEST_THROW_(statement, expected_exception, GTEST_FATAL_FAILURE_) -#define ASSERT_NO_THROW(statement) \ - GTEST_TEST_NO_THROW_(statement, GTEST_FATAL_FAILURE_) -#define ASSERT_ANY_THROW(statement) \ - GTEST_TEST_ANY_THROW_(statement, GTEST_FATAL_FAILURE_) - -// Boolean assertions. Condition can be either a Boolean expression or an -// AssertionResult. For more information on how to use AssertionResult with -// these macros see comments on that class. -#define EXPECT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_NONFATAL_FAILURE_) -#define EXPECT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_NONFATAL_FAILURE_) -#define ASSERT_TRUE(condition) \ - GTEST_TEST_BOOLEAN_(condition, #condition, false, true, \ - GTEST_FATAL_FAILURE_) -#define ASSERT_FALSE(condition) \ - GTEST_TEST_BOOLEAN_(!(condition), #condition, true, false, \ - GTEST_FATAL_FAILURE_) - -// Includes the auto-generated header that implements a family of -// generic predicate assertion macros. -// Copyright 2006, Google Inc. -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * 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. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY 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. - -// This file is AUTOMATICALLY GENERATED on 10/31/2011 by command -// 'gen_gtest_pred_impl.py 5'. DO NOT EDIT BY HAND! -// -// Implements a family of generic predicate assertion macros. - -#ifndef GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ -#define GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Makes sure this header is not included before gtest.h. -#ifndef GTEST_INCLUDE_GTEST_GTEST_H_ -# error Do not include gtest_pred_impl.h directly. Include gtest.h instead. -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ - -// This header implements a family of generic predicate assertion -// macros: -// -// ASSERT_PRED_FORMAT1(pred_format, v1) -// ASSERT_PRED_FORMAT2(pred_format, v1, v2) -// ... -// -// where pred_format is a function or functor that takes n (in the -// case of ASSERT_PRED_FORMATn) values and their source expression -// text, and returns a testing::AssertionResult. See the definition -// of ASSERT_EQ in gtest.h for an example. -// -// If you don't care about formatting, you can use the more -// restrictive version: -// -// ASSERT_PRED1(pred, v1) -// ASSERT_PRED2(pred, v1, v2) -// ... -// -// where pred is an n-ary function or functor that returns bool, -// and the values v1, v2, ..., must support the << operator for -// streaming to std::ostream. -// -// We also define the EXPECT_* variations. -// -// For now we only support predicates whose arity is at most 5. -// Please email googletestframework@googlegroups.com if you need -// support for higher arities. - -// GTEST_ASSERT_ is the basic statement to which all of the assertions -// in this file reduce. Don't use this in your code. - -#define GTEST_ASSERT_(expression, on_failure) \ - GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ - if (const ::testing::AssertionResult gtest_ar = (expression)) \ - ; \ - else \ - on_failure(gtest_ar.failure_message()) - - -// Helper function for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -template -AssertionResult AssertPred1Helper(const char* pred_text, - const char* e1, - Pred pred, - const T1& v1) { - if (pred(v1)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT1. -// Don't use this in your code. -#define GTEST_PRED_FORMAT1_(pred_format, v1, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, v1), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED1. Don't use -// this in your code. -#define GTEST_PRED1_(pred, v1, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred1Helper(#pred, \ - #v1, \ - pred, \ - v1), on_failure) - -// Unary predicate assertion macros. -#define EXPECT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT1(pred_format, v1) \ - GTEST_PRED_FORMAT1_(pred_format, v1, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED1(pred, v1) \ - GTEST_PRED1_(pred, v1, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -template -AssertionResult AssertPred2Helper(const char* pred_text, - const char* e1, - const char* e2, - Pred pred, - const T1& v1, - const T2& v2) { - if (pred(v1, v2)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT2. -// Don't use this in your code. -#define GTEST_PRED_FORMAT2_(pred_format, v1, v2, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, v1, v2), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED2. Don't use -// this in your code. -#define GTEST_PRED2_(pred, v1, v2, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred2Helper(#pred, \ - #v1, \ - #v2, \ - pred, \ - v1, \ - v2), on_failure) - -// Binary predicate assertion macros. -#define EXPECT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT2(pred_format, v1, v2) \ - GTEST_PRED_FORMAT2_(pred_format, v1, v2, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED2(pred, v1, v2) \ - GTEST_PRED2_(pred, v1, v2, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -template -AssertionResult AssertPred3Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3) { - if (pred(v1, v2, v3)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT3. -// Don't use this in your code. -#define GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, v1, v2, v3), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED3. Don't use -// this in your code. -#define GTEST_PRED3_(pred, v1, v2, v3, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred3Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - pred, \ - v1, \ - v2, \ - v3), on_failure) - -// Ternary predicate assertion macros. -#define EXPECT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT3(pred_format, v1, v2, v3) \ - GTEST_PRED_FORMAT3_(pred_format, v1, v2, v3, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED3(pred, v1, v2, v3) \ - GTEST_PRED3_(pred, v1, v2, v3, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -template -AssertionResult AssertPred4Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4) { - if (pred(v1, v2, v3, v4)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT4. -// Don't use this in your code. -#define GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, v1, v2, v3, v4), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED4. Don't use -// this in your code. -#define GTEST_PRED4_(pred, v1, v2, v3, v4, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred4Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4), on_failure) - -// 4-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT4(pred_format, v1, v2, v3, v4) \ - GTEST_PRED_FORMAT4_(pred_format, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED4(pred, v1, v2, v3, v4) \ - GTEST_PRED4_(pred, v1, v2, v3, v4, GTEST_FATAL_FAILURE_) - - - -// Helper function for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -template -AssertionResult AssertPred5Helper(const char* pred_text, - const char* e1, - const char* e2, - const char* e3, - const char* e4, - const char* e5, - Pred pred, - const T1& v1, - const T2& v2, - const T3& v3, - const T4& v4, - const T5& v5) { - if (pred(v1, v2, v3, v4, v5)) return AssertionSuccess(); - - return AssertionFailure() << pred_text << "(" - << e1 << ", " - << e2 << ", " - << e3 << ", " - << e4 << ", " - << e5 << ") evaluates to false, where" - << "\n" << e1 << " evaluates to " << v1 - << "\n" << e2 << " evaluates to " << v2 - << "\n" << e3 << " evaluates to " << v3 - << "\n" << e4 << " evaluates to " << v4 - << "\n" << e5 << " evaluates to " << v5; -} - -// Internal macro for implementing {EXPECT|ASSERT}_PRED_FORMAT5. -// Don't use this in your code. -#define GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(pred_format(#v1, #v2, #v3, #v4, #v5, v1, v2, v3, v4, v5), \ - on_failure) - -// Internal macro for implementing {EXPECT|ASSERT}_PRED5. Don't use -// this in your code. -#define GTEST_PRED5_(pred, v1, v2, v3, v4, v5, on_failure)\ - GTEST_ASSERT_(::testing::AssertPred5Helper(#pred, \ - #v1, \ - #v2, \ - #v3, \ - #v4, \ - #v5, \ - pred, \ - v1, \ - v2, \ - v3, \ - v4, \ - v5), on_failure) - -// 5-ary predicate assertion macros. -#define EXPECT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define EXPECT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_NONFATAL_FAILURE_) -#define ASSERT_PRED_FORMAT5(pred_format, v1, v2, v3, v4, v5) \ - GTEST_PRED_FORMAT5_(pred_format, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) -#define ASSERT_PRED5(pred, v1, v2, v3, v4, v5) \ - GTEST_PRED5_(pred, v1, v2, v3, v4, v5, GTEST_FATAL_FAILURE_) - - - -#endif // GTEST_INCLUDE_GTEST_GTEST_PRED_IMPL_H_ - -// Macros for testing equalities and inequalities. -// -// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual -// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 -// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 -// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 -// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 -// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 -// -// When they are not, Google Test prints both the tested expressions and -// their actual values. The values must be compatible built-in types, -// or you will get a compiler error. By "compatible" we mean that the -// values can be compared by the respective operator. -// -// Note: -// -// 1. It is possible to make a user-defined type work with -// {ASSERT|EXPECT}_??(), but that requires overloading the -// comparison operators and is thus discouraged by the Google C++ -// Usage Guide. Therefore, you are advised to use the -// {ASSERT|EXPECT}_TRUE() macro to assert that two objects are -// equal. -// -// 2. The {ASSERT|EXPECT}_??() macros do pointer comparisons on -// pointers (in particular, C strings). Therefore, if you use it -// with two C strings, you are testing how their locations in memory -// are related, not how their content is related. To compare two C -// strings by content, use {ASSERT|EXPECT}_STR*(). -// -// 3. {ASSERT|EXPECT}_EQ(expected, actual) is preferred to -// {ASSERT|EXPECT}_TRUE(expected == actual), as the former tells you -// what the actual value is when it fails, and similarly for the -// other comparisons. -// -// 4. Do not depend on the order in which {ASSERT|EXPECT}_??() -// evaluate their arguments, which is undefined. -// -// 5. These macros evaluate their arguments exactly once. -// -// Examples: -// -// EXPECT_NE(5, Foo()); -// EXPECT_EQ(NULL, a_pointer); -// ASSERT_LT(i, array_size); -// ASSERT_GT(records.size(), 0) << "There is no record left."; - -#define EXPECT_EQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define EXPECT_NE(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, expected, actual) -#define EXPECT_LE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define EXPECT_LT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define EXPECT_GE(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define EXPECT_GT(val1, val2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -#define GTEST_ASSERT_EQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal:: \ - EqHelper::Compare, \ - expected, actual) -#define GTEST_ASSERT_NE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) -#define GTEST_ASSERT_LE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) -#define GTEST_ASSERT_LT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) -#define GTEST_ASSERT_GE(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) -#define GTEST_ASSERT_GT(val1, val2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) - -// Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of -// ASSERT_XY(), which clashes with some users' own code. - -#if !GTEST_DONT_DEFINE_ASSERT_EQ -# define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_NE -# define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_LE -# define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_LT -# define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_GE -# define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) -#endif - -#if !GTEST_DONT_DEFINE_ASSERT_GT -# define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) -#endif - -// C-string Comparisons. All tests treat NULL and any non-NULL string -// as different. Two NULLs are equal. -// -// * {ASSERT|EXPECT}_STREQ(s1, s2): Tests that s1 == s2 -// * {ASSERT|EXPECT}_STRNE(s1, s2): Tests that s1 != s2 -// * {ASSERT|EXPECT}_STRCASEEQ(s1, s2): Tests that s1 == s2, ignoring case -// * {ASSERT|EXPECT}_STRCASENE(s1, s2): Tests that s1 != s2, ignoring case -// -// For wide or narrow string objects, you can use the -// {ASSERT|EXPECT}_??() macros. -// -// Don't depend on the order in which the arguments are evaluated, -// which is undefined. -// -// These macros evaluate their arguments exactly once. - -#define EXPECT_STREQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define EXPECT_STRNE(s1, s2) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define EXPECT_STRCASEEQ(expected, actual) \ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define EXPECT_STRCASENE(s1, s2)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -#define ASSERT_STREQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, expected, actual) -#define ASSERT_STRNE(s1, s2) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) -#define ASSERT_STRCASEEQ(expected, actual) \ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, expected, actual) -#define ASSERT_STRCASENE(s1, s2)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) - -// Macros for comparing floating-point numbers. -// -// * {ASSERT|EXPECT}_FLOAT_EQ(expected, actual): -// Tests that two float values are almost equal. -// * {ASSERT|EXPECT}_DOUBLE_EQ(expected, actual): -// Tests that two double values are almost equal. -// * {ASSERT|EXPECT}_NEAR(v1, v2, abs_error): -// Tests that v1 and v2 are within the given distance to each other. -// -// Google Test uses ULP-based comparison to automatically pick a default -// error bound that is appropriate for the operands. See the -// FloatingPoint template class in gtest-internal.h if you are -// interested in the implementation details. - -#define EXPECT_FLOAT_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_DOUBLE_EQ(expected, actual)\ - EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_FLOAT_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define ASSERT_DOUBLE_EQ(expected, actual)\ - ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ - expected, actual) - -#define EXPECT_NEAR(val1, val2, abs_error)\ - EXPECT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -#define ASSERT_NEAR(val1, val2, abs_error)\ - ASSERT_PRED_FORMAT3(::testing::internal::DoubleNearPredFormat, \ - val1, val2, abs_error) - -// These predicate format functions work on floating-point values, and -// can be used in {ASSERT|EXPECT}_PRED_FORMAT2*(), e.g. -// -// EXPECT_PRED_FORMAT2(testing::DoubleLE, Foo(), 5.0); - -// Asserts that val1 is less than, or almost equal to, val2. Fails -// otherwise. In particular, it fails if either val1 or val2 is NaN. -GTEST_API_ AssertionResult FloatLE(const char* expr1, const char* expr2, - float val1, float val2); -GTEST_API_ AssertionResult DoubleLE(const char* expr1, const char* expr2, - double val1, double val2); - - -#if GTEST_OS_WINDOWS - -// Macros that test for HRESULT failure and success, these are only useful -// on Windows, and rely on Windows SDK macros and APIs to compile. -// -// * {ASSERT|EXPECT}_HRESULT_{SUCCEEDED|FAILED}(expr) -// -// When expr unexpectedly fails or succeeds, Google Test prints the -// expected result and the actual result with both a human-readable -// string representation of the error, if available, as well as the -// hex result code. -# define EXPECT_HRESULT_SUCCEEDED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -# define ASSERT_HRESULT_SUCCEEDED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTSuccess, (expr)) - -# define EXPECT_HRESULT_FAILED(expr) \ - EXPECT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -# define ASSERT_HRESULT_FAILED(expr) \ - ASSERT_PRED_FORMAT1(::testing::internal::IsHRESULTFailure, (expr)) - -#endif // GTEST_OS_WINDOWS - -// Macros that execute statement and check that it doesn't generate new fatal -// failures in the current thread. -// -// * {ASSERT|EXPECT}_NO_FATAL_FAILURE(statement); -// -// Examples: -// -// EXPECT_NO_FATAL_FAILURE(Process()); -// ASSERT_NO_FATAL_FAILURE(Process()) << "Process() failed"; -// -#define ASSERT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_FATAL_FAILURE_) -#define EXPECT_NO_FATAL_FAILURE(statement) \ - GTEST_TEST_NO_FATAL_FAILURE_(statement, GTEST_NONFATAL_FAILURE_) - -// Causes a trace (including the source file path, the current line -// number, and the given message) to be included in every test failure -// message generated by code in the current scope. The effect is -// undone when the control leaves the current scope. -// -// The message argument can be anything streamable to std::ostream. -// -// In the implementation, we include the current line number as part -// of the dummy variable name, thus allowing multiple SCOPED_TRACE()s -// to appear in the same block - as long as they are on different -// lines. -#define SCOPED_TRACE(message) \ - ::testing::internal::ScopedTrace GTEST_CONCAT_TOKEN_(gtest_trace_, __LINE__)(\ - __FILE__, __LINE__, ::testing::Message() << (message)) - -// Compile-time assertion for type equality. -// StaticAssertTypeEq() compiles iff type1 and type2 are -// the same type. The value it returns is not interesting. -// -// Instead of making StaticAssertTypeEq a class template, we make it a -// function template that invokes a helper class template. This -// prevents a user from misusing StaticAssertTypeEq by -// defining objects of that type. -// -// CAVEAT: -// -// When used inside a method of a class template, -// StaticAssertTypeEq() is effective ONLY IF the method is -// instantiated. For example, given: -// -// template class Foo { -// public: -// void Bar() { testing::StaticAssertTypeEq(); } -// }; -// -// the code: -// -// void Test1() { Foo foo; } -// -// will NOT generate a compiler error, as Foo::Bar() is never -// actually instantiated. Instead, you need: -// -// void Test2() { Foo foo; foo.Bar(); } -// -// to cause a compiler error. -template -bool StaticAssertTypeEq() { - (void)internal::StaticAssertTypeEqHelper(); - return true; -} - -// Defines a test. -// -// The first parameter is the name of the test case, and the second -// parameter is the name of the test within the test case. -// -// The convention is to end the test case name with "Test". For -// example, a test case for the Foo class can be named FooTest. -// -// The user should put his test code between braces after using this -// macro. Example: -// -// TEST(FooTest, InitializesCorrectly) { -// Foo foo; -// EXPECT_TRUE(foo.StatusIsOK()); -// } - -// Note that we call GetTestTypeId() instead of GetTypeId< -// ::testing::Test>() here to get the type ID of testing::Test. This -// is to work around a suspected linker bug when using Google Test as -// a framework on Mac OS X. The bug causes GetTypeId< -// ::testing::Test>() to return different values depending on whether -// the call is from the Google Test framework itself or from user test -// code. GetTestTypeId() is guaranteed to always return the same -// value, as it always calls GetTypeId<>() from the Google Test -// framework. -#define GTEST_TEST(test_case_name, test_name)\ - GTEST_TEST_(test_case_name, test_name, \ - ::testing::Test, ::testing::internal::GetTestTypeId()) - -// Define this macro to 1 to omit the definition of TEST(), which -// is a generic name and clashes with some other libraries. -#if !GTEST_DONT_DEFINE_TEST -# define TEST(test_case_name, test_name) GTEST_TEST(test_case_name, test_name) -#endif - -// Defines a test that uses a test fixture. -// -// The first parameter is the name of the test fixture class, which -// also doubles as the test case name. The second parameter is the -// name of the test within the test case. -// -// A test fixture class must be declared earlier. The user should put -// his test code between braces after using this macro. Example: -// -// class FooTest : public testing::Test { -// protected: -// virtual void SetUp() { b_.AddElement(3); } -// -// Foo a_; -// Foo b_; -// }; -// -// TEST_F(FooTest, InitializesCorrectly) { -// EXPECT_TRUE(a_.StatusIsOK()); -// } -// -// TEST_F(FooTest, ReturnsElementCountCorrectly) { -// EXPECT_EQ(0, a_.size()); -// EXPECT_EQ(1, b_.size()); -// } - -#define TEST_F(test_fixture, test_name)\ - GTEST_TEST_(test_fixture, test_name, test_fixture, \ - ::testing::internal::GetTypeId()) - -} // namespace testing - -// Use this function in main() to run all tests. It returns 0 if all -// tests are successful, or 1 otherwise. -// -// RUN_ALL_TESTS() should be invoked after the command line has been -// parsed by InitGoogleTest(). -// -// This function was formerly a macro; thus, it is in the global -// namespace and has an all-caps name. -int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; - -inline int RUN_ALL_TESTS() { - return ::testing::UnitTest::GetInstance()->Run(); -} - -#endif // GTEST_INCLUDE_GTEST_GTEST_H_ From 408d9d99a9464c80e4af32834b0873a8a567ac7a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 31 Jul 2017 11:35:41 -0600 Subject: [PATCH 239/293] cmake: improve some error messages --- cmake/CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d691386c05..59a2cc1f7b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -179,7 +179,7 @@ if(ENABLE_PYTHON) endif() install(FILES ${CMAKE_SOURCE_DIR}/../python/lammps.py DESTINATION ${PYTHON_INSTDIR}) if(NOT BUILD_SHARED_LIBS) - message(FATAL_ERROR "Python package need lammps to be build shared, -DBUILD_SHARED_LIBS=ON") + message(FATAL_ERROR "Python package need lammps to be build shared, use -DBUILD_SHARED_LIBS=ON") endif() endif() @@ -451,7 +451,7 @@ if(ENABLE_GPU) find_package(CUDA REQUIRED) find_program(BIN2C bin2c) if(NOT BIN2C) - message(FATAL_ERROR "Couldn't find bin2c") + message(FATAL_ERROR "Couldn't find bin2c, use -DBIN2C helping cmake to find it.") endif() include_directories(${CUDA_INCLUDE_DIRS}) list(APPEND LAMMPS_LINK_LIBS ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) @@ -522,7 +522,7 @@ if(INSTALL_LIB) install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/lammps.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) elseif(BUILD_SHARED_LIBS) - message(FATAL_ERROR "Shared library has to be installed, use -DBUILD_SHARED_LIBS=ON to install lammps with a library") + message(FATAL_ERROR "Shared library has to be installed, use -DINSTALL_LIB=ON to install lammps with a library") endif() add_executable(lmp ${LMP_SOURCES}) From 72f50c91ee01cf7744ba14ae320d4c7ac09e991a Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 31 Jul 2017 11:48:22 -0600 Subject: [PATCH 240/293] Add -DLAMMPS_EXCEPTIONS flag --- cmake/CMakeLists.txt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index d691386c05..efc0eac5ca 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -69,6 +69,11 @@ add_definitions(-D${LAMMPS_SIZE_LIMIT}) 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") add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) +option(LAMMPS_EXCEPTIONS "enable the use of C++ exceptions for error messages (useful for library interface)" OFF) +if(LAMMPS_EXCEPTIONS) + add_definitions(-DLAMMPS_EXCEPTIONS) +endif() + option(CMAKE_VERBOSE_MAKEFILE "Verbose makefile" OFF) option(ENABLE_TESTING "Enable testing" OFF) From 71553cf7328eabcf7936d8e0de94e7175f56545d Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 31 Jul 2017 13:53:41 -0600 Subject: [PATCH 241/293] Fix PyLammps regression after output.cpp change --- python/lammps.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/python/lammps.py b/python/lammps.py index d428a097a8..a512efdcda 100644 --- a/python/lammps.py +++ b/python/lammps.py @@ -556,9 +556,10 @@ def get_thermo_data(output): runs = [] columns = [] in_run = False + current_run = {} for line in lines: - if line.startswith("Memory usage per processor"): + if line.startswith("Per MPI rank memory allocation"): in_run = True elif in_run and len(columns) == 0: # first line after memory usage are column names From d3169eeab3e7b6b6e7c6af8041e33de894a8d17c Mon Sep 17 00:00:00 2001 From: Richard Berger Date: Mon, 31 Jul 2017 13:56:20 -0600 Subject: [PATCH 242/293] Remove Make.py reference in PyLammps examples Also fixes some regressions due to command syntax changes --- python/examples/pylammps/.gitignore | 3 + .../pylammps/dihedrals/dihedral.ipynb | 1005 +---------------- .../examples/pylammps/interface_usage.ipynb | 43 +- .../pylammps/interface_usage_bonds.ipynb | 34 +- python/examples/pylammps/montecarlo/mc.ipynb | 117 +- python/examples/pylammps/simple.ipynb | 12 +- 6 files changed, 165 insertions(+), 1049 deletions(-) diff --git a/python/examples/pylammps/.gitignore b/python/examples/pylammps/.gitignore index 95ef7c6bd1..3f885f6a7a 100644 --- a/python/examples/pylammps/.gitignore +++ b/python/examples/pylammps/.gitignore @@ -1 +1,4 @@ *.orig +*-checkpoint.ipynb +*.png +*.mp4 diff --git a/python/examples/pylammps/dihedrals/dihedral.ipynb b/python/examples/pylammps/dihedrals/dihedral.ipynb index db7e81aaf6..6b919816d7 100644 --- a/python/examples/pylammps/dihedrals/dihedral.ipynb +++ b/python/examples/pylammps/dihedrals/dihedral.ipynb @@ -9,10 +9,8 @@ }, { "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "%matplotlib notebook" @@ -20,7 +18,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": { "collapsed": true }, @@ -31,7 +29,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": { "collapsed": true }, @@ -42,29 +40,17 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "LAMMPS output is captured by PyLammps wrapper\n" - ] - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L = IPyLammps()" ] }, { "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "import math\n", @@ -80,47 +66,17 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['Reading data file ...',\n", - " ' triclinic box = (-5 -5 -5) to (5 5 5) with tilt (0 0 0)',\n", - " ' 1 by 1 by 1 MPI processor grid',\n", - " ' reading atoms ...',\n", - " ' 4 atoms',\n", - " ' scanning dihedrals ...',\n", - " ' 1 = max dihedrals/atom',\n", - " ' reading dihedrals ...',\n", - " ' 1 dihedrals',\n", - " 'Finding 1-2 1-3 1-4 neighbors ...',\n", - " ' Special bond factors lj: 0 0 0 ',\n", - " ' Special bond factors coul: 0 0 0 ',\n", - " ' 0 = max # of 1-2 neighbors',\n", - " ' 0 = max # of 1-3 neighbors',\n", - " ' 0 = max # of 1-4 neighbors',\n", - " ' 1 = max # of special neighbors']" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L.read_data(\"data.dihedral\")" ] }, { "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.pair_style(\"zero\", 5)\n", @@ -129,10 +85,8 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.mass(1, 1.0)" @@ -140,10 +94,8 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.velocity(\"all\", \"set\", 0.0, 0.0, 0.0)" @@ -151,10 +103,8 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.run(0);" @@ -162,55 +112,26 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n/x+AnPCD2jXp5gAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L.image(zoom=1.0)" ] }, { "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "(1.0000000000000009, 1.0000000000000009, 0.0)" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L.atoms[3].position" ] }, { "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.atoms[3].position = (1.0, 0.0, 1.0)" @@ -218,55 +139,26 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nTwwAovvK6w3dMisv362uXtPr12TZoVD8TKtNS01VAmeAi8DvA18HRnJybubkNACFXu+sw7HV3o6n\nnrpvS/PdfreJCQwMwGZjvxsxAIj2395bZklJ4urVzbKyGbV6RqFoVyq/pVTmB6uqLwJPAGuxsd0G\nQ73BcAdInpxct9l8V668q2X6br/b+DhsNjid7HcjBgBR2K2thbYFp075O+lWZXlAkt7U6dITE1XB\nTrqvAfGAMz+/OT+/Ecjb2Jh3Orfb2t5xVbXFImJjMT+PsTFYLJiYwPo6urthNHL1JwYA0UFvCzIy\n/J10UyrVlCTdUSr/TaEoAE4CtcB7gd8BVhISOkpL60tL24BEl8ttsfje857//wru73ebm8PwMPr7\nMTfHfjdiABAdJgsLoW3B2bM7VVUrOt2KJNkk6XW9PjMuTh3spPtLIAYYLCxsKixsAnLW1hYdju2O\njl9bVX23381oxOoqlpbw0ktc/en+E3t/oiGidyk3V1y8iNJSqFRQKCJVqqSioiKgAqgDqoF8YAFo\nB+qBdmBsbMxjNvvm5xETIyYnfWYzPB489RSGhmA0wuPBwgL73YgBQHS0ppYQNTU4dQpaLSRJyHKs\nXp8VHa0Nbgv0QCRgAxqB5uvXW/YGQHU1+vuxuYnpafzoR5yhxAAgOrJOnBA1NSgthVIJhSJKrU7O\nzz8RrKo+A+Rcv160NwASEuD1YmwMv/gFpyftI54BEO27sbHAOh4ZKerqtisrF7VafyfdyyUl2ULo\n7vnzbjdsNty+zdWfGABED4qdndCarlSKCxfcBsOoUjkqy1Eu187d3/qP/+DST+HA/wIiOmDR0eLS\nJZSUYGUFGxts+CEGABER7bMIfgRERAwAIiJiABAREQOAiIgYAERExAAgIiIGABERMQCIiIgBQERE\nDAAiImIAEBERA4CIiBgARETEACAiIgYAERExAIiIiAFAREQMACIiYgAQEREDgIiIGABERMQAICIi\nBgARETEAiIgYAERExAAgIiIGABERMQCIiIgBQEREDAAiImIAEBERA4CIiBgARETEACAiIgYAEREx\nAIiIiAFAREQMACIiYgAQEREDgIiIGABERMQAICIiBgARETEAiIiIAUBERAwAIiJiABARMQCIiIgB\nQEREDAAiImIAEBERA4CIiBgARETEACAiIgYAEREdFf8PkjHA9hViIbwAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L.image(zoom=1.0)" ] }, { "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "160.0" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "L.eval(\"pe\")" ] }, { "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.atoms[3].position = (1.0, 0.0, -1.0)" @@ -274,10 +166,8 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "L.run(0);" @@ -285,10 +175,8 @@ }, { "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "phi = [d * math.pi / 180 for d in range(360)]" @@ -296,10 +184,8 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "pos = [(1.0, math.cos(p), math.sin(p)) for p in phi]" @@ -307,7 +193,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": { "collapsed": true }, @@ -321,10 +207,8 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": { - "collapsed": false - }, + "execution_count": null, + "metadata": {}, "outputs": [], "source": [ "pe = []\n", @@ -336,798 +220,9 @@ }, { "cell_type": "code", - "execution_count": 22, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "application/javascript": [ - "/* Put everything inside the global mpl namespace */\n", - "window.mpl = {};\n", - "\n", - "mpl.get_websocket_type = function() {\n", - " if (typeof(WebSocket) !== 'undefined') {\n", - " return WebSocket;\n", - " } else if (typeof(MozWebSocket) !== 'undefined') {\n", - " return MozWebSocket;\n", - " } else {\n", - " alert('Your browser does not have WebSocket support.' +\n", - " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", - " 'Firefox 4 and 5 are also supported but you ' +\n", - " 'have to enable WebSockets in about:config.');\n", - " };\n", - "}\n", - "\n", - "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", - " this.id = figure_id;\n", - "\n", - " this.ws = websocket;\n", - "\n", - " this.supports_binary = (this.ws.binaryType != undefined);\n", - "\n", - " if (!this.supports_binary) {\n", - " var warnings = document.getElementById(\"mpl-warnings\");\n", - " if (warnings) {\n", - " warnings.style.display = 'block';\n", - " warnings.textContent = (\n", - " \"This browser does not support binary websocket messages. \" +\n", - " \"Performance may be slow.\");\n", - " }\n", - " }\n", - "\n", - " this.imageObj = new Image();\n", - "\n", - " this.context = undefined;\n", - " this.message = undefined;\n", - " this.canvas = undefined;\n", - " this.rubberband_canvas = undefined;\n", - " this.rubberband_context = undefined;\n", - " this.format_dropdown = undefined;\n", - "\n", - " this.image_mode = 'full';\n", - "\n", - " this.root = $('
');\n", - " this._root_extra_style(this.root)\n", - " this.root.attr('style', 'display: inline-block');\n", - "\n", - " $(parent_element).append(this.root);\n", - "\n", - " this._init_header(this);\n", - " this._init_canvas(this);\n", - " this._init_toolbar(this);\n", - "\n", - " var fig = this;\n", - "\n", - " this.waiting = false;\n", - "\n", - " this.ws.onopen = function () {\n", - " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", - " fig.send_message(\"send_image_mode\", {});\n", - " fig.send_message(\"refresh\", {});\n", - " }\n", - "\n", - " this.imageObj.onload = function() {\n", - " if (fig.image_mode == 'full') {\n", - " // Full images could contain transparency (where diff images\n", - " // almost always do), so we need to clear the canvas so that\n", - " // there is no ghosting.\n", - " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", - " }\n", - " fig.context.drawImage(fig.imageObj, 0, 0);\n", - " };\n", - "\n", - " this.imageObj.onunload = function() {\n", - " this.ws.close();\n", - " }\n", - "\n", - " this.ws.onmessage = this._make_on_message_function(this);\n", - "\n", - " this.ondownload = ondownload;\n", - "}\n", - "\n", - "mpl.figure.prototype._init_header = function() {\n", - " var titlebar = $(\n", - " '
');\n", - " var titletext = $(\n", - " '
');\n", - " titlebar.append(titletext)\n", - " this.root.append(titlebar);\n", - " this.header = titletext[0];\n", - "}\n", - "\n", - "\n", - "\n", - "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "\n", - "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", - "\n", - "}\n", - "\n", - "mpl.figure.prototype._init_canvas = function() {\n", - " var fig = this;\n", - "\n", - " var canvas_div = $('
');\n", - "\n", - " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", - "\n", - " function canvas_keyboard_event(event) {\n", - " return fig.key_event(event, event['data']);\n", - " }\n", - "\n", - " canvas_div.keydown('key_press', canvas_keyboard_event);\n", - " canvas_div.keyup('key_release', canvas_keyboard_event);\n", - " this.canvas_div = canvas_div\n", - " this._canvas_extra_style(canvas_div)\n", - " this.root.append(canvas_div);\n", - "\n", - " var canvas = $('');\n", - " canvas.addClass('mpl-canvas');\n", - " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", - "\n", - " this.canvas = canvas[0];\n", - " this.context = canvas[0].getContext(\"2d\");\n", - "\n", - " var rubberband = $('');\n", - " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", - "\n", - " var pass_mouse_events = true;\n", - "\n", - " canvas_div.resizable({\n", - " start: function(event, ui) {\n", - " pass_mouse_events = false;\n", - " },\n", - " resize: function(event, ui) {\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " stop: function(event, ui) {\n", - " pass_mouse_events = true;\n", - " fig.request_resize(ui.size.width, ui.size.height);\n", - " },\n", - " });\n", - "\n", - " function mouse_event_fn(event) {\n", - " if (pass_mouse_events)\n", - " return fig.mouse_event(event, event['data']);\n", - " }\n", - "\n", - " rubberband.mousedown('button_press', mouse_event_fn);\n", - " rubberband.mouseup('button_release', mouse_event_fn);\n", - " // Throttle sequential mouse events to 1 every 20ms.\n", - " rubberband.mousemove('motion_notify', mouse_event_fn);\n", - "\n", - " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", - " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", - "\n", - " canvas_div.on(\"wheel\", function (event) {\n", - " event = event.originalEvent;\n", - " event['data'] = 'scroll'\n", - " if (event.deltaY < 0) {\n", - " event.step = 1;\n", - " } else {\n", - " event.step = -1;\n", - " }\n", - " mouse_event_fn(event);\n", - " });\n", - "\n", - " canvas_div.append(canvas);\n", - " canvas_div.append(rubberband);\n", - "\n", - " this.rubberband = rubberband;\n", - " this.rubberband_canvas = rubberband[0];\n", - " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", - " this.rubberband_context.strokeStyle = \"#000000\";\n", - "\n", - " this._resize_canvas = function(width, height) {\n", - " // Keep the size of the canvas, canvas container, and rubber band\n", - " // canvas in synch.\n", - " canvas_div.css('width', width)\n", - " canvas_div.css('height', height)\n", - "\n", - " canvas.attr('width', width);\n", - " canvas.attr('height', height);\n", - "\n", - " rubberband.attr('width', width);\n", - " rubberband.attr('height', height);\n", - " }\n", - "\n", - " // Set the figure to an initial 600x600px, this will subsequently be updated\n", - " // upon first draw.\n", - " this._resize_canvas(600, 600);\n", - "\n", - " // Disable right mouse context menu.\n", - " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", - " return false;\n", - " });\n", - "\n", - " function set_focus () {\n", - " canvas.focus();\n", - " canvas_div.focus();\n", - " }\n", - "\n", - " window.setTimeout(set_focus, 100);\n", - "}\n", - "\n", - "mpl.figure.prototype._init_toolbar = function() {\n", - " var fig = this;\n", - "\n", - " var nav_element = $('
')\n", - " nav_element.attr('style', 'width: 100%');\n", - " this.root.append(nav_element);\n", - "\n", - " // Define a callback function for later on.\n", - " function toolbar_event(event) {\n", - " return fig.toolbar_button_onclick(event['data']);\n", - " }\n", - " function toolbar_mouse_event(event) {\n", - " return fig.toolbar_button_onmouseover(event['data']);\n", - " }\n", - "\n", - " for(var toolbar_ind in mpl.toolbar_items) {\n", - " var name = mpl.toolbar_items[toolbar_ind][0];\n", - " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", - " var image = mpl.toolbar_items[toolbar_ind][2];\n", - " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", - "\n", - " if (!name) {\n", - " // put a spacer in here.\n", - " continue;\n", - " }\n", - " var button = $('