/*
** (c) 1996-2000 The Regents of the University of California (through
** E.O. Lawrence Berkeley National Laboratory), subject to approval by
** the U.S. Department of Energy.  Your use of this software is under
** license -- the license agreement is attached and included in the
** directory as license.txt or you may contact Berkeley Lab's Technology
** Transfer Department at TTD@lbl.gov.  NOTICE OF U.S. GOVERNMENT RIGHTS.
** The Software was developed under funding from the U.S. Government
** which consequently retains certain rights as follows: the
** U.S. Government has been granted for itself and others acting on its
** behalf a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, and perform publicly
** and display publicly.  Beginning five (5) years after the date
** permission to assert copyright is obtained from the U.S. Department of
** Energy, and subject to any subsequent five (5) year renewals, the
** U.S. Government is granted for itself and others acting on its behalf
** a paid-up, nonexclusive, irrevocable, worldwide license in the
** Software to reproduce, prepare derivative works, distribute copies to
** the public, perform publicly and display publicly, and to permit
** others to do so.
*/


#ifndef _HyperCLaw_H_
#define _HyperCLaw_H_

//
// $Id: HyperCLaw.H,v 1.27 2002/03/13 23:15:30 vince Exp $
//

#include <BC_TYPES.H>
#include <AmrLevel.H>
#include <ErrorList.H>
#include <FluxRegister.H>
#include <SplitIntegrator.H>
#ifdef BL_USE_CHEM
#  include <ChemKinDriver.H>
#endif

#include <fstream>
using std::istream;
using std::ostream;

enum StateType { State_Type=0, NUM_STATE_TYPE };

#if (BL_SPACEDIM == 2)
enum StateNames  { Density = 0 };
#else
enum StateNames  { Density = 0 };
#endif

//
//@Man:
//@Memo: AmrLevel-derived class for hyperbolic systems of conservation laws.
/*@Doc: 

  This class advances a system of hyperbolic conservation
  laws in time by calling the LevelAdvance operator.
  It is expected that another, problem-dependent class will be
  derived from this physics-dependent class.
*/

class HyperCLaw
    :
    public AmrLevel
{

public:
    //
    //@ManDoc: Default constructor.  Builds invalid object.
    //
    HyperCLaw ();
    //
    //@ManDoc: The basic constructor.
    //
    HyperCLaw (Amr&            papa,
               int             lev,
               const Geometry& level_geom,
               const BoxArray& bl,
               Real            time);
    //
    //@ManDoc: The destructor.
    //
    virtual ~HyperCLaw ();
    //
    //@ManDoc: Restart from a checkpoint file.
    //
    virtual void restart (Amr&     papa,
                          std::istream& is,
			  bool bReadSpecial = false);

    /*@ManDoc: A string written as the first item in writePlotFile() at
               level zero. It is so we can distinguish between different
               types of plot files. For HyperCLaw it has the form: HyperCLaw-Vnnn
    */
    virtual std::string thePlotFileType () const;
    //
    //@ManDoc: Write a plotfile to specified directory.
    //
    virtual void writePlotFile (const std::string& dir,
                                std::ostream&       os,
                                VisMF::How     how);
    //
    //@ManDoc: Define data descriptors.
    //
    static void variableSetUp ();
    //
    //@ManDoc: Cleanup data descriptors at end of run.
    //
    static void variableCleanUp ();
    //
    //@ManDoc: Initialize grid data at problem start-up.
    //
    virtual void initData ();
    //
    //@ManDoc: Get problem metrics.
    //
    MultiFab& Area (int dir);
    //
    //@ManDoc: The volume of the multifab.
    //
    MultiFab& Volume ();
    //
    //@ManDoc: Set time levels of state data.
    //
    virtual void setTimeLevel (Real time,
                               Real dt_old,
                               Real dt_new);
    //
    //@ManDoc: Initialize data on this level from another HyperCLaw (during regrid).
    //
    virtual void init (AmrLevel& old);
    //
    //@ManDoc: Initialize data on this level after regridding if old level did not previously exist
    //
    virtual void init ();
    //
    //@ManDoc: Proceed with next timestep?
    //
    virtual int okToContinue ();
    //
    //@ManDoc: Advance grids at this level in time.
    //
    virtual Real advance (Real time,
                          Real dt,
                          int  iteration,
                          int  ncycle);
    //
    //@ManDoc: Estimate time step.
    //
    Real estTimeStep ();
    //
    //@ManDoc: Compute initial time step.
    //
    Real initialTimeStep ();
    //
    //@ManDoc: Compute initial `dt'.
    //
    virtual void computeInitialDt (int                   finest_level,
                                   int                   sub_cycle,
                                   Array<int>&           n_cycle,
                                   const Array<IntVect>& ref_ratio,
                                   Array<Real>&          dt_level,
                                   Real                  stop_time);
    //
    //@ManDoc: Compute new `dt'.
    //
    virtual void computeNewDt (int                   finest_level,
                               int                   sub_cycle,
                               Array<int>&           n_cycle,
                               const Array<IntVect>& ref_ratio,
                               Array<Real>&          dt_min,
                               Array<Real>&          dt_level,
                               Real                  stop_time);
    //
    //@ManDoc: Allocate data at old time.
    //
    virtual void allocOldData ();
    //
    //@ManDoc: Remove data at old time.
    //
    virtual void removeOldData ();
    //
    //@ManDoc: Do work after timestep().
    //
    virtual void post_timestep (int iteration);
    //
    //@ManDoc: Do work after regrid().
    //
    virtual void post_regrid (int lbase,
                              int new_finest);   
    //
    //@ManDoc: Do work after a restart().
    //
    virtual void post_restart ();
    //
    //@ManDoc: Do work after init().
    //
    virtual void post_init (Real stop_time);
    //
    //@ManDoc: Error estimation for regridding.
    //
    virtual void errorEst (TagBoxArray& tb,
                           int          clearval,
                           int          tagval,
                           Real         time,
			   int          n_error_buf = 0, int ngrow = 0);
    //
    //@ManDoc: Fill MultiFab at specified time with coarse data.
    //
    void FillCoarseMultiFab (MultiFab&     dest,
                             int           dst_comp,
                             Real          time,
                             int           state_indx,
                             int           src_comp,
                             int           ncomp);

#ifdef BL_USE_CHEM
    //
    //@ManDoc: Access to chemistry driver object
    //
    static ChemKinDriver& getChemDriver ();
#endif

protected:

    static void read_params ();

    HyperCLaw& getLevel (int lev);

    FluxRegister& getFluxReg ();

    FluxRegister& getFluxReg (int lev);

    void reflux ();

    void avgDown ();

    void buildMetrics ();

    // integrate derived quantities over domain

    Real sumDerive (const std::string& name, Real time);

    Real volWgtSum (const std::string& name, Real time);

    virtual void sum_integrated_quantities () = 0;
    //
    // The data.
    //
    MultiFab      volume;
    MultiFab      area[BL_SPACEDIM];
    PArray<Real>  radius;
    FluxRegister* flux_reg;
    //
    // Static data members.
    //
    static int       radius_grow;
    static int       verbose;
    static Real      cfl;
    static Real      init_shrink;
    static Real      change_max;
    static int       do_reflux;
    static int       do_richardson;
    static int       initial_step;
    static ErrorList err_list;
    static Real      gravity;
    static int       NUM_STATE;
    static BCRec     phys_bc;
#ifdef BL_USE_CHEM
    static ChemKinDriver* chemDriver;
    static int       NumSpec;
    static int       FirstSpec;
    static int       LastSpec;
#endif
};    

//
// Inlines.
//

inline
MultiFab&
HyperCLaw::Area (int dir)
{
    return area[dir];
}

inline
MultiFab&
HyperCLaw::Volume ()
{
    return volume;
}

inline
HyperCLaw&
HyperCLaw::getLevel (int lev)
{
    return *(HyperCLaw *) &parent->getLevel(lev);
}

inline
FluxRegister&
HyperCLaw::getFluxReg ()
{
    BL_ASSERT(flux_reg);
    return *flux_reg;
}

inline
FluxRegister&
HyperCLaw::getFluxReg (int lev)
{
    return getLevel(lev).getFluxReg();
}

inline
Real
HyperCLaw::initialTimeStep ()
{
    return init_shrink*estTimeStep();
}

#ifdef BL_USE_CHEM
inline
ChemKinDriver&
HyperCLaw::getChemDriver ()
{
    return *chemDriver;
}
#endif

#endif /*_HyperCLaw_H_*/
