void peanoclaw::interSubgridCommunication::GridLevelTransfer::switchToAndAddVirtualSubgrid(
  Patch& subgrid
) {
  tarch::multicore::Lock lock(_virtualPatchListSemaphore);

  //Push virtual stack
  tarch::la::Vector<DIMENSIONS_PLUS_ONE, double> virtualSubgridKey = createVirtualSubgridKey(subgrid.getPosition(), subgrid.getLevel());
  _virtualPatchDescriptionIndices[virtualSubgridKey] = subgrid.getCellDescriptionIndex();
//  _virtualPatchTimeConstraints[virtualSubgridKey] = subgrid.getMinimalNeighborTimeConstraint();

  if(static_cast<int>(_virtualPatchDescriptionIndices.size()) > _maximumNumberOfSimultaneousVirtualPatches) {
    _maximumNumberOfSimultaneousVirtualPatches = _virtualPatchDescriptionIndices.size();
  }

  //Create virtual patch
  if(subgrid.isVirtual()) {
    subgrid.getAccessor().clearRegion(
      peanoclaw::geometry::Region(tarch::la::Vector<DIMENSIONS, int>(0),
             subgrid.getSubdivisionFactor()),
      false
    );
    subgrid.getAccessor().clearRegion(
      peanoclaw::geometry::Region(tarch::la::Vector<DIMENSIONS, int>(0),
             subgrid.getSubdivisionFactor()),
      true
    );
  } else {
    subgrid.switchToVirtual();
  }
  _numerics.update(subgrid);
}
peanoclaw::ParallelSubgrid::ParallelSubgrid(
  Patch& subgrid
) {
  _cellDescription = &CellDescriptionHeap::getInstance().getData(subgrid.getCellDescriptionIndex()).at(0);
}
void peanoclaw::interSubgridCommunication::GridLevelTransfer::restrictDestroyedSubgrid(
  const Patch&                         destroyedSubgrid,
  Patch&                               coarseSubgrid,
  peanoclaw::Vertex * const            fineGridVertices,
  const peano::grid::VertexEnumerator& fineGridVerticesEnumerator
) {
  assertion2(tarch::la::greaterEquals(coarseSubgrid.getTimeIntervals().getTimestepSize(), 0.0), destroyedSubgrid, coarseSubgrid);

  //Fix timestep size
  assertion1(tarch::la::greaterEquals(coarseSubgrid.getTimeIntervals().getTimestepSize(), 0), coarseSubgrid);
  coarseSubgrid.getTimeIntervals().setTimestepSize(std::max(0.0, coarseSubgrid.getTimeIntervals().getTimestepSize()));

  //Set indices on coarse adjacent vertices
  for(int i = 0; i < TWO_POWER_D; i++) {
    fineGridVertices[fineGridVerticesEnumerator(i)].setAdjacentCellDescriptionIndex(i, coarseSubgrid.getCellDescriptionIndex());
  }

  //Skip update for coarse patch in next grid iteration
  coarseSubgrid.setSkipNextGridIteration(2);

  //Set demanded mesh width for coarse cell to coarse cell size. Otherwise
  //the coarse patch might get refined immediately.
  coarseSubgrid.setDemandedMeshWidth(coarseSubgrid.getSubcellSize());
}
void peanoclaw::interSubgridCommunication::GridLevelTransfer::stepDown(
  Patch*                               coarseSubgrid,
  Patch&                               fineSubgrid,
  peanoclaw::Vertex * const            fineGridVertices,
  const peano::grid::VertexEnumerator& fineGridVerticesEnumerator,
  bool                                 isInitializing,
  bool                                 isPeanoCellLeaf
) {

  //Switch to virtual subgrid if necessary
  if(shouldBecomeVirtualSubgrid(
      fineSubgrid,
      fineGridVertices,
      fineGridVerticesEnumerator,
      isInitializing,
      isPeanoCellLeaf
  )) {
    switchToAndAddVirtualSubgrid(fineSubgrid);
  } else if(fineSubgrid.isVirtual()) {
    //Switch to non-virtual if still virtual
    fineSubgrid.switchToNonVirtual();
  }

  //Prepare flags for subgrid
  if(!fineSubgrid.isLeaf()) {
    fineSubgrid.setWillCoarsen(peano::grid::aspects::VertexStateAnalysis::doesOneVertexCarryRefinementFlag
      (
        fineGridVertices,
        fineGridVerticesEnumerator,
        peanoclaw::records::Vertex::Erasing
      )
    );
  }
  fineSubgrid.getTimeIntervals().resetMinimalNeighborTimeConstraint();
  fineSubgrid.getTimeIntervals().resetMaximalNeighborTimeInterval();
  fineSubgrid.resetNeighboringGhostlayerBounds();
  fineSubgrid.getTimeIntervals().resetMinimalFineGridTimeInterval();

  //Get data from neighbors:
  //  - Ghostlayers data
  //  - Ghostlayer bounds
  //  - Neighbor times
  for(int i = 0; i < TWO_POWER_D; i++) {
    assertion1(fineSubgrid.getCellDescriptionIndex() != -1, fineSubgrid);
    fineGridVertices[fineGridVerticesEnumerator(i)].setAdjacentCellDescriptionIndex(i, fineSubgrid.getCellDescriptionIndex());
    fineGridVertices[fineGridVerticesEnumerator(i)].fillAdjacentGhostLayers(
      fineGridVerticesEnumerator.getLevel(),
      _useDimensionalSplitting,
      _numerics,
      fineGridVerticesEnumerator.getVertexPosition(peano::utils::dDelinearised(i, 2)),
      _subgridStatistics,
//      fineGridVerticesEnumerator.getVertexPosition(i),
      i
    );
  }

  //Data from coarse patch:
  // -> Update minimal time constraint of coarse neighbors
  if(coarseSubgrid != 0) {
    //Patch coarsePatch(coarseCellDescriptionIndex);
    if(coarseSubgrid->getTimeIntervals().shouldFineGridsSynchronize()) {
      //Set time constraint of fine grid to time of coarse grid to synch
      //on that time.
      fineSubgrid.getTimeIntervals().updateMinimalNeighborTimeConstraint(
        coarseSubgrid->getTimeIntervals().getCurrentTime() + coarseSubgrid->getTimeIntervals().getTimestepSize(),
        coarseSubgrid->getCellDescriptionIndex()
      );
    }
  }
}
void peanoclaw::interSubgridCommunication::GridLevelTransfer::finalizeVirtualSubgrid(
  Patch&                               subgrid,
  peanoclaw::Vertex * const            fineGridVertices,
  const peano::grid::VertexEnumerator& fineGridVerticesEnumerator,
  bool                                 isPeanoCellLeaf
) {
  tarch::multicore::Lock lock(_virtualPatchListSemaphore);
  assertion1(_virtualPatchDescriptionIndices.size() >= 0, subgrid.toString());

  tarch::la::Vector<DIMENSIONS_PLUS_ONE, double> virtualSubgridKey = createVirtualSubgridKey(subgrid.getPosition(), subgrid.getLevel());
  int virtualPatchDescriptionIndex = _virtualPatchDescriptionIndices[virtualSubgridKey];
  _virtualPatchDescriptionIndices.erase(virtualSubgridKey);
//  _virtualPatchTimeConstraints.erase(virtualSubgridKey);
  CellDescription& virtualPatchDescription = CellDescriptionHeap::getInstance().getData(virtualPatchDescriptionIndex).at(0);
  Patch virtualPatch(virtualPatchDescription);

  //Assert that we're working on the correct virtual patch
  assertionEquals3(subgrid.getCellDescriptionIndex(), virtualPatchDescriptionIndex, subgrid, virtualPatch, _virtualPatchDescriptionIndices.size());
  assertionNumericalEquals(subgrid.getPosition(), virtualPatch.getPosition());
  assertionNumericalEquals(subgrid.getSize(), virtualPatch.getSize());
  assertionEquals(subgrid.getLevel(), virtualPatch.getLevel());
  assertionEquals(subgrid.getUIndex(), virtualPatch.getUIndex());
//    assertionEquals(finePatch.getUOldIndex(), virtualPatch.getUOldIndex());

  #ifndef PEANOCLAW_USE_ASCEND_FOR_RESTRICTION
  _numerics.postProcessRestriction(subgrid, !subgrid.willCoarsen());
  #endif

  //Fill ghostlayer
  for(int i = 0; i < TWO_POWER_D; i++) {
    fineGridVertices[fineGridVerticesEnumerator(i)].fillAdjacentGhostLayers(
      subgrid.getLevel(),
      _useDimensionalSplitting,
      _numerics,
      #ifdef PEANOCLAW_USE_ASCEND_FOR_RESTRICTION
      tarch::la::multiplyComponents(peano::utils::dDelinearised(i, 2).convertScalar<double>(), subgrid.getSize()) + subgrid.getPosition(),
      #else
      fineGridVerticesEnumerator.getVertexPosition(i),
      #endif
      _subgridStatistics
    );
  }

  //Switch to leaf or non-virtual
  if(isPeanoCellLeaf) {
    assertion1(tarch::la::greaterEquals(subgrid.getTimeIntervals().getTimestepSize(), 0.0), subgrid);
    subgrid.switchToLeaf();
    _numerics.update(subgrid);
    ParallelSubgrid parallelSubgrid(subgrid);
    parallelSubgrid.markCurrentStateAsSent(false);
  } else {
    if(!isPatchAdjacentToRemoteRank(
      fineGridVertices,
      fineGridVerticesEnumerator
    )) {
      subgrid.switchToNonVirtual();
    }
  }

  assertion1(!subgrid.isVirtual()
    || isPatchAdjacentToRemoteRank(
        fineGridVertices,
        fineGridVerticesEnumerator),
    subgrid);
}