#ifndef __RVL_MPIFO #define __RVL_MPIFO #ifdef IWAVE_USE_MPI #include "mpidatatransfer.hh" #endif #include "local.hh" namespace RVL { /** Mixin asserting ability to broadcast internal data. */ class MPISynchRoot { public: /** initialization of internal data */ virtual void set() = 0; /** synchronizes internal data in all instances of object, across processes */ virtual void synch() = 0; virtual ~MPISynchRoot() {}; }; /** MPI-enabled function object for serial evaluation. Simplest parallel evaluation - not parallel at all! This implementation deals only with the world comm, and evaluates a standard FO on rk=0. Constructed to be a pass-through outside of MPI environment. Concrete class, confined to LDCs: depends on being able to cast input to LocalEvaluation. */ template class MPISerialFunctionObject: public LocalFunctionObject { private: LocalEvaluation * fptr; string fname; MPISerialFunctionObject(); public: MPISerialFunctionObject(FunctionObject & f): fptr(NULL) { if (!(fptr=dynamic_cast *>(&f))) { RVLException e; e<<"Error: MPISerialFunctionObject constructor\n"; e<<"input function, named "< const & f) : fptr(f.fptr), fname(f.fname) {} ~MPISerialFunctionObject() {} void operator()(LocalDataContainer & target, vector const *> & sources) { try { #ifdef IWAVE_USE_MPI int rk=0; MPI_Comm_rank(MPI_COMM_WORLD,&rk); if (rk==0) #endif fptr->operator()(target,sources); } catch (RVLException & e) { e<<"\ncalled from MPISerialFunctionObject::operator()\n"; throw e; } } string getName() const { string str="MPISerialFO wrapper around "; str+=fname; return str; } }; /** MPI-enabled serial reduction of data container. Simplest parallel evaluation - not parallel at all! This implementation deals only with the world comm, and evaluates a standard FOR on rk=0. Initialization via set() on ALL PROCESSES. Broadcasts result to other processes via synch(). Thus all invocations must call set() before eval(), then synch(), to correctly compute reduction results and place on all processes. Constructed to be a pass-through outside of MPI environment. Concrete class, confined to LDCs: depends on being able to cast input to LocalConstEval, and to MPISynch. */ template class MPISerialFunctionObjectRedn: public FunctionObjectScalarRedn, public LocalConstEval, public MPISynchRoot { private: LocalConstEval * lrptr; // reduction parent - data op FunctionObjectScalarRedn & f; // FO parent - redn value string fname; // buffer for function name int root; // root process rank int rk; // this process rank #ifdef IWAVE_USE_MPI MPI_Comm comm; #endif MPISerialFunctionObjectRedn(); public: MPISerialFunctionObjectRedn(FunctionObjectScalarRedn & _f, int _root=0 #ifdef IWAVE_USE_MPI , MPI_Comm _comm=MPI_COMM_WORLD #endif ) : FunctionObjectScalarRedn(_f.getValue()), lrptr(NULL), f(_f), root(_root), rk(_root) #ifdef IWAVE_USE_MPI , comm(_comm) #endif { #ifdef IWAVE_USE_MPI MPI_Comm_rank(comm,&rk); #endif if (!(lrptr=dynamic_cast *>(&f))) { RVLException e; e<<"Error: MPISerialFunctionObjectRedn constructor\n"; e<<"input function, named "< const & f) : lrptr(f.lrptr), f(f.f), root(f.root), rk(f.root), #ifdef IWAVE_USE_MPI comm(f.comm), #endif fname(f.fname) { #ifdef IWAVE_USE_MPI MPI_Comm_rank(comm,&rk); #endif } ~MPISerialFunctionObjectRedn() {} void operator()(vector const *> & sources) { try { // cerr<<"MPISFOR: operator() on "<getName()<::getValue(); #ifdef IWAVE_USE_MPI // cerr<<"rk="< bc(root,comm); bc(a); #endif // cerr<<"rk="<::setValue(a); // for safety's sake do same for FOSR data member f.setValue(a); // cerr<<"rk="<::setValue(f.getValue()); } /** implement "blind" reinitialization from parent class */ void set() { this->setValue(); } string getName() const { string str="MPISerialFOR wrapper around "; str+=fname; return str; } }; } #endif