void LocalMultiBlockInfo2D::computeAllPeriodicOverlaps (
    SparseBlockStructure2D const& sparseBlock )
{
    for (pluint iBlock=0; iBlock<myBlocks.size(); ++iBlock) {
        plint blockId = myBlocks[iBlock];
        Box2D bulk;
        sparseBlock.getBulk(blockId, bulk);
        // Speed optimization: execute the test for periodicity
        //   only for bulk-domains which touch the bounding box.
        if (!contained (
                    bulk.enlarge(1), sparseBlock.getBoundingBox() ) )
        {
            computePeriodicOverlaps(sparseBlock, blockId);
        }
    }
}
void MultiGridManagement2D::refineMultiGrid(plint coarseLevel, Box2D coarseDomain){
        
    // The finest multi-block, at level bulks.size()-1, cannot be further refined.
    PLB_PRECONDITION( coarseLevel>=0 && coarseLevel< (plint)bulks.size()-1 );
    plint fineLevel = coarseLevel+1;
    
    // First, trim the domain coarseDomain in case it exceeds the extent of the
    //   multi-block, and determine whether coarseDomain touches one of the boundaries
    //   of the multi-block. This information is needed, because the coarse domain
    //   fully replaces the fine domain on boundaries of the multi-block, and there
    //   is therefore no need to create a coarse-fine coupling.
    bool touchLeft=false, touchRight=false, touchBottom=false, touchTop=false;
    trimDomain(coarseLevel, coarseDomain, touchLeft, touchRight, touchBottom, touchTop);

    // The reduced coarse domain is the one which is going to be excluded from
    //   the original coarse lattice.
    Box2D reducedCoarseDomain(coarseDomain.enlarge(-1));
    // The extended coarse domain it the one which is going to be added
    //   to the original fine lattice.
    Box2D extendedCoarseDomain(coarseDomain.enlarge(overlapWidth));
    
    // If the domain in question touches a boundary of the multi-block,
    //   both the reduced and the extended coarse domain are
    //   identified with the boundary location.
    if (touchLeft) {
        reducedCoarseDomain.x0    -= 1;
        extendedCoarseDomain.x0   += overlapWidth;
    }
    if (touchRight) {
        reducedCoarseDomain.x1    += 1;
        extendedCoarseDomain.x1   -= overlapWidth;
    }
    if (touchBottom) {
        reducedCoarseDomain.y0    -= 1;
        extendedCoarseDomain.y0   += overlapWidth;
    }
    if (touchTop) {
        reducedCoarseDomain.y1    += 1;
        extendedCoarseDomain.y1   -= overlapWidth;
    }

    
    // Do not do anything to the coarse domain
    
    
    // Convert the extended coarse domain to fine units,
    //   and add to the original fine multi-block.
    Box2D extendedFineDomain(extendedCoarseDomain.multiply(2));
    bulks[fineLevel].push_back(extendedFineDomain);

    // Define coupling interfaces for all four sides of the coarsened domain, unless they
    //   touch a boundary of the multi-block.
    if (!touchLeft) {

        // it is a right border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,1));
        fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x0, 
                                                        extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) );
        // it is a left border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,-1));
    }
    if (!touchRight) {

        // it is a left border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,-1));
        fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x1, extendedCoarseDomain.x1, 
                                                        extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) );
        // it is a right border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,1));
    }
    if (!touchBottom) {
        
        fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, 
                                                        extendedCoarseDomain.y0, extendedCoarseDomain.y0 ) );
        // it is an upper border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,1));
        // it is a lower border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,-1));
    }
    if (!touchTop) {
        
        // it is a lower border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,-1));
        fineGridInterfaces[fineLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1, 
                                                        extendedCoarseDomain.y1, extendedCoarseDomain.y1 ) );
        // it is an upper border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,1));
    }
    
    coarseGridInterfaces[coarseLevel].push_back(coarseDomain);
}
void MultiGridManagement2D::coarsen(plint fineLevel, Box2D coarseDomain){
    // The coarsest multi-block, at level 0, cannot be further coarsened.
    PLB_PRECONDITION( fineLevel>=1 && fineLevel<(plint)bulks.size() );
    plint coarseLevel = fineLevel-1;

    // First, trim the domain coarseDomain in case it exceeds the extent of the
    //   multi-block, and determine whether coarseDomain touches one of the boundaries
    //   of the multi-block. This information is needed, because the coarse domain
    //   fully replaces the fine domain on boundaries of the multi-block, and there
    //   is therefore no need to create a coarse-fine coupling.
    bool touchLeft=false, touchRight=false, touchBottom=false, touchTop=false;
    trimDomain(coarseLevel, coarseDomain, touchLeft, touchRight, touchBottom, touchTop);

    // Convert the coarse domain to fine units.
    Box2D fineDomain(coarseDomain.multiply(2));
    // The reduced fine domain is the one which is going to be excluded from
    //   the original fine lattice.
    Box2D intermediateFineDomain(fineDomain.enlarge(-1));
    // The extended coarse domain it the one which is going to be added
    //   to the original coarse lattice.
    Box2D extendedCoarseDomain(coarseDomain.enlarge(1));
    
    // If the domain in question touches a boundary of the multi-block,
    //   both the reduced fine domain and the extended coarse domain are
    //   identified with the boundary location.
    if (touchLeft) {
        intermediateFineDomain.x0 -= 1;
        extendedCoarseDomain.x0   += 1;
    }
    if (touchRight) {
        intermediateFineDomain.x1 += 1;
        extendedCoarseDomain.x1   -= 1;
    }
    if (touchBottom) {
        intermediateFineDomain.y0 -= 1;
        extendedCoarseDomain.y0   += 1;
    }
    if (touchTop) {
        intermediateFineDomain.y1 += 1;
        extendedCoarseDomain.y1   -= 1;
    }

    // Extract reduced fine domain from the original fine multi-block.
    std::vector<Box2D> exceptedBlocks;
    for (pluint iBlock=0; iBlock<bulks[fineLevel].size(); ++iBlock) {
        except(bulks[fineLevel][iBlock], intermediateFineDomain, exceptedBlocks);
    }
    exceptedBlocks.swap(bulks[fineLevel]);

    // Add extended coarse domain to the original coarse multi-block.
    bulks[coarseLevel].push_back(extendedCoarseDomain);
    
    // Define coupling interfaces for all four sides of the refined domain, unless they
    //   touch a boundary of the multi-block.
    if (!touchLeft) {
        coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x0,
                                                            extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) );
        fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x0, 
                                                        coarseDomain.y0, coarseDomain.y1 ) );
                                                        
        // it is a left border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,-1));
        // it is an right border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,1));
    }
    if (!touchRight) {
        coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x1, extendedCoarseDomain.x1,
                                                            extendedCoarseDomain.y0, extendedCoarseDomain.y1 ) );
        fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x1, coarseDomain.x1, 
                                                        coarseDomain.y0, coarseDomain.y1 ) );
                                                        
        // it is a right border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(0,1));
        // it is a left border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(0,-1));
    }
    if (!touchBottom) {
        coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1,
                                                            extendedCoarseDomain.y0, extendedCoarseDomain.y0 ) );
        fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x1, 
                                                        coarseDomain.y0, coarseDomain.y0 ) );
                                                        
        // it is a bottom border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,-1)); //TODO check this!!!
        // it is a top border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,1));        
    }
    if (!touchTop) {
        coarseGridInterfaces[coarseLevel].push_back( Box2D( extendedCoarseDomain.x0, extendedCoarseDomain.x1,
                                                            extendedCoarseDomain.y1, extendedCoarseDomain.y1 ) );
        fineGridInterfaces[fineLevel].push_back( Box2D( coarseDomain.x0, coarseDomain.x1, 
                                                        coarseDomain.y1, coarseDomain.y1 ) );
                                                        
        // it is a top border in the coarse case
        coarseInterfaceOrientations[coarseLevel].push_back(Array<plint,2>(1,1));
        // it is an bottom border in the fine case
        fineInterfaceOrientations[fineLevel].push_back(Array<plint,2>(1,-1));
    }
}