//#####################################################################
// Copyright 2002-2008, Zhaosheng Bao, Robert Bridson, Ronald Fedkiw, Eran Guendelman, Geoffrey Irving, Sergey Koltakov, Nipun Kwatra, Frank Losasso, Andrew Selle, Tamar Shinar, Eftychios Sifakis, Jerry Talton, Joseph Teran.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class GRID
//##################################################################### 
#include <Core/Grids/GRID.h>
#include <Core/Read_Write/READ_WRITE.h>
#include <Core/Symbolics/SYMBOLIC.h>
namespace PhysBAM{
//#####################################################################
// Function Initialize
//#####################################################################
template<class TV> void GRID<TV>::
Initialize(const IV& cells_input,const RANGE<TV>& box)
{
    numbers_of_cells=cells_input;
    domain=box;
    if constexpr(TV::m>0)
    {
        numbers_of_cells=numbers_of_cells.Componentwise_Max(IV());
        if(numbers_of_cells.Min()>0){
            dX=domain.Edge_Lengths()/TV(numbers_of_cells);
            one_over_dX=(T)1/dX;}
        else{dX=TV();one_over_dX=TV();}
    }
}
//#####################################################################
// Function Create_Grid_Given_Cell_Size
//#####################################################################
template<class TV> GRID<TV> GRID<TV>::
Create_Grid_Given_Cell_Size(const RANGE<TV>& domain,const T cell_size,int boundary_nodes)
{
    assert(cell_size);
    IV cells(IV(ceil((domain.Edge_Lengths())/cell_size))+2*boundary_nodes);
    TV domain_center=domain.Center(),actual_domain_half_size=(T).5*cell_size*TV(cells);
    return GRID<TV>(cells,RANGE<TV>(domain_center-actual_domain_half_size,domain_center+actual_domain_half_size));
}
//#####################################################################
// Function Read
//#####################################################################
template<class TV> template<class RW> void GRID<TV>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    T mac_offset=(T)0.5;
    IV counts;
    Get(input,'(');
    Read_Binary(input,counts,domain);
    if(!is_same<RW,char>::value) Read_Binary(input,mac_offset);
    Get(input,')');
    Initialize(counts-!mac_offset,domain);
}
//#####################################################################
// Function Write
//#####################################################################
template<class TV> template<class RW> void GRID<TV>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Beg(output,'(');
    Write_Binary(output,numbers_of_cells,domain);
    if(!is_same<RW,char>::value) Write_Binary(output,(T).5);
    End(output,')');
}
//#####################################################################
template void GRID<VECTOR<float,0> >::Initialize(VECTOR<int,0> const&,RANGE<VECTOR<float,0> > const&);
template void GRID<VECTOR<float,1> >::Initialize(VECTOR<int,1> const&,RANGE<VECTOR<float,1> > const&);
template void GRID<VECTOR<float,2> >::Initialize(VECTOR<int,2> const&,RANGE<VECTOR<float,2> > const&);
template void GRID<VECTOR<float,3> >::Initialize(VECTOR<int,3> const&,RANGE<VECTOR<float,3> > const&);
template GRID<VECTOR<float,1> > GRID<VECTOR<float,1> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<float,1> > const&,float,int);
template GRID<VECTOR<float,2> > GRID<VECTOR<float,2> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<float,2> > const&,float,int);
template GRID<VECTOR<float,3> > GRID<VECTOR<float,3> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<float,3> > const&,float,int);
template void GRID<VECTOR<double,0> >::Initialize(VECTOR<int,0> const&,RANGE<VECTOR<double,0> > const&);
template void GRID<VECTOR<double,1> >::Initialize(VECTOR<int,1> const&,RANGE<VECTOR<double,1> > const&);
template void GRID<VECTOR<double,2> >::Initialize(VECTOR<int,2> const&,RANGE<VECTOR<double,2> > const&);
template void GRID<VECTOR<double,3> >::Initialize(VECTOR<int,3> const&,RANGE<VECTOR<double,3> > const&);
template GRID<VECTOR<double,1> > GRID<VECTOR<double,1> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<double,1> > const&,double,int);
template GRID<VECTOR<double,2> > GRID<VECTOR<double,2> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<double,2> > const&,double,int);
template GRID<VECTOR<double,3> > GRID<VECTOR<double,3> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<double,3> > const&,double,int);
#ifdef USE_SYMBOLIC
template void GRID<VECTOR<SYMBOLIC,0> >::Initialize(VECTOR<int,0> const&,RANGE<VECTOR<SYMBOLIC,0> > const&);
template void GRID<VECTOR<SYMBOLIC,1> >::Initialize(VECTOR<int,1> const&,RANGE<VECTOR<SYMBOLIC,1> > const&);
template void GRID<VECTOR<SYMBOLIC,2> >::Initialize(VECTOR<int,2> const&,RANGE<VECTOR<SYMBOLIC,2> > const&);
template void GRID<VECTOR<SYMBOLIC,3> >::Initialize(VECTOR<int,3> const&,RANGE<VECTOR<SYMBOLIC,3> > const&);
template GRID<VECTOR<SYMBOLIC,1> > GRID<VECTOR<SYMBOLIC,1> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<SYMBOLIC,1> > const&,SYMBOLIC,int);
template GRID<VECTOR<SYMBOLIC,2> > GRID<VECTOR<SYMBOLIC,2> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<SYMBOLIC,2> > const&,SYMBOLIC,int);
template GRID<VECTOR<SYMBOLIC,3> > GRID<VECTOR<SYMBOLIC,3> >::Create_Grid_Given_Cell_Size(RANGE<VECTOR<SYMBOLIC,3> > const&,SYMBOLIC,int);
#endif
template void GRID<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<double,1> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<double,1> >::Write(UNTYPED_OSTREAM<float>&) const;
template void GRID<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<double,2> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<double,2> >::Write(UNTYPED_OSTREAM<float>&) const;
template void GRID<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<double,3> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<double,3> >::Write(UNTYPED_OSTREAM<float>&) const;
template void GRID<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<float,1> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<float,1> >::Write(UNTYPED_OSTREAM<float>&) const;
template void GRID<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<float,2> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<float,2> >::Write(UNTYPED_OSTREAM<float>&) const;
template void GRID<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<char>&);
template void GRID<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<double>&);
template void GRID<VECTOR<float,3> >::Read(UNTYPED_ISTREAM<float>&);
template void GRID<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<char>&) const;
template void GRID<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<double>&) const;
template void GRID<VECTOR<float,3> >::Write(UNTYPED_OSTREAM<float>&) const;
}
