//#####################################################################
// Copyright 2009-2010, Michael Lentine, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#ifndef __SMOKE_EXAMPLE__
#define __SMOKE_EXAMPLE__
#include <Core/Advection/ADVECTION_SEMI_LAGRANGIAN_UNIFORM.h>
#include <Core/Arrays/ARRAYS_ND.h>
#include <Core/Boundaries/BOUNDARY.h>
#include <Core/Grids/CELL_ITERATOR.h>
#include <Core/Grids/FACE_ITERATOR.h>
#include <Core/Interpolation/AVERAGING_UNIFORM.h>
#include <Core/Interpolation/LINEAR_INTERPOLATION.h>
#include <Core/Poisson/PROJECTION_UNIFORM.h>
#include <Core/Read_Write/FILE_UTILITIES.h>
#include <Core/Utilities/VIEWER_DIR.h>
#include <Core/Vectors/VECTOR.h>
#include <Core/Viewer/VIEWER_OUTPUT.h>
namespace PhysBAM{

template<class TV> class DEBUG_PARTICLES;


template<class TV>
class SMOKE_EXAMPLE
{
    typedef typename TV::SCALAR T;
    typedef VECTOR<int,TV::m> IV;
    enum workaround1{d=TV::m};
    // typedef CUBIC_MONOTONIC_INTERPOLATION_ALL<TV,T,ARRAY<typename TV::SCALAR,FACE_INDEX<TV::m> > > T_INTERPOLATION;
    typedef LINEAR_INTERPOLATION_ALL<TV,T> T_INTERPOLATION;

public:
    STREAM_TYPE stream_type;
    DEBUG_PARTICLES<TV>& debug_particles;
    int ghost;

    int last_frame;
    T frame_dt;
    int restart;
    std::string frame_title;
    int write_substeps_level;
    bool write_debug_data;
    VIEWER_DIR viewer_dir;
    VIEWER_OUTPUT viewer_output{stream_type,viewer_dir};
    bool N_boundary;
    bool debug_divergence;
    T alpha;
    T beta;
    T cfl;
    GRID<TV> grid;
        PROJECTION_UNIFORM<TV> projection;
    ARRAY<T,FACE_INDEX<TV::m> > face_velocities;
    ADVECTION_SEMI_LAGRANGIAN_UNIFORM<TV,T, AVERAGING_UNIFORM<TV, ARRAY<typename TV::SCALAR,FACE_INDEX<TV::m> > >,T_INTERPOLATION > advection_scalar;
    BOUNDARY<TV,T> boundary_scalar;
    BOUNDARY<TV,T> *boundary;
    ARRAY<T,IV> density;
    ARRAY<T,IV> temperature;  //add temperature
    VECTOR<VECTOR<bool,2>,TV::m> domain_boundary;    
    RANGE<TV> source1;
    RANGE<TV> source2;

    SMOKE_EXAMPLE(const STREAM_TYPE stream_type_input,int refine=0);
    virtual ~SMOKE_EXAMPLE();
    T CFL(ARRAY<T,FACE_INDEX<TV::m> >& face_velocities);
    void CFL_Threaded(RANGE<IV>& domain,ARRAY<T,FACE_INDEX<TV::m> >& face_velocities,T& dt);
    T Time_At_Frame(const int frame) const;
    void Initialize_Grid(IV counts,RANGE<TV> domain);
    void Initialize_Fields();
    void Get_Scalar_Field_Sources(const T time);
    virtual void Read_Output_Files();
    virtual void Register_Output_Files();
    virtual void Set_Boundary_Conditions(const T time, const T source_velocities = 0);

//#####################################################################
};
}
#endif
