text: // This file is part of the Peano project. For conditions of distribution and 
  // use, please see the copyright notice at www.peano-framework.org
  #ifndef EXAHYPE_ADAPTERS_MergeNeighbours_H_
  #define EXAHYPE_ADAPTERS_MergeNeighbours_H_
  
  
  #include "tarch/logging/Log.h"
  #include "tarch/la/Vector.h"
  
  #include "peano/grid/VertexEnumerator.h"
  #include "peano/MappingSpecification.h"
  #include "peano/CommunicationSpecification.h"
  
  #include "tarch/multicore/MulticoreDefinitions.h"
  
  #include "exahype/Vertex.h"
  #include "exahype/Cell.h"
  #include "exahype/State.h"
  
  
   #include "exahype/mappings/MergeNeighbours.h"
  
  
  
  namespace exahype {
        namespace adapters {
          class MergeNeighbours;
        } 
  }
  
  
  /**
   * This is a mapping from the spacetree traversal events to your user-defined activities.
   * The latter are realised within the mappings. 
   * 
   * @author Peano Development Toolkit (PDT) by  Tobias Weinzierl
   * @version $Revision: 1.10 $
   */
  class exahype::adapters::MergeNeighbours {
    private:
      typedef mappings::MergeNeighbours Mapping0;
  
       Mapping0  _map2MergeNeighbours;
  
  
    public:
      peano::MappingSpecification         touchVertexLastTimeSpecification(int level) const;
      peano::MappingSpecification         touchVertexFirstTimeSpecification(int level) const;
      peano::MappingSpecification         enterCellSpecification(int level) const;
      peano::MappingSpecification         leaveCellSpecification(int level) const;
      peano::MappingSpecification         ascendSpecification(int level) const;
      peano::MappingSpecification         descendSpecification(int level) const;
      peano::CommunicationSpecification   communicationSpecification() const;
  
      MergeNeighbours();
  
      #if defined(SharedMemoryParallelisation)
      MergeNeighbours(const MergeNeighbours& masterThread);
      #endif
  
      virtual ~MergeNeighbours();
    
      #if defined(SharedMemoryParallelisation)
      void mergeWithWorkerThread(const MergeNeighbours& workerThread);
      #endif
  
      void createInnerVertex(
        exahype::Vertex&               fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridH,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfVertex
      );
  
  
      void createBoundaryVertex(
        exahype::Vertex&               fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridH,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfVertex
      );
  
  
      void createHangingVertex(
        exahype::Vertex&               fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridH,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfVertex
      );
  
  
      void destroyHangingVertex(
        const exahype::Vertex&   fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridH,
        exahype::Vertex * const  coarseGridVertices,
        const peano::grid::VertexEnumerator&          coarseGridVerticesEnumerator,
        exahype::Cell&           coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                       fineGridPositionOfVertex
      );
  
  
      void destroyVertex(
        const exahype::Vertex&   fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridH,
        exahype::Vertex * const  coarseGridVertices,
        const peano::grid::VertexEnumerator&          coarseGridVerticesEnumerator,
        exahype::Cell&           coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                       fineGridPositionOfVertex
      );
  
  
      void createCell(
        exahype::Cell&                 fineGridCell,
        exahype::Vertex * const         fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfCell
      );
  
  
      void destroyCell(
        const exahype::Cell&           fineGridCell,
        exahype::Vertex * const        fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfCell
      );
          
      #ifdef Parallel
      void mergeWithNeighbour(
        exahype::Vertex&  vertex,
        const exahype::Vertex&  neighbour,
        int                                           fromRank,
        const tarch::la::Vector<DIMENSIONS,double>&   x,
        const tarch::la::Vector<DIMENSIONS,double>&   h,
        int                                           level
      );
  
      void prepareSendToNeighbour(
        exahype::Vertex&  vertex,
        int                                           toRank,
        const tarch::la::Vector<DIMENSIONS,double>&   x,
        const tarch::la::Vector<DIMENSIONS,double>&   h,
        int                                           level
      );
  
      void prepareCopyToRemoteNode(
        exahype::Vertex&  localVertex,
        int                                           toRank,
        const tarch::la::Vector<DIMENSIONS,double>&   x,
        const tarch::la::Vector<DIMENSIONS,double>&   h,
        int                                           level
      );
  
      void prepareCopyToRemoteNode(
        exahype::Cell&  localCell,
        int  toRank,
        const tarch::la::Vector<DIMENSIONS,double>&   cellCentre,
        const tarch::la::Vector<DIMENSIONS,double>&   cellSize,
        int                                           level
      );
  
      void mergeWithRemoteDataDueToForkOrJoin(
        exahype::Vertex&  localVertex,
        const exahype::Vertex&  masterOrWorkerVertex,
        int                                       fromRank,
        const tarch::la::Vector<DIMENSIONS,double>&  x,
        const tarch::la::Vector<DIMENSIONS,double>&  h,
        int                                       level
      );
  
      void mergeWithRemoteDataDueToForkOrJoin(
        exahype::Cell&  localCell,
        const exahype::Cell&  masterOrWorkerCell,
        int                                       fromRank,
        const tarch::la::Vector<DIMENSIONS,double>&  cellCentre,
        const tarch::la::Vector<DIMENSIONS,double>&  cellSize,
        int                                       level
      );
  
      bool prepareSendToWorker(
        exahype::Cell&                 fineGridCell,
        exahype::Vertex * const        fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfCell,
        int                                                                  worker
      );
  
      void prepareSendToMaster(
        exahype::Cell&                       localCell,
        exahype::Vertex *                    vertices,
        const peano::grid::VertexEnumerator&       verticesEnumerator, 
        const exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&       coarseGridVerticesEnumerator,
        const exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&   fineGridPositionOfCell
      );
  
      void mergeWithMaster(
        const exahype::Cell&           workerGridCell,
        exahype::Vertex * const        workerGridVertices,
        const peano::grid::VertexEnumerator& workerEnumerator,
        exahype::Cell&                 fineGridCell,
        exahype::Vertex * const        fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfCell,
        int                                                                  worker,
        const exahype::State&           workerState,
        exahype::State&                 masterState
      );
  
  
      void receiveDataFromMaster(
        exahype::Cell&                        receivedCell, 
        exahype::Vertex *                     receivedVertices,
        const peano::grid::VertexEnumerator&        receivedVerticesEnumerator,
        exahype::Vertex * const               receivedCoarseGridVertices,
        const peano::grid::VertexEnumerator&        receivedCoarseGridVerticesEnumerator,
        exahype::Cell&                        receivedCoarseGridCell,
        exahype::Vertex * const               workersCoarseGridVertices,
        const peano::grid::VertexEnumerator&        workersCoarseGridVerticesEnumerator,
        exahype::Cell&                        workersCoarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&    fineGridPositionOfCell
      );
  
  
      void mergeWithWorker(
        exahype::Cell&           localCell, 
        const exahype::Cell&     receivedMasterCell,
        const tarch::la::Vector<DIMENSIONS,double>&  cellCentre,
        const tarch::la::Vector<DIMENSIONS,double>&  cellSize,
        int                                          level
      );
  
  
      void mergeWithWorker(
        exahype::Vertex&        localVertex,
        const exahype::Vertex&  receivedMasterVertex,
        const tarch::la::Vector<DIMENSIONS,double>&   x,
        const tarch::la::Vector<DIMENSIONS,double>&   h,
        int                                           level
      );
      #endif
  
  
      void touchVertexFirstTime(
        exahype::Vertex&               fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                          fineGridH,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfVertex
      );
  
  
      void touchVertexLastTime(
        exahype::Vertex&         fineGridVertex,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridX,
        const tarch::la::Vector<DIMENSIONS,double>&                    fineGridH,
        exahype::Vertex * const  coarseGridVertices,
        const peano::grid::VertexEnumerator&          coarseGridVerticesEnumerator,
        exahype::Cell&           coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                       fineGridPositionOfVertex
      );
      
  
      void enterCell(
        exahype::Cell&                 fineGridCell,
        exahype::Vertex * const        fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&                             fineGridPositionOfCell
      );
  
  
      void leaveCell(
        exahype::Cell&                          fineGridCell,
        exahype::Vertex * const                 fineGridVertices,
        const peano::grid::VertexEnumerator&          fineGridVerticesEnumerator,
        exahype::Vertex * const                 coarseGridVertices,
        const peano::grid::VertexEnumerator&          coarseGridVerticesEnumerator,
        exahype::Cell&                          coarseGridCell,
        const tarch::la::Vector<DIMENSIONS,int>&      fineGridPositionOfCell
      );
  
  
      void beginIteration(
        exahype::State&  solverState
      );
  
  
      void endIteration(
        exahype::State&  solverState
      );
  
      void descend(
        exahype::Cell * const          fineGridCells,
        exahype::Vertex * const        fineGridVertices,
        const peano::grid::VertexEnumerator&                fineGridVerticesEnumerator,
        exahype::Vertex * const        coarseGridVertices,
        const peano::grid::VertexEnumerator&                coarseGridVerticesEnumerator,
        exahype::Cell&                 coarseGridCell
      );
  
  
      void ascend(
        exahype::Cell * const    fineGridCells,
        exahype::Vertex * const  fineGridVertices,
        const peano::grid::VertexEnumerator&          fineGridVerticesEnumerator,
        exahype::Vertex * const  coarseGridVertices,
        const peano::grid::VertexEnumerator&          coarseGridVerticesEnumerator,
        exahype::Cell&           coarseGridCell
      );    
  };
  
  
  #endif
  