/* Copyright (c) 2015  Gerald Knizia
 * 
 * This file is part of the IboView program (see: http://www.iboview.org)
 * 
 * IboView 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, version 3.
 * 
 * IboView 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 details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with bfint (LICENSE). If not, see http://www.gnu.org/licenses/
 * 
 * Please see IboView documentation in README.txt for:
 * -- A list of included external software and their licenses. The included
 *    external software's copyright is not touched by this agreement.
 * -- Notes on re-distribution and contributions to/further development of
 *    the IboView software
 */

#ifndef _CT_DFTGRID_H
#define _CT_DFTGRID_H

#include <vector>
#include "CxVec3.h"
#include "CxPodArray.h"
#include "CxFortranInt.h"
#include "CtIo.h"

namespace ct {

typedef double
   FScalar;
typedef TVector3<FScalar>
   FVector3;

struct FDftGridParams
{
   double nLevel;
   bool AdjustByAtomicRadii;
   uint iMinL; // minimum L which this grid should expand exactly.

   explicit FDftGridParams( uint iLevel_ = 3, int iMinL_=0, bool AdjustByAtomicRadii_ = true )
      : nLevel(iLevel_), AdjustByAtomicRadii(AdjustByAtomicRadii_), iMinL(iMinL_)
   {};

   double fTargetAccuracy() const;
   void SetTargetAccuracy(double fAcc);
};

struct FAtomSet;

// 3d DFT integration grid, based on atom positions
struct FDftGrid : public FIntrusivePtrDest
{
   struct FPoint{
      FVector3
         vPos;
      FScalar
         fWeight;
      ptrdiff_t
         iAtomicCenter;
   };

   typedef std::vector<FPoint>
      FPointList;
   FPointList
      // \sum_p p.fWeight integrates to total volume.
      Points;

   struct FGridBlock {
      size_t
         iFirst, iLast; // grid block spans points [iFirst,iLast).
      FVector3
         // average of spanned points
         vCenter;
      FScalar
         // radius around vCenter such that all points spanned by
         // the block lie inside the sphere of fRadius around vCenter.
         fRadius,
         // largest weight of any point within the block.
         fLargestWeight;
      ptrdiff_t
         // atom with which the grid point moves. -1 if not moving with a center.
         iAtomicCenter;
      size_t nPt() const { return iLast - iFirst; }
   };
   typedef std::vector<FGridBlock>
      FGridBlockList;
   FGridBlockList
      GridBlocks;

   FDftGrid( FAtomSet const &Atoms, FDftGridParams const &Params, FLog *pLog = 0 );
   ~FDftGrid();

   // data in compatibility format -- DFTI-CXX expects positions and
   // weights as separate entities.
   TArray<double[3]>
      Positions;
   TArray<double>
      Weights;

private:
   // copy stuff from this->Points to this->Positions and this->Weights.
   void MakeAdditionalRepresentations();
};

typedef boost::intrusive_ptr<FDftGrid>
   FDftGridPtr;


} // namespace ct

#endif // CT_DFTGRID_H
