// $Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetReduce/src/reduce.cc,v 1.9 2002/06/05 19:11:00 schnetter Exp $ #include #include #include #include #include #include #include #include "cctk.h" #include "Carpet/CarpetLib/src/dist.hh" #include "Carpet/Carpet/src/carpet.hh" #include "reduce.hh" static const char* rcsid = "$Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetReduce/src/reduce.cc,v 1.9 2002/06/05 19:11:00 schnetter Exp $"; CCTK_FILEVERSION(CarpetReduce_reduce_cc) #ifndef LLONG_MAX // # warning "no long long int support" #endif #ifndef LDBL_MAX // # warning "no long double support" #endif namespace CarpetReduce { using namespace Carpet; // Poor man's RTTI enum ared { do_count, do_minimum, do_maximum, 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 { ared thered () const { return do_count; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = 0; } static inline void reduce (T& accum, const T& val) { ++accum; } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_SUM; } }; struct minimum : reduction { ared thered () const { return do_minimum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { abort(); } static inline void reduce (T& accum, const T& val) { accum = min(accum, val); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_MIN; } }; template<> inline void minimum::op ::initialise (char & accum) { accum = CHAR_MAX; } template<> inline void minimum::op ::initialise (signed char & accum) { accum = SCHAR_MAX; } template<> inline void minimum::op::initialise (unsigned char& accum) { accum = UCHAR_MAX; } template<> inline void minimum::op ::initialise (short & accum) { accum = SHRT_MAX; } template<> inline void minimum::op ::initialise (int & accum) { accum = INT_MAX; } template<> inline void minimum::op ::initialise (long & accum) { accum = LONG_MAX; } #ifdef LLONG_MAX template<> inline void minimum::op ::initialise (long long & accum) { accum = LLONG_MAX; } #endif template<> inline void minimum::op ::initialise (float & accum) { accum = FLT_MAX; } template<> inline void minimum::op ::initialise (double & accum) { accum = DBL_MAX; } #ifdef LDBL_MAX template<> inline void minimum::op ::initialise (long double & accum) { accum = LDBL_MAX; } #endif template<> inline void minimum::op > ::initialise (complex & accum) { accum = complex(FLT_MAX,FLT_MAX); } template<> inline void minimum::op > ::initialise (complex & accum) { accum = complex(DBL_MAX,DBL_MAX); } #ifdef LDBL_MAX template<> inline void minimum::op > ::initialise (complex & accum) { accum = complex(LDBL_MAX,LDBL_MAX); } #endif template<> inline void minimum::op > ::reduce (complex& accum, const complex& val) { accum = complex(min(accum.real(), val.real()), min(accum.imag(), val.imag())); } template<> inline void minimum::op > ::reduce (complex& accum, const complex& val) { accum = complex(min(accum.real(), val.real()), min(accum.imag(), val.imag())); } #ifdef LDBL_MAX template<> inline void minimum::op > ::reduce (complex& accum, const complex& val) { accum = complex(min(accum.real(), val.real()), min(accum.imag(), val.imag())); } #endif struct maximum : reduction { ared thered () const { return do_maximum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { abort(); } static inline void reduce (T& accum, const T& val) { accum = max(accum, val); } static inline void finalise (T& accum, const T& cnt) { } }; MPI_Op mpi_op () const { return MPI_MAX; } }; template<> inline void maximum::op ::initialise (char & accum) { accum = CHAR_MIN; } template<> inline void maximum::op ::initialise (signed char & accum) { accum = SCHAR_MIN; } template<> inline void maximum::op::initialise (unsigned char& accum) { accum = 0; } template<> inline void maximum::op ::initialise (short & accum) { accum = SHRT_MIN; } template<> inline void maximum::op ::initialise (int & accum) { accum = INT_MIN; } template<> inline void maximum::op ::initialise (long & accum) { accum = LONG_MIN; } #ifdef LLONG_MIN template<> inline void maximum::op ::initialise (long long & accum) { accum = LLONG_MIN; } #endif template<> inline void maximum::op ::initialise (float & accum) { accum = -FLT_MAX; } template<> inline void maximum::op ::initialise (double & accum) { accum = -DBL_MAX; } #ifdef LDBL_MAX template<> inline void maximum::op ::initialise (long double & accum) { accum = -LDBL_MAX; } #endif template<> inline void maximum::op > ::initialise (complex & accum) { accum = complex(-FLT_MAX,-FLT_MAX); } template<> inline void maximum::op > ::initialise (complex & accum) { accum = complex(-DBL_MAX,-DBL_MAX); } #ifdef LDBL_MAX template<> inline void maximum::op > ::initialise (complex & accum) { accum = complex(-LDBL_MAX,-LDBL_MAX); } #endif template<> inline void maximum::op > ::reduce (complex& accum, const complex& val) { accum = complex(max(accum.real(), val.real()), max(accum.imag(), val.imag())); } template<> inline void maximum::op > ::reduce (complex& accum, const complex& val) { accum = complex(max(accum.real(), val.real()), max(accum.imag(), val.imag())); } #ifdef LDBL_MAX template<> inline void maximum::op > ::reduce (complex& accum, const complex& val) { accum = complex(max(accum.real(), val.real()), max(accum.imag(), val.imag())); } #endif struct sum : reduction { ared thered () const { return do_sum; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = 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 { ared thered () const { return do_sum_abs; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = 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 { ared thered () const { return do_sum_squared; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = 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 { ared thered () const { return do_average; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = 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 { ared thered () const { return do_norm1; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = 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 { ared thered () const { return do_norm2; } bool uses_cnt () const { return true; } template struct op { static inline void initialise (T& accum) { accum = 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 = sqrt(accum / cnt); } }; MPI_Op mpi_op () const { return MPI_SUM; } }; template<> inline void norm2::op ::finalise (char & accum, const char & cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op ::finalise (signed char & accum, const signed char & cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op::finalise (unsigned char& accum, const unsigned char& cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op ::finalise (short & accum, const short & cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op ::finalise (int & accum, const int & cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op ::finalise (long & accum, const long & cnt) { accum = sqrt((double)accum / cnt); } template<> inline void norm2::op ::finalise (long long & accum, const long long & cnt) { accum = sqrt((double)accum / cnt); } struct norm_inf : reduction { ared thered () const { return do_norm_inf; } bool uses_cnt () const { return false; } template struct op { static inline void initialise (T& accum) { accum = 0; } static inline void reduce (T& accum, const T& val) { accum = max(accum, 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 = 0; } template void reduce (const int* const dims, 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; for (int k=nghostzones[2]; k void finalise (void* const outval, const void* const cnt) { OP::finalise (*(T*)outval, *(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 > (&((char*)myoutvals)[vartypesize*n], \ &((char*)mycounts)[vartypesize*n]); \ break; #define TYPECASE(N,T) \ case N: { \ switch (red->thered()) { \ INITIALISE(count,T); \ INITIALISE(minimum,T); \ INITIALISE(maximum,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: \ abort(); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef INITIALISE default: abort(); } } // for n } void Reduce (const cGH* const cgh, const int proc, const int* const mydims, 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]<=mydims[d]); } const int vartypesize = CCTK_VarTypeSize(outtype); assert (vartypesize>=0); assert (myoutvals); assert (mycounts); for (int n=0; n > (mydims, 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(minimum,T); \ REDUCE(maximum,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: \ abort(); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef REDUCE default: abort(); } } // 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); char *counts = 0; if (proc==-1 || proc==CCTK_MyProc(cgh)) { counts = new char [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, 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, num_outvals, CarpetMPIDatatype(outtype), MPI_SUM, proc, CarpetMPIComm()); } } if (proc==-1 || proc==CCTK_MyProc(cgh)) { for (int n=0; n > \ (&((char*)outvals)[vartypesize*n], &counts[vartypesize*n]); \ break; #define TYPECASE(N,T) \ case N: { \ switch (red->thered()) { \ FINALISE(count,T); \ FINALISE(minimum,T); \ FINALISE(maximum,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: \ abort(); \ } \ break; \ } #include "Carpet/Carpet/src/typecase" #undef TYPECASE #undef FINALISE default: abort(); } } // for n delete [] counts; } // 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 (num_inarrays == num_outvals); assert (inarrays); for (int n=0; n=0 && num_dims<=dim); for (int d=0; d=0); } int mydims[dim], mynghostzones[dim]; for (int d=0; d=0); char *myoutvals = new char [vartypesize * num_outvals]; char *mycounts = new char [vartypesize * num_outvals]; Initialise (cgh, proc, num_outvals, myoutvals, outtype, mycounts, red); Reduce (cgh, proc, mydims, mynghostzones, num_inarrays, inarrays, intype, num_outvals, myoutvals, outtype, mycounts, red); Finalise (cgh, proc, num_outvals, outvals, outtype, myoutvals, mycounts, red); delete [] myoutvals; delete [] mycounts; 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; // global mode if (component != -1) { CCTK_WARN (0, "It is not possible to use a grid variable reduction operator in local mode"); } assert (component == -1); assert (cgh); assert (proc == -1 || (proc>=0 && proc=0); assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh))); assert (num_invars>=0); assert (num_invars == num_outvals); assert (invars); for (int n=0; n=0 && invars[n]=0 && vi=0 && num_dims<=dim); for (int n=0; n=0); char *myoutvals = new char [vartypesize * num_outvals]; char *mycounts = new char [vartypesize * num_outvals]; Initialise (cgh, proc, num_outvals, myoutvals, outtype, mycounts, red); BEGIN_LOCAL_COMPONENT_LOOP(cgh) { int dims[dim], nghostzones[dim]; ierr = CCTK_GrouplshVI(cgh, num_dims, dims, vi); assert (!ierr); ierr = CCTK_GroupnghostzonesVI(cgh, num_dims, nghostzones, vi); assert (!ierr); for (int d=0; d=0); assert (nghostzones[d]>=0 && 2*nghostzones[d]<=dims[d]); } const void** inarrays = new const void * [num_invars]; for (int n=0; n