/*
    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.
*/

#ifndef WL_HEADER_H
#define WL_HEADER_H

#define NgridMx (110)
#define IonMx (100)
#define NstatesMx (50)
#define do_recursive 1
#define non_recursive 0
#define do_periodic 1
#define non_periodic 0

#ifndef M_PI
#define M_PI    3.141592653589793238462643
#endif


/* This determines whether or not to use BLAS library for bundle^bundle and
   bundle*matrix multiplications (speeds them up by factor of 6-10)*/
#define blasoptimization
/* Used with "blasoptimization"
   Will allocate the data within the bundle, so that it is contiguous.
   Therefore it is not necessary to make temporary copies to pass to BLAS
   This reduces the memory cost of using BLAS to zero
   Seems to give different /on 10^(-13) level/ result
   for now we will attribute this to rounding errors, and return later
   Can be used as well without blasoptimization, but there won't be any
   gain, (or negligible from faster copying)*/
/* #define newgridtype */
#define bgrid

/*****************************************************************************/
/*                          String constants                                 */
#define Electrons -1
#define Nuclei 1

#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
/* Not using fftw package for now! */
   /* #include "fftw.h" */

/*****************************************************************************/
/*                Special heirarchical structure headers                     */

/* Integer vector struct and NULL instance */		        
struct Ivec {int x,y,z;};
static struct Ivec NULLIVEC={0,0,0};
static struct Ivec ONEIVEC={1,1,1};

/* Double precision vector struct and NULL instance */
struct Dvec{double x,y,z;};
static struct Dvec NULLDVEC={0,0,0};
static struct Dvec ONEDVEC={1.,1.,1.};

/* Gridspec entries */
struct Gridspec
{
  int level; /* scale number: 0, 1, 2, ... */
  struct Ivec org, dim; /* location of origin on parent grid, dimensions */
  struct Dvec scale; /*we use it only for the top level*/
};

/* Ionspec entries */
struct Ionspec
{
  double Z; /* atomic number, double used for simplicity*/
  struct Dvec ionloc; /* location of center of chargedistribution*/
};

/* Bundlespec entries */
struct Bundlespec
{
    double weight;
    double kx,ky,kz; /* probably in lattice coordinates */
};

/*
  The main grid structure
  HIERARCHICAL LINKED LIST:
    The siblings under a given parent form a linked list
    The parent points to one child, the first of the siblings
*/
struct Grid
{

  int level; /* Level of current grid */

  int ifperiodic; /*if we have periodic boundary conditions for this grid*/
    
  struct Ivec org; /* Location of origin of current grid on parent grid */
  struct Ivec dim; /* Dimension of current grid, measured in gridpoints */
  struct Dvec scale;/*Physical distance between gridpoints */
    
  int nxyz;  /*Total # of basisfunctions on current level */
  int nxyzwholegrid;/*Total # of basisfunctions on whole grid */

  double *dat; /* Pointer to origin of current grid's data set */

  struct Grid *parent; /* Pointer to parent, NULL if toplevel */
  struct Grid *sibling; /* Pointer to sibling, NULL if none */
  struct Grid *child; /* Pointer to child, NULL if none */

  struct Grid *cousin; /* ipd: 08/15/01 this one is new */
};

typedef struct {
     double re, im;
} COMPLEX;

/*********** SYMMETRY OPERATIONS *********************/
static int cubemirrors[8][9] =
{ {1,0,0,0,1,0,0,0,1}, {-1,0,0,0,-1,0,0,0,-1},
  {-1,0,0,0,1,0,0,0,1}, {1,0,0,0,-1,0,0,0,1}, {1,0,0,0,1,0,0,0,-1},
  {1,0,0,0,-1,0,0,0,-1},   {-1,0,0,0,1,0,0,0,-1}, {-1,0,0,0,-1,0,0,0,1}};

/* this swaps z<->y and z<->x */
static int permz[3][9] = { {1,0,0,
                            0,1,0,
                            0,0,1},
                           
                           {1,0,0,
                            0,0,1,
                            0,1,0},
                           
                           {0,0,1,
                            0,1,0,
                            1,0,0} };

static int perm[6][9] = { {1,0,0,
                           0,1,0,
                           0,0,1},
                          
                          {1,0,0,
                           0,0,1,
                           0,1,0},
                          
                          {0,0,1,
                           0,1,0,
                           1,0,0},

                          {0,0,1,
                           1,0,0,
                           0,1,0},
                           
                          {0,1,0,
                           1,0,0,
                           0,0,1},

                          {0,1,0,
                           0,0,1,
                           1,0,0} };


/*******Filters*******/
/*  transform coefficients   */

/* Half filter length */
#define HFL_T 3

/* Filters */
  static double tr[3*HFL_T+3]={
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862,
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862,
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862
  };
  static double tf[3*HFL_T+3]={
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862,
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862,
0.129395294634647, -0.224090770298784, -0.836502068418095, -0.483016018290862
  };
  static double ts[3*HFL_T+3]={
    1., 9./16, 0., -1./16.,
    1., 9./16, 0., -1./16.,
    1., 9./16, 0., -1./16.
  };

/***********************************************************************
  SAME AND INTER-LEVEL REALSPACE DERIVS
  ***********************************************************************/
#define HFL_D1 2
  static double D1[3*HFL_D1+3]={
    0., 2./3., -1./12.,
    0., 2./3., -1./12.,
    0., 2./3., -1./12.
  };

#define HFL_D2 5
  static double D2[3*HFL_D2+3]={
    0., 59./48., 2./3., -3./32., -1./12., 1./96,
    0., 59./48., 2./3., -3./32., -1./12., 1./96,
    0., 59./48., 2./3., -3./32., -1./12., 1./96
  };

#define HFL_T2 5
  static double T2[3*HFL_T2+3]={
    1.,  9./16.,    0., -1./16.,      0.,     0.,
    1.,  9./16.,    0., -1./16.,      0.,     0.,
    1.,  9./16.,    0., -1./16.,      0.,     0.
  };


/***********************************************************************
  ONE-LEVEL 1ST DERIVATIVE (COEFFICIENT SPACE)
  ***********************************************************************/
#define HFL_cD1 5

static double cD1l_r[HFL_cD1+1] = {
  1.000000 , 0.84652586974116461604, -0.14404040593663738901,
  0.00887027077449399973, -0.00056565321940365816, -0.00000219967169923205
};

static double cD1l_f[HFL_cD1+1] = {
  -0.68334129299898160870, 0.78821650361194905976, -0.11132166398909433547,
  0.00683148445195957098, -0.00038352794932999476, -0.00000150312650312650
};

/* full filter is ANTI-symmetric! -- mhe 4/10/02 */
/***********************************************************************
 *****                         WARNING!!!                          *****
 ***********************************************************************
 ***** If the first element of the full filter (*_s) is non-zero,  *****
 ***** then the filter is assumed to be SYMMETRIC.  If the first   *****
 ***** element is zero, then it is assumed to be ANTISYMMETRIC.    *****
 ***** If this is not the case for any future filters, then a more *****
 ***** sophisticated method to handle symmetry must be introduced  *****
 ***** in the convolution routines (convsets.f and conv3d.c).      *****
 *****     mhe  4/12/02                                            *****
 ***********************************************************************/
static double cD1l_s[3*HFL_cD1+3] = {
  0.000000, -0.692992424242424,  0.105483405483405,
  -0.006507034632035, 0.000384800384800,  0.000001503126503,

  0.000000, -0.692992424242424,  0.105483405483405,
  -0.006507034632035, 0.000384800384800,  0.000001503126503,

  0.000000, -0.692992424242424,  0.105483405483405,
  -0.006507034632035, 0.000384800384800,  0.000001503126503
};

/***********************************************************************
  TWO-LEVEL 1ST DERIVATIVE
  ***********************************************************************/
#define HFL_cD2 8

static double cD2l_r[HFL_cD2+1] = {
  1.59625644241902e-01, 4.11372633189919e-01, 2.84767521688483e-01,
  -1.85156725942224e-02, -4.44402492760929e-02, 6.65079937545460e-03,
  -4.21254645598003e-04, 2.39958072928182e-05, 9.39454064454064e-08
};

static double cD2l_f[HFL_cD2+1] = {
  1.000000000000000000000, 0.577109187742762874684, -1.370247072542784882998,
  -0.529718767122747458131, 0.367310384066273809545, -0.047242485150815187456,
  0.002938489987528746569, -0.000149148444416791930, -0.000000588535801321720
};


/* full filter is ANTI-symmetric! -- mhe 4/11/02 */
/***********************************************************************
 *****                         WARNING!!!                          *****
 ***********************************************************************
 ***** If the first element of the full filter (*_s) is non-zero,  *****
 ***** then the filter is assumed to be SYMMETRIC.  If the first   *****
 ***** element is zero, then it is assumed to be ANTISYMMETRIC.    *****
 ***** If this is not the case for any future filters, then a more *****
 ***** sophisticated method to handle symmetry must be introduced  *****
 ***** in the convolution routines (convsets.f and conv3d.c).      *****
 *****     mhe  4/12/02                                            *****
 ***********************************************************************/
static double cD2l_s[3*HFL_cD2+3] = {
  0.000000, 6.27089345839346e-01, 3.31297160594036e-01,
  -5.30438311688312e-02, -4.00374654280904e-02, 6.37475949975950e-03,
  -4.07535173160173e-04, 2.40500240500240e-05, 9.39454064454064e-08,

  0.000000, 6.27089345839346e-01, 3.31297160594036e-01,
  -5.30438311688312e-02, -4.00374654280904e-02, 6.37475949975950e-03,
  -4.07535173160173e-04, 2.40500240500240e-05, 9.39454064454064e-08,

  0.000000, 6.27089345839346e-01, 3.31297160594036e-01,
  -5.30438311688312e-02, -4.00374654280904e-02, 6.37475949975950e-03,
  -4.07535173160173e-04, 2.40500240500240e-05, 9.39454064454064e-08
};


/***********************************************************************
  SAME LEVEL OVERLAP
  ***********************************************************************/

/* Half filter length */
#define HFL_O1 5

/* Filters */
static double O1l_r[3*HFL_O1+3]={
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0 */
0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365,

0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365,

0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365
};

static double O1l_f[3*HFL_O1+3]={
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0 */
0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365,

0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365,

0.878415112987383284171, 0.164893467575274982329, -0.046420232260384455825,
0.003198222605186628806,-0.000086402091480004050, -0.000000168815978735365
};

static double O1l_s[3*HFL_O1+3]={
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0, */
/*  1,0,0,0,0,0 */
56264./70245., 19253./140490., -2827./70245., 6283./2247840., -16./210735., -1./6743520.,
56264./70245., 19253./140490., -2827./70245., 6283./2247840., -16./210735., -1./6743520.,
56264./70245., 19253./140490., -2827./70245., 6283./2247840., -16./210735., -1./6743520.
};

/***********************************************************************
  TWO LEVEL OVERLAP
  ***********************************************************************/

/* Half filter length */
#define HFL_O2 8

static double O2l_r[3*HFL_O2+3]={
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0 */
  1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
  -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
  -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,

   1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
   -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
   -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,

   1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
   -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
   -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,
};

static double O2l_f[3*HFL_O2+3]={
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0 */
  1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
  -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
  -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,

   1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
   -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
   -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,

   1.13662782356529e-01,   -1.75508280491205e-01,   -7.77753722740183e-01,
   -5.51406116416050e-01,   -4.15434380393901e-02,    1.97657359972897e-02,
   -1.47247939002369e-03,    4.18748091140685e-05,    8.15408218726308e-08,
};

static double O2l_s[3*HFL_O2+3]={
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0, */
/*  1,0,0,0,0,0,0,0,0 */
  9.54790654583956e-01,  5.67468621728711e-01,  2.98483025185660e-02,
  -6.99458146487295e-02, -7.06886017984673e-03,  2.47244762379292e-03,
  -1.74778898854011e-04,  4.74529622511685e-06,  9.26815668968135e-09,

  9.54790654583956e-01,  5.67468621728711e-01,  2.98483025185660e-02,
  -6.99458146487295e-02, -7.06886017984673e-03,  2.47244762379292e-03,
  -1.74778898854011e-04,  4.74529622511685e-06,  9.26815668968135e-09,

  9.54790654583956e-01,  5.67468621728711e-01,  2.98483025185660e-02,
  -6.99458146487295e-02, -7.06886017984673e-03,  2.47244762379292e-03,
  -1.74778898854011e-04,  4.74529622511685e-06,  9.26815668968135e-09
};

/***********************************************************************
  SAME LEVEL LAPLACIAN
  ***********************************************************************/

/* Half filter length */
#define HFL_L1 5

/* Filters */

/*Reverse L same level coefficients*/
static double L1l_r[HFL_L1+1]={
-1.04039590743973487e+00,1.06744216108503376e+00,-1.36966571728440022e-02,
-1.33496189186936131e-02,0,0};

/*Forward L same level coefficients*/
static double L1l_f[HFL_L1+1]={
1.04039590743973509e+00,-1.06744216108503398e+00,1.36966571728440057e-02,
1.33496189186936166e-02,0,0};

static double L1l_s[3*HFL_L1+3]={
  -20./9. , 9./8. , 0. , -1./72. , 0 , 0,
  
  -20./9. , 9./8. , 0. , -1./72. , 0 , 0,
  
  -20./9. , 9./8. , 0. , -1./72. , 0 , 0 };


/***********************************************************************
  TWO LEVEL LAPLACIAN, Torkel's version
  ***********************************************************************/

/* Half filter length */
#define HFL_L2 8

/*Reverse L 2 level coefficients*/
static double L2l_r[HFL_L2+1]={
  -5.02498209110489369e-01,-3.54740061132689077e-01,6.53137641542942293e-01,
  3.55959577521140436e-01,-1.52366922052336429e-01,-1.21951942094572778e-03,
  1.72747989906715154e-03,0,0};


/*Forward L 2 level coefficients*/
static double L2l_f[HFL_L2+1]={
5.02498209110489147e-01,3.54740061132688966e-01,-6.53137641542942071e-01,
-3.55959577521140325e-01,1.52366922052336373e-01,1.21951942094572735e-03,
-1.72747989906715089e-03,0,0};

/*Full L 2 level coefficients*/
static double L2l_s[3*HFL_L2+3]={
  -0.95486111111110, -0.125, 0.5546875, 0.125, -0.078125, 0. , 
  0.00086805555556, 0. , 0. ,

  -0.95486111111110, -0.125, 0.5546875, 0.125, -0.078125, 0. , 
  0.00086805555556, 0. , 0. ,

  -0.95486111111110, -0.125, 0.5546875, 0.125, -0.078125, 0. , 
  0.00086805555556, 0. , 0. };


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

/*****************************************************************************/
/*                    Heirarchical subroutine headers                        */
struct Grid *
mkgrid(struct Gridspec *spec,struct Grid  *parent);

struct Grid *
mkgridnew(struct Gridspec *spec,struct Grid *parent);

struct Grid *
mkbgrid(struct Gridspec *spec,struct Grid  *parent, double **ppdata);

struct Grid *
mkgridfromgrid(struct Grid *ingrid,struct Grid *parent);

struct Grid *
mkgridfromgridnew(struct Grid *ingrid,struct Grid *parent);

struct Grid *
mkexpgridfromgrid(struct Grid *ingrid, struct Grid *parent,
			       int padx, int pady, int padz);

struct Grid *
mkbgridfromgrid(struct Grid *ingrid,struct Grid *parent, double **ppdata);

void killgrid(struct Grid *ingrid);


void killgridnew(struct Grid *ingrid);

void killbgrid(struct Grid *ingrid);

void copygridtoarray(double **outarray,struct Grid *ingrid);


void copyarraytogrid(struct Grid *outgrid,double **inarray);

void print3d(FILE *fp,double *out,int nx,int ny,int nz);

void printgrid(FILE *fp,struct Grid *self);

void radialprintgrid(FILE *fp,struct Grid *self,struct Dvec porg);

void printgridstruct(FILE *fp,struct Grid *self);

void getgridsizemx(struct Grid *self,struct Ivec *mx);

void setnewparent(struct Grid *self,struct Ivec org, struct Grid *newparent);
void evalgrid(struct Grid *self, struct Dvec porg,
              double func(struct Dvec) );
void evalgrid_periodic(struct Grid *self, struct Dvec porg,
                       struct Dvec R, double func(struct Dvec) );

void evalgrid_param(struct Grid *self, struct Dvec param, struct Dvec porg,
                    double func(struct Dvec, struct Dvec) );


void evalgridgen(struct Grid *self, struct Dvec porg, double func(struct Dvec) );
/*  evalgridgen(struct Grid *self,  */
/*  	    struct Dvec scl, struct Dvec porg, */
/*  	    int int1, */
/*  	    double func(struct Dvec, int) ); */

void evalgridpad(struct Grid *self, struct Dvec porg, struct Dvec top,
            int pad,  double func(struct Dvec) );

double sumgrid(struct Grid *ingrid);

void outputfromcenter(struct Grid *ingrid);

void outputplane(struct Grid *ingrid, int recursion);

void evalnucpot(struct Grid *self, struct Dvec porg, struct Dvec top, 
                int pad, double Z);

void getquotient(struct Grid *q, struct Grid *in);

void gridsub_level(struct Grid *diff,struct Grid *in1,struct Grid *in2);

void killgrid_level(struct Grid *ingrid);


/* OPERATORS */


void I(struct Grid *self,double *work,double *work_extra,int lwork);
void I_S2D(struct Grid *outre, struct Grid *outim,
           struct Grid *inre, struct Grid *inim , struct Dvec kvec,
           double *work,double *work_extra,int lwork);

void Idag_D2S(struct Grid *outre, struct Grid *outim,
              struct Grid *inre, struct Grid *inim , struct Dvec kvec,
              double *work,double *work_extra,int lwork);

void 
Idag(struct Grid *self,double *work,double *work_extra,int lwork);

void 
J(struct Grid *self,double *work,double *work_extra,int lwork);

void 
Jdag(struct Grid *self,double *work,double *work_extra,int lwork);



double griddot(struct Grid *self1,struct Grid *self2);

#ifdef newgridtype
extern void 
gridsubnew(struct Grid *out,struct Grid *in1, struct Grid *in2);
#else
extern void 
gridsub(struct Grid *out,struct Grid *in1, struct Grid *in2);
#endif

#ifdef newgridtype
extern void 
gridaddnew(struct Grid *out,struct Grid *in1, struct Grid *in2);
#else
extern void 
gridadd(struct Grid *out,struct Grid *in1, struct Grid *in2);
#endif

extern void gridaccum(struct Grid *out, struct Grid *in);


#ifdef newgridtype
extern void 
gridptmulnew(struct Grid *out,struct Grid *in1,struct Grid *in2);
extern void
gridptmulteqnew(struct Grid *out,struct Grid *in);
#else
extern void 
gridptmult(struct Grid *out,struct Grid *in1, struct Grid *in2);
extern void
gridptmulteq(struct Grid *out,struct Grid *in);
#endif

#ifdef newgridtype
extern double 
gridcarrotnew(struct Grid *in1, struct Grid *in2);
#else
extern double 
gridcarrot(struct Grid *in1, struct Grid *in2);
#endif

#ifdef newgridtype
extern double 
gridcarrotsimple(struct Grid *in1, struct Grid *in2);
#else
extern double 
gridcarrotsimple(struct Grid *in1, struct Grid *in2);
#endif


extern void
map_rg_2_2x_rg(struct Grid *dense, struct Grid *sparse);
extern void
map_2x_rg_2_rg(struct Grid *sparse, struct Grid *dense);


#ifdef newgridtype
void 
projectoutgridnew(struct Grid *main, struct Grid *in1, double coeff);
#else
void 
projectoutgrid(struct Grid *main, struct Grid *in1, double coeff);
#endif

extern void scalareqself(struct Grid *self, double d);

#ifdef newgridtype
extern void 
scalarmultnew(struct Grid *out,double op2, struct Grid *in);
#else
extern void 
scalarmult(struct Grid *out,double op2, struct Grid *in);
#endif

extern void scalarmultself(struct Grid *self, double d);

extern void scalarmultadd(struct Grid *out,double op2, struct Grid *in);

extern void scalarmultsubtract(struct Grid *out,double op2, struct Grid *in);
#ifdef newgridtype
extern void 
scalarmultcumnew(struct Grid *out,double op2, struct Grid *in);
#else
extern void 
scalarmultcum(struct Grid *out,double op2, struct Grid *in);
#endif


double gridsum(struct Grid *self, int displayeachlevel);

double gridsumabs(struct Grid *self, int displayeachlevel);

void gridghost(struct Grid *self);

double gauss(struct Dvec r);

double atomic_psi(struct Dvec relcord);
/*  atomic_psi(struct Dvec relcord,int state); */

double s1(struct Dvec r);

double Z1V(struct Dvec r);

double one(struct Dvec r);

double zero(struct Dvec r);

double nucpot(struct Dvec r, double z);

double rnd(struct Dvec r);

double SHO(struct Dvec in);

void readfromfile(FILE *fpi,struct Grid *ingrid);

void writetofile(FILE *fpi,struct Grid *ingrid);

void readfromfilebin(char *fname, double *data, int totdat);

void writetofilebin(char *fname, double *data, int totdat);

void writegrid(char *filename,struct Grid *self);

double gridckghosts(struct Grid *self,int ghost);

double multi(struct Dvec r);

double multi2(struct Dvec r);

double rnd(struct Dvec r);

void readgridspec(FILE *fp,struct Gridspec spec[]);

void readionloc(FILE *fp,struct Ionspec spec[]);

void abs2(struct Grid *, struct Grid *);

double ckconsist(double *upper,double *lower,int nux,int nuy,int nuz,
	  int nlx,int nly,int nlz,int czflag);

void consist(double *upper,double *lower,int nux,int nuy,int nuz,
	int nlx,int nly,int nlz,int czflag);

void putzerosbelow(struct Grid *ingrid, int boundary);

void zeroghost(struct Grid *ingrid);

void zeroghostrec(struct Grid *ingrid);

void outputgridstruct(struct Grid *ingrid);

void outputgridstructx(struct Grid *ingrid);

void outputgridstructy(struct Grid *ingrid);

void outputmem(double *indat, int nlx, int nly, int nlz,
	  int i, int j, int k,int direction);

void copygrid(struct Grid *out,struct Grid *in);

void copygridnew(struct Grid *out,struct Grid *in);

void copyarrayred(double *out,double *in,int nxout, int nyout, int nzout,
	     int nxin, int nyin, int nzin,int padx, int pady, int padz);

void copyarrayexp(double *out,double *in,int nxout, int nyout, int nzout,
	     int nxin, int nyin, int nzin, int padx, int pady, int padz,
	     int mode);
void copyarray(double *out,double *in, int length);


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

void aconvP3d(double upper[], double lower[], int sign,double tr[], double tf[],
	 double ts[],int nux, int nuy, int nuz,int nlx, int nly, int nlz,
	 int hfl,double work[],double work_extra[]);



void aconvP3dadd(double upper[], double lower[], double addon[],
	    double revfilt[], double forwfilt[], double fullfilt[],
	    int nux, int nuy, int nuz,
	    int nlx, int nly, int nlz,int hfl, 
	    double work[],double work_extra[]);

void conv3d(double datout[], double *reversefilter, double *forwardfilter,
       double *fullfilter,
       int nx, int ny, int nz, 
       int npx, int npy, int npz,
       int hfl);


void conv3dnew(double datin[],double datout[],int ifcum,int periodic,
	  double *reversefilter, double *forwardfilter, double *fullfilter,
	  int nlx, int nly, int nlz, 
	  int hfl, double work[], double work_extra[]);

void aPconv3d(double upper[], double lower[], int sign,
	 double reversefilter[], double forwardfilter[], 
	 double fullfilter[],
	 int nux, int nuy, int nuz,
	 int nlx, int nly, int nlz,
	 int hfl,
	 double work[],
	 double work_extra[]);


/*****************************************************************************/
/*                    Headers for multilevelop                               */
void Oabovesimple( struct Grid *self, double *workspace1,double *workspace2, 
	      double forwardfilter[],double reversefilter[],
	      double fullfilter[]);

void Oabovenew( struct Grid *out,struct Grid *in,int sign,
                double forwardfilter[],double reversefilter[],double fullfilter[],
                struct Grid *workgrid,double *workspace1,double *workspace2);

void Osame(struct Grid *self,double *workspace1,double *workspace2);

void Osamenew(struct Grid *out, struct Grid *self, int sign,
              double forwardfilter[],double reversefilter[],
              double fullfilter[],double *workspace1,double *workspace2);

void Obelowsimple( struct Grid *self, double *workspace,double *workspace2,
                   double forwardfilter[],double reversefilter[],
                   double fullfilter[]);

void Obelownew( struct Grid *out,struct Grid *self,int sign,
                double forwardfilter[],double reversefilter[],
                double fullfilter[],double *workspace1,double *workspace2);

void O( struct Grid *out,struct Grid *in,double O1lf[],double O1lr[],
        double O1lfull[],double O2lf[],double O2lr[],double O2lfull[],
        struct Grid *workgrid,double *workspace1,double *workspace2);

void Labovenew( struct Grid *out,struct Grid *in,int sign,
                double forwardfilter[],double reversefilter[],
                double fullfilter[],struct Grid *workgrid, 
                double *workspace1,double *workspace2);

void Lsamenew(struct Grid *out, struct Grid *self, int sign,
              double forwardfilter[],double reversefilter[],
              double fullfilter[],double *workspace1,
              double *workspace2);

void Lbelownew( struct Grid *out,struct Grid *self,int sign,
                double forwardfilter[],double reversefilter[],
                double fullfilter[],double *workspace1,double *workspace2);

void L( struct Grid *out,struct Grid *in,double L1lf[], double L1lr[],
        double L1lfull[],double L2lf[],double L2lr[],double L2lfull[],
        struct Grid *workgrid,double *workspace,double *workspace2);


void D(int d, struct Grid *out,struct Grid *in,
       struct Grid *work,double *work1,double *work2,int lwork);

void Ddag(int d, struct Grid *out,struct Grid *in,
          struct Grid *work,double *work1,double *work2,int lwork);

void cD( struct Grid *out, struct Grid *in,
         double D1lf[], double D1lr[], double D1lfull[],
         double D2lf[], double D2lr[], double D2lfull[],
         struct Grid *workgrid,double *workspace1, double *workspace2, 
         int dir1, int dir2 );


/************************************************************/
/*             in invC.c                                    */

void invCcomplex(COMPLEX *matout,COMPLEX *matin,int n, int m);

void invC(double *matout,double *matin,int n, int m);

void diagdoubleC(double *eigs,double *evecs,double *a,int n);

void diagcomplexC(double *eigs, COMPLEX *evecs, COMPLEX *a, int n);

void adjustdown(struct Grid *in);



double totcharge(struct Grid *ingrid);


void getcubesym48(int symgroup[48][9]);

void setsymzero(struct Grid *self);

void symmetrize_accum(struct Grid* out, struct Grid* in,
                      int* symop, struct Ivec Rsym);

void expandgridspec2x(struct Gridspec  out[],struct Gridspec spec[]);

#endif /* WL_HEADER_H */
