/*
 * Copyright University of Reims Champagne-Ardenne
 * Authors and Contributors: Akilan RAJAMANI, Corentin LEFEBVRE, Johanna KLEIN,
 *                           Emmanuel PLUOT, Gaetan RUBEZ, Hassan KHARTABIL,
 *                           Jean-Charles BOISSON and Eric HENON
 * (24/07/2017)
 * jean-charles.boisson@univ-reims.fr, eric.henon@univ-reims.fr
 *
 * This software is a computer program whose purpose is to
 * detect and quantify interactions from electron density
 * obtained either internally from promolecular density or
 * calculated from an input wave function input file. It also
 * prepares for the visualization of isosurfaces representing
 * several descriptors (dg) coming from the IGM methodology.
 *
 * This software is governed by the CeCILL-C license under French law and
 * abiding by the rules of distribution of free software.  You can  use,
 * modify and/ or redistribute the software under the terms of the CeCILL-C
 * license as circulated by CEA, CNRS and INRIA at the following URL
 * "http://www.cecill.info".
 *
 * As a counterpart to the access to the source code and  rights to copy,
 * modify and redistribute granted by the license, users are provided only
 * with a limited warranty  and the software's author,  the holder of the
 * economic rights,  and the successive licensors  have only  limited
 * liability.
 *
 * In this respect, the user's attention is drawn to the risks associated
 * with loading,  using,  modifying and/or developing or reproducing the
 * software by the user in light of its specific status of free software,
 * that may mean  that it is complicated to manipulate,  and  that  also
 * therefore means  that it is reserved for developers  and  experienced
 * professionals having in-depth computer knowledge. Users are therefore
 * encouraged to load and test the software's suitability as regards their
 * requirements in conditions enabling the security of their systems and/or
 * data to be ensured and,  more generally, to use and operate it in the
 * same conditions as regards security.
 *
 * The fact that you are presently reading this means that you have had
 * knowledge of the CeCILL-C license and that you accept its terms.
 *
 * */

/**
 * @file Node.h
 * @brief Worker for one Node of the NCI grid
 * @author Emmanuel */

#ifndef _NODE_H_
#define _NODE_H_

// LOCAL
#include <Results.h>
//#include <ProgData.h>

/**
 * @brief Class used to handle every node data storage and processing ; implemented for multiprocessing implementation ; therefore, thread proof */
class Node
{
	
 private :
	
  // Variables relevant to the node itself

  //! The number of atom, both molecule combined
  int nbAtom;

  //! The number of atom in molecule A
  int nbAtomMolA;

  //! The local data' values
  LocalData * data;

  //! The program's data
  ProgData & pdata;
	
  // Variables relevant in the computing of density and, therefore, gradiant and hessian values

  //! Differences between node position and atom's position over x axis
  double * __restrict diffX;

  //! Differences between node position and atom's position over y axis
  double * __restrict diffY;

  //! Differences between node position and atom's position over z axis
  double * __restrict diffZ;

  //! Square of difference value "diffX" over the x axis
  double * __restrict squareX;

  //! Square of difference value "diffY" over the y axis
  double * __restrict squareY;

  //! Square of difference value "diffZ" over the z axis
  double * __restrict squareZ;

  //! Rho value processed over the x axis
  double * __restrict rho1;

  //! Rho value processed over the y axis
  double * __restrict rho2;

  //! Rho value processed over the z axis
  double * __restrict rho3;

  //! Distance value between the node position and the atom
  double * __restrict distance;
  
  //! Rho value processed during density processing
  double rho;

  //! Contribution value processed during density processing
  double contribution;

  // Determinant value
  // NOT USED
  //double determinant;

  //! Tells if the density matched the desired values
  bool shouldCompute;
		
  // Variables relevant in the computing of the gradient and hessian values

  //! Six hessian values
  double hess[6];

  //! Three lambda's values (eigenvalues of the ED hessian)
  double lambdas[3];

  //! Three eigenvectors
  double eigV[3][3]; // a static ARRAY

  //! Partial gradients added to process gradient values
  axis_t partialGradient;

  //! Sum multiplications of rhos' values and B values
  double sumBRho;

  //!  Sum multiplications of rhos' values and squares of B values
  double sumSquareBRho;

  //! Multiplicative inverse of the distance
  double multInvR;

  //! Square of the multiplicative inverse of the distance
  double squareMultInvR;

  // Lambda processing values : a (TO DOCUMENT)
  // NOT USED
  //double a;

  // Lambda processing values : b (TO DOCUMENT)
  // NOT USED
  //double b;

  // Lambda processing values : c (TO DOCUMENT)
  // NOT USED
  //double c;

  // Lambda processing values : p (TO DOCUMENT)
  // NOT USED
  //double p;

  // Lambda processing values : q (TO DOCUMENT)
  // NOT USED
  //double q;

  //! Optimization value 1
  // double opti;array over atoms
  double * __restrict opti;

  //! Optimization value 2
  double opti2;

  // Optimization value 3
  // NOT USED
  //double opti3;

  //! Temporary value
  double tmp;
		
  // Miscealenous constants

  //! Constant used for accessing x axis in three element's array
  static const int X = 0;

  //! Constant used for accessing y axis in three element's array
  static const int Y = 1;

  //! Constant used for accessing z axis in three element's array
  static const int Z = 2;
		
  //! TO DOCUMENT
  int lol2;

 public : 
	
  /**
   * @fn Node()
   * @brief Main constructor
   * @param nbAtomParam number of atom counting both molecule
   * @param nbAtomMolAParam the number of atom in the first molecule
   * @param pdataParam the program's data */
  Node(int nbAtomParam, int nbAtomMolAParam, ProgData &pdataParam);

  /**
   * @fn ~Node()
   * @brief Destructor */
  ~Node();
		
  /**
   * @fn void computeDensity(axis_t &posGrid, param_t & params) 
   * @brief Computes density
   * @param posGrid current position in the grid on all three axis
   * @param params the parameters initially read at the beginning of the program
   * @return the value of rho */
  void computeDensity(axis_t & __restrict posGrid, param_t & __restrict params);

  /**
   * @fn void computeGradHess()
   * @brief Computes gradient and hessian's values */
  void computeGradHess();
  /**
   * @fn void reComputeGrad()
   * @brief Computes gradient only, ig ED gradiet have already been computed before */
  void reComputeGrad();
		
  /**
   * @fn void sortLambdas()
   * @brief Sorting function used to sort lambdas' values */
  void sortLambdas();

  /**
   * @fn void computeSortLambdas()
   * @brief Function used to compute and sort lambdas' values */
  void computeSortLambdas();
	
  /**
   * @fn void process( axis_t & posGrid, int index, Results &results, param_t & params )
   * @brief Process all the information for an entire line of the grid
   * @param posGrid the current position in the grid
   * @param index index position in the grid
   * @param results objet containing the finale results
   * @param params parameters read at the beggining */
  void process( axis_t & posGrid, int index, Results &results, param_t & params );
		
  /**
   * @fn void getLambdaOfHessian()
   * @brief Diagonalize the ED hessian within promolecular mode  and compute eigenvalues and eigenvectors*/
  void diagonalizeHessian();

  /**
   * @fn void basisChange(double matrixHessianEigVec[3][3])
   * @brief basis change for every vector of the IGM approach : ED gradient, ED IGM gradient, ...
   * @param matrixHessianEigVec: input --> the matrix for the basis change */
  void basisChange(double matrixHessianEigVec[3][3]);


}; // end of class Node

#endif
