// $Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetReduce/src/reduce.cc,v 1.34 2004/03/01 21:36:39 schnetter Exp $ #include #include #include #include #include #include #include #include #include #include #include "cctk.h" #include "dist.hh" #include "vect.hh" #include "carpet.hh" #include "reduce.hh" extern "C" { static const char* rcsid = "$Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetReduce/src/reduce.cc,v 1.34 2004/03/01 21:36:39 schnetter Exp $"; CCTK_FILEVERSION(Carpet_CarpetReduce_reduce_cc); } namespace CarpetReduce { using namespace std; using namespace Carpet; // Helper functions and types // The minimum of two values template inline T mymin (const T x, const T y) { return min(x, y); } // The maximum of two values template inline T mymax (const T x, const T y) { return max(x, y); } // Square root template inline T mysqrt (const T x) { return sqrt(x); } // Properties of numeric types template struct my_numeric_limits { // The smallest possible value static T min () { return mymin (numeric_limits::min(), -numeric_limits::max()); } // The largest possible value static T max () { return mymax (numeric_limits::max(), -numeric_limits::min()); } }; // Provide for each Cactus type a "good" type, translating between // CCTK_COMPLEX* and complex template struct typeconv { typedef T goodtype; typedef T badtype; }; // Overload the above helper functions and types for complex values #ifdef CCTK_REAL4 template<> inline complex mymin (const complex x, const complex y) { return complex (mymin(x.real(), y.real()), mymin(x.imag(), y.imag())); } template<> inline complex mymax (const complex x, const complex y) { return complex (mymax(x.real(), y.real()), mymax(x.imag(), y.imag())); } template<> struct my_numeric_limits > { static complex min () { return complex (my_numeric_limits::min(), my_numeric_limits::min()); } static complex max () { return complex (my_numeric_limits::max(), my_numeric_limits::max()); } }; template<> struct typeconv { typedef complex goodtype; typedef CCTK_COMPLEX8 badtype; }; #endif #ifdef CCTK_REAL8 template<> inline complex mymin (const complex x, const complex y) { return complex (mymin(x.real(), y.real()), mymin(x.imag(), y.imag())); } template<> inline complex mymax (const complex x, const complex y) { return complex (mymax(x.real(), y.real()), mymax(x.imag(), y.imag())); } template<> struct my_numeric_limits > { static complex min () { return complex (my_numeric_limits::min(), my_numeric_limits::min()); } static complex max () { return complex (my_numeric_limits::max(), my_numeric_limits::max()); } }; template<> struct typeconv { typedef complex goodtype; typedef CCTK_COMPLEX16 badtype; }; #endif #ifdef CCTK_REAL16 template<> inline complex mymin (const complex x, const complex y) { return complex (mymin(x.real(), y.real()), mymin(x.imag(), y.imag())); } template<> inline complex mymax (const complex x, const complex y) { return complex (mymax(x.real(), y.real()), mymax(x.imag(), y.imag())); } template<> struct my_numeric_limits > { static complex min () { return complex (my_numeric_limits::min(), my_numeric_limits::min()); } static complex max () { return complex (my_numeric_limits::max(), my_numeric_limits::max()); } }; template<> struct typeconv { typedef complex goodtype; typedef CCTK_COMPLEX32 badtype; }; #endif // Provide a square root function for integer values #ifdef CCTK_INT1 template<> inline CCTK_INT1 mysqrt (const CCTK_INT1 x) { return sqrt((CCTK_REAL)x); } #endif #ifdef CCTK_INT2 template<> inline CCTK_INT2 mysqrt (const CCTK_INT2 x) { return sqrt((CCTK_REAL)x); } #endif #ifdef CCTK_INT4 template<> inline CCTK_INT4 mysqrt (const CCTK_INT4 x) { return sqrt((CCTK_REAL)x); } #endif #ifdef CCTK_INT8 template<> inline CCTK_INT8 mysqrt (const CCTK_INT8 x) { return sqrt((CCTK_REAL)x); } #endif // Poor man's RTTI enum ared { do_count, do_origin, do_minimum, do_maximum, do_product, do_sum, do_sum_abs, do_sum_squared, do_average, do_norm1, do_norm2, do_norm_inf }; struct reduction { virtual ared thered () const = 0; virtual bool uses_cnt () const = 0; virtual MPI_Op mpi_op () const = 0; }; // count: count the number of grid points struct count : reduction { count () { } ared thered () const { return do_count; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += T(1); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct origin : reduction { origin () { } ared thered () const { return do_origin; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { assert(0); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct minimum : reduction { minimum () { } ared thered () const { return do_minimum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = my_numeric_limits::max(); } static inline void reduce (T& accum, const T& val) { accum = mymin(accum, val); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_MIN; } }; struct maximum : reduction { maximum () { } ared thered () const { return do_maximum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = my_numeric_limits::min(); } static inline void reduce (T& accum, const T& val) { accum = mymax(accum, val); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_MAX; } }; struct product : reduction { product () { } ared thered () const { return do_product; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(1); } static inline void reduce (T& accum, const T& val) { accum *= val; } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_PROD; } }; struct sum : reduction { sum () { } ared thered () const { return do_sum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += val; } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct sum_abs : reduction { sum_abs () { } ared thered () const { return do_sum_abs; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += abs(val); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct sum_squared : reduction { sum_squared () { } ared thered () const { return do_sum_squared; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += val*val; } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct average : reduction { average () { } ared thered () const { return do_average; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += val; } static inline void finalise (T& accum, const T& cnt) { accum /= cnt; } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct norm1 : reduction { norm1 () { } ared thered () const { return do_norm1; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += abs(val); } static inline void finalise (T& accum, const T& cnt) { accum /= cnt; } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct norm2 : reduction { norm2 () { } ared thered () const { return do_norm2; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum += abs(val)*abs(val); } static inline void finalise (T& accum, const T& cnt) { accum = mysqrt(accum / cnt); } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct norm_inf : reduction { norm_inf () { } ared thered () const { return do_norm_inf; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = T(0); } static inline void reduce (T& accum, const T& val) { accum = mymax(accum, (T)abs(val)); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; template void initialise (void* const outval, void* const cnt) { OP::initialise (*(T*)outval); *(T*)cnt = T(0); } template void reduce (const int* const lsh, const int* const bbox, const int* const nghostzones, const void* const inarray, void* const outval, void* const cnt) { const T *myinarray = (const T*)inarray; T myoutval = *(T*)outval; T mycnt = *(T*)cnt; vect imin, imax; for (int d=0; d void finalise (void* const outval, const void* const cnt) { OP::finalise (*(T*)outval, *(const T*)cnt); } void Initialise (const cGH* const cgh, const int proc, const int num_outvals, void* const myoutvals, const int outtype, void* const mycounts, const reduction* const red) { assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); const int vartypesize = CCTK_VarTypeSize(outtype); assert (vartypesize>=0); assert (myoutvals); assert (mycounts); assert (red); for (int n=0; n::goodtype T; \ initialise > (&((char*)myoutvals)[vartypesize*n], \ &((char*)mycounts )[vartypesize*n]); \ break; \ } #define TYPECASE(N,T) \ case N: { \ switch (red->thered()) { \ INITIALISE(count,T); \ INITIALISE(origin,T); \ INITIALISE(minimum,T); \ INITIALISE(maximum,T); \ INITIALISE(product,T); \ INITIALISE(sum,T); \ INITIALISE(sum_abs,T); \ INITIALISE(sum_squared,T); \ INITIALISE(average,T); \ INITIALISE(norm1,T); \ INITIALISE(norm2,T); \ INITIALISE(norm_inf,T); \ default: \ assert (0); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef INITIALISE default: assert (0); } } // for n } void Copy (const cGH* const cgh, const int proc, const int lsize, const int num_inarrays, const void* const* const inarrays, const int intype, const int num_outvals, void* const myoutvals, const int outtype, void* const mycounts) { assert (cgh); assert (proc == -1 || (proc>=0 && proc= 0); assert (num_outvals>=0); assert (num_inarrays>=0); assert (num_inarrays * lsize == num_outvals); assert (inarrays); for (int n=0; n::goodtype T; \ ((T*)myoutvals)[n+lsize*m] = ((const T*)inarrays[m])[n]; \ ((T*)mycounts )[n+lsize*m] = T(1); \ } #define TYPECASE(N,T) \ case N: { \ COPY(T); \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef COPY default: assert (0); } } // for } // for } void Reduce (const cGH* const cgh, const int proc, const int* const mylsh, const int* const mybbox, const int* const mynghostzones, const int num_inarrays, const void* const* const inarrays, const int intype, const int num_outvals, void* const myoutvals, const int outtype, void* const mycounts, const reduction* const red) { assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); assert (num_inarrays>=0); assert (num_inarrays == num_outvals); assert (inarrays); for (int n=0; n=0); assert (mynghostzones[d]>=0 && 2*mynghostzones[d]<=mylsh[d]); } const int vartypesize = CCTK_VarTypeSize(outtype); assert (vartypesize>=0); assert (myoutvals); assert (mycounts); assert (outtype == intype); for (int n=0; n::goodtype T; \ reduce > (mylsh, mybbox, mynghostzones, inarrays[n], \ &((char*)myoutvals)[vartypesize*n], \ &((char*)mycounts )[vartypesize*n]); \ break; \ } #define TYPECASE(N,T) \ case N: { \ switch (red->thered()) { \ REDUCE(count,T); \ REDUCE(origin,T); \ REDUCE(minimum,T); \ REDUCE(maximum,T); \ REDUCE(product,T); \ REDUCE(sum,T); \ REDUCE(sum_abs,T); \ REDUCE(sum_squared,T); \ REDUCE(average,T); \ REDUCE(norm1,T); \ REDUCE(norm2,T); \ REDUCE(norm_inf,T); \ default: \ assert (0); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef REDUCE default: assert (0); } } // for n } void Finalise (const cGH* const cgh, const int proc, const int num_outvals, void* const outvals, const int outtype, const void* const myoutvals, const void* const mycounts, const reduction* const red) { assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh))); const int vartypesize = CCTK_VarTypeSize(outtype); assert (vartypesize>=0); assert (myoutvals); assert (mycounts); vector counts; if (proc==-1 || proc==CCTK_MyProc(cgh)) { counts.resize(vartypesize * num_outvals); } if (proc == -1) { MPI_Allreduce ((void*)myoutvals, outvals, num_outvals, CarpetMPIDatatype(outtype), red->mpi_op(), CarpetMPIComm()); if (red->uses_cnt()) { MPI_Allreduce ((void*)mycounts, &counts[0], num_outvals, CarpetMPIDatatype(outtype), MPI_SUM, CarpetMPIComm()); } } else { MPI_Reduce ((void*)myoutvals, outvals, num_outvals, CarpetMPIDatatype(outtype), red->mpi_op(), proc, CarpetMPIComm()); if (red->uses_cnt()) { MPI_Reduce ((void*)mycounts, &counts[0], num_outvals, CarpetMPIDatatype(outtype), MPI_SUM, proc, CarpetMPIComm()); } } if (proc==-1 || proc==CCTK_MyProc(cgh)) { for (int n=0; n::goodtype T; \ finalise > (&((char*)outvals)[vartypesize*n], \ & counts [vartypesize*n]); \ break; \ } #define TYPECASE(N,T) \ case N: { \ switch (red->thered()) { \ FINALISE(count,T); \ FINALISE(origin,T); \ FINALISE(minimum,T); \ FINALISE(maximum,T); \ FINALISE(product,T); \ FINALISE(sum,T); \ FINALISE(sum_abs,T); \ FINALISE(sum_squared,T); \ FINALISE(average,T); \ FINALISE(norm1,T); \ FINALISE(norm2,T); \ FINALISE(norm_inf,T); \ default: \ assert (0); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef FINALISE default: assert (0); } } // for n } // if } int ReduceArrays (const cGH* const cgh, const int proc, const int num_dims, const int* const dims, const int num_inarrays, const void* const* const inarrays, const int intype, const int num_outvals, void* const outvals, const int outtype, const reduction* const red) { assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh))); assert (num_inarrays>=0); assert (inarrays); for (int n=0; n=0 && num_dims<=dim); for (int d=0; d=0); } int lsize = 1; for (int d=0; d mylsh, mynghostzones; vect,dim> mybbox; for (int d=0; d=0); vector myoutvals (vartypesize * num_inarrays * num_outvals); vector mycounts (vartypesize * num_inarrays * num_outvals); Initialise (cgh, proc, num_inarrays * num_outvals, &myoutvals[0], outtype, &mycounts[0], red); if (do_local_reduction) { Reduce (cgh, proc, &mylsh[0], &mybbox[0][0], &mynghostzones[0], num_inarrays, inarrays, intype, num_inarrays * num_outvals, &myoutvals[0], outtype, &mycounts[0], red); } else { Copy (cgh, proc, lsize, num_inarrays, inarrays, intype, num_inarrays * num_outvals, &myoutvals[0], outtype, &mycounts[0]); } Finalise (cgh, proc, num_inarrays * num_outvals, outvals, outtype, &myoutvals[0], &mycounts[0], red); return 0; } int ReduceGVs (const cGH* const cgh, const int proc, const int num_outvals, const int outtype, void* const outvals, const int num_invars, const int* const invars, const reduction* const red) { int ierr; assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); assert (num_outvals==1); assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh))); assert (num_invars>=0); assert (invars); for (int n=0; n=0 && invars[n]0); const int vi = invars[0]; assert (vi>=0 && vi=0 && grpdim<=dim); for (int n=0; n=0); bool const reduce_arrays = CCTK_GroupTypeFromVarI(vi) != CCTK_GF; for (int n=0; n myoutvals (vartypesize * num_invars * num_outvals); vector mycounts (vartypesize * num_invars * num_outvals); Initialise (cgh, proc, num_invars * num_outvals, &myoutvals[0], outtype, &mycounts[0], red); int const saved_reflevel = reflevel; int const saved_map = Carpet::map; int const saved_component = component; BEGIN_GLOBAL_MODE(cgh) { BEGIN_REFLEVEL_LOOP(cgh) { BEGIN_MAP_LOOP(cgh, reduce_arrays ? CCTK_ARRAY : CCTK_GF) { BEGIN_LOCAL_COMPONENT_LOOP(cgh, reduce_arrays ? CCTK_ARRAY : CCTK_GF) { if (reduce_arrays || ((saved_reflevel==-1 || reflevel==saved_reflevel) && (saved_map==-1 || Carpet::map==saved_map) && (saved_component==-1 || component==saved_component))) { assert (grpdim<=dim); int lsh[dim], bbox[2*dim], nghostzones[dim]; ierr = CCTK_GrouplshVI(cgh, grpdim, lsh, vi); assert (!ierr); ierr = CCTK_GroupbboxVI(cgh, 2*grpdim, bbox, vi); assert (!ierr); ierr = CCTK_GroupnghostzonesVI(cgh, grpdim, nghostzones, vi); assert (!ierr); for (int d=0; d=0); assert (nghostzones[d]>=0 && 2*nghostzones[d]<=lsh[d]); } vector inarrays (num_invars); for (int n=0; n mylsh, mynghostzones; vect,dim> mybbox; for (int d=0; d