//-----------------------------------------------------------------------------
//
//  Peter Richter (prichter@princeton.edu)
//  Princeton Plasma Physics Laboratory
//  August 2000
//
//  iireaction.cpp - Implementation of ionization reaction class.
//
//-----------------------------------------------------------------------------
 
#include "preact/iireaction.h"
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <math.h>
#include "preact/fortran.h"
#include "preact/global.h"
#include "preact/table.h"
 
using namespace std ;

#define L 180
 
//-----------------------------------------------------------------------------
 
IIReaction :: IIReaction(char tag[], int errlo, int errhi) : coldTarget_data(),
  warmTarget_data()
{
  init_aladdin();
 
  this->errlo = errlo;
  this->errhi = errhi;
  if (!strcmp(tag, "H->H(ii)")) {
    code = 1;
    setTableParameters((char *)"ii/iitabl/");
  }
  else if (!strcmp(tag, "H+->He0i")) {
    code = 2;
    setTableParameters((char *)"ii/pheiit/");
  }
  else if (!strcmp(tag, "He++>H0i")) {
    code = 3;
    setTableParameters((char *)"ii/hehixt/");
  }
  else if (!strcmp(tag, "He++>Hei")) {
    code = 4;
    setTableParameters((char *)"ii/heitbl/");
  }
  else if (!strcmp(tag, "H+->Li0i")) {
    code = 5;
    setTableParameters((char *)"ii/pliiit/");
  }
  else if (!strcmp(tag, "He++>Lii")) {
    code = 6;
    setTableParameters((char *)"ii/heliit/");
  }
  else if (!strcmp(tag, "Li+++->H")) {
    code = 7;
    setTableParameters((char *)"ii/lihiit/");
  }
  else if (!strcmp(tag, "Li+++>He")) {
    code = 8;
    setTableParameters((char *)"ii/liheit/");
  }
  else if (!strcmp(tag, "Li+++>Li")) {
    code = 9;
    setTableParameters((char *)"ii/liliit/");
  }
  else {
    cerr << "Error in IIReaction constructor: invalid reaction tag:\n";
    cerr << "    " << tag << endl;
    F77NAME(bad_exit)();
  }
}
 
//-----------------------------------------------------------------------------
 
IIReaction :: ~IIReaction()
{
  if (coldTarget_data.vector != NULL) {
    delete[] coldTarget_data.vector;
    delete[] coldTarget_data.domain;
  }
  if (warmTarget_data.matrix != NULL) {
    delete[] warmTarget_data.matrix;
    delete[] warmTarget_data.domain1;
    delete[] warmTarget_data.domain2;
  }
}
 
//-----------------------------------------------------------------------------
 
fp_64 IIReaction :: sigma(fp_64 Erel)
{
  fp_64 sigma, vrel;
  setKReactVariable();
  sigma = F77NAME(sigall_z)(Erel, vrel);
  return sigma;
}
 
//-----------------------------------------------------------------------------
 
fp_64 IIReaction :: vrel(fp_64 Erel)
{
  fp_64 sigma, vrel;
  setKReactVariable();
  sigma = F77NAME(sigall_z)(Erel, vrel);
  return vrel;
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: g_tablefile(char table[], char file[])
{
  // gen the table filename
  switch (code) {
  case 1: maptable((char *)"ii/iitabl/", table, file); break;
  case 2: maptable((char *)"ii/pheiit/", table, file); break;
  case 3: maptable((char *)"ii/hehixt/", table, file); break;
  case 4: maptable((char *)"ii/heitbl/", table, file); break;
  case 5: maptable((char *)"ii/pliiit/", table, file); break;
  case 6: maptable((char *)"ii/heliit/", table, file); break;
  case 7: maptable((char *)"ii/lihiit/", table, file); break;
  case 8: maptable((char *)"ii/liheit/", table, file); break;
  case 9: maptable((char *)"ii/liliit/", table, file); break;
  }
}
//-----------------------------------------------------------------------------
 
void IIReaction :: range_error_exit(char table[])
{
  char tablename[L];
  g_tablefile(table, tablename);
  cerr << " error interpolating data from table: " << endl;
  cerr << "    " << tablename << endl;
  F77NAME(bad_exit)();
}
//-----------------------------------------------------------------------------
 
void IIReaction :: range_error_warn(char table[])
{
  char tablename[L];
  g_tablefile(table, tablename);
  cerr << " interpolation range warning from table: " << endl;
  cerr << "    " << tablename << endl;
}
//-----------------------------------------------------------------------------
 
void IIReaction :: coldTarget_sigmaTimesV(fp_64 E[], fp_64 f[], int n)
{
  // read table into memory if not done yet...
  if (coldTarget_data.vector == NULL) {
    char filename[L];
    fstream datafile;
 
    g_tablefile((char *)"coldTarget", filename);
    datafile.open(filename, ios :: in);
 
    // compute table if not done yet...
    if ( !datafile )
      compute1DTable(coldTarget_data, filename);
    else
      datafile.close();
 
    // now read table into memory...
    read1DTable(coldTarget_data, filename);
  }
 
  // interpolate from data and return sigma*v...
  interp1DTable((char *)"coldTarget", coldTarget_data, E, (char *)"energy", f, n);
}
 
//-----------------------------------------------------------------------------
 
range IIReaction :: coldTarget_ERange() const
{
  return coldTarget_data.endpoints;
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: coldTarget_EPolicy(int errlo, int errhi)
{
  coldTarget_data.modify(errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: warmTarget_sigmaTimesV(fp_64 E[], fp_64 T[],fp_64 f[],int n)
{
  // read table into memory if not done yet...
  if (warmTarget_data.matrix == NULL) {
    char filename[L];
    fstream datafile;
 
    g_tablefile((char *)"warmTarget", filename);
    datafile.open(filename, ios :: in);
 
    // compute table if not done yet...
    if ( !datafile )
      compute2DTable(warmTarget_data, filename);
    else
      datafile.close();
 
    // now read table into memory...
    read2DTable(warmTarget_data, filename);
  }
 
  // interpolate from data and return sigma*v...
  interp2DTable((char *)"warmTarget",
		warmTarget_data, E, (char *)"energy", T, (char *)"temperature", f, n);
}
 
//-----------------------------------------------------------------------------
 
range IIReaction :: warmTarget_ERange() const
{
  return warmTarget_data.endpoints1;
}
 
//-----------------------------------------------------------------------------
 
range IIReaction :: warmTarget_TRange() const
{
  return warmTarget_data.endpoints2;
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: warmTarget_EPolicy(int errlo, int errhi)
{
  warmTarget_data.modify1(errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: warmTarget_TPolicy(int errlo, int errhi)
{
  warmTarget_data.modify2(errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: setTableParameters(char dir[])
{
  fp_64 p1[8], p2[8];
  int n = strlen(dir);
  char table[L];
 
  strcpy(table, dir);
  strcpy(table + n, "coldTarget");
  getparam(table, p1);
  strcpy(table + n, "warmTarget");
  getparam(table, p2);
 
  coldTarget_data.set(p1, errlo, errhi);
  warmTarget_data.set(p2, errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: setKReactVariable()
{
  int ireact;
  switch (code) {
  case 1: ireact = 2;  break;
  case 2: ireact = 13; break;
  case 3: ireact = 14; break;
  case 4: ireact = 16; break;
  case 5: ireact = 18; break;
  case 6: ireact = 20; break;
  case 7: ireact = 21; break;
  case 8: ireact = 22; break;
  case 9: ireact = 24; break;
  }
  F77NAME(sigprep_z)(ireact);
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: computeAxis(fp_64 axis[], int npts, range endpts,
			       int spac)
{
  if (spac == LOG) {
    fp_64 t = log(endpts.maximum / endpts.minimum);
    for (int i = 0; i < npts - 1; i++)
      axis[i] = endpts.minimum * exp(fp_64(i) * t / fp_64(npts - 1));
    axis[npts - 1] = endpts.maximum;
  }
  else /* spac == LIN */ {
    fp_64 t = endpts.maximum - endpts.minimum;
    for (int i = 0; i < npts - 1; i++)
      axis[i] = endpts.minimum + fp_64(i) * t / fp_64(npts - 1);
    axis[npts - 1] = endpts.maximum;
  }
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: compute1DTable(grid_1D& g, char file[])
{
  ofstream f(file);
  if ( !f ) {
    cerr << "preact: output file open failure: " << file << endl;
    F77NAME(bad_exit)();
  }
  f.precision(15);
  fp_64 sigma, vrel;
  fp_64 *axis = new fp_64[g.npoints];
  computeAxis(axis, g.npoints, g.endpoints, g.spacing);
  setKReactVariable();
  cout << "[...preact:  computing: " << file << " ]" << endl;
  for (int i = 0; i < g.npoints; i++) {
    sigma = F77NAME(sigall_z)(axis[i], vrel);
    f << sigma * vrel << '\n';
  }
  delete[] axis;
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: compute2DTable(grid_2D& g, char file[])
{
  ofstream f(file);
  if ( !f ) {
    cerr << "preact: output file open failure: " << file << endl;
    F77NAME(bad_exit)();
  }
  f.precision(15);
  fp_64 *mtx = new fp_64[g.npoints1 * g.npoints2];
  fp_64 *axis1 = new fp_64[g.npoints1];
  fp_64 *axis2 = new fp_64[g.npoints2];
  int ikey, ier = 0;
  computeAxis(axis1, g.npoints1, g.endpoints1, g.spacing1);
  computeAxis(axis2, g.npoints2, g.endpoints2, g.spacing2);
  setKReactVariable();
  ikey = 2;
  cout << "[...preact:  computing: " << file << " ]" << endl;
  F77NAME(setkey_z)(ikey);
  F77NAME(comptabl_z)(NULL, mtx, axis1, axis2, g.npoints1, g.npoints2, ier);
  for (int j = 0; j < g.npoints2; j++)
    for (int i = 0; i < g.npoints1; i++){
      f << mtx[g.npoints1 * j + i] << '\n';
      //      cout << "IIReaction " << mtx[g.npoints1 * j + i] << " \n" << endl;
    }
  delete[] mtx;
  delete[] axis1;
  delete[] axis2;
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: read1DTable(grid_1D& g, char file[])
{
  ifstream f(file);
  g.vector = new fp_64[g.npoints];
  g.domain = new fp_64[g.npoints];
  for (int i = 0; i < g.npoints; i++) {
    f >> g.vector[i];
  }
  computeAxis(g.domain, g.npoints, g.endpoints, g.spacing);
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: read2DTable(grid_2D& g, char file[])
{
  ifstream f(file);
  g.matrix = new fp_64[g.npoints1 * g.npoints2];
  g.domain1 = new fp_64[g.npoints1];
  g.domain2 = new fp_64[g.npoints2];
  for (int j = 0; j < g.npoints2; j++)
    for (int i = 0; i < g.npoints1; i++) {
      int ia = g.npoints1 * j + i;
      f >> g.matrix[ia];
    }
  computeAxis(g.domain1, g.npoints1, g.endpoints1, g.spacing1);
  computeAxis(g.domain2, g.npoints2, g.endpoints2, g.spacing2);
  f.close();
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: interp1DTable(char table[], grid_1D& g,
				 fp_64 x[], char xdim[],
				 fp_64 f[], int n)
{
  int iwarn;
  F77NAME(flin1_z)(x, f, n, g.vector, g.endpoints.minimum,
		   g.endpoints.maximum, g.ln, g.npoints, iwarn);
 
  if (iwarn) {
    int halt = FALSE, warn = FALSE;
    table_errchk(x, f, n, xdim, g.endpoints, warn, halt);
    if (halt == TRUE)
      range_error_exit(table);
    if (warn == TRUE)
      range_error_warn(table);
  }
}
 
//-----------------------------------------------------------------------------
 
void IIReaction :: interp2DTable(char table[], grid_2D& g,
				 fp_64 x[], char xdim[],
				 fp_64 y[], char ydim[], fp_64 f[], int n)
{
  int iwarn;
  F77NAME(flint_z)(x, y, f, n, g.matrix, g.endpoints1.minimum,
		   g.endpoints1.maximum, g.ln1, g.npoints1,
		   g.endpoints2.minimum, g.endpoints2.maximum, g.ln2,
		   g.npoints2, iwarn);
 
  if (iwarn) {
    int halt = FALSE, warn = FALSE;
    table_errchk(x, f, n, xdim, g.endpoints1, warn, halt);
    table_errchk(y, f, n, ydim, g.endpoints2, warn, halt);
    if (halt == TRUE)
      range_error_exit(table);
    if (warn == TRUE)
      range_error_warn(table);
  }
}
 
//-----------------------------------------------------------------------------
