/*
    DFT++ is a density functional package developed by the research group
    of Professor Tomas Arias

    Copyright 1996-2003 Sohrab Ismail-Beigi

    This file is part of DFT++.

    DFT++ is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    DFT++ is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with DFT++; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    Please see the file CREDITS for a list of authors.

    For academic users, we request that publications using results obtained with
    this software reference

    "New algebraic formulation of density functional calculation," by Sohrab Ismail-Beigi
    and T.A. Arias, Computer Physics Communications 128:1-2, 1-45 (June 2000).

    and, if using the wavelet basis, further reference

    "Multiresolution analysis of electronic structure: semicardinal and wavelet bases,"
    T.A. Arias, Reviews of Modern Physics 71:1, 267-311 (January 1999).

    and 

    "Robust ab initio calculation of condensed matter: transparent convergence through
    semicardinal multiresolution analysis,'' I.P. Daykov, T.A. Arias, and
    Torkel D. Engeness, Physical Review Letters, 90:21, 216402 (May 2003).

    For your convenience, preprints of the above articles may be obtained from
    http://arXiv.org/abs/cond-mat/9909130, 9805262, and 0204411, respectively.
*/

#include "header.h"

// constructor
Ioninfo::Ioninfo()
{
  nspecies = 0;
  species = NULL;
  read_vloc_flag = FALSE;
}

Ioninfo::~Ioninfo()
{
  if (nspecies>0)
    {
      for (int sp=0; sp < nspecies; sp++)
	species[sp].Speciesinfo::~Speciesinfo();
      myfree(species);
    }
}

//
// Do the setup for the ionic information (read psps, alloc space, blah blah)
// 
void
Ioninfo::setup(Everything &e)
{
  dft_log("----- Ioninfo::setup() -----\n");

  // Call the species setup routines
  for (int sp=0; sp < e.ioninfo.nspecies; sp++)
    e.ioninfo.species[sp].setup(e);

  // Check atomic positions for problems
  check_pos();

  // Print out the internals of Ioninfo structure to the log file
  dft_log("\n");
  print(dft_global_log, e);
  dft_log("\n");
}

// Print internal info for each species
void Ioninfo::print(Output *out, Everything &e)
{
  out->printf("Displaying Ioninfo contents:\n");
  out->printf("Found %d species:\n",nspecies);
  for (int sp = 0; sp < nspecies; sp++)
    species[sp].print(out, e);
}


/*
 * Make sure no atoms are layed on top of each other.
 */
void Ioninfo::check_pos()
{
  int dieflag = 0;
  real sizetest = 0;
  vector3 vtest[2];

  for (int sp=0; sp < nspecies; sp++)
    for (int n=0; n < species[sp].natoms; n++) {
      vtest[0] = species[sp].atpos[n];
      for (int sp1 = sp; sp1 < nspecies; sp1++)
	for (int n1 = ((sp1==sp) ? (n+1) : 0);
	     n1 < species[sp1].natoms; n1++) {
	  vtest[1] = vtest[0] - species[sp1].atpos[n1];
	  sizetest = vtest[1] * vtest[1];
	  if (sizetest < MIN_ION_DISTANCE) {
	    dieflag = 1;
	    dft_log(">>Atoms' positions coincide!!\n");
	    dft_log(">>(sp %d : at %d) = (sp %d : at %d) : ",
		       sp, n, sp1, n1);
	    species[sp].atpos[n].print(dft_global_log," %f ");
	  }
	}
    }

  if(dieflag != 0)
    die(">> You put atoms on top of each other, moron. I have to quit now. Bye\n");
}


int Ioninfo::symmetrize_force(const Symmetries &symm)
{
  if (symm.nrot <= 1) // no need to do any symmetrization
    return 0;

  // for each atom, each symmetry maps it to one of its own species.

  for (int sp = 0; sp < nspecies; sp++)
    {
      vector3 *forces_tmp;
      int iat;

      int natoms = species[sp].natoms;
      vector3 *forces = species[sp].forces;
      forces_tmp = (vector3*)mymalloc(sizeof(vector3)*natoms,
				      "forces_tmp",
				      "symmetrize_force");
      for (iat = 0; iat < natoms; iat++)
	forces_tmp[iat] = 0;
      for (iat = 0; iat < natoms; iat++)
	for (int irot = 0; irot < symm.nrot; irot++)
	  forces_tmp[symm.maps[sp][irot][iat]] +=
	                      symm.f_sym[irot] * forces[iat];
      for (iat = 0; iat < natoms; iat++)
	forces[iat] = forces_tmp[iat] / symm.nrot;
      myfree(forces_tmp);
    }
  return 1;

}

void Ioninfo::print_force(const Output *out, Everything &e) const
{
  for (int sp=0; sp < nspecies; sp++)
    species[sp].print_force(out, e);
}
