/*------------------------------constants.c------------------------------------
  This file contains the constant parameters of Brenner's potential. This
  software was written by Stephen Jordan and modeled on code from Zyvex as well
  as DW Brenner's original Fortran.
  ----------------------------------------------------------------------------*/

#include <stdio.h>
#include <math.h>      //for exp
#include "constants.h"
#include "cell.h"

double Dmax(int type1, int type2) {
  if(type1 == 1 && type2 == 1) return 2.0;
  if(type1 == 1 && type2 == 2) return 1.8;
  if(type1 == 2 && type2 == 1) return 1.8;
  if(type1 == 2 && type2 == 2) return 1.7;
  //otherwise:
  printf("Invilid type in Dmax.\n");
  return 0.0;
}


//as in equation 20 of Brenner's paper
double Dmin(int type1, int type2) {
  if(type1 == 1 && type2 == 1) return 1.7;
  if(type1 == 1 && type2 == 2) return 1.3;
  if(type1 == 2 && type2 == 1) return 1.3;
  if(type1 == 2 && type2 == 2) return 1.1;
  //otherwise:
  printf("Invalid type in Dmin.\n");
  return 0.0;
}


/*This is taken from Brenner's software, it has no counterpart in
  any of his papers, but REG*exp(XDB) serves a purpose analogous
  to the exponential term exp(lambda sub ijk) in equation 8 of
  Brenner's new paper.*/
double XDB(int type1, int type2, int type3) {
  if(type1 == 2 && type2 == 2 && type3 == 2) return 4.0;
  if(type1 == 2 && type2 == 1 && type3 == 2) return 4.0;
  if(type1 == 2 && type2 == 2 && type3 == 1) return 4.0;
  if(type1 == 2 && type2 == 1 && type3 == 1) return 4.0;
  //otherwise:
  return 0.0;
}


//Q as in equation 5 of Brenner's new paper
double Q(int type1, int type2) {
  if(type1 == 1 && type2 == 1) return 0.3134602960833;
  if(type1 == 1 && type2 == 2) return 0.340775728;
  if(type1 == 2 && type2 == 1) return 0.340775728;
  if(type1 == 2 && type2 == 2) return 0.370471487045;
  //otherwise:
  printf("Error in Q, invalid type.\n");
  return 0.0;
}

//A as in equation 5 of Brenner's new paper
double A(int type1, int type2) {
  if(type1 == 1 && type2 == 1) return 10953.544162170;
  if(type1 == 1 && type2 == 2) return   149.94098723;
  if(type1 == 2 && type2 == 1) return   149.94098723;
  if(type1 == 2 && type2 == 2) return    32.817355747;
  //otherwise:
  printf("Error in A, invalid type.\n");
  return 0.0;
}


//alpha as in equation 5 of Brenner's new paper
//(not the same as alpha in the old paper)
double alpha(int type1, int type2) {
  if(type1 == 1 && type2 == 1) return 4.7465390606595;
  if(type1 == 1 && type2 == 2) return 4.10254983;
  if(type1 == 2 && type2 == 1) return 4.10254983;
  if(type1 == 2 && type2 == 2) return 3.536298648;
  //otherwise:
  printf("Error in alpha, invalid type.\n");
  return 0.0;
}


//this is B as used in equation 6 of Brenner's new paper
double B(int type1, int type2, int n) {
  if(type1 == 1 && type2 == 1) {//C-C
    if(n == 1) return 12388.79197798;
    if(n == 2) return    17.56740646509;
    if(n == 3) return    30.71493208065;
    //otherwise
    printf("Error in B, invalid n.\n");
    return 0.0;
  }
  if((type1 == 1 && type2 == 2)||(type1 == 2 && type2 == 1)) { //C-H or H-C
    if(n == 1) return 32.3551866587;
    if(n == 2 || n == 3) return 0.0;
    //otherwise:
    printf("Error in B, invalid n.\n");
    return 0.0;
  }
  if(type1 == 2 && type2 == 2) { //H-H
    if(n == 1) return 29.632593;
    if(n == 2 || n == 3) return  0.0;
    //otherwise
    printf("Error in B, invalid n.\n");
    return 0.0;
  }
  //otherwise:
  printf("Error in B, invalid type.\n");
  return 0.0;
}


//this is beta as used in equation 6 of Brenner's new paper  
double beta(int type1, int type2, int n) {
  if(type1 == 1 && type2 == 1) {//C-C
    if(n == 1) return 4.7204523127;
    if(n == 2) return 1.4332132499;
    if(n == 3) return 1.3826912506;
    //otherwise
    printf("Error in beta, invalid n.\n");
    return 0.0;
  }
  if((type1 == 1 && type2 == 2)||(type1 == 2 && type2 == 1)) { //C-H or H-C
    if(n == 1) return 1.43445805925;
    if(n == 2 || n == 3) return 0.0;
    //otherwise:
    printf("Error in beta, invalid n.\n");
    return 0.0;
  }
  if(type1 == 2 && type2 == 2) { //H-H
    if(n == 1) return 1.71589217;
    if(n == 2 || n == 3) return  0.0;
    //otherwise
    printf("Error in beta, invalid n.\n");
    return 0.0;
  }
  //otherwise:
  printf("Error in beta, invalid type.\n");
  return 0.0;
}


double REG(int type1, int type2, int type3) {
  double RHH = 0.7415886997;
  double RCH = 1.09;
  if(type1 == 2 && type2 == 1 && type3 == 2) return exp(XDB(type1, type2, type3)*(RHH-RCH));
  if(type1 == 2 && type2 == 2 && type3 == 1) return exp(XDB(type1, type2, type3)*(RCH-RHH));
  //otherwise:
  return 1.0;
}


void constants(bond *b_array, int length) {
  int b, n;
  int type1, type2, type3;
  for(b = 0; b < length; b++) {
    type1 = b_array[b].bond_atom[0]->type;
    type2 = b_array[b].bond_atom[1]->type;
    b_array[b].Dmin = Dmin(type1, type2);
    b_array[b].Dmax = Dmax(type1, type2);
    b_array[b].Q = Q(type1, type2);
    b_array[b].A = A(type1, type2);
    b_array[b].alpha = alpha(type1, type2);
    for(n = 0; n < 3; n++) { //thunk these to 0-based
      b_array[b].B[n] = B(type1, type2, n+1);
      b_array[b].beta[n] = beta(type1, type2, n+1);
    }
    for(n = 0; n < b_array[b].neighbs[0]; n++) {
      type3 = b_array[b].neighb_a[0][n]->type;
      b_array[b].XDB[0][n] = XDB(type1, type2, type3);
      b_array[b].REG[0][n] = REG(type1, type2, type3);
    }
    for(n = 0; n < b_array[b].neighbs[1]; n++) {
      type3 = b_array[b].neighb_a[1][n]->type;
      b_array[b].XDB[1][n] = XDB(type2, type1, type3);
      b_array[b].REG[1][n] = REG(type2, type1, type3);
    }
  }  
}
