aboutsummaryrefslogtreecommitdiff
path: root/Carpet/CarpetReduce/src/reduce.cc
diff options
context:
space:
mode:
Diffstat (limited to 'Carpet/CarpetReduce/src/reduce.cc')
-rw-r--r--Carpet/CarpetReduce/src/reduce.cc1174
1 files changed, 1174 insertions, 0 deletions
diff --git a/Carpet/CarpetReduce/src/reduce.cc b/Carpet/CarpetReduce/src/reduce.cc
new file mode 100644
index 000000000..622d63291
--- /dev/null
+++ b/Carpet/CarpetReduce/src/reduce.cc
@@ -0,0 +1,1174 @@
+// $Header: /home/eschnett/C/carpet/Carpet/Carpet/CarpetReduce/src/reduce.cc,v 1.43 2004/08/02 11:43:35 schnetter Exp $
+
+#include <assert.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <complex>
+#include <limits>
+#include <vector>
+
+#include <mpi.h>
+
+#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.43 2004/08/02 11:43:35 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<typename T> inline T
+ mymin (const T x, const T y)
+ {
+ return min(x, y);
+ }
+
+ // The maximum of two values
+ template<typename T> inline T
+ mymax (const T x, const T y)
+ {
+ return max(x, y);
+ }
+
+ // Square root
+ template<typename T> inline T
+ mysqrt (const T x)
+ {
+ return sqrt(x);
+ }
+
+
+
+ // Properties of numeric types
+ template<typename T>
+ struct my_numeric_limits {
+
+ // The smallest possible value
+ static T min ()
+ {
+ return mymin (numeric_limits<T>::min(), -numeric_limits<T>::max());
+ }
+
+ // The largest possible value
+ static T max ()
+ {
+ return mymax (numeric_limits<T>::max(), -numeric_limits<T>::min());
+ }
+
+ };
+
+
+
+ // Provide for each Cactus type a "good" type, translating between
+ // CCTK_COMPLEX* and complex<CCTK_REAL*>
+ template<typename T>
+ struct typeconv {
+ typedef T goodtype;
+ typedef T badtype;
+ };
+
+
+
+ // Overload the above helper functions and types for complex values
+
+#ifdef CCTK_REAL4
+
+ template<> inline complex<CCTK_REAL4>
+ mymin (const complex<CCTK_REAL4> x, const complex<CCTK_REAL4> y)
+ {
+ return complex<CCTK_REAL4> (mymin(x.real(), y.real()),
+ mymin(x.imag(), y.imag()));
+ }
+
+ template<> inline complex<CCTK_REAL4>
+ mymax (const complex<CCTK_REAL4> x, const complex<CCTK_REAL4> y)
+ {
+ return complex<CCTK_REAL4> (mymax(x.real(), y.real()),
+ mymax(x.imag(), y.imag()));
+ }
+
+ template<>
+ struct my_numeric_limits<complex<CCTK_REAL4> > {
+ static complex<CCTK_REAL4> min ()
+ {
+ return complex<CCTK_REAL4> (my_numeric_limits<CCTK_REAL4>::min(),
+ my_numeric_limits<CCTK_REAL4>::min());
+ }
+ static complex<CCTK_REAL4> max ()
+ {
+ return complex<CCTK_REAL4> (my_numeric_limits<CCTK_REAL4>::max(),
+ my_numeric_limits<CCTK_REAL4>::max());
+ }
+ };
+
+ template<>
+ struct typeconv<CCTK_COMPLEX8> {
+ typedef complex<CCTK_REAL4> goodtype;
+ typedef CCTK_COMPLEX8 badtype;
+ };
+
+#endif
+
+#ifdef CCTK_REAL8
+
+ template<> inline complex<CCTK_REAL8>
+ mymin (const complex<CCTK_REAL8> x, const complex<CCTK_REAL8> y)
+ {
+ return complex<CCTK_REAL8> (mymin(x.real(), y.real()),
+ mymin(x.imag(), y.imag()));
+ }
+
+ template<> inline complex<CCTK_REAL8>
+ mymax (const complex<CCTK_REAL8> x, const complex<CCTK_REAL8> y)
+ {
+ return complex<CCTK_REAL8> (mymax(x.real(), y.real()),
+ mymax(x.imag(), y.imag()));
+ }
+
+ template<>
+ struct my_numeric_limits<complex<CCTK_REAL8> > {
+ static complex<CCTK_REAL8> min ()
+ {
+ return complex<CCTK_REAL8> (my_numeric_limits<CCTK_REAL8>::min(),
+ my_numeric_limits<CCTK_REAL8>::min());
+ }
+ static complex<CCTK_REAL8> max ()
+ {
+ return complex<CCTK_REAL8> (my_numeric_limits<CCTK_REAL8>::max(),
+ my_numeric_limits<CCTK_REAL8>::max());
+ }
+ };
+
+ template<>
+ struct typeconv<CCTK_COMPLEX16> {
+ typedef complex<CCTK_REAL8> goodtype;
+ typedef CCTK_COMPLEX16 badtype;
+ };
+
+#endif
+
+#ifdef CCTK_REAL16
+
+ template<> inline complex<CCTK_REAL16>
+ mymin (const complex<CCTK_REAL16> x, const complex<CCTK_REAL16> y)
+ {
+ return complex<CCTK_REAL16> (mymin(x.real(), y.real()),
+ mymin(x.imag(), y.imag()));
+ }
+
+ template<> inline complex<CCTK_REAL16>
+ mymax (const complex<CCTK_REAL16> x, const complex<CCTK_REAL16> y)
+ {
+ return complex<CCTK_REAL16> (mymax(x.real(), y.real()),
+ mymax(x.imag(), y.imag()));
+ }
+
+ template<>
+ struct my_numeric_limits<complex<CCTK_REAL16> > {
+ static complex<CCTK_REAL16> min ()
+ {
+ return complex<CCTK_REAL16> (my_numeric_limits<CCTK_REAL16>::min(),
+ my_numeric_limits<CCTK_REAL16>::min());
+ }
+ static complex<CCTK_REAL16> max ()
+ {
+ return complex<CCTK_REAL16> (my_numeric_limits<CCTK_REAL16>::max(),
+ my_numeric_limits<CCTK_REAL16>::max());
+ }
+ };
+
+ template<>
+ struct typeconv<CCTK_COMPLEX32> {
+ typedef complex<CCTK_REAL16> 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_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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { accum += T(weight); }
+ 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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = my_numeric_limits<T>::max(); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) 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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = my_numeric_limits<T>::min(); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) 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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(1); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum *= weight==1 ? val : pow(val,weight); }
+ 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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum += weight*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<class T>
+ struct op {
+ static inline void initialise (T& accum) { accum = T(0); }
+ static inline void reduce (T& accum, const T& val, const CCTK_REAL weight) { if (weight>0) accum = mymax(accum, T(abs(val))); }
+ static inline void finalise (T& accum, const T& cnt) { }
+ };
+ MPI_Op mpi_op () const { return MPI_MAX; }
+ };
+
+
+
+ template<class T,class OP>
+ void initialise (void* const outval, void* const cnt)
+ {
+ OP::initialise (*(T*)outval);
+ *(T*)cnt = T(0);
+ }
+
+ template<class T,class OP>
+ void reduce (const int* const lsh, const int* const bbox,
+ const int* const nghostzones,
+ vector<const void*> const& inarrays,
+ vector<CCTK_REAL> const& tfacs,
+ void* const outval, void* const cnt,
+ const CCTK_REAL* const weight, const CCTK_REAL levfac)
+ {
+ for (size_t tl=0; tl<inarrays.size(); ++tl) {
+ assert (inarrays.at(tl));
+ }
+ assert (tfacs.size() == inarrays.size());
+ T myoutval = *(T*)outval;
+ T mycnt = *(T*)cnt;
+ vect<int,dim> imin, imax;
+ for (int d=0; d<dim; ++d) {
+ imin[d] = bbox[2*d ] ? 0 : nghostzones[d];
+ imax[d] = bbox[2*d+1] ? lsh[d] : lsh[d] - nghostzones[d];
+ }
+ assert (dim==3);
+ for (int k=imin[2]; k<imax[2]; ++k) {
+ for (int j=imin[1]; j<imax[1]; ++j) {
+ for (int i=imin[0]; i<imax[0]; ++i) {
+ const int index = i + lsh[0] * (j + lsh[1] * k);
+ CCTK_REAL const w = (weight ? weight[index] : 1.0) * levfac;
+ T myinval = T(0);
+ for (size_t tl=0; tl<inarrays.size(); ++tl) {
+ myinval += (static_cast<const T*>(inarrays.at(tl))[index]
+ * tfacs.at(tl));
+ }
+ OP::reduce (myoutval, myinval, w);
+ mycnt += w;
+ }
+ }
+ }
+ *(T*)outval = myoutval;
+ *(T*)cnt = mycnt;
+ }
+
+ template<class T,class OP>
+ 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<CCTK_nProcs(cgh)));
+
+ assert (num_outvals>=0);
+
+ const int vartypesize = CCTK_VarTypeSize(outtype);
+ assert (vartypesize>=0);
+
+ assert (myoutvals);
+ assert (mycounts);
+
+ assert (red);
+
+ for (int n=0; n<num_outvals; ++n) {
+
+ switch (outtype) {
+#define INITIALISE(OP,S) \
+ case do_##OP: { \
+ typedef typeconv<S>::goodtype T; \
+ initialise<T,OP::op<T> > (&((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(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<CCTK_nProcs(cgh)));
+
+ assert (lsize >= 0);
+ assert (num_outvals>=0);
+
+ assert (num_inarrays>=0);
+ assert (num_inarrays * lsize == num_outvals);
+ assert (inarrays);
+ for (int n=0; n<num_inarrays; ++n) {
+ assert (inarrays[n]);
+ }
+
+ assert (myoutvals);
+ assert (mycounts);
+
+ assert (outtype == intype);
+
+ for (int m=0; m<num_inarrays; ++m) {
+ for (int n=0; n<lsize; ++n) {
+
+ switch (outtype) {
+#define COPY(S) \
+ { \
+ typedef typeconv<S>::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,
+ vector<const void* const*> const& inarrays,
+ vector<CCTK_REAL> const& tfacs, const int intype,
+ const int num_outvals,
+ void* const myoutvals, const int outtype,
+ void* const mycounts,
+ const reduction* const red,
+ CCTK_REAL const * const weight, CCTK_REAL const levfac)
+ {
+ assert (cgh);
+
+ assert (proc == -1 || (proc>=0 && proc<CCTK_nProcs(cgh)));
+
+ assert (num_outvals>=0);
+
+ assert (num_inarrays>=0);
+ assert (num_inarrays == num_outvals);
+ for (size_t tl=0; tl<inarrays.size(); ++tl) {
+ assert (inarrays.at(tl));
+ for (int n=0; n<num_inarrays; ++n) {
+ assert (inarrays.at(tl)[n]);
+ }
+ }
+ assert (tfacs.size() == inarrays.size());
+
+ for (int d=0; d<dim; ++d) {
+ assert (mylsh[d]>=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);
+
+ vector<const void*> myinarrays(inarrays.size());
+
+ for (int n=0; n<num_outvals; ++n) {
+
+ for (size_t tl=0; tl<inarrays.size(); ++tl) {
+ myinarrays.at(tl) = inarrays.at(tl)[n];
+ }
+
+ switch (outtype) {
+#define REDUCE(OP,S) \
+ case do_##OP: { \
+ typedef typeconv<S>::goodtype T; \
+ reduce<T,OP::op<T> > (mylsh, mybbox, mynghostzones, \
+ myinarrays, tfacs, \
+ &((char*)myoutvals)[vartypesize*n], \
+ &((char*)mycounts )[vartypesize*n], \
+ weight, levfac); \
+ break; \
+ }
+#define TYPECASE(N,T) \
+ case N: { \
+ switch (red->thered()) { \
+ REDUCE(count,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<CCTK_nProcs(cgh)));
+
+ assert (num_outvals>=0);
+ assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh)));
+
+ const int vartypesize = CCTK_VarTypeSize(outtype);
+ assert (vartypesize>=0);
+
+ assert (myoutvals);
+ assert (mycounts);
+
+ vector<char> counts;
+ if (proc==-1 || proc==CCTK_MyProc(cgh)) {
+ counts.resize(vartypesize * num_outvals);
+ }
+
+ const MPI_Datatype mpitype = CarpetSimpleMPIDatatype(outtype);
+ const int mpilength = CarpetSimpleMPIDatatypeLength(outtype);
+ if (proc == -1) {
+ MPI_Allreduce ((void*)myoutvals, outvals, mpilength*num_outvals,
+ mpitype, red->mpi_op(),
+ CarpetMPIComm());
+ if (red->uses_cnt()) {
+ MPI_Allreduce ((void*)mycounts, &counts[0], num_outvals*mpilength,
+ mpitype, MPI_SUM,
+ CarpetMPIComm());
+ }
+ } else {
+ MPI_Reduce ((void*)myoutvals, outvals, num_outvals*mpilength,
+ mpitype, red->mpi_op(),
+ proc, CarpetMPIComm());
+ if (red->uses_cnt()) {
+ MPI_Reduce ((void*)mycounts, &counts[0], num_outvals*mpilength,
+ mpitype, MPI_SUM,
+ proc, CarpetMPIComm());
+ }
+ }
+
+ if (proc==-1 || proc==CCTK_MyProc(cgh)) {
+
+ for (int n=0; n<num_outvals; ++n) {
+
+ assert (outvals);
+ assert ((int)counts.size() == vartypesize * num_outvals);
+
+ switch (outtype) {
+#define FINALISE(OP,S) \
+ case do_##OP: { \
+ typedef typeconv<S>::goodtype T; \
+ finalise<T,OP::op<T> > (&((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(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<CCTK_nProcs(cgh)));
+
+ assert (num_outvals>=0);
+ assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh)));
+
+ assert (num_inarrays>=0);
+ assert (inarrays);
+ for (int n=0; n<num_inarrays; ++n) {
+ assert (inarrays[n]);
+ }
+
+ assert (num_dims>=0 && num_dims<=dim);
+ for (int d=0; d<num_dims; ++d) {
+ assert (dims[d]>=0);
+ }
+
+ int lsize = 1;
+ for (int d=0; d<num_dims; ++d) {
+ lsize *= dims[d];
+ }
+
+ const bool do_local_reduction = num_outvals == 1;
+
+ if (! do_local_reduction) {
+ assert (num_outvals == lsize);
+ }
+
+ vect<int,dim> mylsh, mynghostzones;
+ vect<vect<int,2>,dim> mybbox;
+ for (int d=0; d<num_dims; ++d) {
+ mylsh[d] = dims[d];
+ mybbox[d][0] = 0;
+ mybbox[d][1] = 0;
+ mynghostzones[d] = 0;
+ }
+ for (int d=num_dims; d<dim; ++d) {
+ mylsh[d] = 1;
+ mybbox[d][0] = 0;
+ mybbox[d][1] = 0;
+ mynghostzones[d] = 0;
+ }
+
+ vector<const void* const*> myinarrays(1);
+ vector<CCTK_REAL> tfacs(1);
+ myinarrays.at(0) = inarrays;
+ tfacs.at(0) = 1.0;
+
+ const int vartypesize = CCTK_VarTypeSize(outtype);
+ assert (vartypesize>=0);
+
+ vector<char> myoutvals (vartypesize * num_inarrays * num_outvals);
+ vector<char> 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, myinarrays, tfacs, intype,
+ num_inarrays * num_outvals, &myoutvals[0], outtype,
+ &mycounts[0], red,
+ NULL, 1.0);
+ } 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<CCTK_nProcs(cgh)));
+
+ assert (num_outvals>=0);
+ assert (num_outvals==1);
+ assert (outvals || (proc!=-1 && proc!=CCTK_MyProc(cgh)));
+
+ assert (num_invars>=0);
+ assert (invars);
+ for (int n=0; n<num_invars; ++n) {
+ assert (invars[n]>=0 && invars[n]<CCTK_NumVars());
+ }
+
+ if (num_invars==0) return 0;
+
+ assert (num_invars>0);
+ const int vi = invars[0];
+ assert (vi>=0 && vi<CCTK_NumVars());
+
+ const int grpdim = CCTK_GroupDimFromVarI(vi);
+ assert (grpdim>=0 && grpdim<=dim);
+ for (int n=0; n<num_invars; ++n) {
+ assert (CCTK_GroupDimFromVarI(invars[n]) == grpdim);
+ }
+
+ const int intype = CCTK_VarTypeI(vi);
+ for (int n=0; n<num_invars; ++n) {
+ assert (CCTK_VarTypeI(invars[n]) == intype);
+ }
+
+ const int vartypesize = CCTK_VarTypeSize(outtype);
+ assert (vartypesize>=0);
+
+
+
+ // meta mode
+ if (is_meta_mode()) {
+ CCTK_WARN (0, "Grid variable reductions are not possible in meta mode");
+ }
+
+ bool const reduce_arrays = CCTK_GroupTypeFromVarI(vi) != CCTK_GF;
+ bool const want_global_mode = is_global_mode() && ! reduce_arrays;
+ bool const want_level_mode = is_level_mode() && ! reduce_arrays;
+
+ for (int n=0; n<num_invars; ++n) {
+ if ((CCTK_GroupTypeFromVarI(invars[n]) != CCTK_GF) != reduce_arrays) {
+ CCTK_WARN (0, "Cannot (yet) reduce grid functions and grid arrays/scalars at the same time");
+ }
+ }
+
+ // Ensure that all maps have the same number of refinement levels
+ for (int m=0; m<(int)vhh.size(); ++m) {
+ assert (vhh.at(m)->reflevels() == vhh.at(0)->reflevels());
+ }
+ int const minrl = reduce_arrays ? 0 : want_global_mode ? 0 : reflevel;
+ int const maxrl = reduce_arrays ? 1 : want_global_mode ? vhh.at(0)->reflevels() : reflevel+1;
+ int const minm = reduce_arrays ? 0 : want_global_mode || want_level_mode ? 0 : Carpet::map;
+ int const maxm = reduce_arrays ? 1 : want_global_mode || want_level_mode ? maps : Carpet::map+1;
+
+
+
+ // Find the time interpolation order
+ int partype;
+ void const * const parptr
+ = CCTK_ParameterGet ("prolongation_order_time", "Carpet", &partype);
+ assert (parptr);
+ assert (partype == PARAMETER_INTEGER);
+ int const prolongation_order_time = * (CCTK_INT const *) parptr;
+
+ CCTK_REAL const current_time = cgh->cctk_time / cgh->cctk_delta_time;
+
+
+
+ vector<char> myoutvals (vartypesize * num_invars * num_outvals);
+ vector<char> mycounts (vartypesize * num_invars * num_outvals);
+
+ Initialise (cgh, proc, num_invars * num_outvals, &myoutvals[0], outtype,
+ &mycounts[0], red);
+
+ BEGIN_GLOBAL_MODE(cgh) {
+ for (int rl=minrl; rl<maxrl; ++rl) {
+ enter_level_mode (const_cast<cGH*>(cgh), rl);
+
+
+
+ // Number of necessary time levels
+ CCTK_REAL const level_time = cgh->cctk_time / cgh->cctk_delta_time;
+ bool need_time_interp
+ = (! reduce_arrays
+ && (fabs(current_time - level_time)
+ > 1e-12 * (fabs(level_time) + fabs(current_time)
+ + fabs(cgh->cctk_delta_time))));
+ assert (! (! want_global_mode && need_time_interp));
+ assert (! (reduce_arrays && need_time_interp));
+ int num_tl = need_time_interp ? prolongation_order_time + 1 : 1;
+
+ // Are there enought time levels?
+ if (need_time_interp) {
+
+ if (CCTK_ActiveTimeLevelsVI(cgh, vi) < num_tl) {
+ static vector<bool> have_warned;
+ if (have_warned.empty()) {
+ have_warned.resize (CCTK_NumVars(), false);
+ }
+ if (! have_warned.at(vi)) {
+ char * const fullname = CCTK_FullName(vi);
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Grid function \"%s\" has only %d active time levels on refinement level %d; this is not enough for time interpolation. Using the current time level instead",
+ fullname, CCTK_ActiveTimeLevelsVI(cgh, vi), reflevel);
+ free (fullname);
+ have_warned.at(vi) = true;
+ }
+
+ // fall back
+ need_time_interp = false;
+ num_tl = 1;
+ }
+
+ }
+
+ vector<CCTK_REAL> tfacs(num_tl);
+
+ // Interpolate in time, if necessary
+ if (need_time_interp) {
+
+ // Get interpolation times
+ CCTK_REAL const time = current_time;
+ vector<CCTK_REAL> times(num_tl);
+ for (int tl=0; tl<num_tl; ++tl) {
+ times.at(tl) = vtt.at(0)->time (-tl, reflevel, mglevel);
+ }
+
+ // Calculate interpolation weights
+ switch (num_tl) {
+ case 1:
+ // no interpolation
+ assert (fabs((time - times.at(0)) / fabs(time + times.at(0) + cgh->cctk_delta_time)) < 1e-12);
+ tfacs.at(0) = 1.0;
+ break;
+ case 2:
+ // linear (2-point) interpolation
+ tfacs.at(0) = (time - times.at(1)) / (times.at(0) - times.at(1));
+ tfacs.at(1) = (time - times.at(0)) / (times.at(1) - times.at(0));
+ break;
+ case 3:
+ // quadratic (3-point) interpolation
+ tfacs.at(0) = (time - times.at(1)) * (time - times.at(2)) / ((times.at(0) - times.at(1)) * (times.at(0) - times.at(2)));
+ tfacs.at(1) = (time - times.at(0)) * (time - times.at(2)) / ((times.at(1) - times.at(0)) * (times.at(1) - times.at(2)));
+ tfacs.at(2) = (time - times.at(0)) * (time - times.at(1)) / ((times.at(2) - times.at(0)) * (times.at(2) - times.at(1)));
+ break;
+ default:
+ assert (0);
+ }
+
+ } else { // if ! need_time_interp
+
+ assert (num_tl == 1);
+ tfacs.at(0) = 1;
+
+ } // if ! need_time_interp
+
+
+
+ for (int m=minm; m<maxm; ++m) {
+ enter_singlemap_mode (const_cast<cGH*>(cgh), m);
+ BEGIN_LOCAL_COMPONENT_LOOP(cgh, reduce_arrays ? CCTK_ARRAY : CCTK_GF) {
+
+
+
+ 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<grpdim; ++d) {
+ assert (lsh[d]>=0);
+ assert (nghostzones[d]>=0 && 2*nghostzones[d]<=lsh[d]);
+ }
+
+ vect<int,dim> mylsh, mynghostzones;
+ vect<vect<int,2>,dim> mybbox;
+ for (int d=0; d<grpdim; ++d) {
+ mylsh[d] = lsh[d];
+ mybbox[d][0] = bbox[2*d ];
+ mybbox[d][1] = bbox[2*d+1];
+ mynghostzones[d] = nghostzones[d];
+ }
+ for (int d=grpdim; d<dim; ++d) {
+ mylsh[d] = 1;
+ mybbox[d][0] = 0;
+ mybbox[d][1] = 0;
+ mynghostzones[d] = 0;
+ }
+
+
+
+ CCTK_REAL const * weight;
+ CCTK_REAL levfac;
+ if (want_global_mode) {
+ weight = (static_cast<CCTK_REAL const *>
+ (CCTK_VarDataPtr (cgh, 0, "CarpetReduce::weight")));
+ assert (weight);
+ levfac = pow(CCTK_REAL(reflevelfact), -grpdim);
+ } else {
+ weight = NULL;
+ levfac = 1.0;
+ }
+
+ vector<vector<const void*> > myinarrays (num_tl);
+ vector<const void* const*> inarrays (num_tl);
+ for (int tl=0; tl<num_tl; ++tl) {
+ myinarrays.at(tl).resize (num_invars);
+ for (int n=0; n<num_invars; ++n) {
+ myinarrays.at(tl).at(n) = CCTK_VarDataPtrI(cgh, tl, invars[n]);
+ assert (myinarrays.at(tl).at(n));
+ }
+ inarrays.at(tl) = &myinarrays.at(tl).at(0);
+ }
+
+
+
+ Reduce (cgh, proc, &mylsh[0], &mybbox[0][0], &mynghostzones[0],
+ num_invars, inarrays, tfacs, intype,
+ num_invars * num_outvals, &myoutvals[0], outtype,
+ &mycounts[0], red,
+ weight, levfac);
+
+
+
+ } END_LOCAL_COMPONENT_LOOP;
+ leave_singlemap_mode (const_cast<cGH*>(cgh));
+ } // for m
+
+ leave_level_mode (const_cast<cGH*>(cgh));
+ } // for rl
+ } END_GLOBAL_MODE;
+
+ Finalise (cgh, proc, num_invars * num_outvals, outvals, outtype,
+ &myoutvals[0], &mycounts[0], red);
+
+ return 0;
+ }
+
+
+
+#define REDUCTION(OP) \
+ int OP##_arrays (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 OP red; \
+ return ReduceArrays \
+ (cgh, proc, num_dims, dims, \
+ num_inarrays, inarrays, intype, num_outvals, outvals, outtype, \
+ &red); \
+ } \
+ \
+ int OP##_GVs (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 OP red; \
+ return ReduceGVs (cgh, proc, \
+ num_outvals, outtype, outvals, num_invars, invars, \
+ &red); \
+ }
+
+ REDUCTION(count);
+ REDUCTION(minimum);
+ REDUCTION(maximum);
+ REDUCTION(product);
+ REDUCTION(sum);
+ REDUCTION(sum_abs);
+ REDUCTION(sum_squared);
+ REDUCTION(average);
+ REDUCTION(norm1);
+ REDUCTION(norm2);
+ REDUCTION(norm_inf);
+
+#undef REDUCTION
+
+
+
+ void CarpetReduceStartup ()
+ {
+ CCTK_RegisterReductionOperator (count_GVs, "count");
+ CCTK_RegisterReductionOperator (minimum_GVs, "minimum");
+ CCTK_RegisterReductionOperator (maximum_GVs, "maximum");
+ CCTK_RegisterReductionOperator (product_GVs, "product");
+ CCTK_RegisterReductionOperator (sum_GVs, "sum");
+ CCTK_RegisterReductionOperator (sum_abs_GVs, "sum_abs");
+ CCTK_RegisterReductionOperator (sum_squared_GVs, "sum_squared");
+ CCTK_RegisterReductionOperator (average_GVs, "average");
+ CCTK_RegisterReductionOperator (norm1_GVs, "norm1");
+ CCTK_RegisterReductionOperator (norm2_GVs, "norm2");
+ CCTK_RegisterReductionOperator (norm_inf_GVs, "norm_inf");
+
+ CCTK_RegisterReductionArrayOperator (count_arrays, "count");
+ CCTK_RegisterReductionArrayOperator (minimum_arrays, "minimum");
+ CCTK_RegisterReductionArrayOperator (maximum_arrays, "maximum");
+ CCTK_RegisterReductionArrayOperator (product_arrays, "product");
+ CCTK_RegisterReductionArrayOperator (sum_arrays, "sum");
+ CCTK_RegisterReductionArrayOperator (sum_abs_arrays, "sum_abs");
+ CCTK_RegisterReductionArrayOperator (sum_squared_arrays, "sum_squared");
+ CCTK_RegisterReductionArrayOperator (average_arrays, "average");
+ CCTK_RegisterReductionArrayOperator (norm1_arrays, "norm1");
+ CCTK_RegisterReductionArrayOperator (norm2_arrays, "norm2");
+ CCTK_RegisterReductionArrayOperator (norm_inf_arrays, "norm_inf");
+ }
+
+} // namespace CarpetReduce