hypre/sstruct_ls/HYPRE_sstruct_split.c
falgout b365889e9f Completed the implementation of SetNeighborBox for all variable types:
- Generalized the Struct communication routines to handle data transformations
- Added more flexibility to Set(Box)Values routines for efficiency.
- Inter-part shared boundary data is now updated appropriately
- Added SetNeighborPart function (to replace SetNeighborBox)
- Added a finite-element-style input file capability for the sstruct driver
- The Split solver can now be used standalone (added to struct/sstruct drivers)
- Added a Jacobi block solver to Split (useful for regression testing)
- Added regression tests for the new SetNeighborPart features
2008-01-23 01:14:45 +00:00

521 lines
18 KiB
C

/*BHEADER**********************************************************************
* Copyright (c) 2007, Lawrence Livermore National Security, LLC.
* Produced at the Lawrence Livermore National Laboratory.
* Written by the HYPRE team. UCRL-CODE-222953.
* All rights reserved.
*
* This file is part of HYPRE (see http://www.llnl.gov/CASC/hypre/).
* Please see the COPYRIGHT_and_LICENSE file for the copyright notice,
* disclaimer, contact information and the GNU Lesser General Public License.
*
* HYPRE 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 2.1 dated February 1999.
*
* HYPRE 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 terms and conditions of the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* $Revision$
***********************************************************************EHEADER*/
/******************************************************************************
*
* HYPRE_SStructSplit solver interface
*
* This solver does the following iteration:
*
* x_{k+1} = M^{-1} (b + N x_k) ,
*
* where A = M - N is a splitting of A, and M is the block-diagonal
* matrix of structured intra-variable couplings.
*
*****************************************************************************/
#include "headers.h"
/*--------------------------------------------------------------------------
* hypre_SStructSolver data structure
*--------------------------------------------------------------------------*/
typedef struct hypre_SStructSolver_struct
{
hypre_SStructVector *y;
int nparts;
int *nvars;
void ****smatvec_data;
int (***ssolver_solve)();
int (***ssolver_destroy)();
void ***ssolver_data;
double tol;
int max_iter;
int zero_guess;
int num_iterations;
double rel_norm;
int ssolver;
void *matvec_data;
} hypre_SStructSolver;
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitCreate( MPI_Comm comm,
HYPRE_SStructSolver *solver_ptr )
{
hypre_SStructSolver *solver;
solver = hypre_TAlloc(hypre_SStructSolver, 1);
(solver -> y) = NULL;
(solver -> nparts) = 0;
(solver -> nvars) = 0;
(solver -> smatvec_data) = NULL;
(solver -> ssolver_solve) = NULL;
(solver -> ssolver_destroy) = NULL;
(solver -> ssolver_data) = NULL;
(solver -> tol) = 1.0e-06;
(solver -> max_iter) = 200;
(solver -> zero_guess) = 0;
(solver -> num_iterations) = 0;
(solver -> rel_norm) = 0;
(solver -> ssolver) = HYPRE_SMG;
(solver -> matvec_data) = NULL;
*solver_ptr = solver;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitDestroy( HYPRE_SStructSolver solver )
{
hypre_SStructVector *y;
int nparts;
int *nvars;
void ****smatvec_data;
int (***ssolver_solve)();
int (***ssolver_destroy)();
void ***ssolver_data;
int (*sdestroy)();
void *sdata;
int part, vi, vj;
if (solver)
{
y = (solver -> y);
nparts = (solver -> nparts);
nvars = (solver -> nvars);
smatvec_data = (solver -> smatvec_data);
ssolver_solve = (solver -> ssolver_solve);
ssolver_destroy = (solver -> ssolver_destroy);
ssolver_data = (solver -> ssolver_data);
HYPRE_SStructVectorDestroy(y);
for (part = 0; part < nparts; part++)
{
for (vi = 0; vi < nvars[part]; vi++)
{
for (vj = 0; vj < nvars[part]; vj++)
{
if (smatvec_data[part][vi][vj] != NULL)
{
hypre_StructMatvecDestroy(smatvec_data[part][vi][vj]);
}
}
hypre_TFree(smatvec_data[part][vi]);
sdestroy = ssolver_destroy[part][vi];
sdata = ssolver_data[part][vi];
sdestroy(sdata);
}
hypre_TFree(smatvec_data[part]);
hypre_TFree(ssolver_solve[part]);
hypre_TFree(ssolver_destroy[part]);
hypre_TFree(ssolver_data[part]);
}
hypre_TFree(nvars);
hypre_TFree(smatvec_data);
hypre_TFree(ssolver_solve);
hypre_TFree(ssolver_destroy);
hypre_TFree(ssolver_data);
hypre_SStructMatvecDestroy(solver -> matvec_data);
hypre_TFree(solver);
}
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetup( HYPRE_SStructSolver solver,
HYPRE_SStructMatrix A,
HYPRE_SStructVector b,
HYPRE_SStructVector x )
{
hypre_SStructVector *y;
int nparts;
int *nvars;
void ****smatvec_data;
int (***ssolver_solve)();
int (***ssolver_destroy)();
void ***ssolver_data;
int ssolver = (solver -> ssolver);
MPI_Comm comm;
hypre_SStructGrid *grid;
hypre_SStructPMatrix *pA;
hypre_SStructPVector *px;
hypre_SStructPVector *py;
hypre_StructMatrix *sA;
hypre_StructVector *sx;
hypre_StructVector *sy;
HYPRE_StructMatrix sAH;
HYPRE_StructVector sxH;
HYPRE_StructVector syH;
int (*ssolve)();
int (*sdestroy)();
void *sdata;
int part, vi, vj;
comm = hypre_SStructVectorComm(b);
grid = hypre_SStructVectorGrid(b);
HYPRE_SStructVectorCreate(comm, grid, &y);
HYPRE_SStructVectorInitialize(y);
HYPRE_SStructVectorAssemble(y);
nparts = hypre_SStructMatrixNParts(A);
nvars = hypre_TAlloc(int, nparts);
smatvec_data = hypre_TAlloc(void ***, nparts);
ssolver_solve = (int (***)()) hypre_MAlloc((sizeof(int (**)()) * nparts));
ssolver_destroy = (int (***)()) hypre_MAlloc((sizeof(int (**)()) * nparts));
ssolver_data = hypre_TAlloc(void **, nparts);
for (part = 0; part < nparts; part++)
{
pA = hypre_SStructMatrixPMatrix(A, part);
px = hypre_SStructVectorPVector(x, part);
py = hypre_SStructVectorPVector(y, part);
nvars[part] = hypre_SStructPMatrixNVars(pA);
smatvec_data[part] = hypre_TAlloc(void **, nvars[part]);
ssolver_solve[part] =
(int (**)()) hypre_MAlloc((sizeof(int (*)()) * nvars[part]));
ssolver_destroy[part] =
(int (**)()) hypre_MAlloc((sizeof(int (*)()) * nvars[part]));
ssolver_data[part] = hypre_TAlloc(void *, nvars[part]);
for (vi = 0; vi < nvars[part]; vi++)
{
smatvec_data[part][vi] = hypre_TAlloc(void *, nvars[part]);
for (vj = 0; vj < nvars[part]; vj++)
{
sA = hypre_SStructPMatrixSMatrix(pA, vi, vj);
sx = hypre_SStructPVectorSVector(px, vj);
smatvec_data[part][vi][vj] = NULL;
if (sA != NULL)
{
smatvec_data[part][vi][vj] = hypre_StructMatvecCreate();
hypre_StructMatvecSetup(smatvec_data[part][vi][vj], sA, sx);
}
}
sA = hypre_SStructPMatrixSMatrix(pA, vi, vi);
sx = hypre_SStructPVectorSVector(px, vi);
sy = hypre_SStructPVectorSVector(py, vi);
sAH = (HYPRE_StructMatrix) sA;
sxH = (HYPRE_StructVector) sx;
syH = (HYPRE_StructVector) sy;
switch(ssolver)
{
case HYPRE_Jacobi:
HYPRE_StructJacobiCreate(comm, (HYPRE_StructSolver *)&sdata);
HYPRE_StructJacobiSetMaxIter(sdata, 1);
HYPRE_StructJacobiSetTol(sdata, 0.0);
if (solver -> zero_guess)
{
HYPRE_StructJacobiSetZeroGuess(sdata);
}
HYPRE_StructJacobiSetup(sdata, sAH, syH, sxH);
ssolve = HYPRE_StructJacobiSolve;
sdestroy = HYPRE_StructJacobiDestroy;
break;
case HYPRE_SMG:
HYPRE_StructSMGCreate(comm, (HYPRE_StructSolver *)&sdata);
HYPRE_StructSMGSetMemoryUse(sdata, 0);
HYPRE_StructSMGSetMaxIter(sdata, 1);
HYPRE_StructSMGSetTol(sdata, 0.0);
if (solver -> zero_guess)
{
HYPRE_StructSMGSetZeroGuess(sdata);
}
HYPRE_StructSMGSetNumPreRelax(sdata, 1);
HYPRE_StructSMGSetNumPostRelax(sdata, 1);
HYPRE_StructSMGSetLogging(sdata, 0);
HYPRE_StructSMGSetPrintLevel(sdata, 0);
HYPRE_StructSMGSetup(sdata, sAH, syH, sxH);
ssolve = HYPRE_StructSMGSolve;
sdestroy = HYPRE_StructSMGDestroy;
break;
case HYPRE_PFMG:
HYPRE_StructPFMGCreate(comm, (HYPRE_StructSolver *)&sdata);
HYPRE_StructPFMGSetMaxIter(sdata, 1);
HYPRE_StructPFMGSetTol(sdata, 0.0);
if (solver -> zero_guess)
{
HYPRE_StructPFMGSetZeroGuess(sdata);
}
HYPRE_StructPFMGSetRelaxType(sdata, 1);
HYPRE_StructPFMGSetNumPreRelax(sdata, 1);
HYPRE_StructPFMGSetNumPostRelax(sdata, 1);
HYPRE_StructPFMGSetLogging(sdata, 0);
HYPRE_StructPFMGSetPrintLevel(sdata, 0);
HYPRE_StructPFMGSetup(sdata, sAH, syH, sxH);
ssolve = HYPRE_StructPFMGSolve;
sdestroy = HYPRE_StructPFMGDestroy;
break;
}
ssolver_solve[part][vi] = ssolve;
ssolver_destroy[part][vi] = sdestroy;
ssolver_data[part][vi] = sdata;
}
}
(solver -> y) = y;
(solver -> nparts) = nparts;
(solver -> nvars) = nvars;
(solver -> smatvec_data) = smatvec_data;
(solver -> ssolver_solve) = ssolver_solve;
(solver -> ssolver_destroy) = ssolver_destroy;
(solver -> ssolver_data) = ssolver_data;
if ((solver -> tol) > 0.0)
{
hypre_SStructMatvecCreate(&(solver -> matvec_data));
hypre_SStructMatvecSetup((solver -> matvec_data), A, x);
}
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSolve( HYPRE_SStructSolver solver,
HYPRE_SStructMatrix A,
HYPRE_SStructVector b,
HYPRE_SStructVector x )
{
hypre_SStructVector *y = (solver -> y);
int nparts = (solver -> nparts);
int *nvars = (solver -> nvars);
void ****smatvec_data = (solver -> smatvec_data);
int (***ssolver_solve)() = (solver -> ssolver_solve);
void ***ssolver_data = (solver -> ssolver_data);
double tol = (solver -> tol);
int max_iter = (solver -> max_iter);
int zero_guess = (solver -> zero_guess);
void *matvec_data = (solver -> matvec_data);
hypre_SStructPMatrix *pA;
hypre_SStructPVector *px;
hypre_SStructPVector *py;
hypre_StructMatrix *sA;
hypre_StructVector *sx;
hypre_StructVector *sy;
int (*ssolve)();
void *sdata;
hypre_ParCSRMatrix *parcsrA;
hypre_ParVector *parx;
hypre_ParVector *pary;
int iter, part, vi, vj;
double b_dot_b, r_dot_r;
/* part of convergence check */
if (tol > 0.0)
{
/* eps = (tol^2) */
hypre_SStructInnerProd(b, b, &b_dot_b);
/* if rhs is zero, return a zero solution */
if (b_dot_b == 0.0)
{
hypre_SStructVectorSetConstantValues(x, 0.0);
(solver -> rel_norm) = 0.0;
return hypre_error_flag;
}
}
for (iter = 0; iter < max_iter; iter++)
{
/* convergence check */
if (tol > 0.0)
{
/* compute fine grid residual (b - Ax) */
hypre_SStructCopy(b, y);
hypre_SStructMatvecCompute(matvec_data, -1.0, A, x, 1.0, y);
hypre_SStructInnerProd(y, y, &r_dot_r);
(solver -> rel_norm) = sqrt(r_dot_r/b_dot_b);
if ((solver -> rel_norm) < tol)
{
break;
}
}
/* copy b into y */
hypre_SStructCopy(b, y);
/* compute y = y + Nx */
if (!zero_guess || (iter > 0))
{
for (part = 0; part < nparts; part++)
{
pA = hypre_SStructMatrixPMatrix(A, part);
px = hypre_SStructVectorPVector(x, part);
py = hypre_SStructVectorPVector(y, part);
for (vi = 0; vi < nvars[part]; vi++)
{
for (vj = 0; vj < nvars[part]; vj++)
{
sdata = smatvec_data[part][vi][vj];
sy = hypre_SStructPVectorSVector(py, vi);
if ((sdata != NULL) && (vj != vi))
{
sA = hypre_SStructPMatrixSMatrix(pA, vi, vj);
sx = hypre_SStructPVectorSVector(px, vj);
hypre_StructMatvecCompute(sdata, -1.0, sA, sx, 1.0, sy);
}
}
}
}
parcsrA = hypre_SStructMatrixParCSRMatrix(A);
hypre_SStructVectorConvert(x, &parx);
hypre_SStructVectorConvert(y, &pary);
hypre_ParCSRMatrixMatvec(-1.0, parcsrA, parx, 1.0, pary);
hypre_SStructVectorRestore(x, NULL);
hypre_SStructVectorRestore(y, pary);
}
/* compute x = M^{-1} y */
for (part = 0; part < nparts; part++)
{
pA = hypre_SStructMatrixPMatrix(A, part);
px = hypre_SStructVectorPVector(x, part);
py = hypre_SStructVectorPVector(y, part);
for (vi = 0; vi < nvars[part]; vi++)
{
ssolve = ssolver_solve[part][vi];
sdata = ssolver_data[part][vi];
sA = hypre_SStructPMatrixSMatrix(pA, vi, vi);
sx = hypre_SStructPVectorSVector(px, vi);
sy = hypre_SStructPVectorSVector(py, vi);
ssolve(sdata, sA, sy, sx);
}
}
}
(solver -> num_iterations) = iter;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetTol( HYPRE_SStructSolver solver,
double tol )
{
(solver -> tol) = tol;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetMaxIter( HYPRE_SStructSolver solver,
int max_iter )
{
(solver -> max_iter) = max_iter;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetZeroGuess( HYPRE_SStructSolver solver )
{
(solver -> zero_guess) = 1;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetNonZeroGuess( HYPRE_SStructSolver solver )
{
(solver -> zero_guess) = 0;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitSetStructSolver( HYPRE_SStructSolver solver,
int ssolver )
{
(solver -> ssolver) = ssolver;
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitGetNumIterations( HYPRE_SStructSolver solver,
int *num_iterations )
{
*num_iterations = (solver -> num_iterations);
return hypre_error_flag;
}
/*--------------------------------------------------------------------------
*--------------------------------------------------------------------------*/
int
HYPRE_SStructSplitGetFinalRelativeResidualNorm( HYPRE_SStructSolver solver,
double *norm )
{
*norm = (solver -> rel_norm);
return hypre_error_flag;
}