/*
** (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.
*/


//
// $Id: AmrDeriveBinTrac.cpp,v 1.9 2001/08/01 21:51:06 lijewski Exp $
//

#include <new>
#include <iostream>
#include <cstdlib>
#include <cstring>

#include <unistd.h>

#include "REAL.H"
#include "Box.H"
#include "FArrayBox.H"
#include "ParmParse.H"
#include "ParallelDescriptor.H"
#include "DataServices.H"
#include "Utility.H"
#include "VisMF.H"
#include "Derived.H"

static
void
PrintUsage (char* progName)
{
    cout << "\nUsage:\n"
         << progName
         << "\n\tinfile = inputFileName"
         << "\n\t[-help]"
         << "\n\n";
    exit(1);
}

static
Array<Real>
BinTrac (AmrData& amrData)
{
    Array<Real> sum(3,0);

    const int dcomp = 0;  // Density component number.
    const int tcomp = 5;  // Tracer component number.

    int finest_level = amrData.FinestLevel();

    FArrayBox fab_d, fab_t;

    for (int iLevel = 0; iLevel <= finest_level; ++iLevel)
    {
        const Real* dx = amrData.DxLevel()[iLevel].dataPtr();

        MultiFabIterator mfi_d(amrData.GetGrids(iLevel, dcomp));
        MultiFabIterator mfi_t(amrData.GetGrids(iLevel, tcomp));

        for ( ; mfi_d.isValid(); ++mfi_d, ++mfi_t)
        {
            //
            // Make copy of FABs so that we can change them.
            //
            fab_d.resize(mfi_d.fabbox(), 1);
            fab_t.resize(mfi_t.fabbox(), 1);

            fab_d.copy(mfi_d(), 0, 0, 1);
            fab_t.copy(mfi_t(), 0, 0, 1);

            if (iLevel < finest_level)
            {
                const BoxArray& f_box = amrData.boxArray(iLevel+1);

                for (int j = 0; j < f_box.length(); j++)
                {
                    Box c_box = ::coarsen(f_box[j],amrData.RefRatio()[iLevel]);
                    c_box &= mfi_d.validbox();
                    if (c_box.ok())
                    {
                        fab_d.setVal(0.0, c_box, 0);
                        fab_t.setVal(0.0, c_box, 0);
                    }
                }
            }
            Real s[3];

            const Real* dat_d = fab_d.dataPtr();
            const int* dlo    = fab_d.loVect();
            const int* dhi    = fab_d.hiVect();
            const Real* dat_t = fab_t.dataPtr();
            const int* lo     = mfi_d.validbox().loVect();
            const int* hi     = mfi_d.validbox().hiVect();

            FORT_BINTRAC(dat_t,ARLI(dlo),ARLIM(dhi),dat_d,lo,hi,dx,s);

            for (int i = 0; i < 3; i++)
                sum[i] += s[i];
        }
    }

    ParallelDescriptor::ReduceRealSum(sum[0]);
    ParallelDescriptor::ReduceRealSum(sum[1]);
    ParallelDescriptor::ReduceRealSum(sum[2]);

    return sum;
}

int
main (int   argc,
      char* argv[])
{
    //
    // Make sure to catch new failures.
    //
    set_new_handler(Utility::OutOfMemory);

    if (argc == 1)
        PrintUsage(argv[0]);

    ParallelDescriptor::StartParallel(&argc, &argv);

    ParmParse pp(argc-1,argv+1);

    if (pp.contains("help"))
        PrintUsage(argv[0]);

//    FArrayBox::setFormat(FABio::FAB_IEEE_32);
    FArrayBox::setFormat(FABio::FAB_NATIVE);
    //
    // Set default info.
    //
    Real gam = 1.667;
    FORT_SETGAMMA(&gam);
    //
    // Scan the arguments.
    //
    std::string iFile;
    pp.query("infile", iFile);
    if (iFile.isNull())
        BoxLib::Abort("You must specify `infile'");

    DataServices::SetBatchMode();
    FileType fileType(NEWPLT);
    
    DataServices dataServices(iFile, fileType);

    if (!dataServices.AmrDataOk())
    {
        //
        // This calls ParallelDescriptor::EndParallel() and exit()
        //
        DataServices::Dispatch(DataServices::ExitRequest, NULL);
    }
    AmrData& amrData = dataServices.AmrDataRef();

    BL_ASSERT(amrData.NComp() == NSTATECOMPS);

    Array<Real> sum = BinTrac(amrData);

    if (ParallelDescriptor::IOProcessor())
    {
        const Array<Real>& size = amrData.ProbSize();

        cout << amrData.Time()
             << ','
             << sum[0]
             << ','
             << sum[1]
             << ','
             << sum[2]
             << '\n';
    }

    DataServices::Dispatch(DataServices::ExitRequest, NULL);
}
