/*
 * 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 WFreader.cpp
 * @brief Implementation of the methods declared in WFNreader.h */

#ifndef _WFNREADER_CPP_
//! For managing C header inclusion for WFreader.cpp
#define _WFNREADER_CPP_

// LOCAL
#include "WFreader.h"

#define WFX_NUCLEI_NUMBER_SECTION            "Number of Nuclei"
#define WFX_ATOMIC_NUMBER_SECTION            "Atomic Numbers"
#define WFX_NUCLEI_COORDINATE_SECTION        "Nuclear Cartesian Coordinates"
#define WFX_NUCLEI_CHARGE_SECTION            "Nuclear Charges"
#define WFX_PRIMITIVE_NUMBER_SECTION         "Number of Primitives"
#define WFX_PRIMITIVE_CENTER_SECTION         "Primitive Centers"
#define WFX_PRIMITIVE_TYPE_SECTION           "Primitive Types"
#define WFX_PRIMITIVE_EXPONENT_SECTION       "Primitive Exponents"
#define WFX_MO_NUMBER_SECTION                "Number of Occupied Molecular Orbitals"
#define WFX_MO_OCCUPANCY_NUMBER_SECTION      "Molecular Orbital Occupation Numbers"
#define WFX_MO_ENERGY_SECTION                "Molecular Orbital Energies"
#define WFX_MO_PRIMITIVE_COEFFICIENT_SECTION "Molecular Orbital Primitive Coefficients"
#define WFX_NET_CHARGE_SECTION               "Net Charge"



//! a flag to know if a file is already loaded
bool fileLoaded=false;

//! Number of molecule orbitals
unsigned int nbOrbitals=0;

//! Number ot primitives
unsigned int nbPrimitives=0;

//! Number of nuclei
unsigned int nbNuclei=0;  

//! Array that defines the re-ordering of atoms between the user's list and ADF atom numbering
unsigned int* user2ADF_atomOrder=NULL; // input 0_based, output 1_based
//! Arrays that define the re-ordering of atoms between the ADF's list and user atom numbering
unsigned int* ADF2user_atomOrder=NULL; // input 0_based, output 1_based

//! Variable for saving center data
centerData* centers=NULL;

//! Variable for saving the primitive data 
unsigned int* primitiveCenters=NULL;

//! Variable for saving the primitive types
unsigned int* primitiveTypes=NULL;

// JC RKF ADD
//! Variable for saving the primitive kr (TO DOC)
// remember that a GTO expression is: r^kr x^kx y^ky z^kz exp(-alpha r)
// --> in addition to the triplet (kx,ky,kz), STO needs the value kr to be known
unsigned int* primitiveKRs=NULL;

//! Variable for saving the exponents
double* primitiveExponents=NULL;

//! Variable for saving the net charge in WFN(WFX)
int netCharge=NOCHARGE;

//! Vector of molecules
std::vector<moleculeOrbital> moleculeOrbitals;

//! WFX section names
std::vector<std::string> wfxSectionNames;

//! To save where begin the data of each section
std::vector<int> inputFileSectionPositions;

//! Total energy (only used in WFN reading)
double totalEnergy=0.0;

//! Virial value (only used in WFN reading)
double virial = 0.0;

const std::string WF_ATOM_NAMES[] =
  {
    "H","He","Li","Be","B","C","N","O","F","Ne","Na","Mg","Al","Si","P","S","Cl","Ar","K","Ca","Sc","Ti","V","Cr","Mn","Fe","Co","Ni","Cu","Zn","Ga","Ge","As","Se","Br","Kr","Rb","Sr","Y","Zr","Nb","Mo","Tc", "Ru","Rh","Pd","Ag","Cd","In","Sn","Sb","Te","I","Xe","Cs","Ba","La","Ce","Pr","Nd","Pm","Sm","Eu","Gd","Tb","Dy","Ho","Er","Tm","Yb","Lu","Hf","Ta","W","Re","Os","Ir","Pt","Au","Hg","Tl","Pb","Bi","Po","At","Rn","Fr","Ra","Ac","Th","Pa","U","Np","Pu","Am","Cm","Bk","Cf","Es","Fm","Md","No","Lr"
  };
  
// ################## wf_allocateMemory ###################
void
wf_allocateMemory()
{ 
  if(nbNuclei==0)
    {
      std::cerr << "[ERROR] Error: nbNuclei == 0, the corresponding memory can not be allocated" << std::endl;
      std::cerr << "The program will now exit." << std::endl;
      exit(EXIT_FAILURE);
    }
  
  
  centers = new centerData[nbNuclei];

  if(nbPrimitives==0)
    {
      std::cerr << "[ERROR] Error: nbPrimitives == 0, the corresponding memory can not be allocated" << std::endl;
      std::cerr << "The program will now exit." << std::endl;
      exit(EXIT_FAILURE);
    }
  
  primitiveCenters   = new unsigned int[nbPrimitives];
  
  primitiveTypes     = new unsigned int[nbPrimitives];

  primitiveExponents = new       double[nbPrimitives];

} // end of wf_allocateMemory()

// ################## wfn_read_GAUSSIAN_line ##############
void
wfn_read_GAUSSIAN_line(const std::string & line, const bool verbose)
{
  std::string readData;

  std::stringstream ss(line);

  ss >> readData; // avoid "GAUSSIAN"

  ss >> nbOrbitals;

  ss >> readData; // avoid "MOL "
  ss >> readData; // avoid "ORBITALS"

  ss >> nbPrimitives;

  ss >> readData; // avoid "PRIMITIVES"
  ss >> nbNuclei;



  // As nbNuclei is known, make the corresponding allocation
  wf_allocateMemory();
  
  if(verbose)
    {
      wf_printGlobalBounds();
    }
} // end of wfn_read_GAUSSIAN_line

/* modif Eric: 18/11/2018 */
// ################## wfn_read_center_data ################
void
wfn_read_center_data(std::ifstream & inputFile, const bool verbose)
{ // read coordinates in bohr from inputfile

  std::string line, readData;
  char* stringAfter;

  for(unsigned int i=0;i<nbNuclei;i++)
    {
      std::getline(inputFile, line);
      std::stringstream ss(line);
      std::string tmps;

// MODIF ERIC 27/07/2020
      // read atom name and remove any white character:
      //tmps = line.substr(2,2);
      ss >> tmps;
     // for(unsigned int ichar=0;ichar<tmps.length();ichar++) {
      //   if (tmps[ichar] == ' ') tmps.erase(ichar,1);
    //  }

      centers[i].element = new std::string(tmps);

   // std::cout << "\tElement     : " << *(centers[i].element) << std::endl;

      centers[i].value = i+1;

      centers[i].rank = i+1;


      // convert to a double: cartesian coordinates in bohr from wf
      centers[i].coordinates[0] = strtod(line.substr(24,12).c_str(), &stringAfter);
      centers[i].coordinates[1] = strtod(line.substr(36,12).c_str(), &stringAfter);
      centers[i].coordinates[2] = strtod(line.substr(48,12).c_str(), &stringAfter);

      //centers[i].coordinates[0] = stod(line.substr(24,12));
      //centers[i].coordinates[1] = stod(line.substr(36,12));
      //centers[i].coordinates[2] = stod(line.substr(48,12));


      //charge
      // convert it to a double
      centers[i].charge = strtod(line.substr(70,5).c_str(), &stringAfter);
      //centers[i].charge = stod(line.substr(70,5));

    }

  if(verbose)
    {
      wf_printCenterData();
    }
} // end of wfn_read_center_data

/* modif Eric: 18/11/2018 */
// ################## wfn_read_primitive_centers ##########
void
wfn_read_primitive_centers(std::ifstream & inputFile, const bool verbose)
{
  std::string line;

  int nbCent=0; /*number of center indexes on the current line*/

  unsigned int primitiveIndex=0;

  bool notEnough=true;
  std::getline(inputFile, line);
  while(notEnough) {
     nbCent = (line.length() - 20)/3; // number of centers on this line
     for(int i=0;i<nbCent;i++)
    {
      primitiveCenters[primitiveIndex] = atoi(line.substr(20+i*3,3).c_str());
      //primitiveCenters[primitiveIndex] = stoi(line.substr(20+i*3,3));
      primitiveIndex++;
    }

     notEnough = (primitiveIndex != nbPrimitives);
     if(notEnough)
        {
          std::getline(inputFile,line);
        }

  } // end of while( notEnough) 

  if(primitiveIndex!=nbPrimitives)
    {
      std::cout << "Error in primitive centers" << std::endl;
      std::cerr << std::endl;
      std::cerr << "[ERROR] Error: read primitive centers differ from nbPrimitives =  " << nbPrimitives  << std::endl;
      std::cerr << "The program will now exit." << std::endl;
      exit(EXIT_FAILURE);
    }

  if(verbose)
    {
      wf_printPrimitiveCenters();
    }

} // end of wfn_read_primitive_centers

/* modif Eric: 18/11/2018 */
// ################## wfn_read_primitive_types ############
void
wfn_read_primitive_types(std::ifstream & inputFile, const bool verbose)
{

  std::string line;

  int nbCent=0; /*number of orbital types on the current line*/

  unsigned int typeIndex=0;

  bool notEnough=true;
  std::getline(inputFile, line);
  while(notEnough) {
     nbCent = (line.length() - 20)/3; // number of centers on this line
     for(int i=0;i<nbCent;i++)
    {
      primitiveTypes[typeIndex] = atoi(line.substr(20+i*3,3).c_str());
//    primitiveTypes[typeIndex] = stoi(line.substr(20+i*3,3));

      typeIndex++;
    }

     notEnough = (typeIndex != nbPrimitives);
     if(notEnough)
        {
          std::getline(inputFile,line);
        }

  } // end of while( notEnough) 

     if(typeIndex!=nbPrimitives)
    {
      std::cout << "Error in primitive centers" << std::endl;
    }


  if(verbose)
    {
      wf_printPrimitiveTypes();
    }

} // end of wfn_read_primitive_types


// ################## wfn_read_primitive_exponents ########
void
wfn_read_primitive_exponents(std::ifstream & inputFile, const bool verbose)
{
  std::string line;

  std::getline(inputFile, line);

  unsigned int exponentIndex=0;

  std::string toCompare("EXPONENTS");

  bool notEnough=true;
  
  while( notEnough && (line.compare(0, toCompare.length(), toCompare) == 0) )
    {
      wfn_fromFortranRealToCppReal(line);
      std::stringstream ss(line.substr(toCompare.length()));
      while (ss.good())
	{
	  ss >> primitiveExponents[exponentIndex];
	  exponentIndex++;
	}

      notEnough = (exponentIndex != nbPrimitives);

      if(notEnough)
	{
	  std::getline(inputFile,line);
	}
    }

  if(exponentIndex!=nbPrimitives)
    {
      std::cout << "Error in primitive exponents readings" << std::endl;
    }

  if(verbose)
    {
      wf_printPrimitiveExponents();
    }
} // end of wfn_read_primitive_exponents

// ################## wfn_read_molecule_orbitals ##########
void
wfn_read_molecule_orbitals(std::ifstream & inputFile, const bool verbose)
{
  std::string line;
  std::string readData;

  std::getline(inputFile, line);

  unsigned int nbOrbitalsRead=0;

  std::string toCompare("MO");

      // MODIF ERIC 27/07/2020
// ====================     modif eric =====================================================
 // while( nbOrbitalsRead!=nbOrbitals && (line.compare(0, toCompare.length(), toCompare) == 0) )
    while( nbOrbitalsRead!=nbOrbitals )
    {
      moleculeOrbital bufferMoleculeOrbital;
      std::stringstream ss(line);

      // detect MO pattern
      readData = removeSpaces(line);
      // 'MO' must be the two first letters of the line
      if ((readData.substr(0,2)).compare("MO")!=0) 
         {
           std::cerr << std::endl;
           std::cerr << std::endl;
           std::cerr << "[ERROR] Failed to find MO keyword upon reading MO details in WFN" << std::endl;
           std::cerr << "[ERROR] in routine wfn_read_molecule_orbitals." << std::endl;
           std::cerr << "[ERROR] Line is : " << line << std::endl;
           std::cerr << "[ERROR] The program will now exit." << std::endl;
           exit(EXIT_FAILURE);
         };

      // removing  the 'MO' pattern from the current line and extracting the MO index
      readData = line.substr(2,line.length());

      // read MO index (must come just after 'MO' pattern)
      ss.str(readData);
      ss >> bufferMoleculeOrbital.rank;
     
      // skip until meeting "OCC"
      ss >> readData; 
      while (readData.compare("OCC")!=0) {
        ss >> readData; 
      }
      // set to zero data2 (not used)
      bufferMoleculeOrbital.data2 = 0.0;

     // skip NO and =
     ss >> readData;
     ss >> readData;

     // read ocupation number
     // ss >> bufferMoleculeOrbital.data2;
     // ss >> readData; // reading OCC, not used
     // ss >> readData; // reading NO, not used
     // ss >> readData; // reading =, not used
     ss >> bufferMoleculeOrbital.occupancy;

     // concat the remaining ss stream and remove spaces
     // to be able to read both gaussian and ADF wfn MO energies
     readData = removeSpaces(ss.str());
     size_t posEnergy = readData.find("ENERGY=");
     if ( posEnergy != std::string::npos) 
      { // extract the number found after the pattern ENERGY=
        readData = readData.substr(posEnergy+7, readData.length()-(posEnergy+7));
        if (isDouble(readData)) 
         {
           bufferMoleculeOrbital.orbitalEnergy = toDouble(readData);
         } // end of if (isDouble(readData)

        else 
        {
           std::cerr << std::endl;
           std::cerr << "[WARNING] Failed to convert MO Energy read from WFN ..." << std::endl;
           std::cerr << "[WARNING] in routine wfn_read_molecule_orbitals." << std::endl;
           std::cerr << "[WARNING] Line is : " << line << std::endl;
           std::cerr << "[WARNING] A value of 0.0 is given to the MO energy" << std::endl;
        }
     } // end of if ( posEnergy != std::string::npos)
     else
     {
        std::cerr << std::endl;
        std::cerr << "[WARNING] Failed to find Energy= pattern from WFN ..." << std::endl;
        std::cerr << "[WARNING] Line is : " << line << std::endl;
        std::cerr << "[WARNING] in routine wfn_read_molecule_orbitals" << std::endl;
        std::cerr << "[WARNING] A value of 0.0 is given to the MO energy" << std::endl;
     }
   

     // ss >> readData; // reading ORB., not used
     // ss >> readData; // reading ENERGY, not used
     // ss >> readData; // reading =, not used
     // ss >> bufferMoleculeOrbital.orbitalEnergy;


     
      // read the MO coefficients now       
      unsigned int nbCoefficients=0;
      bufferMoleculeOrbital.coefficients=new double[nbPrimitives];
      while(nbCoefficients!=nbPrimitives)
	{
	  std::getline(inputFile,line);
	  wfn_fromFortranRealToCppReal(line);
	  std::stringstream ss(line);
	  while (ss.good())
	    {
	      ss >> bufferMoleculeOrbital.coefficients[nbCoefficients];
	      nbCoefficients++;
	    }
	  
	}

      moleculeOrbitals.push_back(bufferMoleculeOrbital);
      nbOrbitalsRead++;

      if( nbOrbitalsRead != nbOrbitals )
	{
	  std::getline(inputFile,line);
	}

    } // end of   while( nbOrbitalsRead!=nbOrbitals &&


      if( nbOrbitalsRead != nbOrbitals )
        {
           std::cerr << std::endl;
           std::cerr << "[ERROR] Error upon reading the MO coefficients in WFN" << std::endl;
           std::cerr << "[ERROR] in routine wfn_read_molecule_orbitals." << std::endl;
           std::cerr << "[ERROR] MO read / total MO  = " <<  nbOrbitalsRead << " / " << nbOrbitals << std::endl;
           std::cerr << "[ERROR] Check WFN file format." << std::endl;
           std::cerr << "[ERROR] The program will now exit." << std::endl;
           exit(EXIT_FAILURE);
        }



// ==================== end modif eric =====================================================

  if(verbose)
    {
      wf_printMO();
    }
} // end of wfn_read_molecule_orbitals


// ################## wfn_read_total_energy_and_virial ####
void
wfn_read_total_energy_and_virial(std::ifstream & inputFile, const bool verbose)
{
  std::string line, readData;
  std::getline(inputFile,line);

  std::string toCompare(" TOTAL ENERGY =");
  
  if(line.compare(0, toCompare.length(), toCompare) == 0)
    {
      std::stringstream ss(line.substr(toCompare.length()));
      ss >> totalEnergy;
      ss >> readData; // avoid THE
      ss >> readData; // avoid VIRIAL(-V/T)=
      ss >> virial;
    }

  if(verbose)
    {
      wfn_printTotalEnergyAndVirial();
    }
} // end of wfn_read_total_energy_and_virial

// ################## wfn_load_file #######################
void
wfn_load_file(std::ifstream & inputFile, const bool verbose)
{
  if(verbose)
    {
      std::cout << std::endl
		<< "WFN loading" << std::endl;
    }

  std::string line;

//  std::string toCompare("GAUSSIAN");
    std::string toCompare("PRIMITIVES");
  do
    {
      std::getline(inputFile,line);
    }
// MODIF ERIC: 07/2020 : we are not necessarily seeking for the GAUSSIAN keyword,
// but instead the PRIMITIVES Keyword:
//  while( (inputFile.good()) && ( line.compare(0, toCompare.length(), toCompare ) != 0) );
    while( (inputFile.good()) && ( line.find(toCompare) == std::string::npos) );

  if( ! inputFile.good() )
    {
// MODIF ERIC: 07/2020
//      std::cerr << "The file has a strange format, GAUSSIAN line is missing ..." << std::endl;
        std::cerr << std::endl;
        std::cerr << "The wfn file has a strange format, PRIMITIVES keyword not found ..." << std::endl;
        std::cerr << "[ERROR] Could not read file WFN in routine wfn_load_file" << std::endl
                  << "[ERROR] The program will now exit." << std::endl;
        exit(EXIT_FAILURE);

//      return;
    }
  
  wfn_read_GAUSSIAN_line(line,verbose);

  wfn_read_center_data(inputFile,verbose); // in bohr !

  wfn_read_primitive_centers(inputFile,verbose);

  wfn_read_primitive_types(inputFile,verbose);

  wfn_read_primitive_exponents(inputFile,verbose);
  
  wfn_read_molecule_orbitals(inputFile, verbose);

  std::getline(inputFile, line);

  toCompare=std::string("END DATA");
  if(line.compare(0, toCompare.length(), toCompare) != 0)
    {
      std::cout << "Error at the end of the file, END DATA not found after molecule information" << std::endl;
      return;
    }

  wfn_read_total_energy_and_virial(inputFile,verbose);

  // avoid the end of the file
  while( inputFile.good() )
    {
      std::getline(inputFile,line);
      //std::cout << line << std::endl;
    }

} // end of wfn_load_file ..........................................................................



/* ==================  QM treatment: parsing WFN input FILE =========================================*/
void wf_load_file(const std::string & fileName, const bool verbose)
{
  std::ifstream inputFile;

  if(fileLoaded)
    {
      wf_cleaning(verbose);
    }

  //std::cout << fileName << std::endl;

  std::string wfn(".wfn");
  std::string wfx(".wfx");
  std::string rkf(".rkf");

  size_t index=fileName.rfind(".");

  if(index==std::string::npos)
    {
      std::cout << "There is a problem with the file name, no extension founded ..." << std::endl;
      return;
    }

  std::string extension=fileName.substr(index);

  inputFile.open(fileName.c_str());

  if(! inputFile.is_open())
    {
      std::cout << "The file " << fileName << " does not exist or can not be opened" << std::endl;
      return;
    }

  if(! inputFile.good() )
    {
      std::cout << "The file " << fileName << " is opened but there is a problem with it ..." << std::endl;
      return;
    }

  if(verbose)
    {
      std::cout << std::endl
		<< "Loading " << fileName << std::endl;
    }
 
  // =============  W  F  N  ===================================== 
  if(extension.compare(wfn)==0)
    {
      wfn_load_file(inputFile, verbose);
    }
  else
  // =============  W  F  X  =====================================
    {
      if(extension.compare(wfx)==0)
	{
	  // To prepare the vector of the section names and other stuff ...
	  wfx_init();

	  // To check the global file and where the data are stored in the file
	  // (check present xml tags, ...)
	  wfx_load_file(inputFile, verbose);

	  // To really load the data
	  wfx_read_data(inputFile, verbose);
	}
      else
	
  // =============  R  K  F  =====================================
       {
	  if(extension.compare(rkf)==0)
	    {
	      //std::cout << "RKF file" << std::endl;
              // load the content of the binary adf.rkf 
              // generated by the ADF program (using STO instead of GTO)
	      load_rkf_file(fileName); 
	    }
	  else   
	    {
	      std::cout << "There is a problem with the file name, it is not a wfn nor a wfx file ..." << std::endl;
	    }
	}
    }

  fileLoaded=true;
  inputFile.close();
  
} // end of wf_load_file


// ################## wfn_fromFortranRealToCppReal ########
void
wfn_fromFortranRealToCppReal(std::string & line)
{
  size_t returnValue;
  do
    {
      returnValue=line.find("D");
      if(returnValue != std::string::npos)
	{
	  line.replace(returnValue,1,"E");
	}
    }
  while(returnValue != std::string::npos);
} // end of wfn_fromFortranRealToCppReal




// ################## wf_cleaning #########################
void
wf_cleaning(const bool verbose)
 {
   if(verbose)
     {
       std::cout << "Cleaning ";
       std::cout.flush();
     }

   if( user2ADF_atomOrder != NULL)
     {
       delete[] user2ADF_atomOrder;
     }

   if( ADF2user_atomOrder != NULL)
     {
       delete[] ADF2user_atomOrder;
     }


   if(verbose)
     {
       std::cout << "Cleaning ";
       std::cout.flush();
     }
   
   if( centers != NULL)
     {
       for(unsigned int i=0;i<nbNuclei;i++)
	 {
	   delete centers[i].element;
	   //delete[] centers[i].datas;
	 }
       delete[] centers;

       centers=NULL;
     }

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }

   if( primitiveCenters != NULL)
     {
       delete[] primitiveCenters;

       primitiveCenters=NULL;
     }

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }
   
   
   if( primitiveTypes != NULL )
     {
       delete[] primitiveTypes;

       primitiveTypes=NULL;
     }

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }

   if( primitiveKRs != NULL )
     {
       delete[] primitiveKRs;

       primitiveKRs=NULL;
     }

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }

   
   
   if( primitiveExponents != NULL)
     {
       delete[] primitiveExponents;

       primitiveExponents=NULL;
     }

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }
   
   
   if( moleculeOrbitals.size() != 0)
     {
       for(std::vector<moleculeOrbital>::const_iterator it=moleculeOrbitals.begin();it!=moleculeOrbitals.end();it++)
	 {
	   delete[] it->coefficients;
	 }

       moleculeOrbitals.clear();
     }

   if(verbose)
     {
       std::cout << ".";;
       std::cout.flush();
     }

   wfxSectionNames.clear();
   inputFileSectionPositions.clear();

   if(verbose)
     {
       std::cout << ".";
       std::cout.flush();
     }
   
   
   fileLoaded=false;

   nbOrbitals=0;

   nbPrimitives=0;

   nbNuclei=0;

   fileLoaded=false;
   
   if(verbose)
     {
       std::cout << " ended." << std::endl;
     }
 } // end of wf_cleaning


// ################## wf_file_already_loaded ##############
bool
wf_file_already_loaded()
{
  return fileLoaded;
} // end of wf_file_already_loaded

// ################## wf_user2ADF_atomOrder ###############
unsigned int*
wf_user2ADF_atomOrder()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: user2ADF_atomOrder required but no file already loaded" << std::endl;
    }
  return user2ADF_atomOrder;
} // end of wf_user2ADF_atomOrder

// ################## wf_ADF2user_atomOrder ###############
unsigned int*
wf_ADF2user_atomOrder()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: ADF2user_atomOrder required but no file already loaded" << std::endl;
    }
  return ADF2user_atomOrder;
} // end of wf_ADF2user_atomOrder




// ################## wf_number_of_orbitals ###############
unsigned int
wf_number_of_orbitals()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: number of orbitals required but no file already loaded" << std::endl;
    }
  return nbOrbitals;
} // end of wf_number_of_orbitals


// ################## wf_number_of_primitives #############
unsigned int
wf_number_of_primitives()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: number of primitives required but no file already loaded" << std::endl;
    }
  return nbPrimitives;
} // end of wf_number_of_primitives

// ################## wf_number_of_nuclei #################
unsigned int
wf_number_of_nuclei()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: number of nuclei required but no file already loaded" << std::endl;
    }
  return nbNuclei;
} // end of wf_number_of_nuclei


// ################## wf_center_data ######################
centerData*
wf_center_data()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: center data required but no file already loaded" << std::endl;
    }
  return centers;
} // end of wf_center_data


// ################## wf_primitive_centers ################
unsigned int*
wf_primitive_centers()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: primitive centers required but no file already loaded" << std::endl;
    }
  return primitiveCenters;
} // end of wf_primitive_center


// ################## wf_primitive_types ##################
unsigned int*
wf_primitive_types()
{
  if(! fileLoaded )
    {
      std::cout << "WARNING: primitive types required but no file already loaded" << std::endl;
    }
  return primitiveTypes;
} // end of wf_primitive_types

// ################## wf_primitive_exponents ##############
double*
wf_primitive_exponents()
{
   if(! fileLoaded )
    {
      std::cout << "WARNING: primitive exponents required but no file already loaded" << std::endl;
    }
  return primitiveExponents;
} // end of wf_primitive_exponents

// ################## wf_netCharge ########################
int wf_netCharge()
{
   if(! fileLoaded )
    {
      std::cout << "WARNING: Net Charge required but no file already loaded" << std::endl;
    }
  return netCharge;           
} // end of wf_netCharge

// ################## wf_setNetCharge ########################
void wf_setNetCharge(int value)
{ // since the NetCharge is not available in the WFN input file
  // it has to be supplied before reading the WFN ... ! upon reading
  // the param.igm input file (CHARGE keywords)
   if (value != NOCHARGE) 
     {
        netCharge = value; 
     }     
   else
     {
      std::cerr << std::endl;
      std::cerr << "[ERROR] Net Charge must differ from " << NOCHARGE << std::endl;
      std::cerr << "[ERROR] in wf_setNetCharge" << std::endl;
      std::cerr << "The program will now exit." << std::endl;
      exit(EXIT_FAILURE);
     }

} // end of wf_setNetCharge


// ################## wf_molecular_orbitals ###############
std::vector<moleculeOrbital>
wf_molecular_orbitals()
{
    if(! fileLoaded )
    {
      std::cout << "WARNING: molecular orbitals required but no file already loaded" << std::endl;
    }
  return moleculeOrbitals;
} // end of wf_molecular_orbitals


// ################## wf_molecular_orbitals_sort ##########
bool 
wf_molecular_orbitals_sort()
{
// Reorganize MOs in ascending order of energy
    bool changed = false;
    for( unsigned int imo=0 ; imo< moleculeOrbitals.size()-1 ; ++imo)
      {
        for( unsigned int jmo=imo+1 ; jmo< moleculeOrbitals.size() ; ++jmo)
          {
           if (moleculeOrbitals[jmo].orbitalEnergy < moleculeOrbitals[imo].orbitalEnergy)
               { // exchange them
                 std::swap(moleculeOrbitals[imo], moleculeOrbitals[jmo]);
                 changed = true; 
               } // end of if (molecularOrbitals[jmo].orbitalEnergy < molecularOrbitals[imo].orbitalEnergy)
          } // end of loop over jmo
      } // end of loop over imo   
    return changed;
} // end of routine wf_molecular_orbitals_sort()


// ################## wfx_load_file #######################
void
wfx_load_file(std::ifstream & inputFile, const bool verbose)
{
  if(verbose)
    {
      std::cout << std::endl << "WFX loading" << std::endl << std::endl;
    }

  // To test if all the required sections exist
  // Initialize to false each section
  std::vector<bool> availableSections;
  for(unsigned int i(0);i<wfxSectionNames.size();++i)
    {
      availableSections.push_back(false);
    }

  std::string line;

  // For checking begin/end of each section
  std::vector<std::string> currentSections;

// now, we are going to build inputFileSectionPositions[index]
// an array storing the CHARACTER starting position 
// of each section tag in the WFX file
  do
    {
      std::getline(inputFile,line);

      // If the line is empty or not beginning with '<'
      // next line ...
      if( line.length()==0 || line[0] != '<')
	{
	  continue;
	}

      // finding index of the end of the section name
      size_t index=line.rfind(">");

      // If not '>' ==> ERROR
      if(index==std::string::npos)
	{
	  std::cerr << "[ERROR] Error: There is a problem with the current line, no final \">\" for the section ... " << std::endl;
	  std::cerr << "               The corresponding line is : \"" << line << "\"" << std::endl;
	  std::cerr << "The program will now exit." << std::endl;
	  exit(EXIT_FAILURE);
	}

      // The section Name
      std::string sectionName=line.substr(1,index-1);


      // The line finishes a section : it is a finishing tag
      if(sectionName[0]=='/')
	{
	  // Only for checking it is a correct ending section
	  sectionName=sectionName.substr(1);

	  // The current section is the last saved in currentSections vector
	  std::string currentSection=currentSections.back();
	  if( sectionName.compare(currentSection) != 0 )
	    {
	      std::cerr << "[ERROR] Error: There is a problem with the current section end" << std::endl;
	      std::cerr << "             : the beginning is \"" << currentSection << "\" and the end is \"" << sectionName << "\"" <<  std::endl;
	      std::cerr << "The program will now exit." << std::endl;
	      exit(EXIT_FAILURE);
	    }

	  // For debugging
	  /*if(verbose)
	    {
	      for(unsigned int i(1);i<currentSections.size();++i)
		{
		  std::cout << "\t";
		}
	      std::cout << "Exiting from " << sectionName << std::endl << std::endl;
	      }*/

	  // if no error, the section is closed can be forgotten
	  currentSections.pop_back();
	      
	}
      else  // it is a starting TAG
	{
	  currentSections.push_back(sectionName);

	  // For debugging
	  /*if(verbose)
	    {
	      for(unsigned int i(1);i<currentSections.size();++i)
		{
		  std::cout << "\t";
		}
	      std::cout << "Entering in  " << sectionName << std::endl;
	      }*/
	      

          // search the name of the current xml TAG in the IGMPLot list of XML fields
	  std::vector<std::string>::iterator it=std::find(wfxSectionNames.begin(), wfxSectionNames.end(), sectionName);
	     

          // if this section belongs to the IGMPlot section list
          // ==> we store its position in "inputFileSectionPositions"
	  if(it != wfxSectionNames.end())
	    {
              // convert iterator in integer index 
              // index <--> position of the current xml tag in the IGMPlot tag list
	      unsigned int index = std::distance(wfxSectionNames.begin(), it);

              // check it was not read before !!
	      if(availableSections[index])
		{
		  std::cerr << "[ERROR] Error: The section " << sectionName << " has been already founded" << std::endl;
		  std::cerr << "The program will now exit." << std::endl;
		  exit(EXIT_FAILURE);
		}
	      
	      // The section is considered as founded
	      availableSections[index]=true;

	      // The begining of the section data is here (tellg)
	      // store the current CHARACTER (!) position in the inputfile
	      // and associates it with the current KEYWORD ! (a given section)
	      inputFileSectionPositions[index]=inputFile.tellg();
	    }
	}
    }
  // At the end, something will be not good :-)
  while( inputFile.good() );

  // If any value in availableSections is not true, there is a problem.
  // since no IGMPlot xml section has been reacin the WFX input file ...
  std::vector<bool>::iterator it=std::find(availableSections.begin(), availableSections.end(), false);
  if(it!=availableSections.end())
    {
      unsigned int index = std::distance(availableSections.begin(), it);
      std::cout << "[ERROR] Error: One or more sections are missing in the WFX file ... For instance the section " << wfxSectionNames[index] << std::endl; 
      std::cerr << "The program will now exit." << std::endl;
       exit(EXIT_FAILURE);
    }

} // end of wfx_load_file


// ################## wfx_init ############################
void
wfx_init()
{
  wfxSectionNames.clear();
  
  //Can not be automatically constructed with old C++ Compilers
  wfxSectionNames.push_back(WFX_NUCLEI_NUMBER_SECTION);
  wfxSectionNames.push_back(WFX_ATOMIC_NUMBER_SECTION);
  wfxSectionNames.push_back(WFX_NUCLEI_COORDINATE_SECTION);
  wfxSectionNames.push_back(WFX_NUCLEI_CHARGE_SECTION);
  wfxSectionNames.push_back(WFX_PRIMITIVE_NUMBER_SECTION);
  wfxSectionNames.push_back(WFX_PRIMITIVE_CENTER_SECTION);
  wfxSectionNames.push_back(WFX_PRIMITIVE_TYPE_SECTION);
  wfxSectionNames.push_back(WFX_PRIMITIVE_EXPONENT_SECTION);
  wfxSectionNames.push_back(WFX_MO_NUMBER_SECTION);
  wfxSectionNames.push_back(WFX_MO_OCCUPANCY_NUMBER_SECTION);
  wfxSectionNames.push_back(WFX_MO_ENERGY_SECTION);
  wfxSectionNames.push_back(WFX_MO_PRIMITIVE_COEFFICIENT_SECTION);
  wfxSectionNames.push_back(WFX_NET_CHARGE_SECTION);


  inputFileSectionPositions.clear();
  
  for(unsigned int i(0);i<wfxSectionNames.size();++i)
    {
      inputFileSectionPositions.push_back(-1);
    }

} // end of wfx_init

// ################## wfx_read_data #######################
// once the xml tags have been read before (wfx_load_file)
// we really read now the data present within each WFX tag => requires to re-read the whole input wfx file
void
wfx_read_data(std::ifstream & inputFile, const bool verbose)
{
  // Reading WFX information can begin after a previous first passage (wfx_load_file)
  // already achieved to detect present tags in the xml file
  
  // Forgot the current state of the inputfile (EOF)
  inputFile.clear();
  
  unsigned int index;
  
  // Reading number of molecular orbital
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_MO_NUMBER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  inputFile >> nbOrbitals;
  
  // Reading number of primitives
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_PRIMITIVE_NUMBER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  inputFile >> nbPrimitives;

  // Reading the net charge       
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_NET_CHARGE_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  inputFile >> netCharge;
  

  
  // Reading number of nuclei
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_NUCLEI_NUMBER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  inputFile >> nbNuclei;
  
  wf_allocateMemory();

  // For debugging
  /*if(verbose)
    {
      wf_printGlobalBounds();
      }*/
    
  // Reading atomic numbers
  unsigned int *atomic_numbers=new unsigned int[nbNuclei];
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_ATOMIC_NUMBER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<unsigned int>(inputFile, atomic_numbers, nbNuclei);

  // For debugging
  /*if(verbose)
    {
      std::cout << "Atomic numbers" << std::endl;
      for(unsigned int i=0;i<nbNuclei;++i)
	{
	  std::cout << "\t" << atomic_numbers[i] << std::endl;
	}
      std::cout << std::endl;
      
      }*/

  // Reading nuclear cartesian coordinates (normally, given in Bohr in a wfn/WFX input file)
  double *nuclei_coordinates=new double[nbNuclei*3];
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_NUCLEI_COORDINATE_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<double>(inputFile, nuclei_coordinates, nbNuclei*3); // nuclei_coordinates normally read in bohr from WFX/WFN

  // For debugging
  /*if(verbose)
    {
      std::cout << "Coordinates of nuclei";
      for(unsigned int i=0;i<nbNuclei*3;++i)
	{
	  if(i%3==0)
	    {
	      std::cout << std::endl;
	    }

	  std::cout << "\t" << std::scientific << std::setprecision(12) << nuclei_coordinates[i] << " ";
	}
      std::cout << std::endl << std::endl;
      }*/

  // Reading charge of nuclei
  double *nuclei_charges=new double[nbNuclei];
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_NUCLEI_CHARGE_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<double>(inputFile, nuclei_charges, nbNuclei);

  // For debbuging
  /*if(verbose)
    {
      std::cout << "Charges of nuclei" << std::endl;
      for(unsigned int i=0;i<nbNuclei;++i)
	{
	  std::cout << "\t" << std::scientific << std::setprecision(12) << nuclei_charges[i] << std::endl;
	}
      std::cout << std::endl;
      }*/

  // Reading primitive centers
  // primitiveCenters already allocated
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(), WFX_PRIMITIVE_CENTER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<unsigned int>(inputFile, primitiveCenters, nbPrimitives);

  // For debugging
  /*if(verbose)
    {
      wf_printPrimitiveCenters();
      }*/

  // Reading primitive types
  // primitiveTypes already allocated
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(), WFX_PRIMITIVE_TYPE_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<unsigned int>(inputFile, primitiveTypes, nbPrimitives);

  // For debugging
  /*if(verbose)
    {
      wf_printPrimitiveTypes();
      }*/
 
  // Reading primitive exponents
  // primitiveExponents already allocated
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(), WFX_PRIMITIVE_EXPONENT_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<double>(inputFile, primitiveExponents, nbPrimitives);

  // For debugging
  /*if(verbose)
    {
      wf_printPrimitiveExponents();
      }*/


  // Reading occupation of MO
  double *mo_occupations=new double[nbOrbitals];
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_MO_OCCUPANCY_NUMBER_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<double>(inputFile, mo_occupations, nbOrbitals);

  // For debugging
  /*if(verbose)
    {
      std::cout << "Occupation numbers of molecular orbitals" << std::endl;
      for(unsigned int i=0;i<nbOrbitals;++i)
	{
	  std::cout << "\t" << std::scientific << std::setprecision(12) << mo_occupations[i] << std::endl;
	}
      std::cout << std::endl;
      }*/

  // Reading energy of MO
  double *mo_energies=new double[nbOrbitals];
  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_MO_ENERGY_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);
  loadInputFileData<double>(inputFile, mo_energies, nbOrbitals);

  // For debugging
  /*if(verbose)
    {
      std::cout << "Energy of molecular orbitals" << std::endl;
      for(unsigned int i=0;i<nbOrbitals;++i)
	{
	  std::cout << "\t" << std::scientific << std::setprecision(12) << mo_energies[i] << std::endl;
	}
      std::cout << std::endl;
      }*/

  // Reading primitive coefficient of each MO
  double **mo_primitive_coefficients=new double*[nbOrbitals];
  for(unsigned int i(0);i<nbOrbitals;++i)
    {
      mo_primitive_coefficients[i]=new double[nbPrimitives];
    }

  index=std::distance(wfxSectionNames.begin(), std::find(wfxSectionNames.begin(), wfxSectionNames.end(),WFX_MO_PRIMITIVE_COEFFICIENT_SECTION));
  inputFile.seekg(inputFileSectionPositions[index]);

  std::string line;
  unsigned int currentMO;
  for(unsigned int i(0);i<nbOrbitals;++i)
    {
      //avoid line <MO Number>
      std::getline(inputFile, line);
      //std::cout << "1 : [" << line << "]" << std::endl;
      
      inputFile >> currentMO;

      // avoid end of the line after reading currentMO
      std::getline(inputFile, line);
      //std::cout << "2 : [" << line << "]" << std::endl;

      //std::cout << currentMO << " " << i+1 << std::endl;
      if( currentMO != i+1)
	{
	  std::cerr << "[ERROR] Error: reading primitive coefficient for molecular orbital " << i+1 << " but in the WFX file, it is the molecular orbital " << currentMO << "..." << std::endl;
	  std::cerr << "The program will now exit." << std::endl;
	  exit(EXIT_FAILURE);
	}

      //avoid line </MO Number>
      std::getline(inputFile, line);
      //std::cout << "3 : [" << line << "]" << std::endl;

      loadInputFileData<double>(inputFile, mo_primitive_coefficients[i], nbPrimitives);

      // avoid end of the last line of primitive coefficient reading
      std::getline(inputFile, line);
      //std::cout << "4 : [" << line << "]" << std::endl;
    }

  // For debugging
  /*if(verbose)
    {
      std::cout << "Primitive coefficients of molecular orbitals" << std::endl << std::endl;
      for(unsigned int i(0);i<nbOrbitals;++i)
 	{
	  std::cout << "\t Molecular Orbital " << i+1 << std::endl;

	  for(unsigned int j(0);j<nbPrimitives;++j)
	    {
	      if(j%4==0)
		{
		  std::cout << std::endl << "\t\t";
		}
	      std::cout << std::scientific << std::setprecision(12) << mo_primitive_coefficients[i][j] << " ";
	    }
	  std::cout << std::endl << std::endl;
	}
      std::cout << std::endl;
      }*/

  for(unsigned int i(0);i<nbOrbitals;++i)
    {
      moleculeOrbital bufferMoleculeOrbital;

      bufferMoleculeOrbital.rank=i+1;

      // Not used in WFX
      bufferMoleculeOrbital.data2=0.0;

      bufferMoleculeOrbital.occupancy=mo_occupations[i];
      bufferMoleculeOrbital.orbitalEnergy=mo_energies[i];
            
      bufferMoleculeOrbital.coefficients=new double[nbPrimitives];
      for(unsigned int j(0);j<nbPrimitives;++j)
	{
	  bufferMoleculeOrbital.coefficients[j]=mo_primitive_coefficients[i][j];
	}

      moleculeOrbitals.push_back(bufferMoleculeOrbital);
    }

  // For debugging
  /*if(verbose)
    {
      wf_printMO();
      }*/

  for(unsigned int i(0);i<nbNuclei;++i)
    {
      centers[i].element = new std::string(WF_ATOM_NAMES[atomic_numbers[i]-1]);

      centers[i].value = i+1;

      centers[i].rank = i+1;

      centers[i].charge = nuclei_charges[i];

      centers[i].coordinates[0] = nuclei_coordinates[i*3 + 0]; // coordinates normally in bohr from WFX / WFN
      centers[i].coordinates[1] = nuclei_coordinates[i*3 + 1];
      centers[i].coordinates[2] = nuclei_coordinates[i*3 + 2];
    }

  if(verbose)
    {
      wf_printGlobalBounds();
      wf_printCenterData();
      wf_printPrimitiveCenters();
      wf_printPrimitiveTypes();
      wf_printPrimitiveExponents();
      wf_printMO();
    }
  
  delete[] atomic_numbers;
  delete[] nuclei_coordinates;
  delete[] nuclei_charges;
  delete[] mo_occupations;
  delete[] mo_energies;

  for(unsigned int i(0);i<nbOrbitals;++i)
    {
      delete[] mo_primitive_coefficients[i];
    }
  delete[] mo_primitive_coefficients;
} // end of wfx_read_data

void
wf_printMO()
{
  if(moleculeOrbitals.size()==0)
    {
      return;
    }

  std::cout << std::endl;

  std::cout << "### MOLECULE ORBITALS #################################################################################"<< std::endl;

  for(std::vector<moleculeOrbital>::iterator it=moleculeOrbitals.begin();it!=moleculeOrbitals.end();++it)
    {
      std::cout << "\tMolecule orbital rank " << (*it).rank << std::endl;
      std::cout << "\t\tdata2 " << std::fixed << std::setprecision(1) << (*it).data2 << std::endl;
      std::cout << "\t\tOccupancy " << (*it).occupancy << std::endl;
      std::cout << "\t\tOrbital energy " << std::scientific << std::setprecision(12) << (*it).orbitalEnergy << std::endl;
      
      std::cout << "\t\tCoefficients";
      wf_printInformation((*it).coefficients, nbPrimitives, 4,3);
      std::cout << std::endl;
    }

  std::cout << "#######################################################################################################"<< std::endl;
} // end of wf_printMO

void
wf_printPrimitiveCenters()
{
  if( primitiveCenters==NULL || nbPrimitives==0)
    {
      return;
    }
  
  std::cout << std::endl;
  std::cout << "### PRIMITIVE CENTERS ###################################";
  wf_printInformation(primitiveCenters, nbPrimitives, 10,1,false);
  std::cout << "#########################################################"<< std::endl;
} // end of wf_printPrimitiveCenters

void
wf_printPrimitiveTypes()
{
  if( primitiveTypes==NULL || nbPrimitives==0)
    {
      return;
    }
  
  std::cout << std::endl;
  std::cout << "### PRIMITIVE TYPES #####################################";
  wf_printInformation(primitiveTypes, nbPrimitives, 10,1,false);
  std::cout << "#########################################################"<< std::endl;
}// end of wf_printPrimitiveTypes

void
wf_printPrimitiveExponents()
{
  if( primitiveExponents==NULL || nbPrimitives==0)
    {
      return;
    }
  
  std::cout << std::endl;
  std::cout << "### PRIMITIVE Exponents ###############################################################";
  wf_printInformation(primitiveExponents, nbPrimitives, 4);
  std::cout << "#######################################################################################"<< std::endl;
} // end of wf_printPrimitiveExponents

void
wf_printCenterData()
{
  if( centers==NULL || nbNuclei==0)
    {
      return;
    }
  
  std::cout << std::endl;
  std::cout << "### CENTER DATA ################################################################"<< std::endl;
  std::cout << std::scientific << std::setprecision(12);
  for(unsigned int i(0);i<nbNuclei;++i)
    {
      std::cout << "Center " << i+1 << std::endl;
      std::cout << "\tElement     : " << *(centers[i].element) << std::endl;
      std::cout << "\tValue       : " << centers[i].value << std::endl;
      std::cout << "\tRank        : " << centers[i].rank << std::endl;
      std::cout << "\tCoordinates : "
		<< centers[i].coordinates[0] << " "
		<< centers[i].coordinates[1] << " "
		<< centers[i].coordinates[2] << std::endl;
      std::cout << "\tCharge      : " << centers[i].charge << std::endl;
      std::cout << std::endl;
    }
  std::cout << "################################################################################"<< std::endl;
} // end of wf_printCenterData

void
wf_printGlobalBounds()
{
  std::cout << std::endl;
  std::cout << "### BOUNDS #######################" << std::endl;
  std::cout << "Number of orbitals   = "            << nbOrbitals << std::endl;
  std::cout << "Number of primitives = "            << nbPrimitives << std::endl;
  std::cout << "Number of nuclei     = "            << nbNuclei << std::endl;
  std::cout << "##################################" << std::endl;
} // end of wf_printGlobalBounds

void
wfn_printTotalEnergyAndVirial()
{
  std::cout << std::endl;
  std::cout << "### TOTAL ENERGY AND VIRIAL ############"<< std::endl;
  std::cout << std::fixed << std::setprecision(12);
  std::cout << "Total Energy = " << totalEnergy << std::endl;
  std::cout << std::setprecision(8);
  std::cout << "virial       = " << virial << std::endl;
  std::cout << "########################################"<< std::endl;
} // end of wfn_printTotalEnergyAndVirial

// Function to remove spaces 
std::string
removeSpaces(std::string str)
{

    std::stringstream ss;
    std::string temp;

    // Storing the whole string 
    // into string stream 
    ss << str;

    // Making the string empty 
    str = "";

    // Running loop till end of stream 
    while (!ss.eof()) {

        // Extracting word by word from stream 
        ss >> temp;

        // Concatenating in the string to be 
        // returned 
        str = str + temp;

        // clear the temporary variable
        temp="";
    }
    return str;
} // end of removeSpaces

// Function to  test if a string is a number (double)
bool isDouble(std::string text)
{
  std::istringstream iss (text);
  double number;
  iss >> number;
  if (iss.fail()) {
    // something wrong happened
    return false;
  }
  return true;
}  // end of isNumber


// Function to  convert a  string to a double
double toDouble(std::string text)
{
  std::istringstream iss (text);
  double number;
  iss >> number;
  if (iss.fail()) {
    // something wrong happened
    return 0.0;
  }
  return number;
}  // end of isNumber


void
load_rkf_file(const std::string & fileName) {

    KFFile kf;

    if (ADF_openKFFile(&kf, fileName.c_str()) < 0) {
      std::cerr << std::endl;
      std::cerr << "[ERROR] RKF File "<< fileName << "is not a valid RKF file" << std::endl;
      std::cerr << "[ERROR] in load_rkf_file" << std::endl;
      std::cerr << "The program will now exit." << std::endl;
      exit(EXIT_FAILURE);
    }

    rkf_load_nbNuclei(&kf);

    //printf("Nb of atoms      = %d\n", nbNuclei);

    rkf_load_data(&kf, fileName.c_str());
    
    ADF_closeKFFile (&kf);
  
} // end of load_rkf_file

void
rkf_load_nbNuclei(KFFile* kf) {
  
  std::string field = "Geometry%nr of atoms";
  
  int datasize      = ADF_getKFVariableLength(kf, field.c_str());
  int* rkf_nbNuclei = (int*) malloc (datasize*sizeof(int));
  if (ADF_getKFData(kf, field.c_str(), (void*) rkf_nbNuclei) < 0){
    std::cerr << std::endl;
    std::cerr << "[ERROR] Impossible to get the number of nuclei from rkf file" << std::endl;
    std::cerr << "[ERROR] in rkf_load_nbNuclei" << std::endl;
    std::cerr << "The program will now exit." << std::endl;
    exit(EXIT_FAILURE);
  }
  
  nbNuclei=*rkf_nbNuclei;
  
  free(rkf_nbNuclei);
} // end of rkf_load_nbNuclei

// .....................................................
// ..                R K F    R E A D I N G           ..
// .....................................................
void
rkf_load_data(KFFile* kf, const char* filename) {

    /* Declare/allocate necessary objects */
    int    datasize;

    const char *var0 = "General%nspin";
    int  *nspin;

    /* =========================================== 
       nspin = 1 for restricted 2 for unrestricted
       =========================================== */

    // Already read
    //const char *var3 = "Geometry%nr of atoms";
    //int  *nbNuclei;

    const char *var4 = "Geometry%ntyp";
    int  *ntyp;

    /* 118 atom type max in the periodic table and 2 letters max per atom + null character */
    char typelabel[118][3]; 
    const char *var5 = "Geometry%nuclab";
    char *nuclab=NULL;

    int iattype= -1; /* init */

    const char *var6 = "Geometry%nr of fragments";
    int  *nfrag;               

    const char *var7 = "Geometry%fragment and atomtype index";
    int  *TMPattype;

    int *attype;
    int iat;
    int atnum;

    const char *var8 = "Geometry%atomtype total charge";
    /* typecharge = charge for each type of atom
           charge = charge for each         atom */
    double  *typecharge, *charge;  

    const char *var9 = "Geometry%xyz";
    double  *coord;

    int icoord;
    
    const char *var25 = "ETS%qcore";
    double  *qcore;

    const char *var23 = "Core%ncos";
    int  *ncos;

    double nelecCOR;

    const char *var1b = "Basis%nbos";
    int  *nbos;

    const char *var2 = "A%npart";
    int  rkf_nbPrimitives;

    const char *var1 = "Symmetry%norb";

    int *rkf_primitiveCenters; /* to store the atomic center index for each primitive */

    double *rkf_primitiveExponents; /* to store the exponent value for each primitive */

    int *rkf_primitiveTypes; /*  to store the primitive type (type assignment) for each primitive */

    double *primitiveNorm; /*  to store the primitive normalization factor for each primitive */

    /* temporary array*/
    int *primTMPint;
    
    /*  Not needed by IGMPLOT: for display and just to check:*/
    int *primkx; 

    int *primky;

    int *primkz;

    /*  needed by IGMPLOT fr STO */
    int *primkr;

    double *primTMPdouble;

    char** label=NULL;
    
    const char *var10 = "Basis%nbptr";
    int  *nbptr;

    int iatType; 

    int  *kx, *ky, *kz, *kr;
    const char *var11 = "Basis%kx";
    const char *var12 = "Basis%ky";
    const char *var13 = "Basis%kz";
    const char *var14 = "Basis%kr";
    
    double **WFNcoord=NULL;

    int ifu;

    const char *var15 = "Geometry%nqptr";
    /* nqptr gives the number of atoms for type i: nqptr(i+1)-nqptr(i) */
    int  *nqptr;

    /* alf = the exponents for the functions */
    const char *var16 = "Basis%alf";
    double  *alf;

    const char *var17 = "Basis%bnorm";
    double  *bnorm;

    int iprim;

    /* npart = list of ordered primitives used in the MO expansions !!!        
       ==> means that we have to reorder every primitive array !! */
    const char *var18 = "A%npart";
    int  *npart;

    /* arrayx 2D nbMOs x rkf_nbPrimitives */
    double **molOrbitalCoefalpha=NULL;
    
    int imo;

    /* arrayx 2D nbMOs x rkf_nbPrimitives */
    double **molOrbitalCoefbeta=NULL; 

    /* there is always a set for alpha electrons (restricted or unrestricted calculation)*/
    const char *var19 = "A%Eigen-Bas_A";  
    double  *coeffADFalpha;
    double  *coeffADFbeta=NULL;

    int iadfcoef;
    
    const char *var24 = "General%electrons";
    double  *nelecVAL;

    
    const char *var34 = "Energy%SCF Bond Energy";
    double *energy;

    const char *var20 = "A%froc_A";
    double  *occAlphaVal;
    double  *occBetaVal=NULL;

    int irow;
    int minMO, maxMO;
    
    const char *var21 = "A%Eigen-Bas_B";  
    /*double  *coeffADFbeta; */

    /*int iadfcoef;*/

    const char *var22 = "A%froc_B";

    /*int irow;
      int minMO, maxMO;*/
    
    const char *var26 = "Core%ccor";
    double  *ccor;

    const char *var27 = "Core%nrcorb";
    int  *nrcorb;

    const char *var28 = "Core%nrcset";
    int  *nrcset;

    const char *var29 = "Geometry%atom order index";
    unsigned int *ADF_atomOrder; // input 0_based, output 1_based


    int nfrozCORE;    /* FROZEN CORE MOs */
    int COREWFNnprim; /* FROZEN CORE primitives */
    int iSTO_TYPE;   /* index over STO types [0:3] = s,p,d,f */

    double *frozCOREocc = NULL;
    
    const char    *var30 = "Core%alfcor";
    double  *alfcor;

    const char    *var31 = "Core%cornrm";
    double  *cornrm;

    const char    *var32 = "Core%nqcor";
    int     *nqcor;

    const char    *var33 = "Core%lqcor";
    int     *lqcor;

    /* to store the atomic center index for each primitive (core+valence) */
    int *COREWFNprimitiveCenters=NULL;

    /* to store the exponent value for each primitive (core + valence) */
    double *COREWFNprimitiveExponents=NULL;

    /* to store the primitive type (type assignment) for each primitive (core + valence) */
    int *COREWFNprimitiveTypes=NULL;

    /*  to store the primitive normalization factor for each primitive (core + valence) */
    double *COREWFNprimitiveNorm=NULL;

    /*  to store the kr parameters defining the STO with kx,ky and kz. */
    int *COREWFNprimkr=NULL;

    /* to store kx */
    int *COREWFNprimkx=NULL;

    /* to store ky */
    int *COREWFNprimky=NULL;

    /* to store kz */
    int *COREWFNprimkz=NULL;

    // JC NOT USED
    //int iSTOs;
    
    /* index in the range[0:ncset-1] = the current core STO for current atom type and current atom */
    int iCORESTO=-1;
    
    /* the nb of expansion STO already treated for previous atom TYPES */
    int previousSTOs;

    /* cursor on a given STO expansion */
    int iexpans=-1; 

    int COREnprim;

    /* nb of electron in a given core shell */
    double nbelec;
    
    /* current index of frozen core 'MOs' */
    int    ifrozCORE;
    
    /* cursor on frozen core MOs for a given shell */
    int    ifroz;
    
    /* the nb of ccor coefficients already ascribed to previous atom TYPES */
    int previousCCOR = 0;
    
    /* the nb of primitives already examined for previous atoms */
    int previousPRIM = 0;

    /* cursor running over ccor coefficients */
    int    iccor=-1;

    /* arrayx 2D nbCOREMO x rkf_nbPrimitives */
    double **COREmolOrbitalCoef;

    int WFNnprim;

    /* to store the atomic center index for each primitive (core+valence) */
    int *WFNprimitiveCenters=NULL;

    /* to store the exponent value for each primitive (core + valence) */
    double *WFNprimitiveExponents=NULL;

    /* to store the primitive type (type assignment) for each primitive (core + valence) */
    int *WFNprimitiveTypes=NULL;

    /* to store the primitive normalization factor for each primitive (core + valence) */
    double *WFNprimitiveNorm=NULL;

    /* to store the kr parameters defining the STO with kx,ky and kz. */
    int *WFNprimkr=NULL; 

    /* to store kx */
    int *WFNprimkx=NULL;

    /* to store ky */
    int *WFNprimky=NULL;

    /* to store kz */
    int *WFNprimkz=NULL;
    
    int VALiprim; 

    int WFNnbOrb;

    /* arrayx 2D tot. nbMOs x tot. rkf_nbPrimitives; */
    double **WFNmolOrbitalCoef;

    double *WFNoccupancy = NULL;
    char **MOdesc = NULL;

    int VALimo;

    int WFNHOMO=0;
    int iLUMO;
    int alphaHOMO=-1;
    int betaHOMO=-1;

    int min, max;

    int* rkf_nbOrbitals;
    
    /* Building filename */
    // extract the filename prefix
    std::string fs(filename);
    std::ostringstream os; 
    size_t index=fs.rfind(".");
    os << fs.substr(0,index) << "-rkf" << ".txt";

    /* Opening writing stream */
    std::ofstream writer(os.str().c_str()); // was previously directed towards standard output
                                            // now redirected towards adf-rkf.txt

     /* Get the data */
    writer << "================= D A T A   r e a d   f r o m   A D F . r k f ==============\n" << std::endl;
    
    /*  RESTRICTED or UNRESTRICTED */
    /* Find out the size of 
       the variable in data type units */
    datasize = ADF_getKFVariableLength(kf, var0);
    nspin = (int*) malloc (datasize*sizeof(int));  /* allocate enough memory */
    if (ADF_getKFData(kf, var0, (void*) nspin) < 0) exit(1);
    if (*nspin ==1) {writer << "\nSPIN: spin-restricted calculation\n";}
    else {writer << "\nSPIN: spin-unrestricted calculation\n";}

    writer << "\n\n===============================================\n";
    writer << "   C E N T E R S \n";
    writer << "===============================================\n\n";


    /* ===========================================
       centers[i].element
       ===========================================*/
    writer << "Nb of atoms      = " << nbNuclei << std::endl;
    /* (1) find the nb of atom types */
    datasize = ADF_getKFVariableLength(kf, var4);
    ntyp = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var4, (void*) ntyp) < 0) exit(1);
    writer << "Nb of atom types = "<< *ntyp;
  
    /* (2) find the label of each atom type (not for each atom...) */
    writer << "\n";
   
    datasize = ADF_getKFVariableLength(kf, var5);
    if( datasize/160 != *ntyp) /* only strings of 160 characters for each atomtype are returned */
        {
          std::cerr << "[ERROR] Error: reading Atom type labels: datasize/160 differs from the number";
          std::cerr << " of atom types given by ntyp" << std::endl;
          std::cerr << "The program will now exit." << std::endl;
          exit(EXIT_FAILURE);
        }
    nuclab =(char *) malloc ( (datasize+1)*sizeof(char)); /* a string of (nb of atom x 160) characters */
    if (ADF_getKFData(kf, var5, (char *) nuclab) < 0) exit(1);
    /* search for ATOMIC SYMBOL */
    for (iattype=0; iattype<*ntyp; iattype++) {
       int indexFirstLett = iattype*160;
       if (nuclab[indexFirstLett+1] == ' ')  { /* one letter atom label */
              strncpy(typelabel[iattype],nuclab+indexFirstLett,1); /* on recupere le symbole d'une lettre */
              typelabel[iattype][1] = '\0';
              writer << "Atom type " << iattype+1 << " typelabel = " <<  typelabel[iattype] << std::endl;
       } /* end of if (nuclab[indexFirstLett+1] == ' ') */
       else /* two-letters atom label */
       {
              strncpy(typelabel[iattype], nuclab+indexFirstLett, 2); /*on recupere le symbole (2lettres)*/
              typelabel[iattype][2] = '\0';
              writer << "Atom type " << iattype+1 << " typelabel = " << typelabel[iattype] << std::endl;
       }/* end of else of if (nuclab[indexFirstLett+1] == ' ') */
       
    } // end of for (iat=0; iat<*ntyp; iat++) 


    /* (3) check that the number of fragments = nb of atoms*/
    datasize = ADF_getKFVariableLength(kf, var6);
    nfrag = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var6, (void*) nfrag) < 0) exit(1);
    if (*nfrag !=  (int)nbNuclei) {
      printf("Error, fragments must be single atoms, stopping.\n");
      printf("Nb fragments = %d Nb atoms = %d \n",*nfrag,(int)nbNuclei);
      exit(1);
    }
    /* => then we can extract the atom indexes */

    datasize = ADF_getKFVariableLength(kf, var7);
    TMPattype = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var7, (void*) TMPattype) < 0) exit(1);
    
    attype = (int*) malloc ( (datasize/2)*sizeof(int));

    for (iat = datasize/2; iat < datasize; ++iat) { /* take care, datasize = nbr of atoms x 2 */
      /* and one takes the 'datasize/2' last numbers */
      atnum = iat-datasize/2; /* ranges [0:nbAtoms-1]*/
      attype[atnum] = TMPattype[iat];
      /*   printf("  %d       %d        %s\n", atnum+1, attype[atnum], typelabel[attype[atnum]-1]);*/
      
    }
    
    /* store the atom label for every atom: */
    label = (char**)malloc((nbNuclei)*sizeof(char*)); /* a dynamic array to save label strings*/
    for (iat = 0; iat < (int)nbNuclei; ++iat) {
      label[iat] = (char*)malloc(strlen(typelabel[0]) + 1);
      /*strcpy(label[iat], typelabel[attype[iat]-1]);*/
      label[iat] = strdup(typelabel[attype[iat]-1]);
    }

    /* ===============================================================
       retrieve the array defining the re-ordering of atoms 
       Actually the internal ADF numbering differs from the user's one
       =============================================================== */
    datasize = ADF_getKFVariableLength(kf, var29);
    if ((int)(2*nbNuclei) != datasize) exit(1);
    ADF_atomOrder = (unsigned int*) malloc (datasize*sizeof(unsigned int)); // Array that defines the re-ordering of atoms 
    if (ADF_getKFData(kf, var29, (void*) ADF_atomOrder) < 0) exit(1);

    

    /* ===========================================
       centers[i].charge
       =========================================== */
    datasize = ADF_getKFVariableLength(kf, var8);
    typecharge = (double*) malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var8, (void*) typecharge) < 0) exit(1);
    charge = (double*) malloc ((nbNuclei)*sizeof(double));
    for (iat = 0; iat < (int)nbNuclei; ++iat) { 
          charge[iat] = typecharge[ attype[iat]-1 ];
       }

 
    /* ===========================================
       centers[i].coordinates[0]
       centers[i].coordinates[1]
       centers[i].coordinates[2]
       =========================================== */
    datasize = ADF_getKFVariableLength(kf, var9);
    if ((datasize/3) != (int)nbNuclei) {
        printf("Error in readADF.c, nb of XYZ coordinates (%d)/3\n", datasize);
        printf("differs from 3 x the number of nuclei: %d\n",(nbNuclei)*3);
        exit(1);
    }
    coord = (double *)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var9, (void*) coord) < 0) exit(1);

    WFNcoord = (double **)malloc((nbNuclei)*sizeof(double *));
    for (iat=0; iat < (int)nbNuclei; iat++) {
       WFNcoord[iat] = (double *)malloc(3*sizeof(double));
       int ix;
       for (ix=0; ix<3; ix++) {
         WFNcoord[iat][ix]=0.0;
       }
    }

    iat = -1;
    writer << "\n ATOM |ADF index| |USER index|    TYPE     X         Y         Z   in bohr   CHARGE   \n";
    for (icoord=0; icoord < datasize; icoord=icoord+3) {
      iat++; 
//ERIC 
      writer << std::fixed;
      writer << std::setw(11) << std::right << iat+1 <<  std::setw(11) << std::right << ADF_atomOrder[iat+nbNuclei];
      writer << std::setw(11) << label[iat] << std::setw(4) << attype[iat];
      writer << std::setw(10) << std::setprecision(5) << coord[icoord];
      writer << std::setw(10) << std::setprecision(5) << coord[icoord+1];
      writer << std::setw(10) << std::setprecision(5) << coord[icoord+2];
      writer << std::setw(17) << std::setprecision(1) << charge[iat];
      writer << std::endl;
     /* fill the WFN coord array */
     WFNcoord[iat][0] = coord[icoord];
     WFNcoord[iat][1] = coord[icoord+1];
     WFNcoord[iat][2] = coord[icoord+2];

    } /* end of  for (icoord=0; icoord < datasize; icoord=icoord+3)*/


    writer << "\n\n===============================================\n";
    writer << "  E L E C T R O N S \n";
    writer << "===============================================\n";

    datasize = ADF_getKFVariableLength(kf, var25);
    qcore = (double*) malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var25, (void*) qcore) < 0) exit(1);

    nelecCOR = 0.0;
    for (iat=0; iat < datasize; iat++) {
      nelecCOR = nelecCOR+qcore[iat];
    }
    writer << "  1] Core electrons    = " << std::setprecision(2) << std::setw(6) << nelecCOR;
    writer << " (integration of the core (MO) orbital expansions\n";
    writer << "                                 in STO core expansion functions) \n";

    datasize = ADF_getKFVariableLength(kf, var24);
    nelecVAL = (double*) malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var24, (void*) nelecVAL) < 0) exit(1);
    writer << "  2] Valence electrons = " << std::setprecision(2) << std::setw(6) << *nelecVAL;
    writer << " (not necessarily the same as the chemical valence space) \n";


    writer << "\n\n===============================================\n";
    writer << "  W A V E   F U N C T I O N   A N A L Y S I S \n";
    writer << "===============================================\n";

    /*  ===========================================
	CORE: Total number of core functions (CF) (orthogonalization functions)
	      in the 'valence' MO expansion
	=========================================== */
    
    datasize = ADF_getKFVariableLength(kf, var23);
    ncos     = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var23, (void*)ncos) < 0) exit(1);


    writer <<"\n 1] STO primitives used in    S C F\n";
    writer <<"    ---------------------------------\n";

    datasize = ADF_getKFVariableLength(kf, var1b);
    nbos = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var1b, (void*) nbos) < 0) exit(1);
    writer <<"Cartesian basis functions             = " << *nbos;
    writer <<" (not counting the copies of the functions on the different atoms) \n\n";


    /* =================================================================
       rkf_nbPrimitives for 'ADF valence' (including core orthog. functions)
       ================================================================= */
   
    rkf_nbPrimitives = ADF_getKFVariableLength(kf, var2);
    writer <<"SCF Nb of primitives                  = " << rkf_nbPrimitives << " (to describe Valence MOs, SCF) \n";
    writer <<"                                       ----- \n";
    writer <<"SCF Nb of primitives 'orthogon. val.' = " << *ncos <<"   (as much as CORE orbitals, in SCF)\n";
    writer <<"                                        +  \n";
    writer <<"SCF Nb of primitives 'pure      val.' = " << (rkf_nbPrimitives-*ncos) <<" ('chemical' valence space, in SCF)\n";


    /* ===========================================
       rkf_nbOrbitals = number of Molecular Orbitals
       =========================================== */

    datasize = ADF_getKFVariableLength(kf, var1);
    rkf_nbOrbitals = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var1, (void*) rkf_nbOrbitals) < 0) exit(1);
    writer << "\nVALENCE Nb of Molecular Orbitals      = " << *rkf_nbOrbitals << " (Fock Matrix size, variational deg. of freedom)\n";


    /* ===========================================
       primitiveTypes   
       primitiveCenters
       primitiveExponents
       =========================================== */
    
    /* With array nbptr you locate the subsections in the function list 
       that correspond to the different types of atoms: for atom type i the 
       functions nbptr(i)…nbptr(i+1)-1. The distinct atom types have been read above */


    /* ==> allocation for VALENCE primitive centers and exponents */
    rkf_primitiveCenters   = (int*) malloc (rkf_nbPrimitives*sizeof(int));

    rkf_primitiveExponents = (double*) malloc (rkf_nbPrimitives*sizeof(double));

    rkf_primitiveTypes     = (int*)    malloc (rkf_nbPrimitives*sizeof(int));

    primitiveNorm      = (double*) malloc (rkf_nbPrimitives*sizeof(double));

    primkx             = (int*)    malloc (rkf_nbPrimitives*sizeof(int));

    primky             = (int*)    malloc (rkf_nbPrimitives*sizeof(int));
 
    primkz             = (int*)    malloc (rkf_nbPrimitives*sizeof(int));

    primkr             = (int*)    malloc (rkf_nbPrimitives*sizeof(int));

    primTMPint         = (int*)    malloc (rkf_nbPrimitives*sizeof(int));

    primTMPdouble      = (double*) malloc (rkf_nbPrimitives*sizeof(double));

    /* (1) First, locate the subsections in the function list that correspond */
    /*     to the different types of atoms */
    datasize = ADF_getKFVariableLength(kf, var10);
    nbptr = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var10, (void*) nbptr) < 0) exit(1);
    if (*ntyp != (datasize-1) ) {
      printf("Error: nb of atom types               : %d\n",*ntyp);
      printf("       nb of Basis subsections differs: %d\n",(datasize-1));
      exit(1);
    }


    writer <<"\nSUBSECTIONS in the function list that correspond to the different types of atoms\n";
    for (iatType=0; iatType < *ntyp; iatType++) {
      writer << "Atom type " << iatType+1 << " (" <<  std::setw(2) << typelabel[iatType] << ")";
      writer << " function range [" << nbptr[iatType] << ":" << nbptr[iatType+1]-1 << "]\n";
    }
    /* (2) Read the function quadruplets: kx,ky,kz,kr: 
       STO = x^kx  y^ky   z^kz  r^kr  exp(-alpha r) */
    /* kx */
    datasize = ADF_getKFVariableLength(kf, var11);
    int nbfunc = datasize;
    kx = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var11, (void*) kx) < 0) exit(1);  /* kx in the range [0:4] */

    /* ky */
    datasize = ADF_getKFVariableLength(kf, var12);
    ky = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var12, (void*) ky) < 0) exit(1);  /* ky in the range [0:4]*/

    /* kz */
    datasize = ADF_getKFVariableLength(kf, var13);
    kz = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var13, (void*) kz) < 0) exit(1);  /* kz in the range [0:4] */

    /* kr */
    datasize = ADF_getKFVariableLength(kf, var14);
    kr = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var14, (void*) kr) < 0) exit(1);  /* kr in the range [0:6],  to be checked */

    /* Display to check: */
    writer << "\n" << nbfunc << " STO FUNCTIONS (for atom types only)\n";
    writer << "Function       kx    ky    kz    kr\n";

    for (ifu=0; ifu < nbfunc; ifu++) {
      writer << "  " << std::setw(3) << ifu+1;
      writer << "        " << std::setw(3) << kx[ifu];
      writer << "   " << std::setw(3) << ky[ifu];
      writer << "   " << std::setw(3) << kz[ifu];
      writer << "    " << std::setw(3) << kr[ifu] << "\n";
    }  


    datasize = ADF_getKFVariableLength(kf, var15);
    nqptr    = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var15, (void*) nqptr) < 0) exit(1);
    
    
    datasize = ADF_getKFVariableLength(kf, var16);
    alf      = (double*) malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var16, (void*) alf) < 0) exit(1);
    
    /* bnorm = Normalization factors for the nbos Cartesian STO basis functions, but for each atom type.
       since in ADF MO =  sum_i C_i x bnorm_i x STO_i  (C_i = expansion coefficients)
       while in WFN/WFX MO = sum_i C_i x STO_i (C_i = expansion coefficients including Normalization factors!) */
    datasize = ADF_getKFVariableLength(kf, var17);
    bnorm      = (double*) malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var17, (void*) bnorm) < 0) exit(1);

    /* ==================================================================================================== */
    /* D I S T R I B U T E    T Y P E,  C E N T E R,  E X P O N, b n o r m     o n    a l l    a t o m s  */
    /* ==================================================================================================== */

    /* initialisation */
    iprim = -1;

    for (iatType=0; iatType < *ntyp; iatType++) { /* loop over atom types */
      for (iat=nqptr[iatType]; iat < nqptr[iatType+1]; iat++) { /* loop over atoms of that type */
	
	/* for current atom, run over all its functions */
	for (ifu=nbptr[iatType]; ifu<nbptr[iatType+1]; ifu++) {
	  iprim++;
	  if (iprim >= rkf_nbPrimitives) {
	    printf("Error in readADF, number of built primitives > %d\n", rkf_nbPrimitives);
	    exit(1);
	  }
	  rkf_primitiveTypes[iprim]     = ADF_primtype(kx[ifu-1], ky[ifu-1], kz[ifu-1]);
	  rkf_primitiveCenters[iprim]   = iat; /* return iat in the range[1:nb of atoms] */
	  rkf_primitiveExponents[iprim] = alf[ifu-1];
	  primitiveNorm[iprim]      = bnorm[ifu-1];
	  primkr[iprim]             = kr[ifu-1]; /* krprim in the range [0:4] ([0:3] in ADF) */
	  
	  /* not needed by IGMPLOT:
	     just for display and check here */
	  primkx[iprim] = kx[ifu-1]; 
	  primky[iprim] = ky[ifu-1];
	  primkz[iprim] = kz[ifu-1];
	  
	} /* end of loop over functions for this atom of that type */
	
      }  /*  end of loop over atoms of that TYPE */
      
    } /* end of loop over atom TYPES */
    
    /* display to check:
       ORIGINAL ordering */
    writer << "\n     P R I M I T I V E S   d e t a i l s\n";
    writer << "--------------------------------------------------------------\n";
    
    writer << "PRIMITIVE Type Assign X  Y  Z  R   exponent     Norm   on Atom\n";
    writer << "                      ==========   ========     ====   =======\n";
    
    for (iprim=0; iprim<rkf_nbPrimitives; iprim++) {
      writer << std::setw(10) << iprim+1;
      writer << std::setw(3)  << rkf_primitiveTypes[iprim];
      writer << "       " << std::setw(3) << primkx[iprim];
      writer << std::setw(3) << primky[iprim];
      writer << std::setw(3) << primkz[iprim];
      writer << std::setw(3) << primkr[iprim];
      writer << "    " << std::setw(7) << std::setprecision(3) << rkf_primitiveExponents[iprim];
      writer << "  " << std::setw(7) << std::setprecision(3) << primitiveNorm[iprim];
      writer << "    " << std::setw(5) << rkf_primitiveCenters[iprim] << std::endl;;
    } /* end of loop over primitives */

    datasize = ADF_getKFVariableLength(kf, var18);
    if (datasize != rkf_nbPrimitives) {
      printf("Error in readADF.c, npart size (%d) differs from  the nb of primitives %d\n",
	     datasize,rkf_nbPrimitives);
    }
    npart    = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var18, (void*) npart) < 0) exit(1);
    

    /* ===========================================
       Molecular Orbitals Coefficients : moleculeOrbital.coefficients
       =========================================== */
    
    /* A L L O C A T I O N   ALPHA*/

    molOrbitalCoefalpha = (double **)malloc ( (*rkf_nbOrbitals)*sizeof(double *));
    for (imo=0; imo<*rkf_nbOrbitals; imo++) {
      molOrbitalCoefalpha[imo] = (double *)malloc(rkf_nbPrimitives*sizeof(double));
    } /* end of loop over MOs */
    
    /* A L L O C A T I O N   BETA */
    molOrbitalCoefbeta  = (double **)malloc ( (*rkf_nbOrbitals)*sizeof(double *));
    for (imo=0; imo<*rkf_nbOrbitals; imo++) {
      molOrbitalCoefbeta[imo]  = (double *)malloc(rkf_nbPrimitives*sizeof(double));
    } /* end of loop over MOs         */
    
    /*    *** A L P H A     e l e c t r o n s *** */
    
    datasize = ADF_getKFVariableLength(kf, var19);
    /* the number of SCF MOs is = norb, and nbPrim=npart --> datasize of Eigen-Bas should be
                                  norb x npart  */
    if (datasize != ((*rkf_nbOrbitals)*rkf_nbPrimitives) ) {
      printf("Error in readADF.c while reading MO coefficients\n");
      printf("nb of primitives (SCF) read in adf.rkf  (npart)       = %d\n", rkf_nbPrimitives);
      printf("nb of MOs (SCF) expected                (norb )       = %d\n", *rkf_nbOrbitals);
      printf("nb of total expansion coeff. expected (norb x npart)  = %d\n", (*rkf_nbOrbitals) * rkf_nbPrimitives);
      printf("nb of total expansion coeff. read (Eigen-Bas_A matrix)= %d\n", datasize);
      exit(1);
    }
    /* retrieve all coefficients for all alpha MOs in ADF: */
    coeffADFalpha    = (double*)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var19, (void*) coeffADFalpha) < 0) exit(1);
    
    /* dispatch the coefficients in the new structure for IGMPlot */
    for (iadfcoef=0; iadfcoef<datasize; iadfcoef++) {
      iprim = iadfcoef % rkf_nbPrimitives;    /* --> the normal entry in the BAS function list */
      iprim = npart[iprim] - 1;           /* --> npart = A list of indices [1:...] of the bas functions */
                                          /*     used in the CLOA !! */
      imo   = floor(iadfcoef/rkf_nbPrimitives);
      molOrbitalCoefalpha[imo][iprim] = coeffADFalpha[iadfcoef];
    }
    
    /* ===========================================
       Molecular Orbitals occup number : moleculeOrbital.occupancy    
       (for 'ADF Valence')
       =========================================== */
     datasize = ADF_getKFVariableLength(kf, var20);
    if (datasize != *rkf_nbOrbitals) {
      printf("Error in readADF.c while reading MO occupancy\n");
      printf("froc_A section in rkf file has %d numbers compared to %d valence MOs\n",datasize,*rkf_nbOrbitals);
      exit(1);
    }
    
    /* retrieve all occupancy numbers for all MOs in ADF: */
    occAlphaVal    = (double*)malloc ((*rkf_nbOrbitals)*sizeof(double));
    if (ADF_getKFData(kf, var20, (void*)occAlphaVal) < 0) exit(1);
    
    /* ------ TEST if all ALPHA MOs are grouped ahead of the list of MOs ----- */
    iLUMO = -1;
    for (imo=0; imo<(*rkf_nbOrbitals); imo++) {

      /* detect the first non-occupied MO */
      if ( (occAlphaVal[imo] == 0.0) && (iLUMO == -1) ) {
        iLUMO = imo; 
        if (iLUMO == 0) {
          printf("Error in readADF.c, first alpha MO is unoccupied\n");
          exit(1);
        }

      } else if (occAlphaVal[imo] != 0.0) {
        /* check that if iLUMO has been found, no further MO is occupied */
        if (iLUMO >= 0) {
          printf("Error in readADF.c, all alpha occupied MOs should be grouped");
          printf(" at the beginning in the list of MOs \n");
          exit(1);
        }
      } /* end of else of if (occAlphaVal[imo] == 0.0) */
    }  /* end of for (imo=0; imo<TOTnbOrbital; imo++) */
    /* if no empty MO has been found  ==> all MOs are occupied, alphaHOMO = the last one */
    if (iLUMO == -1) {
       alphaHOMO = (*rkf_nbOrbitals)-1; /* the 0-based index of the alpha HOMO.*/
    }
    else { /* the HOMO is before the LUMO (which is not the first) */
       alphaHOMO = iLUMO - 1; /* alphaHOMO in the range [0:...] */
    }
    /* =======================
       Display to check
       ======================= */
    writer << "\n 2] Molecular Orbital Coefficients and occupancy read from ADF for 'VALENCE'\n";
    writer << "    ----------------------------------------------------------  \n";
    if (*nspin == 1) 
      {writer << " ============== S P I N    A L P H A    +    B E T A =========\n";}
    else
      {writer << " ============== S P I N    A L P H A =========================\n";}
    writer << " ==== occupied:  " << std::setw(3) << alphaHOMO+1;
    writer << "     unoccupied:  " << std::setw(3) << (*rkf_nbOrbitals)-alphaHOMO-1 << " ====================\n";

    
    for (irow=0; irow< (floor( (*rkf_nbOrbitals-1)/4 ) +1); irow++) {
      minMO = irow*4; 
      //JC for avoiding sequence-point warning
      //maxMO = ( (*rkf_nbOrbitals-minMO)>=4?maxMO=minMO+(4-1):(*rkf_nbOrbitals-1) );
      if((*rkf_nbOrbitals-minMO)>=4)
	maxMO=minMO+(4-1);
      else
	maxMO=(*rkf_nbOrbitals-1);
      
      writer << "MO --> ";
      for (imo=minMO; imo<=maxMO; imo++) {
	writer << std::setw(3) << imo+1 << "         ";
      }
      writer << "\n";
      writer << "occup. ";
      for (imo=minMO; imo<=maxMO; imo++) {
	writer << std::setw(8) << std::setprecision(4) << std::fixed << occAlphaVal[imo] << "    ";
      }
      writer << "\n";
      
      for (iprim=0; iprim<rkf_nbPrimitives; iprim++) {
	writer << std::setw(3) << iprim+1 << "  ";
	for (imo=minMO; imo<=maxMO; imo++) {
	  writer << std::setw(10) << std::setprecision(3) << std::scientific <<  std::uppercase << molOrbitalCoefalpha[imo][iprim] << "  ";
	} /* end of loop over primitives */
	writer << "\n";
      } /* end of loop over MOs */
      
      writer << "\n\n";
    } /* end over irow */
    
    if (*nspin == 2) {
      /*    *** B E T A       e l e c t r o n s *** */

      datasize = ADF_getKFVariableLength(kf, var21);

    /* the number of SCF MOs is = norb, and nbPrim=npart --> datasize of Eigen-Bas should be
                                  norb x npart  */
    if (datasize != ((*rkf_nbOrbitals)*rkf_nbPrimitives) ) {
      printf("Error in readADF.c while reading Beta MO coefficients\n");
      printf("nb of primitives (SCF) read in adf.rkf  (npart)       = %d\n", rkf_nbPrimitives);
      printf("nb of MOs (SCF) expected                (norb )       = %d\n", *rkf_nbOrbitals);
      printf("nb of total expansion coeff. expected (norb x npart)  = %d\n", (*rkf_nbOrbitals) * rkf_nbPrimitives);
      printf("nb of total expansion coeff. read (Eigen-Bas_A matrix)= %d\n", datasize);
      exit(1);
    }

      /* retrieve all occupancy numbers for all beta MOs in ADF:*/
      coeffADFbeta     = (double*)malloc (datasize*sizeof(double));
      if (ADF_getKFData(kf, var21, (void*) coeffADFbeta) < 0) exit(1);
      
      /* dispatch the coefficients in the new structure for IGMPlot*/
      for (iadfcoef=0; iadfcoef<datasize; iadfcoef++) {
	iprim = iadfcoef % rkf_nbPrimitives;
        iprim = npart[iprim] - 1;           /* --> npart = A list of indices [1:...] of the bas functions */
                                            /*     used in the CLOA !! */
	imo   = floor(iadfcoef/rkf_nbPrimitives);
         molOrbitalCoefbeta[imo][iprim] = coeffADFbeta[iadfcoef];
      }

      /* ============================================================
	 Molecular Orbitals occup number : moleculeOrbital.occupancy    
	 ============================================================ */
      datasize = ADF_getKFVariableLength(kf, var22);
      if (datasize != *rkf_nbOrbitals) {
	 printf("Error in readADF.c while reading MO occupancy\n");
	 printf("froc_B section in rkf file has %d numbers compared to %d MOs\n",datasize,*rkf_nbOrbitals);
	 exit(1);
      }

      /* retrieve all coefficients for all MOs in ADF:*/
      occBetaVal    = (double*)malloc ((*rkf_nbOrbitals)*sizeof(double));
      if (ADF_getKFData(kf, var22, (void*)occBetaVal) < 0) exit(1);

     /* ------ TEST if all BETA MOs are grouped ahead of the list of MOs ----- */
    iLUMO = -1;
    for (imo=0; imo<(*rkf_nbOrbitals); imo++) {

      /* detect the first non-occupied MO */
      if ( (occBetaVal[imo] == 0.0) && (iLUMO == -1) ) {
        iLUMO = imo; 

      } else if (occBetaVal[imo] != 0.0) {
        /* check that if iLUMO has been found, no further MO is occupied */
        if (iLUMO >= 0) {
          printf("Error in readADF.c, all occupied MOs should be grouped");
          printf(" at the beginning in the list of MOs \n");
          exit(1);
        }
      } /* end of else of if (WFNoccupancy[imo] == 0.0) */
    }  /* end of for (imo=0; imo<TOTnbOrbital; imo++) */
    /* if no empty MO has been found  ==> all MOs are occupied, betaHOMO = the last one */
    if (iLUMO == -1) {
       betaHOMO = (*rkf_nbOrbitals)-1; /* the 0-based index of the beta HOMO.*/
    }
    else { /* the HOMO is before the LUMO (which is not the first) */
            if (iLUMO>0) {betaHOMO = iLUMO - 1;} /* betaHOMO in the range [0:...] */
            else /* HOMO = LUMO = first beta MO*/
              {betaHOMO = 0;}
         }
      /* ============================
	 Display to check
	 ============================ */
      writer << " ============== S P I N    B E T A ===========================\n";
      writer << " ==== occupied:  " << std::setw(3) << betaHOMO+1;
      writer << "     unoccupied:  "<< std::setw(3) << (*rkf_nbOrbitals)-betaHOMO-1 << " ====================\n";
      
      for (irow=0; irow< (floor( (*rkf_nbOrbitals-1)/4 ) +1); irow++) {
	minMO = irow*4; 
	//JC for avoiding sequence-point warning
	//maxMO = ( (*rkf_nbOrbitals-minMO)>=4?maxMO=minMO+(4-1):(*rkf_nbOrbitals-1) );
	if((*rkf_nbOrbitals-minMO)>=4)
	  maxMO=minMO+(4-1);
	else
	  maxMO=(*rkf_nbOrbitals-1);
	writer << "MO --> ";
	for (imo=minMO; imo<=maxMO; imo++) {
	  writer << std::setw(3) << imo+1 << "         ";
	}
	writer << "\n";
	writer << "occup. ";
	for (imo=minMO; imo<=maxMO; imo++) {
	  writer << std::setw(3) << std::setprecision(4) << occBetaVal[imo] << "    ";
	}
	writer << "\n";
        
	for (iprim=0; iprim<rkf_nbPrimitives; iprim++) {
	  writer << std::setw(3) << iprim+1 << "  ";
	  for (imo=minMO; imo<=maxMO; imo++) {
	    writer << std::setw(10) << std::setprecision(3) << std::uppercase << std::scientific;
            writer << molOrbitalCoefbeta[imo][iprim] <<  "  ";
	  } /* end of loop over primitives */
	  writer << "\n";
	} /* end of loop over MOs */
	
	writer << "\n\n";
      } /* end over global MOs */
      
    } /* end of if (*nspin ==2) */


    /* ==============================================================
       FROZEN CORE expansions to add to previous 'VALENCE' expansions
       ============================================================== */

    /* 1] retrieve FROZEN CORE 'MO' coefficients */
    
    datasize = ADF_getKFVariableLength(kf, var26);
    ccor     = (double*)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var26, (void*)ccor) < 0) exit(1);

    /* 2] retrieve the number of frozen CORE orbitals per l-value and per non-dummy atom type. */
    datasize = ADF_getKFVariableLength(kf, var27);
    nrcorb   = (int*)malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var27, (void*)nrcorb) < 0) exit(1);
    if ( (datasize/4) != *ntyp) {
      printf("Error in readADF.c while reading nrcorb,\n");
      printf("Nb of atom types according to nrcorb                   = %d\n",datasize/4);
      printf("Nb of atom types according toe types according to ntyp = %d\n",*ntyp);
      exit(1);
    }

    /* 3] retrieve The number of STO function sets to describe each frozen core orbitals in the calculation */
    datasize = ADF_getKFVariableLength(kf, var28);
    nrcset   = (int*)malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var28, (void*)nrcset) < 0) exit(1);
    
    /* ......................................
       4] number of frozen core MOs + primitives
       ...................................... */
    nfrozCORE = 0;
    COREWFNnprim = 0;
    for (iatType=0; iatType < *ntyp; iatType++) { /* loop over atom types */
      for (iat=nqptr[iatType]; iat < nqptr[iatType+1]; iat++) { /* loop over atom list in each atom type */
	for (iSTO_TYPE=0; iSTO_TYPE<4; iSTO_TYPE++) {
/*	  nfrozCORE    = nfrozCORE     + nrcorb[iatType*4+iSTO_TYPE]*ml[iSTO_TYPE];*/  /* !! don't forget that we have to */
                                                                                    /* provide the angular part for each shell s p d or f */
          nfrozCORE    = nfrozCORE     + nrcorb[iatType*4+iSTO_TYPE];
	  COREWFNnprim = COREWFNnprim  + nrcset[iatType*4+iSTO_TYPE];
	} /* end over iSTO_TYPE */
      }  /* end over iat */
    } /* end over iatType */
    
    frozCOREocc = (double *)malloc(nfrozCORE*sizeof(double));  /* allocate enough memory */

    /* 5] retrieve the exponential decay factors for the core STOs */
    datasize = ADF_getKFVariableLength(kf, var30);
    alfcor   = (double*)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var30, (void*)alfcor) < 0) exit(1);

    /* 6] retrieve the normalization factors for the core STOs */
    datasize = ADF_getKFVariableLength(kf, var31);
    cornrm  = (double*)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var31, (void*)cornrm) < 0) exit(1);
    
    /* 7] retrieve the 'n' values (main quantum number) for the core STOs */
    datasize = ADF_getKFVariableLength(kf, var32);
    nqcor    = (int*) malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var32, (void*)nqcor) < 0) exit(1);
    
    /* 8] retrieve the 'l' values (second quantum number) for the core STOs */

    datasize = ADF_getKFVariableLength(kf, var33);
    lqcor  = (int*)malloc (datasize*sizeof(int));
    if (ADF_getKFData(kf, var33, (void*)lqcor) < 0) exit(1);

    /* ==> allocation for WFN primitive centers and exponents */
    COREWFNprimitiveCenters   = (int*)malloc (COREWFNnprim*sizeof(int));

    COREWFNprimitiveExponents = (double*)malloc (COREWFNnprim*sizeof(double));

    COREWFNprimitiveTypes     = (int*)malloc (COREWFNnprim*sizeof(int));

    COREWFNprimitiveNorm      = (double*)malloc (COREWFNnprim*sizeof(double));

    COREWFNprimkr             = (int*)malloc (COREWFNnprim*sizeof(int));

    /* not really needed by IGMPlot, just for display here:*/
    COREWFNprimkx             = (int*)malloc (COREWFNnprim*sizeof(int));
    COREWFNprimky             = (int*)malloc (COREWFNnprim*sizeof(int));
    COREWFNprimkz             = (int*)malloc (COREWFNnprim*sizeof(int));

    iprim=-1;        /* total number of primitive since the beginning */
    previousSTOs=0;
    /* %%%%%%%% atom TYPES   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
    for (iatType=0; iatType < *ntyp; iatType++) { /* loop over atom types */
      
      /* %%%%%%%%  A T O M S      %%%%%%%%%%%%%%%%%%%%%%% */
      for (iat=nqptr[iatType]; iat < nqptr[iatType+1]; iat++) { /* loop over atoms of that type */
	
	/* reinit. iCORESTO; index running over the sum of total core STO functions (ncset) */
	iCORESTO=-1;
	/* %%%%%%%% STO_TYPE (s,p,d,f)  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
	for (iSTO_TYPE=0; iSTO_TYPE<4; iSTO_TYPE++) { /* for the 4 orbital types : s, p, d and f, successively */
	  
	  /* %%%%%%%%%% EXPANSION STO %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
	  for (iexpans=0; iexpans < nrcset[iatType*4+iSTO_TYPE]; iexpans++) {/* loop over the STO expansion (s or p or d or f) */
	    iCORESTO++; 
	    
	    iprim++;
	    if (iprim >= COREWFNnprim ) {
	      printf("Error in readADF, number of built COREWFN primitives > %d\n", COREWFNnprim );
	      exit(1);
	    }
	    COREWFNprimitiveTypes[iprim]     = ADF_primtype(0, 0, 0); /* only S orbital is considered since core orbitals  */
                                                                  /* are always fully occupied and have a spherical shape ED */
                                                                  
	    COREWFNprimitiveCenters[iprim]   = iat; /* return iat in the range[1:nb of atoms] */
	    COREWFNprimitiveExponents[iprim] = alfcor[iCORESTO+previousSTOs];/*  note that previousSTOs represents */
                                                                             /* the nb of STOs type already ascribed */
                                                                             /* from previous atom types */

            /* IMPORTANT !! : instead of considering a set of frozen core (px,py,pz) */
            /*                each occupied by 2 electrons, we will consider one single */
            /*                s (of same n) occupied by 6 e- (occupancy=6 instead of 2)!!, but having the same alfa exponent */
            /*                than the 2px,y,z shell, in order to represent quicly (only one single orbital) */
            /*                the spherical shape of the ED provided by npx,npy,npz fully occupied ! */ 
            /*                In that case, the normalization coefficient to consider is no longer */
            /*                cornrm[npx,y,z] but cornrm[ns] derived with the exponent alfa associated to the npx,y,z */
            /*                Since there is always the same ratio cornrm[npx,y,z]/cornrm[ns] = sqrt(3) for the */
            /*                same given alfa exponent, knowing cornrm[npx,y,z] provided by ADF, we only need to */
            /*                derive cornrm[ns] = cornrm[npx,y,z] / sqrt(3) !! */
            /*                The same approach can be processed for d and f orbitals : */
            /*                (d): instead of considering a set of a set of n'd' frozen core  fully occupied by 10e- */
            /*                     --> replaced by a n's' (same exponent) with cornrm[ns] = cornrm[ndz2] / sqrt(5) !! */
            /*                (d): instead of considering a set of a set of n'f' frozen core  fully occupied by 14e- */
            /*                     --> replaced by a n's' (same exponent) with cornrm[ns] = cornrm[nfz3] / sqrt(7) !! */
            /* !!! core np --> ns !!! */
            /* !!! core nd --> ns !!! */
            /* !!! core nf --> ns !!! */
     
            /* DEPRECATED: COREWFNprimkr[iprim] = nqcor[iCORESTO+previousSTOs]-(lqcor[iCORESTO+previousSTOs]+1); */
            /*             with COREWFNprimkr in the range [0:3] in ADF */
            /*--------- k = n - (l + 1) ----- */
            COREWFNprimkr[iprim] = nqcor[iCORESTO+previousSTOs]-(0+1); /* Always consider a 's' orbital)   */

            /*--------- S NORM from S ------- */
            if (lqcor[iCORESTO+previousSTOs] == 0) 
               {COREWFNprimitiveNorm[iprim]      = cornrm[iCORESTO+previousSTOs];} /* --> ADF cornrm taken as is */

            /*--------- S NORM from P ------- */
            if (lqcor[iCORESTO+previousSTOs] == 1) 
               {COREWFNprimitiveNorm[iprim]      = cornrm[iCORESTO+previousSTOs]/sqrt(3.0);} /* --> NORMS= NORMP/sqrt(3) */

            /*--------- S NORM from D ------- */
            if (lqcor[iCORESTO+previousSTOs] == 2) 
               {COREWFNprimitiveNorm[iprim]      = cornrm[iCORESTO+previousSTOs]/sqrt(5.0);} /* --> NORMS= NORMD/sqrt(5) */  

            /*--------- S NORM from F ------- */
            if (lqcor[iCORESTO+previousSTOs] == 3) 
               {COREWFNprimitiveNorm[iprim]      = cornrm[iCORESTO+previousSTOs]/sqrt(7.0);} /* --> NORMS= NORMF/sqrt(7) */  
                      
	  }  /* end of loop over iexpans                          */
	  /* _______ iEXPANS __________________________________ */
	  
	} /* end of loop over iSTO_TYPE*/
	/* _____ iSTO_TYPE ____________________________________________ */
	
      } /* end of loop over ATOM of THAT TYPE */
      /* __________ ATOM ___________________________________________________________ */
      
      
      /* store the nb of CORE STOS type already used in the total amount of ncset*/
      previousSTOs = previousSTOs + iCORESTO+1;
      
    } /* end of loop over atom TYPES */
      /* _______atomTYPE___________________________________________________________________________ */
    
    /* store the nb of CORE primitives */
    COREnprim = iprim+1;
    if (COREnprim != COREWFNnprim) {
      printf("Error in readADF.c, numerical counting of COREnprim = %d\n",COREnprim);
      printf("differs from results obtained with nrcorb and nrcset sections of adf.rkf:%d\n",COREWFNnprim);
    }

    /* store the nb of frozen core orbitals 
       and their electrons for current orbital type
       and the associated MO coeffs */
    nbelec=0.;
    ifrozCORE=-1;
    previousCCOR = 0;
    previousPRIM = 0;



    /* ==============================================================
       Allocation for core molOrbitalCoef
       ============================================================== */
    COREmolOrbitalCoef = (double **)malloc (nfrozCORE*sizeof(double *));
    
    for (imo=0; imo<nfrozCORE; imo++) {
      COREmolOrbitalCoef[imo] = (double *)malloc(COREWFNnprim*sizeof(double));
      
      for (iprim=0; iprim<COREWFNnprim; iprim++) {
	COREmolOrbitalCoef[imo][iprim]=0.0;
      } /* end of loop over primitives */
      
    } /* end of loop over MOs */
    
    /* %%%%%%%% atom TYPES   %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
    for (iatType=0; iatType < *ntyp; iatType++) { /*loop over atom types */
      
      /* %%%%%%%%  A T O M S      %%%%%%%%%%%%%%%%%%%%%%% */
      for (iat=nqptr[iatType]; iat < nqptr[iatType+1]; iat++) { /* loop over atoms of that type */
	/* reinit. iccor index running over the coefficients ccor  */
	iccor=-1;
	
	/*  %%%%%%%% STO_TYPE (s,p,d,f)  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
	for (iSTO_TYPE=0; iSTO_TYPE<4; iSTO_TYPE++) { /* for the 4 orbital types : s, p, d and f, successively */
	  /* determine the number of electrons in that shell */
	  if (iSTO_TYPE == 0) {        /* s shell */
	    nbelec = 2.;
	  } else if (iSTO_TYPE == 1) { /* p shell */
	    nbelec = 6.;
	  } else if (iSTO_TYPE == 2) { /* d shell */
	    nbelec = 10.;
	  } else if (iSTO_TYPE == 3) { /* f shell */
	    nbelec = 14.;
	  };
	  /* %%%%%%%%%%%% Expansion SETs  %%%%%%%%%%%%%%%%%% */
	  for (ifroz=0; ifroz<nrcorb[iatType*4+iSTO_TYPE] ; ifroz++) {
	    ifrozCORE ++; /* increments the nb of frozen CORE MOs */
	    frozCOREocc[ifrozCORE] = nbelec;
	    
	    /* store the MO coefficients ccor over corresponding primitives for this current frozen core MO
	       %%%%%% EXPANSION STO %%%% */
	    for (iexpans=0; iexpans < nrcset[iatType*4+iSTO_TYPE]; iexpans++) {/* loop over the STO expansion (s or p or d or f) */
	      iccor++;
	      /* each expansion of a given shell is developed over the same set of primitives as for other shells of same type ! */
	      COREmolOrbitalCoef[ifrozCORE][iexpans+previousPRIM] = ccor[iccor+previousCCOR];
	    } /* end of loop over iexpans */
	    /* _____ iEXPANS ______________________________________________ */
	    
	  } /* end of loop over ifroz */
	  /* _____ iFROZ _______________________________________ */
	  
	  /* if and only if the current SPDF STO-type has at least one Frozen core for the current atom type
	     store the nb of primitives already used  */
	  if (nrcorb[iatType*4+iSTO_TYPE] !=0) 
	    { previousPRIM = previousPRIM+iexpans;}
	  
	} /* end of loop over iSTO_TYPE */
	/* _____ iSTO_TYPE ____________________________________________ */
	
      } /* end of loop over ATOM of THAT TYPE */
      /* __________ ATOM ___________________________________________________________ */
      
      /* store the nb of ccor coefficients already ascribed to previous atom types    */
      previousCCOR = previousCCOR+iccor+1;
      
      
    } /* end of loop over atom TYPES */
      /* _______atomTYPE___________________________________________________________________________ */


    /* check the nb of frozen core MOs */
    if (ifrozCORE+1 != nfrozCORE) {
      printf("Error in readADF.c, numerical counting of frozen core MOs = %d\n",ifrozCORE+1);
      printf("differs from results obtained with nrcset sections of adf.rkf:%d\n",nfrozCORE);
      exit(1);
    }
   

    if(COREWFNnprim>0) {
        /* ============================
           Display CORE to check
           ============================       
           CORE STOs primitives */
    
    
           writer << "--------------------------------------------------------------\n";
           writer << "  ***  F R O Z E N      C O R E       S T O s  ***\n";
           writer << "PRIMITIVE Type Assign X  Y  Z     R     Alpha      Norm   on Atom\n";
           writer << "                      =======   ===     =====   =========\n";
    
           for (iprim=0; iprim<COREWFNnprim; iprim++) {
           writer << std::setw(10) << iprim+1;
           writer << std::setw(3)  << COREWFNprimitiveTypes[iprim];
           writer << "         0  0  0   ";
           writer << std::setw(3)  <<  COREWFNprimkr[iprim];
           writer << "  ";
           writer << std::setw(9) << std::setprecision(3) << COREWFNprimitiveExponents[iprim];
           writer << "  ";
           writer << std::setw(9) << std::setprecision(3) << COREWFNprimitiveNorm[iprim];
           writer << "  ";
           writer << std::setw(4) << COREWFNprimitiveCenters[iprim] << "\n";
           } /* end over primitives */
    
    
    
        writer <<"\n\n ============== C O R E   M O ================================\n";
        /* CORE MOs */
        for (irow=0; irow< (floor( (nfrozCORE-1)/4 ) +1); irow++) {
          minMO = irow*4;
	  // JC for avoiding sequence-point warning
	  //maxMO = ( (nfrozCORE-minMO)>=4?maxMO=minMO+(4-1):(nfrozCORE-1) );
	  if((nfrozCORE-minMO)>=4)
	    maxMO=minMO+(4-1);
	  else
	    maxMO=(nfrozCORE-1);
          writer <<"MO --> ";
          for (imo=minMO; imo<=maxMO; imo++) {
    	writer << std::setw(3) << imo+1 << "         ";
          }
          writer <<"\n";
          writer <<"occup. ";
          for (imo=minMO; imo<=maxMO; imo++) {
    	writer <<std::setw(8) << std::setprecision(4) << std::fixed << frozCOREocc[imo] << "    ";
          }
          writer <<"\n";
          
          for (iprim=0; iprim<COREWFNnprim; iprim++) {
    	writer << std::setw(3) << iprim+1 << "  ";
    	for (imo=minMO; imo<=maxMO; imo++) {
    	  writer <<std::setw(10) << std::setprecision(3) << std::scientific << std::uppercase << COREmolOrbitalCoef[imo][iprim] << "  ";
    	} /* end of loop over primitives */
    	writer <<"\n";
          } /* end of loop over MOs          */
          
          writer <<"\n\n";
        } /* end over irow   */
   }/* end of if(COREWFNnprim>0) */

    /* =================================
       MERGE Valence and CORE primitives
       ================================= */

    /* ++++++++++++++++++++++++++++++++++++++++++++++
       +      P R I M I T I V E S                   +
       ++++++++++++++++++++++++++++++++++++++++++++++ */
       
    /* ==> allocation for WFN primitive centers and exponents... */
    WFNnprim = COREWFNnprim + rkf_nbPrimitives;

    WFNprimitiveCenters   = (int*)malloc (WFNnprim*sizeof(int));

    WFNprimitiveExponents = (double*)malloc (WFNnprim*sizeof(double));

    WFNprimitiveTypes     = (int*)malloc (WFNnprim*sizeof(int));

    WFNprimitiveNorm      = (double*)malloc (WFNnprim*sizeof(double));

    WFNprimkr             = (int*)malloc (WFNnprim*sizeof(int));

    /* not really needed by IGMPlot, just for display here: */
    WFNprimkx             = (int*)malloc (WFNnprim*sizeof(int));
    WFNprimky             = (int*)malloc (WFNnprim*sizeof(int));
    WFNprimkz             = (int*)malloc (WFNnprim*sizeof(int));

    /* +++++++++++++++++++++++++++
       1) START with FROZEN CORE MO
       +++++++++++++++++++++++++++ */

    for (iprim=0; iprim<COREWFNnprim; iprim++) {
      WFNprimitiveTypes[iprim]     = COREWFNprimitiveTypes[iprim];  
      WFNprimitiveCenters[iprim]   = COREWFNprimitiveCenters[iprim];              
      WFNprimitiveExponents[iprim] = COREWFNprimitiveExponents[iprim];  
      WFNprimitiveNorm[iprim]      = COREWFNprimitiveNorm[iprim];
      WFNprimkr[iprim]             = COREWFNprimkr[iprim]; 
    } /* end over CORE primitives */

    /* +++++++++++++++++++++++++++
       2) END   with VALENCE     MO
       +++++++++++++++++++++++++++ */

    for (VALiprim=0; VALiprim<rkf_nbPrimitives; VALiprim++) {
      iprim = COREWFNnprim+VALiprim; 
      WFNprimitiveTypes[iprim]     = rkf_primitiveTypes[VALiprim];  
      WFNprimitiveCenters[iprim]   = rkf_primitiveCenters[VALiprim];              
      WFNprimitiveExponents[iprim] = rkf_primitiveExponents[VALiprim];  
      WFNprimitiveNorm[iprim]      = primitiveNorm[VALiprim];
      WFNprimkr[iprim]             = primkr[VALiprim];
    } /* end over VAL primitives*/

    /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++
       +      M O L E C U L A R    O R B I T A L S   (M O)  +
       ++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
    
    /* ==> ALLOCATION for WFN primitive centers and exponents... */

    if (*nspin == 1) { 
           WFNnbOrb = nfrozCORE + *rkf_nbOrbitals;
    }
    else if (*nspin == 2) {
           WFNnbOrb = nfrozCORE + 2* (*rkf_nbOrbitals);
    } else {printf("Error in readADF.c, spin differs from 1 or 2\n");
            exit(1);
           }

    
    WFNmolOrbitalCoef = (double **)malloc ( (WFNnbOrb)*sizeof(double *));
    for (imo=0; imo<WFNnbOrb; imo++) {
      WFNmolOrbitalCoef[imo] = (double *)malloc(WFNnprim*sizeof(double));
    } /* end of loop over MOs         */

    WFNoccupancy = (double *)malloc (WFNnbOrb*sizeof(double));
    MOdesc = (char **)malloc(WFNnbOrb * sizeof(char *));
    for (imo=0; imo<WFNnbOrb; imo++) {
       MOdesc[imo]=NULL;        
    }

    /* dispatch ALL  MOs coefficients in the big array */

    /* +++++++++++++++++++++++++++
       1) START with FROZEN CORE MO
       +++++++++++++++++++++++++++ */

    for (imo=0; imo<nfrozCORE; imo++) {
      WFNoccupancy[imo] = frozCOREocc[imo];
      MOdesc[imo]=strdup("CORE      ");

      /*   .... CORE primitives .... */
      for (iprim=0; iprim<COREWFNnprim; iprim++) {
         WFNmolOrbitalCoef[imo][iprim] = COREmolOrbitalCoef[imo][iprim] *
                                         WFNprimitiveNorm[iprim];
      }

      /*   .... VAL primitives .... */
      for (VALiprim=0; VALiprim<rkf_nbPrimitives; VALiprim++) {
         iprim = COREWFNnprim+VALiprim;
         WFNmolOrbitalCoef[imo][iprim] = 0.0; 
      } 
    }  /* end of loop over CORE MOs */

    /* +++++++++++++++++++++++++++
       2) VALENCE  alpha         MO
       +++++++++++++++++++++++++++ */

    /*for (VALimo=0; VALimo<*rkf_nbOrbitals; VALimo++)  */
    for (VALimo=0; VALimo<=alphaHOMO; VALimo++) {
      imo = nfrozCORE + VALimo; 
      WFNoccupancy[imo] = occAlphaVal[VALimo];
      if (*nspin ==1) {MOdesc[imo]=strdup("ALPHA/BETA");}
      else {MOdesc[imo]=strdup("ALPHA     ");}

      /*   .... CORE primitives .... */
      for (iprim=0; iprim<COREWFNnprim; iprim++) {
         WFNmolOrbitalCoef[imo][iprim] = 0.0;
      }

      /*   .... VAL alpha primitives .... */
      for (VALiprim=0; VALiprim<rkf_nbPrimitives; VALiprim++) {
         iprim = COREWFNnprim+VALiprim;
	 WFNmolOrbitalCoef[imo][iprim] = molOrbitalCoefalpha[VALimo][VALiprim] *  
                                         WFNprimitiveNorm[iprim]; 
      }
    }  /* end of loop over VAL  MOs */


    if (*nspin == 2) {
      /* +++++++++++++++++++++++++++
	 3) VALENCE  beta          MO
	 +++++++++++++++++++++++++++ */
      
     /* for (VALimo=0; VALimo<*rkf_nbOrbitals; VALimo++)  */
      for (VALimo=0; VALimo<=betaHOMO; VALimo++) {
      /*imo = nfrozCORE + *rkf_nbOrbitals + VALimo; */
        imo = nfrozCORE + (alphaHOMO+1) + VALimo;
	WFNoccupancy[imo] = occBetaVal[VALimo];
	MOdesc[imo]=strdup("BETA      ");
	
	/*   .... CORE primitives .... */
	for (iprim=0; iprim<COREWFNnprim; iprim++) {
	  WFNmolOrbitalCoef[imo][iprim] = 0.0;
	}
	
	/*   .... VAL beta  primitives .... */
	for (VALiprim=0; VALiprim<rkf_nbPrimitives; VALiprim++) {
	  iprim = COREWFNnprim+VALiprim;
	  WFNmolOrbitalCoef[imo][iprim] = molOrbitalCoefbeta[VALimo][VALiprim] *
	                                  WFNprimitiveNorm[iprim];
	}
      }  /* end of loop over VAL  MOs */
    } /* spin BETA */
    

    writer << "================ W  F  N ================\n";

    /* header */
    writer << "\n*** IGMPlot ***\n";

    /* General information  */
    WFNHOMO = nfrozCORE + (alphaHOMO+1)+(betaHOMO+1); /* Total nb of MOs */
    writer << "  SLATER             " << std::setw(4) << WFNHOMO;
    writer << " MOL ORBITALS    " << std::setw(4) << WFNnprim;
    writer << " PRIMITIVES       " << std::setw(4) << nbNuclei << " NUCLEI\n" ;

    /* XYZ coord. */
    for (iat=0; iat < (int)nbNuclei; iat++) {
      writer << std::setw(2) << label[iat];
      writer << "   " << std::setw(3) << iat+1;
      writer << "    (CENTRE" << std::setw(3) << iat+1;
      writer << std::fixed;
      writer << ")  " << std::setw(11) << std::setprecision(8) << WFNcoord[iat][0];
      writer << " "   << std::setw(11) << std::setprecision(8) << WFNcoord[iat][1];
      writer << " "   << std::setw(11) << std::setprecision(8) << WFNcoord[iat][2];
      writer << "  CHARGE =" << std::setw(5) << std::setprecision(1) << charge[iat] << "\n";
    } /* end of  for (icoord=0; icoord < datasize; icoord=icoord+3) */

    /* ++++++++++++++++++++++++++
       +    PRIMITIVE FEATURES  +
       ++++++++++++++++++++++++++ */
    
    /*   A] CENTRE ASSIGNMENTS */
    for (irow=0; irow< (floor( (WFNnprim-1)/20 ) +1); irow++) { 
      min = irow*20;
      max = ( (WFNnprim-min)>=20?min+(20-1):(WFNnprim-1) );
      writer << "CENTRE ASSIGNMENTS  ";
      for (iprim=min; iprim<=max; iprim++) {
	writer << std::setw(3) << WFNprimitiveCenters[iprim]; 
      }
      writer << "\n"; 
    } /* end over CENTRE ASSIGNMENTS  */
    
    /* B] TYPE   ASSIGNMENTS */
    for (irow=0; irow< (floor( (WFNnprim-1)/20 ) +1); irow++) {
      min = irow*20;
      max = ( (WFNnprim-min)>=20?min+(20-1):(WFNnprim-1) );
      writer << "TYPE ASSIGNMENTS    ";
      for (iprim=min; iprim<=max; iprim++) {
	writer << std::setw(3) << WFNprimitiveTypes[iprim]; /* common to GTO and STO */  
      }
      writer << "\n";
    } /* end over TYPE   ASSIGNMENTS  */
    
    /* C] EXPONENTS */
    for (irow=0; irow< (floor( (WFNnprim-1)/5 ) +1); irow++) {
      min = irow*5;
      max = ( (WFNnprim-min)>=5?min+(5-1):(WFNnprim-1) );
      writer << "EXPONENTS " << std::scientific;
      for (iprim=min; iprim<=max; iprim++) {
	writer << " " << std::setw(13) << std::setprecision(7) << WFNprimitiveExponents[iprim] ;
      }
      writer << "\n";
    } /* end over TYPE   EXPONENTS    */
    
    
    /* ++++++++++++++++++++++++++
       +    MO        FEATURES  +
       ++++++++++++++++++++++++++ */
    for (imo=0; imo<WFNHOMO; imo++) { 
      writer << "MO " << std::setw(3) << imo+1;
      writer << " " << MOdesc[imo] << "         OCC NO =    ";
      writer << std::setw(9) << std::setprecision(7) << std::fixed << WFNoccupancy[imo];
      writer << "  ORB. ENERGY=   0.0000000\n";

      for (irow=0; irow< (floor( (WFNnprim-1)/5 ) +1); irow++) {
        min = irow*5;
        max = ( (WFNnprim-min)>=5?min+(5-1):(WFNnprim-1) );
        for (iprim=min; iprim<=max; iprim++) {
          writer << std::setw(16) << std::setprecision(8) << std::scientific << std::uppercase << WFNmolOrbitalCoef[imo][iprim];
        }
        writer << "\n";
      }

    } /* end of loop over imo */

    /* ++++++++++++++++++++++++++
       +    S C F   E N E R G Y +
       ++++++++++++++++++++++++++ */
    /* 9] retrieve the energy value  */
    datasize = ADF_getKFVariableLength(kf, var34);
    energy  = (double*)malloc (datasize*sizeof(double));
    if (ADF_getKFData(kf, var34, (void*)energy) < 0) exit(1);
    writer << "\n=========== A D F       E N E R G Y =====\n";
    writer << "SCF Bond Energy (hartree): ";
    writer << std::setprecision(15) << std::setw(25) << *energy << "\n\n";
 
    
    writer << "END DATA\n";

    /* write the k values for IGMPLOT testing */
    writer << std::endl << std::endl;
    writer << "================ kr  ================\n";
    writer << "k values to be used for the STOs :" << std::endl;
    writer << "static int k[] = {" << WFNprimkr[0];
    for (iprim=1; iprim<WFNnprim; iprim++) {
        writer << ", " << WFNprimkr[iprim]; 
    }
    writer << "}\n";
    /* Close the file */
    writer.close();

    /***************************************************************************************************************
     * TRANSFER TO IGMPLOT VARIABLES */
    
    // everything is loaded ==> copy to igmplot variable (it is not efficient but it works)
    nbPrimitives=WFNnprim;
    nbOrbitals=WFNHOMO;

    // allocate memory for variables common to WFN, WFX and RKF 
    wf_allocateMemory();

    // allocate memory for variables specific to RKF
    primitiveKRs=new unsigned int[nbPrimitives];
    user2ADF_atomOrder=new unsigned int[nbNuclei]; // Arrays that define the re-ordering of atoms
    ADF2user_atomOrder=new unsigned int[nbNuclei]; // between the user's list and ADF atom numbering
                                                   // both arrays indices are in the range [0:nbNuclei-1]

    for(unsigned int iat=0;iat<nbNuclei;iat++) {
      user2ADF_atomOrder[iat] = ADF_atomOrder[iat]; // user2ADF_atomOrder[0:nbAtoms-1] --> [1:nbAtoms]
      ADF2user_atomOrder[iat] = ADF_atomOrder[iat+nbNuclei]; // ADF2user_atomOrder[0:nbAtoms-1] --> [1:nbAtoms]
    }
    
    for(unsigned int i=0;i<nbNuclei;i++) {

      centers[i].element=new std::string(label[i]);

      //std::cout << *centers[i].element << std::endl;
      
      centers[i].coordinates[0]=WFNcoord[i][0];
      centers[i].coordinates[1]=WFNcoord[i][1];
      centers[i].coordinates[2]=WFNcoord[i][2];

      /*std::cout << centers[i].coordinates[0] << " "
		<< centers[i].coordinates[1] << " "
		<< centers[i].coordinates[2] << std::endl;*/
      
      centers[i].charge=charge[i];

      //std::cout << centers[i].charge << std::endl;
    }

    for(unsigned int i=0;i<nbPrimitives;i++) {
      primitiveCenters[i]   = WFNprimitiveCenters[i];
      primitiveTypes[i]     = WFNprimitiveTypes[i];
      primitiveExponents[i] = WFNprimitiveExponents[i];
      primitiveKRs[i]       = WFNprimkr[i];

      //if(i%20==0) std::cout << std::endl;
      //if(i%5==0) std::cout << std::endl;
      
      //std::cout << primitiveCenters[i] << " ";
      //std::cout << primitiveTypes[i] << " ";
      //std::cout << primitiveExponents[i] << " ";
      //std::cout << primitiveKRs[i] << " ";
      
    }

   for(unsigned int i=0;i<nbOrbitals;i++) {
      
      moleculeOrbital bufferMoleculeOrbital;
      
      // Not used ?
      bufferMoleculeOrbital.data2 = 0.0;
      
      // Not used ?
      bufferMoleculeOrbital.orbitalEnergy = 0.0;

      bufferMoleculeOrbital.rank = i+1;
      
      bufferMoleculeOrbital.occupancy=WFNoccupancy[i];

      //std::cout << bufferMoleculeOrbital.occupancy << " " << WFNoccupancy[i] << " ";
      
      bufferMoleculeOrbital.coefficients=new double[nbPrimitives];

      for(unsigned int j=0;j<nbPrimitives;j++) {
	bufferMoleculeOrbital.coefficients[j]=WFNmolOrbitalCoef[i][j];
      }
      
      moleculeOrbitals.push_back(bufferMoleculeOrbital);
    }

   /*for(std::vector<moleculeOrbital>::const_iterator it=moleculeOrbitals.begin();it!=moleculeOrbitals.end();it++)
      {
	std::cout << "MO " << it->rank << " " << "OCC " << it->occupancy << std::endl;
	for(unsigned int i=0;i<nbPrimitives;i++){
	  if(i%5==0) std::cout << std::endl;
	  std::cout << it->coefficients[i] << " ";
	}
	std::cout << std::endl;
      }
    */

    /***************************************************************************************************************/

    /* Free the memory */
    free(   ADF_atomOrder);
    free(   ntyp);                             
    free(   nuclab);
    free(   nfrag);
    free(   TMPattype);                                  
    free(   attype);
    
    for (iat=0; iat<(int)nbNuclei;iat++) {
     free(label[iat]);
    }

    free(label);
    free(typecharge);
    free(charge);
    free(coord);

    for (iat=0; iat < (int)nbNuclei; iat++){
       free(WFNcoord[iat]);
    }
    free(WFNcoord);

    free(qcore);
    free(nelecVAL);
    free(   ncos);
    free(nbos);
    free(rkf_primitiveCenters);
    free(rkf_primitiveExponents);
    free(rkf_primitiveTypes);
    free(primitiveNorm);
    free(primkx);
    free(primky);                                                                                             
    free(primkz);                                                                                             
    free(primkr);                                                                                             
    free(primTMPint);                                                                                             
    free(primTMPdouble);
    free(   nbptr);                                                                                             
    free(   kx);                                                                                             
    free(   ky);                                                                                             
    free(   kz);                                                                                             
    free(   kr);                                                                                             
    free(   nqptr);                                                                                             
    free(   alf);                                                                                             
    free(   bnorm);                                                                                             
    free(   npart);                                                                                             
    free(   coeffADFalpha);
    free(   occAlphaVal);
   //MODIF ERIC
   // if (*nspin == 2) 
      free(coeffADFbeta);
      free(   occBetaVal);
      
      for (imo=0; imo<(*rkf_nbOrbitals); imo++) {
	free(molOrbitalCoefbeta[imo]);
      }
      free(molOrbitalCoefbeta);
    //
    free(nspin);
    free(   ccor);                                                                                             
    free(   nrcorb);                                                                                             
    free(   nrcset);                                                                                             
    free(   frozCOREocc); 
    free(   alfcor);                                                                                             
    free(   cornrm);                                                                                             
    free(   nqcor);                                                                                             
    free(   lqcor);                                                                                             
    free(COREWFNprimitiveCenters);
    free(COREWFNprimitiveExponents);
    free(COREWFNprimitiveTypes);
    free(COREWFNprimitiveNorm);
    free(COREWFNprimkr);
    free(COREWFNprimkx);
    free(COREWFNprimky);
    free(COREWFNprimkz);
    
    for (imo=0; imo<nfrozCORE; imo++) {
       free(COREmolOrbitalCoef[imo]);
    }
    free(COREmolOrbitalCoef);

    free(WFNprimitiveCenters);
    free(WFNprimitiveExponents);
    free(WFNprimitiveTypes);
    free(WFNprimitiveNorm);
    free(WFNprimkr);                                                                                             
    free(WFNprimkx);                                                                                             
    free(WFNprimky);                                                                                             
    free(WFNprimkz);                                                                                             
    for (imo=0; imo<WFNnbOrb; imo++) {
       free(WFNmolOrbitalCoef[imo]);
    }
    free(WFNmolOrbitalCoef);
    free(WFNoccupancy);
    for (imo=0; imo<WFNnbOrb; imo++) {
       free(MOdesc[imo]);
    }
    free(MOdesc);

    free(energy);

    for (imo=0; imo<(*rkf_nbOrbitals); imo++) {
      free(molOrbitalCoefalpha[imo]);
    }
    free(molOrbitalCoefalpha);

    free( rkf_nbOrbitals );
} // end of rkf_load_data

unsigned int*
wf_primitive_krs(){
  return primitiveKRs;
} // end of wf_primitive_krs

#endif
