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

//BL_COPYRIGHT_NOTICE
#include <winstd.H>

#include <new>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <list>
#include <map>
#include <algorithm>

#ifndef WIN32
#include <unistd.h>
#endif

#include "ParmParse.H"
#include "ParallelDescriptor.H"
#include "DataServices.H"
#include "Utility.H"
#include "FArrayBox.H"
#include "Utility.H"

#include "ChemKinDriver.H"


static
void 
print_usage (int,
             char* argv[])
{
	std::cerr << "usage:\n";
    std::cerr << argv[0] << " infile [options] \n\tOptions:\n";
    exit(1);
}

void clonePlotfile(AmrData& amrData,
				   const PArray<MultiFab>& mfout,
				   std::string& oFile,
				   const Array<std::string>& names,
			       bool verbose)
{
    if (ParallelDescriptor::IOProcessor())
        if (!BoxLib::UtilCreateDirectory(oFile,0755))
            BoxLib::CreateDirectoryFailed(oFile);
    //
    // Force other processors to wait till directory is built.
    //
    ParallelDescriptor::Barrier();

    std::string oFileHeader(oFile);
    oFileHeader += "/Header";
  
    VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);

	std::ofstream os;
  
    os.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
  
    if (verbose && ParallelDescriptor::IOProcessor())
		std::cout << "Opening file = " << oFileHeader << '\n';

    os.open(oFileHeader.c_str(), std::ios::out|std::ios::binary);

    if (os.fail())
        BoxLib::FileOpenFailed(oFileHeader);
    //
    // Start writing plotfile.
    //
    os << amrData.PlotFileVersion() << '\n';
    int n_var = mfout[0].nComp();
    os << n_var << '\n';
    for (int n = 0; n < n_var; n++) os << names[n] << '\n';
    os << BL_SPACEDIM << '\n';
    os << amrData.Time() << '\n';
	const int finestLevel = mfout.size() - 1;
    os << finestLevel << '\n';
    for (int i = 0; i < BL_SPACEDIM; i++) os << amrData.ProbLo()[i] << ' ';
    os << '\n';
    for (int i = 0; i < BL_SPACEDIM; i++) os << amrData.ProbHi()[i] << ' ';
    os << '\n';
    for (int i = 0; i < finestLevel; i++) os << amrData.RefRatio()[i] << ' ';
    os << '\n';
    for (int i = 0; i <= finestLevel; i++) os << amrData.ProbDomain()[i] << ' ';
    os << '\n';
    for (int i = 0; i <= finestLevel; i++) os << 0 << ' ';
    os << '\n';
    for (int i = 0; i <= finestLevel; i++)
    {
        for (int k = 0; k < BL_SPACEDIM; k++)
            os << amrData.DxLevel()[i][k] << ' ';
        os << '\n';
    }
    os << amrData.CoordSys() << '\n';
    os << "0\n"; // The bndry data width.
    //
    // Write out level by level.
    //
    for (int iLevel = 0; iLevel <= finestLevel; ++iLevel)
    {
        //
        // Write state data.
        //
        int nGrids = amrData.boxArray(iLevel).size();
        char buf[64];
        sprintf(buf, "Level_%d", iLevel);
    
        if (ParallelDescriptor::IOProcessor())
        {
            os << iLevel << ' ' << nGrids << ' ' << amrData.Time() << '\n';
            os << 0 << '\n';
    
            for (int i = 0; i < nGrids; ++i)
            {
                for (int n = 0; n < BL_SPACEDIM; n++)
                {
                    os << amrData.GridLocLo()[iLevel][i][n]
                       << ' '
                       << amrData.GridLocHi()[iLevel][i][n]
                       << '\n';
                }
            }
            //
            // Build the directory to hold the MultiFabs at this level.
            //
            std::string Level(oFile);
            Level += '/';
            Level += buf;
    
            if (!BoxLib::UtilCreateDirectory(Level, 0755))
                BoxLib::CreateDirectoryFailed(Level);
        }
        //
        // Force other processors to wait till directory is built.
        //
        ParallelDescriptor::Barrier();
        //
        // Now build the full relative pathname of the MultiFab.
        //
        static const std::string MultiFabBaseName("/MultiFab");
    
        std::string PathName(oFile);
        PathName += '/';
        PathName += buf;
        PathName += MultiFabBaseName;
    
        if (ParallelDescriptor::IOProcessor())
        {
            //
            // The full name relative to the Header file.
            //
            std::string RelativePathName(buf);
            RelativePathName += '/';
            RelativePathName += MultiFabBaseName;
            os << RelativePathName << '\n';
        }
        VisMF::Write(mfout[iLevel], PathName, VisMF::OneFilePerCPU);
    }

    os.close();
}

#define PI	3.141593			/* pi */
#define C	29979245800.0	/* Speed of Light in cm/s  */
#define H	6.6260755e-34	/* Planck's constant in Js */
#define K	1.380662e-23	/* Boltzmann constant J/K */

/********************************************************************************
**
**	Definition of structures for all data transfer between functions.
**	The following structures are used:
**
**	BoundaryParams (bparm):	pressure, temperature, name, molar mass and molefraction of up to 50 species. 
**	QuenchParams (qparm):	name and quenching parameters according to harpoon model for up to 50 species.
**
**	The molecule parameters (mass/molefraction and quenching) are interconnected between the two structures by their name.
**	It is thus important to use the same name (implemented as string) within both structures!
**
********************************************************************************/

struct QuenchParams
{
	int number;					// number of quenching species for which parameters are in this structure

	char qname[50][10];		// name of up to 50 species
	int qclass[50];			// harpoon class
	float c0[50];				// harpoon coefficients
	float c1[50];
	float c2[50];
	float c3[50];
	float c4[50];
};

struct BoundaryParams
{
	float temp;					// temperature
	float press;				// pressure

	int snumber;				// number of species. the 1st must be the molecule for which the simulation is performed!
	char sname[500][10];		// name of up to 50 species
	float smass[500];			// molecular mass [u]
	float smolefract[500];	// mole fraction (0...1)
};

/********************************************************************************
**
**	void LoadQuenchParams(char *filename, struct QuenchParams *qparm)
**
**
** Load the quenching coefficients from the ASCII file "filename" and puts it into qparm.
**	The necessary memory must already be assigned!
**
********************************************************************************/



void LoadQuenchParams(char *filename, QuenchParams& qparm)
{
	FILE *fp;
	int i;
	
	void ReadInt(FILE*,int*);
	void ReadFloat(FILE*,float*);
	void ReadString(FILE*,char*);

	if((fp = fopen(filename,"r")) == NULL)
	{
		printf("File %s could not be opened!",filename);
		exit(-1);
	}

	ReadInt(fp,&qparm.number);
	for(i = 0; i < qparm.number; i++)
	{
		ReadString(fp,qparm.qname[i]);
		ReadInt(fp,&qparm.qclass[i]);
		ReadFloat(fp,&qparm.c0[i]);
		ReadFloat(fp,&qparm.c1[i]);
		ReadFloat(fp,&qparm.c2[i]);
		ReadFloat(fp,&qparm.c3[i]);
		ReadFloat(fp,&qparm.c4[i]);
	}
	
	fclose(fp);
}

/********************************************************************************
**
**	void ReadFloat(FILE *fp, float *value)
**	void ReadString(FILE *fp, char *string)
**	void ReadInt(FILE *fp, int *value)
**
**
**	reads the next float value/next string/next integer value out of the ASCII file which is already opened to read
** with the file pointer fp.
**	lines starting with "*" are considered as comments.
**	lines containing a "*" are comments from that position on.
**	values can be separated using one or multiple TAB or SPACE or CR
**
********************************************************************************/



void ReadFloat(FILE* fp, float *value)
{
	int c;
	int pos;
	char line[100];


	do
	{
		c = fgetc(fp);
		if(c == '*')
		{
			while((( c = fgetc(fp)) != '\n') && (c != EOF))
				;
		}
		if(c == EOF)
		{
			*value = 0.0;
			return;
		}
	} while(c == '\t' || c == '\n' || c == ' ');
	

	pos = 0;
	do
		line[pos++] = c;
	while((( c= fgetc(fp)) != '\t') && (c != '\n') && (c != EOF) && (c != '*') && (c != ' '));
	line[pos] = 0;

	*value = (float) atof(line);

}

void ReadInt(FILE* fp, int *value)
{
	int c;
	int pos;
	char line[100];


	do
	{
		c = fgetc(fp);
		if(c == '*')
		{
			while((( c = fgetc(fp)) != '\n') && (c != EOF))
				;
		}
		if(c == EOF)
		{
			*value = 0;
			return;
		}
	} while(c == '\t' || c == '\n' || c == ' ');
	

	pos = 0;
	do
		line[pos++] = c;
	while((( c= fgetc(fp)) != '\t') && (c != '\n') && (c != EOF) && (c != '*') && (c != ' '));
	line[pos] = 0;

	*value = (int) atof(line);

}

void ReadString(FILE* fp, char *string)
{
	int c;
	int pos;


	do
	{
		c = fgetc(fp);
		if(c == '*')
		{
			while((( c = fgetc(fp)) != '\n') && (c != EOF))
				;
		}
		if(c == EOF)
		{
			string[0] = 0;
			return;
		}
	} while(c == '\t' || c == '\n' || c == ' ');
	

	pos = 0;
	do
		string[pos++] = c;
	while((( c= fgetc(fp)) != '\t') && (c != '\n') && (c != EOF) && (c != '*') && (c != ' '));

	string[pos] = 0;

}




/********************************************************************************
**
**	Calculation of Gamma functions.
**
**	from: Press, Teukolsky, Vetterling, Flannery, Numerical recipes in C, Cambridge University Press
**
********************************************************************************/



// Returns the value ln[greek-G(xx)]for xx > 0.

float gammln(float xx)
{
	//Internal arithmetic will be done in double precision, a nicety that you can omit if ve-gure
	//accuracy is good enough.
	double x,y,tmp,ser;
	static double cof[6]={76.18009172947146,-86.50532032941677,
		24.01409824083091,-1.231739572450155,
		0.1208650973866179e-2,-0.5395239384953e-5};
	int j;

	y=x=xx;
	tmp=x+5.5;
	tmp -= (x+0.5)*log(tmp);
	ser=1.000000000190015;
	for (j=0;j<=5;j++) ser += cof[j]/++y;
	return -tmp+log(2.5066282746310005*ser/x);
}




// Returns the incomplete gamma function P(a; x).
float gammp(float a, float x)
{
	void gcf(float *gammcf, float a, float x, float *gln);
	void gser(float *gamser, float a, float x, float *gln);
	void nrerror(char error_text[]);
	float gamser,gammcf,gln;

	if (x < 0.0 || a <= 0.0) nrerror("Invalid arguments in routine gammp");
	if (x < (a+1.0)) { // Use the series representation.
		gser(&gamser,a,x,&gln);
		return gamser;
	} else { // Use the continued fraction representation
		gcf(&gammcf,a,x,&gln);
	return 1.0-gammcf; // and take its complement.
	}
}


// Returns the incomplete gamma function greek-g(a; x).. P(a,x) = greek-g(a,x) / greek-G(a)
// WGB 13.7.2001
float gammg(float a, float x)
{
	void gcf(float *gammcf, float a, float x, float *gln);
	void gser(float *gamser, float a, float x, float *gln);
	void nrerror(char error_text[]);
	float gamser,gammcf,gln;

	if (x < 0.0 || a <= 0.0) nrerror("Invalid arguments in routine gammp");
	if (x < (a+1.0)) { // Use the series representation.
		gser(&gamser,a,x,&gln);
		return gamser * exp(gln);
	} else { // Use the continued fraction representation
		gcf(&gammcf,a,x,&gln);
	return (1.0-gammcf) * exp(gln); // and take its complement.
	}
}


// Returns the incomplete gamma function Q(a; x) = 1 - P(a; x).
float gammq(float a, float x)
{
	void gcf(float *gammcf, float a, float x, float *gln);
	void gser(float *gamser, float a, float x, float *gln);
	void nrerror(char error_text[]);
	float gamser,gammcf,gln;

	if (x < 0.0 || a <= 0.0) nrerror("Invalid arguments in routine gammq");
	if (x < (a+1.0)) { // Use the series representation
		gser(&gamser,a,x,&gln);
		return 1.0-gamser; // and take its complement.
	} else { // Use the continued fraction representation.
		gcf(&gammcf,a,x,&gln);
		return gammcf;
	}
}



#define ITMAX 100 /* Maximum allowed number of iterations. */
#define EPS 3.0e-7 /* Relative accuracy.*/
#define FPMIN 1.0e-30 /* Number near the smallest representable floating-point number.*/


// Returns the incomplete gamma function P(a; x) evaluated by its series representation as gamser.
// Also returns ln greek-G(a) as gln.
void gser(float *gamser, float a, float x, float *gln)
{
	float gammln(float xx);
	void nrerror(char error_text[]);
	int n;
	float sum,del,ap;

	*gln=gammln(a);
	if (x <= 0.0) {
		if (x < 0.0) nrerror("x less than 0 in routine gser");
		*gamser=0.0;
		return;
	} else {
		ap=a;
		del=sum=1.0/a;
		for (n=1;n<=ITMAX;n++) {
			++ap;
			del *= x/ap;
			sum += del;
			if (fabs(del) < fabs(sum)*EPS) {
				*gamser=sum*exp(-x+a*log(x)-(*gln));
				return;
			}
		}
		nrerror("a too large, ITMAX too small in routine gser");
		return;
	}
}


// Returns the incomplete gamma function Q(a; x) evaluated by its continued fraction represen-
// tation as gammcf. Also returns ln greek-G(a) as gln.

void gcf(float *gammcf, float a, float x, float *gln)
{
	float gammln(float xx);
	void nrerror(char error_text[]);
	int i;
	float an,b,c,d,del,h;

	*gln=gammln(a);
	b=x+1.0-a; // Set up for evaluating continued fraction by modied Lentz's method ( x 5.2) with b0 = 0.
	c=float(1.0/FPMIN);
	d=1.0/b;
	h=d;
	for (i=1;i<=ITMAX;i++) { // Iterate to convergence. 
		an = -i*(i-a);
		b += 2.0;
		d=an*d+b;
		if (fabs(d) < FPMIN) d=float(FPMIN);
		c=b+an/c;
		if (fabs(c) < FPMIN) c=float(FPMIN);
		d=1.0/d;
		del=d*c;
		h *= del;
		if (fabs(del-1.0) < EPS) break;
	}
	if (i > ITMAX) nrerror("a too large, ITMAX too small in gcf");
	*gammcf=exp(-x+a*log(x)-(*gln))*h; // Put factors in front.
}

void nrerror(char error_text[])
/* Numerical Recipes standard error handler */
{
	fprintf(stderr,"Numerical Recipes run-time error...\n");
fprintf(stderr,"%s\n",error_text);
fprintf(stderr,"...now exiting to system...\n");
exit(1);
}

/********************************************************************************
**
**	double CalculateQuenchRate(struct QuenchParams *qparm, struct BoundaryParams *bparm)
**
**
** Gives back the total calculated quenching rate [1/s], based on the quenching parameters given in qparm
**	and the boundary parameters given in bparm.
**
********************************************************************************/



double CalculateQuenchRate(QuenchParams& qparm, BoundaryParams& bparm, int idxQspec)
{
	float gammg(float a, float x);	// this gives back the incomplete gamma function. implemented from "numerical recipes".
	double qrate;
	double cross;
	double eta;
	int i,j;


	// calculation of effective cross section by summation over species: cross section x molefraction x mass dependence
	qrate = 0;
	for(i = 0; i < bparm.snumber; i++)	// all molecules in system
	{
		if(bparm.smolefract[i] > 0.0)
		{
			// find molecule in quenching table by comparing name
			j = 0;
			while(strcmp(bparm.sname[i],qparm.qname[j]) && j < qparm.number)	// strcmp() returns 0 if strings are identical
				j++;

			if(j >= qparm.number)
			{}//printf("No quenching data available for %s!\n",bparm.sname[i]);
			else
			{
				// calculate t-dependent quenching cross section according to harpoon model
				if(qparm.qclass[j] == 1)	
					cross = 0.0;
				else if(qparm.qclass[j] == 2)	
					cross = qparm.c0[j] + qparm.c1[j] * exp((-1.0) * qparm.c2[j] * 300.0/bparm.temp) + qparm.c3[j]*exp((-1.0) * qparm.c4[j] * 300.0/bparm.temp);
				else if(qparm.qclass[j] == 3)
				{
					eta = qparm.c2[j] *300.0/bparm.temp  + qparm.c3[j]*300.0/bparm.temp*300.0/bparm.temp;
					cross = qparm.c0[j]*((1.0 + eta) * exp((-1.0)*eta) + qparm.c1[j]*pow(eta,1.0/3.0)*gammg(5.0/3.0,eta) );
				}
				else if(qparm.qclass[j] == 4)
					cross = qparm.c0[j];
				else if(qparm.qclass[j] == 5)
					cross = qparm.c0[j] + qparm.c1[j] * pow(300.0/bparm.temp, qparm.c2[j]);
				else if(qparm.qclass[j] == 6)
				{
					eta = qparm.c2[j] *300.0/bparm.temp  + qparm.c3[j]*300.0/bparm.temp*300.0/bparm.temp;
					cross = qparm.c0[j]* ((1.0 + eta) * exp((-1.0)*eta) + qparm.c1[j]*pow(eta,1.0/3.0)*gammg(5.0/3.0,eta) );
				}
	
//				printf("Quenching cross section for %s: %g\n",qparm.qname[j],cross);
				
				// add cross section to total quench rate
				qrate += bparm.smolefract[i] * sqrt(1 + bparm.smass[idxQspec]/bparm.smass[i]) * cross;
			}
		
		}
	}
	

	// qrate now contains the total effective quenching cross section in Angstrom^2.
	// To convert into 1/s, we need to multiply by p/kT * <v>

	qrate *= bparm.press / (K * bparm.temp) * sqrt(8.0 * K * bparm.temp / (PI * bparm.smass[idxQspec]));
	
	// conversion of amu, bar and Angstrom to kg, Pa and m
	qrate *= 2.4539855e-2;														
	
	return(qrate);
}

Real func_T(Real T)
{
	// set 1
	Real coeff[8] = {  1.82078E31, -1.83238E29, +6.19957E26, -7.31098E23, +4.46668E20, -1.52894E17, +2.78638E13, -2.1079E9 };

	//set 2
    //Real coeff[8] = { -3.49899E29, +2.69897E27, -7.47569E24, +9.21223E21, -5.17156E18, +1.47748E15, -2.07914E11, +1.11425E7 }; 

	return (1/T) * (coeff[0] + coeff[1]*T + coeff[2]*pow(T,2) + coeff[3]*pow(T,3)
		+ coeff[4]*pow(T,4) + coeff[5]*pow(T,5) + coeff[6]*pow(T,6) + coeff[7]*pow(T,7) );
}

void
main (int   argc,
      char* argv[])
{
    BoxLib::Initialize(argc,argv);

    if (argc < 2)
        print_usage(argc,argv);

    ParmParse pp;

    if (pp.contains("help"))
        print_usage(argc,argv);

    if (pp.contains("verbose"))
        AmrData::SetVerbose(true);

    std::string infile;
	pp.get("file",infile);

    std::string Qspec = "NO";
	pp.query("Qspec",Qspec);

    std::string excessspec = "N2";
	pp.query("excessspec",excessspec);

	// the following two structures will contain all the necessary parameters for the quenching correction
	// (definition see at top of file).

	QuenchParams qparm;		// info on quenching efficiency of different species (loaded from no-quenching.dat)
	BoundaryParams bparm;		// info on boundary conditions such as temperature, pressure, and mole fractions

	// load quenching parameters
	LoadQuenchParams("no-quenching.dat",qparm);	

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

    if (!dataServices.AmrDataOk())
        //
        // This calls ParallelDescriptor::EndParallel() and exit()
        //
        DataServices::Dispatch(DataServices::ExitRequest, NULL);

    AmrData& amrData = dataServices.AmrDataRef();

    int Nlev = amrData.FinestLevel() + 1;

	std::string chemInFile = "chemGlar.inp";
	std::string chemOutFile = "chemGlar.out";
	std::string thermInFile = "thermGlar.dat";
	std::string tranInFile = "tranGlar.dat";
	ChemKinDriver ckd(chemInFile,chemOutFile,thermInFile,tranInFile);
	const Array<std::string> chemnames = ckd.speciesNames();

	Array<std::string> plotnames = amrData.PlotVarNames();
    int idT = -1;
	int idX = -1;
	int idxQspec = -1;
	int idxXS = -1;
	for (int i=0; i<chemnames.size(); ++i)
	{
		if (chemnames[i] == Qspec) idxQspec = i;
		if (chemnames[i] == excessspec) idxXS = i;
	}
	for (int i=0; i<plotnames.size(); ++i)
	{
		if (plotnames[i] == "temp") idT = i;
		if (plotnames[i] == "X(" + chemnames[0] + ")" ) idX = i;
	}
	const int Nspec = ckd.numSpecies();

	PArray<MultiFab> mfout(Nlev);
	Array<std::string> names(Nspec+2);
	for (int i=0; i<Nspec; ++i)
		names[i] = "X(" + ckd.speciesNames()[i] + ")";
	names[Nspec] = "temp";
	names[Nspec+1] = "Quenched_X(" + Qspec + ")";

	Array<Real> vals(names.size());

	bparm.press = 1.0;
	bparm.snumber = Nspec;
	const Array<Real> molecWeight = ckd.speciesMolecWt();
	for (int i=0; i<Nspec; ++i)
	{
		strcpy(bparm.sname[i],chemnames[i].c_str());
		bparm.smass[i] = molecWeight[i];
	}

    for (int lev=0; lev<Nlev; ++lev)
    {
		mfout.set(lev,new MultiFab(amrData.boxArray(lev),Nspec+2,0));
		mfout[lev].copy(amrData.GetGrids(lev,idT),0,Nspec,1);
        for (int iComp = 0; iComp < Nspec; ++iComp)
		{
			mfout[lev].copy(amrData.GetGrids(lev,idX+iComp),0,iComp,1);
        }
		
		for (MFIter mfi(mfout[lev]); mfi.isValid(); ++mfi)
		{
			Box box = mfi.validbox();
			FArrayBox& fab = mfout[lev][mfi];
			for (IntVect iv = box.smallEnd(); iv<=box.bigEnd(); box.next(iv))
			{
				fab.getVal(vals.dataPtr(),iv);
				bparm.temp = vals[Nspec];
				Real sum = 0.0;
				for (int i=0; i<Nspec; ++i)
				{
					//bparm.smolefract[i] = vals[i];
					bparm.smolefract[i] = std::max(vals[i],0.0);
					if (i != idxXS)
						sum += bparm.smolefract[i];
				}
				bparm.smolefract[idxXS] = 1.0 - sum;

				// calculate total quench rate in 1/s and correction factor
				const float quenchrate = CalculateQuenchRate(qparm,bparm,idxQspec);

				//const float calibrationquenchrate = 6.53308e8; //quenching rate at calibration point
				//const float calibrationquenchrate = 6.61197e8;	//updated value, 11/19
				//fab(iv,Nspec+1) = vals[idxQspec] * (calibrationquenchrate / quenchrate);

				const Real f_T = func_T(bparm.temp);

				//const Real scale = 6.61197e8*102.2/(4.07e-4 * func_T(2150.));

				//set 2
				//const Real scale = 6.61197e8*101.7/(4.07e-4 * func_T(2150.));

				// set 1
				const Real scale = 6.61197e8*3091./(4.07e-4 * func_T(2150.));


				//fab(iv,Nspec+1) =  scale * (f_T / quenchrate);
				fab(iv,Nspec+1) =  quenchrate / bparm.temp;
				//fab(iv,Nspec+1) = vals[idxQspec] * scale * (f_T / quenchrate);
			}
		}
    }

	std::cout << "Writing pltfile...";
    clonePlotfile(amrData,mfout,std::string(infile + "_qr2qinvT"),names,false);
	std::cout << "...done" << std::endl;

    BoxLib::Finalize();
}
