//-----------------------------------------------------------------------------
//
//  Peter Richter (prichter@princeton.edu)
//  Princeton Plasma Physics Laboratory
//  August 2000
//
//  svreaction.cpp - Implementation of ionization reaction class.
//
//-----------------------------------------------------------------------------
 
#include "preact/svreaction.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
 
//-----------------------------------------------------------------------------
 
SVReaction :: SVReaction(char tag[], int errlo, int errhi) : coldTarget_data()
{
  init_aladdin();
 
  this->errlo = errlo;
  this->errhi = errhi;
 
  if (!strcmp(tag, "C+6->H")) {
    code = 1;
    Zimp = 6, Zplas = 1;
    setTableParameters((char *)"sv/cstoph/");
  }
  else if (!strcmp(tag, "C+6->He")) {
    code = 2;
    Zimp = 6, Zplas = 2;
    setTableParameters((char *)"sv/cstphe/");
  }
  else if (!strcmp(tag, "C+6->Li")) {
    code = 3;
    Zimp = 6, Zplas = 3;
    setTableParameters((char *)"sv/cstphe/");
  }
  else if (!strcmp(tag, "O+8->H")) {
    code = 4;
    Zimp = 8, Zplas = 1;
    setTableParameters((char *)"sv/cstphe/");
  }
  else if (!strcmp(tag, "O+8->He")) {
    code = 5;
    Zimp = 8, Zplas = 2;
    setTableParameters((char *)"sv/cstphe/");
  }
  else if (!strcmp(tag, "O+8->Li")) {
    code = 6;
    Zimp = 8, Zplas = 3;
    setTableParameters((char *)"sv/cstphe/");
  }
  else {
    cerr << "Error in SVReaction constructor: invalid reaction tag:\n";
    cerr << "    " << tag << endl;
    F77NAME(bad_exit)();
  }
}
 
//-----------------------------------------------------------------------------
 
SVReaction :: ~SVReaction()
{
  if (coldTarget_data.vector != NULL) {
    delete[] coldTarget_data.vector;
    delete[] coldTarget_data.domain;
  }
}
 
//-----------------------------------------------------------------------------
 
fp_64 SVReaction :: sigmav(fp_64 Erel)
{
  fp_64 sigmav;
  sigmav = F77NAME(sigv_zstop)(Erel, Zplas, Zimp);
  return sigmav;
}
 
//-----------------------------------------------------------------------------
 
void SVReaction :: g_tablefile(char table[], char file[])
{
  // gen the table filename
  switch (code) {
  case 1: maptable((char *)"sv/cstoph/", table, file); break;
  case 2: maptable((char *)"sv/cstphe/", table, file); break;
  case 3: maptable((char *)"sv/cstpli/", table, file); break;
  case 4: maptable((char *)"sv/ostoph/", table, file); break;
  case 5: maptable((char *)"sv/ostphe/", table, file); break;
  case 6: maptable((char *)"sv/ostpli/", table, file); break;
  }
}
//-----------------------------------------------------------------------------
 
void SVReaction :: 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 SVReaction :: range_error_warn(char table[])
{
  char tablename[L];
  g_tablefile(table, tablename);
  cerr << " interpolation range warning from table: " << endl;
  cerr << "    " << tablename << endl;
}
//-----------------------------------------------------------------------------
 
void SVReaction :: 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 SVReaction :: coldTarget_ERange() const
{
  return coldTarget_data.endpoints;
}
 
//-----------------------------------------------------------------------------
 
void SVReaction :: coldTarget_EPolicy(int errlo, int errhi)
{
  coldTarget_data.modify(errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void SVReaction :: setTableParameters(char dir[])
{
  fp_64 p1[8];
  int n = strlen(dir);
  char table[L];
 
  strcpy(table, dir);
  strcpy(table + n, "coldTarget");
  getparam(table, p1);
 
  coldTarget_data.set(p1, errlo, errhi);
}
 
//-----------------------------------------------------------------------------
 
void SVReaction :: 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 SVReaction :: 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 sigmav;
  fp_64 *axis = new fp_64[g.npoints];
  computeAxis(axis, g.npoints, g.endpoints, g.spacing);
  cout << "[...preact:  computing: " << file << " ]" << endl;
  for (int i = 0; i < g.npoints; i++) {
    sigmav = F77NAME(sigv_zstop)(axis[i], Zplas, Zimp);
    f << sigmav << '\n';
  }
  delete[] axis;
  f.close();
}

//-----------------------------------------------------------------------------
 
void SVReaction :: 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 SVReaction :: 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);
  }
}
 
//-----------------------------------------------------------------------------
