/**
 *  @ingroup PMGC
 *  @author  Tucker Beck [fortran ->c translation], Michael Holst [original]
 *  @brief Multigrid subroutines
 *  @version $Id:
 *
 *  @attention
 *  @verbatim
 *
 * APBS -- Adaptive Poisson-Boltzmann Solver
 *
 * Nathan A. Baker (nathan.baker@pnl.gov)
 * Pacific Northwest National Laboratory
 *
 * Additional contributing authors listed in the code documentation.
 *
 * Copyright (c) 2010-2020 Battelle Memorial Institute. Developed at the Pacific Northwest National Laboratory, operated by Battelle Memorial Institute, Pacific Northwest Division for the U.S. Department Energy.  Portions Copyright (c) 2002-2010, Washington University in St. Louis.  Portions Copyright (c) 2002-2010, Nathan A. Baker.  Portions Copyright (c) 1999-2002, The Regents of the University of California. Portions Copyright (c) 1995, Michael Holst.
 * All rights reserved.
 *
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * -  Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 *
 * - Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * - Neither the name of Washington University in St. Louis nor the names of its
 * contributors may be used to endorse or promote products derived from this
 * software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * @endverbatim
 */

#ifndef _MGSUBD_H_
#define _MGSUBD_H_

#include "apbscfg.h"

#include "maloc/maloc.h"

#include "generic/vhal.h"
#include "generic/vmatrix.h"
#include "pmgc/matvecd.h"
#include "pmgc/buildAd.h"
#include "pmgc/buildPd.h"
#include "pmgc/buildBd.h"
#include "pmgc/buildGd.h"

#define HARMO2(a, b)                   (2.0 * (a) * (b) / ((a) + (b)))
#define HARMO4(a, b, c, d)             (1.0 / ( 0.25 * ( 1.0/(a) + 1.0/(b) + 1.0/(c) + 1.0/(d))))
#define ARITH2(a, b)                   (((a) + (b)) / 2.0)
#define ARITH4(a, b, c, d)             (((a) + (b) + (c) + (d)) / 4.0)
#define ARITH6(a, b, c, d, e, f)       (((a) + (b) + (c) + (d) + (e) + (f)) / 6.0)
#define ARITH8(a, b, c, d, e, f, g, h) (((a) + (b) + (c) + (d) + (e) + (f) + (g) + (h)) / 8.0)

/** @brief   Build operators, boundary arrays, modify affine vectors
 *             ido==0: do only fine level
 *             ido==1: do only coarse levels (including second op at coarsest)
 *             ido==2: do all levels
 *             ido==3: rebuild the second operator at the coarsest level
 *
 *  @note    The fine level must be build before any coarse levels.
 *  @ingroup PMGC
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *
 *  Replaces buildops from mgsubd.f
 */
VEXTERNC void Vbuildops(
        int    *nx,     ///< @todo: doc
        int    *ny,     ///< @todo: doc
        int    *nz,     ///< @todo: doc
        int    *nlev,   ///< @todo: doc
        int    *ipkey,  ///< @todo: doc
        int    *iinfo,  ///< @todo: doc
        int    *ido,    ///< @todo: doc
        int    *iz,     ///< @todo: doc
        int    *mgprol, ///< @todo: doc
        int    *mgcoar, ///< @todo: doc
        int    *mgsolv, ///< @todo: doc
        int    *mgdisc, ///< @todo: doc
        int    *ipc,    ///< @todo: doc
        double *rpc,    ///< @todo: doc
        double *pc,     ///< @todo: doc
        double *ac,     ///< @todo: doc
        double *cc,     ///< @todo: doc
        double *fc,     ///< @todo: doc
        double *xf,     ///< @todo: doc
        double *yf,     ///< @todo: doc
        double *zf,     ///< @todo: doc
        double *gxcf,   ///< @todo: doc
        double *gycf,   ///< @todo: doc
        double *gzcf,   ///< @todo: doc
        double *a1cf,   ///< @todo: doc
        double *a2cf,   ///< @todo: doc
        double *a3cf,   ///< @todo: doc
        double *ccf,    ///< @todo: doc
        double *fcf,    ///< @todo: doc
        double *tcf     ///< @todo: doc
        );

/** @brief   Build the nexted operator framework in the array iz
 *  @note    iz(50,i) indexes into the gridfcn arrays
 *           for each level i=(1,...,nlev+1) as follows:
 *
 *           fun(i)    = fun (iz(1,i))
 *           bndx(i)   = bndx(iz(2,i))
 *           bndy(i)   = bndy(iz(3,i))
 *           bndz(i)   = bndz(iz(4,i))
 *           ipc(i)    = ipc(iz(5,i))
 *           rpc(i)    = rpc(iz(6,i))
 *           oper(i)   = oper(iz(7,i))
 *           grdx(i)   = brdx(iz(8,i))
 *           grdy(i)   = brdy(iz(9,i))
 *           grdz(i)   = brdz(iz(10,i))
 *
 *  @ingroup PMGC
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces buildstr from mgsubd.f
 */
VEXTERNC void Vbuildstr(
        int *nx,   ///< @todo  Document
        int *ny,   ///< @todo  Document
        int *nz,   ///< @todo  Document
        int *nlev, ///< @todo  Document
        int *iz    ///< @todo  Document
        );

/** @brief   Form the Galerkin coarse grid system
 *  @note    Although the fine grid matrix may be 7 or 27 diagonal,
 *           the coarse grid matrix is always 27 diagonal.
 *           (only 14 stored due to symmetry.)
 *  @ingroup PMGC
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces buildgaler0 from mgsubd.f
 */
VEXTERNC void Vbuildgaler0(
        int    *nxf,    ///< @todo: doc
        int    *nyf,    ///< @todo: doc
        int    *nzf,    ///< @todo: doc
        int    *nxc,    ///< @todo: doc
        int    *nyc,    ///< @todo: doc
        int    *nzc,    ///< @todo: doc
        int    *ipkey,  ///< @todo: doc
        int    *numdia, ///< @todo: doc
        double *pcFF,   ///< @todo: doc
        int    *ipcFF,  ///< @todo: doc
        double *rpcFF,  ///< @todo: doc
        double *acFF,   ///< @todo: doc
        double *ccFF,   ///< @todo: doc
        double *fcFF,   ///< @todo: doc
        int    *ipc,    ///< @todo: doc
        double *rpc,    ///< @todo: doc
        double *ac,     ///< @todo: doc
        double *cc,     ///< @todo: doc
        double *fc      ///< @todo: doc
        );



/** @brief   Coarsen a grid
 *           Compute the number of grid points in the coarser grid, given the
 *           number of grid points in a finger grid in each direction.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces mkcors from mgsubd.f
 */
VEXTERNC void Vmkcors(
        int *numlev, ///< @todo: doc
        int *nxold,  ///< @todo: doc
        int *nyold,  ///< @todo: doc
        int *nzold,  ///< @todo: doc
        int *nxnew,  ///< @todo: doc
        int *nynew,  ///< @todo: doc
        int *nznew   ///< @todo: doc
        );

/** @brief   Coarsen a grid
 *           Compute the number of grid points in the coarser grid, given the
 *           number of grid points in a finger grid in each direction.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces mkcors from mgsubd.f
 */
VEXTERNC void Vcorsr(
        int *nold, ///< @todo: doc
        int *nnew  ///< @todo: doc
        );



/** @brief   Refine a grid
 *           Compute the number of grid points in the finer grid, given the
 *           number of grid points in a coarser grid in each direction.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces mkfine from mgsubd.f
 */
VEXTERNC void Vmkfine(
        int *numlev, ///< @todo: doc
        int *nxold,  ///< @todo: doc
        int *nyold,  ///< @todo: doc
        int *nzold,  ///< @todo: doc
        int *nxnew,  ///< @todo: doc
        int *nynew,  ///< @todo: doc
        int *nznew   ///< @todo: doc
        );

/** @brief   Refine a grid
 *           Compute the number of grid points in the finer grid, given the
 *           number of grid points in a coarser grid.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces mkfine from mgsubd.f
 */
VEXTERNC void Vfiner(
        int *nold, ///< @todo: doc
        int *nnew  ///< @todo: doc
        );



/** @brief   Coarsen a single dimension of a grid
 *           Compute the number of grid points in the coarser grid, given the
 *           number of grid points in a finer grid.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces corsr from mgsubd.f
 */
VEXTERNC int Vivariv(
        int *nu,   ///< @todo: doc
        int *level ///< @todo: doc
        );

/** @brief   Find maximum multigrid possible coarsenning
 *           common to three grid sizes
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces maxlev from mgsubd.f
 */
VEXTERNC int Vmaxlev(
        int n1, ///< The first grid size
        int n2, ///< The second grid size
        int n3  ///< The third grid size
        );


/// @todo  Get rid of these globals in refactor
double bf, oh, cputme;

/** @brief   This routine prints out some info and such from inside multigrid.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces prtstp from mgsubd.f
 */
VEXTERNC void Vprtstp(
        int  iok,      ///< @todo  Document
        int  iters,    ///< @todo  Document
        double  rsnrm, ///< @todo  Document
        double  rsden, ///< @todo  Document
        double  orsnrm ///< @todo  Document
        );



/** @brief   Print out a column-compressed sparse matrix in Harwell-Boeing
 *           format.
 *  @ingroup Vpmg
 *  @author  Nathan Baker
 *  @bug  Can this path variable be replaced with a Vio socket?
 */
VEXTERNC void Vpackmg(
        int *iparm,
        double *rparm,
        size_t *nrwk,
        int *niwk,
        int *nx,
        int *ny,
        int *nz,
        int *nlev,
        int *nu1,
        int *nu2,
        int *mgkey,
        int *itmax,
        int *istop,
        int *ipcon,
        int *nonlin,
        int *mgsmoo,
        int *mgprol,
        int *mgcoar,
        int *mgsolv,
        int *mgdisc,
        int *iinfo,
        double *errtol,
        int *ipkey,
        double *omegal,
        double *omegan,
        int *irite,
        int *iperf
        );



/** @brief   Produce information for a coarser grid.
 *           Also harmonically average the problem coefficients.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces buildharm0 from mgsubd.f
 */
VEXTERNC void Vbuildharm0(
        int *nx,      ///< @todo  Document
        int *ny,      ///< @todo  Document
        int *nz,      ///< @todo  Document
        int *nxf,     ///< @todo  Document
        int *nyf,     ///< @todo  Document
        int *nzf,     ///< @todo  Document
        double *xc,   ///< @todo  Document
        double *yc,   ///< @todo  Document
        double *zc,   ///< @todo  Document
        double *gxc,  ///< @todo  Document
        double *gyc,  ///< @todo  Document
        double *gzc,  ///< @todo  Document
        double *a1c,  ///< @todo  Document
        double *a2c,  ///< @todo  Document
        double *a3c,  ///< @todo  Document
        double *cc,   ///< @todo  Document
        double *fc,   ///< @todo  Document
        double *tc,   ///< @todo  Document
        double *xf,   ///< @todo  Document
        double *yf,   ///< @todo  Document
        double *zf,   ///< @todo  Document
        double *gxcf, ///< @todo  Document
        double *gycf, ///< @todo  Document
        double *gzcf, ///< @todo  Document
        double *a1cf, ///< @todo  Document
        double *a2cf, ///< @todo  Document
        double *a3cf, ///< @todo  Document
        double *ccf,  ///< @todo  Document
        double *fcf,  ///< @todo  Document
        double *tcf   ///< @todo  Document
        );



/** @brief   Produce information for a coarser grid.
 *           Also harmonically average the problem coefficients.
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces buildharm0 from mgsubd.f
 */
VEXTERNC void Vbuildcopy0(
        int    *nx,   ///< @todo  Document
        int    *ny,   ///< @todo  Document
        int    *nz,   ///< @todo  Document
        int    *nxf,  ///< @todo  Document
        int    *nyf,  ///< @todo  Document
        int    *nzf,  ///< @todo  Document
        double *xc,   ///< @todo  Document
        double *yc,   ///< @todo  Document
        double *zc,   ///< @todo  Document
        double *gxc,  ///< @todo  Document
        double *gyc,  ///< @todo  Document
        double *gzc,  ///< @todo  Document
        double *a1c,  ///< @todo  Document
        double *a2c,  ///< @todo  Document
        double *a3c,  ///< @todo  Document
        double *cc,   ///< @todo  Document
        double *fc,   ///< @todo  Document
        double *tc,   ///< @todo  Document
        double *xf,   ///< @todo  Document
        double *yf,   ///< @todo  Document
        double *zf,   ///< @todo  Document
        double *gxcf, ///< @todo  Document
        double *gycf, ///< @todo  Document
        double *gzcf, ///< @todo  Document
        double *a1cf, ///< @todo  Document
        double *a2cf, ///< @todo  Document
        double *a3cf, ///< @todo  Document
        double *ccf,  ///< @todo  Document
        double *fcf,  ///< @todo  Document
        double *tcf   ///< @todo  Document
        );



/** @brief   Build RHS algebraically for analysis purposes
 *  @author  Tucker Beck [C Translation], Michael Holst [Original]
 *  @note    Replaces buildALG from mgsubd.f
 *           The fine level must be built before any coarse levels
 */
VEXTERNC void Vbuildalg(
        int      *nx, ///< @todo  Document
        int      *ny, ///< @todo  Document
        int      *nz, ///< @todo  Document
        int    *mode, ///< @todo  Document
        int    *nlev, ///< @todo  Document
        int      *iz, ///< @todo  Document
        int     *ipc, ///< @todo  Document
        double  *rpc, ///< @todo  Document
        double   *ac, ///< @todo  Document
        double   *cc, ///< @todo  Document
        double   *fc, ///< @todo  Document
        double    *x, ///< @todo  Document
        double    *y, ///< @todo  Document
        double  *tmp  ///< @todo  Document
);



#endif // _MGSUBD_H_
