//#####################################################################
// Copyright 2002-2007, Ronald Fedkiw, Geoffrey Irving, Nipun Kwatra, Frank Losasso.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class PERIODIC_BOUNDARY_HELPER
//#####################################################################
#ifndef __PERIODIC_BOUNDARY_HELPER__
#define __PERIODIC_BOUNDARY_HELPER__

#include <Core/Arrays/ARRAYS_ND_BASE.h>
#include <Core/Arrays/FACE_ARRAYS.h>
#include <Core/Grids/GRID.h>
namespace PhysBAM{

// Note that periodic domains treat the right/top/back faces of face arrays as
// copies of the left/bottom/front faces.  These routines are intended to work
// correctly when u only covers a patch of the grid domain, in which case
// portions of the array that do not have a periodic counterpart are considered
// degrees of freedom.  These routines assume the grid is at least as wide as
// the ghost region.

namespace PBH
{
struct ADD
{
    template<class T> T operator()(const T& a, const T& b) const {return a+b;}
};
struct OR
{
    template<class T> T operator()(const T& a, const T& b) const {return a|b;}
};
}

template<class T2,class IV> void
Fill_Ghost_Periodic(const IV& numbers_of_cells,
    ARRAYS_ND_BASE<T2,VECTOR<int,IV::m> >& u,
    const VECTOR<bool,IV::m>& is_periodic);
template<class T2,class TV> void
Fill_Ghost_Cells_Periodic(const GRID<TV>& grid,
    ARRAYS_ND_BASE<T2,VECTOR<int,TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic)
{Fill_Ghost_Periodic(grid.numbers_of_cells,u,is_periodic);}
template<class T2,class TV> void
Fill_Ghost_Nodes_Periodic(const GRID<TV>& grid,
    ARRAYS_ND_BASE<T2,VECTOR<int,TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic)
{Fill_Ghost_Periodic(grid.numbers_of_cells,u,is_periodic);}
template<class T2,class TV> void
Fill_Ghost_Faces_Periodic(const GRID<TV>& grid,
    ARRAY<T2,FACE_INDEX<TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic)
{
    // This handles the right/top/back faces correctly, since those faces are
    // not degrees of freedom.
    for(int a=0;a<TV::m;a++)
        Fill_Ghost_Periodic(grid.numbers_of_cells,u.Component(a),is_periodic);
}
template<class OP,class T2,class IV> void
Fill_Ghost_Periodic_Accum(const IV& numbers_of_cells,
    ARRAYS_ND_BASE<T2,VECTOR<int,IV::m> >& u,
    const VECTOR<bool,IV::m>& is_periodic,const OP& op);
template<class OP,class T2,class TV> void
Fill_Ghost_Cells_Periodic_Accum(const GRID<TV>& grid,
    ARRAYS_ND_BASE<T2,VECTOR<int,TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic,const OP& op)
{Fill_Ghost_Periodic_Accum(grid.numbers_of_cells,u,is_periodic,op);}
template<class OP,class T2,class TV> void
Fill_Ghost_Nodes_Periodic_Accum(const GRID<TV>& grid,
    ARRAYS_ND_BASE<T2,VECTOR<int,TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic,const OP& op)
{Fill_Ghost_Periodic_Accum(grid.numbers_of_cells,u,is_periodic,op);}
template<class OP,class T2,class TV> void
Fill_Ghost_Faces_Periodic_Accum(const GRID<TV>& grid,
    ARRAY<T2,FACE_INDEX<TV::m> >& u,
    const VECTOR<bool,TV::m>& is_periodic,const OP& op)
{
    // This handles the right/top/back faces correctly, since those faces are
    // not degrees of freedom.
    for(int a=0;a<TV::m;a++)
        Fill_Ghost_Periodic_Accum(grid.numbers_of_cells,u.Component(a),is_periodic,op);
}
template<int d> void
Valid_Periodic_Regions(const RANGE<VECTOR<int,d> >& array_domain,
    const RANGE<VECTOR<int,d> >& grid_domain,
    const VECTOR<bool,d>& is_periodic,
    VECTOR<RANGE<VECTOR<int,d> >,2*d>& ghost_domains);
}
#endif
