* Allocate buffer on heap memory * Fix Pragma definition for MSVC * Fix uninitiliazed variable * Loop counter cannot be non-negative for MSVC
180 lines
5.4 KiB
C
180 lines
5.4 KiB
C
/******************************************************************************
|
|
* Copyright (c) 1998 Lawrence Livermore National Security, LLC and other
|
|
* HYPRE Project Developers. See the top-level COPYRIGHT file for details.
|
|
*
|
|
* SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
|
*******************************************************************************/
|
|
|
|
/******************************************************************************
|
|
*
|
|
* FSAI solve routine
|
|
*
|
|
******************************************************************************/
|
|
|
|
#include "_hypre_parcsr_ls.h"
|
|
|
|
/*--------------------------------------------------------------------
|
|
* hypre_FSAISolve
|
|
*--------------------------------------------------------------------*/
|
|
|
|
HYPRE_Int
|
|
hypre_FSAISolve( void *fsai_vdata,
|
|
hypre_ParCSRMatrix *A,
|
|
hypre_ParVector *b,
|
|
hypre_ParVector *x )
|
|
{
|
|
MPI_Comm comm = hypre_ParCSRMatrixComm(A);
|
|
hypre_ParFSAIData *fsai_data = (hypre_ParFSAIData*) fsai_vdata;
|
|
|
|
/* Data structure variables */
|
|
hypre_ParVector *r_work = hypre_ParFSAIDataRWork(fsai_data);
|
|
HYPRE_Real tol = hypre_ParFSAIDataTolerance(fsai_data);
|
|
HYPRE_Int zero_guess = hypre_ParFSAIDataZeroGuess(fsai_data);
|
|
HYPRE_Int max_iter = hypre_ParFSAIDataMaxIterations(fsai_data);
|
|
HYPRE_Int print_level = hypre_ParFSAIDataPrintLevel(fsai_data);
|
|
HYPRE_Int logging = hypre_ParFSAIDataLogging(fsai_data);
|
|
|
|
/* Local variables */
|
|
HYPRE_Int iter, my_id;
|
|
HYPRE_Real old_resnorm, resnorm, rel_resnorm;
|
|
HYPRE_Complex one = 1.0;
|
|
HYPRE_Complex neg_one = -1.0;
|
|
HYPRE_Complex zero = 0.0;
|
|
|
|
/* Sanity check */
|
|
if (hypre_ParVectorNumVectors(b) > 1)
|
|
{
|
|
hypre_error_w_msg(HYPRE_ERROR_GENERIC, "FSAI doesn't support multicomponent vectors");
|
|
return hypre_error_flag;
|
|
}
|
|
|
|
HYPRE_ANNOTATE_FUNC_BEGIN;
|
|
hypre_GpuProfilingPushRange("FSAISolve");
|
|
|
|
hypre_MPI_Comm_rank(comm, &my_id);
|
|
|
|
/*-----------------------------------------------------------------
|
|
* Preconditioned Richardson - Main solver loop
|
|
* x(k+1) = x(k) + omega * (G^T*G) * (b - A*x(k))
|
|
* ----------------------------------------------------------------*/
|
|
|
|
if (my_id == 0 && print_level > 1)
|
|
{
|
|
hypre_printf("\n\n FSAI SOLVER SOLUTION INFO:\n");
|
|
}
|
|
|
|
iter = 0;
|
|
rel_resnorm = resnorm = 1.0;
|
|
|
|
if (my_id == 0 && print_level > 1)
|
|
{
|
|
hypre_printf(" new relative\n");
|
|
hypre_printf(" iter # res norm res norm\n");
|
|
hypre_printf(" -------- -------- --------\n");
|
|
}
|
|
|
|
if (max_iter > 0)
|
|
{
|
|
/* First iteration */
|
|
if (zero_guess)
|
|
{
|
|
/* Compute: x(k+1) = omega*G^T*G*b */
|
|
hypre_FSAIApply(fsai_vdata, zero, b, x);
|
|
}
|
|
else
|
|
{
|
|
/* Compute: x(k+1) = x(k) + omega*G^T*G*(b - A*x(k)) */
|
|
hypre_ParCSRMatrixMatvecOutOfPlace(neg_one, A, x, one, b, r_work);
|
|
hypre_FSAIApply(fsai_vdata, one, r_work, x);
|
|
}
|
|
|
|
/* Update iteration count */
|
|
iter++;
|
|
}
|
|
else
|
|
{
|
|
hypre_ParVectorCopy(b, x);
|
|
}
|
|
|
|
/* Apply remaining iterations */
|
|
for (; iter < max_iter; iter++)
|
|
{
|
|
/* Update residual */
|
|
hypre_ParCSRMatrixMatvecOutOfPlace(neg_one, A, x, one, b, r_work);
|
|
|
|
if (tol > 0.0)
|
|
{
|
|
old_resnorm = resnorm;
|
|
resnorm = hypre_ParVectorInnerProd(r_work, r_work);
|
|
|
|
/* Compute rel_resnorm */
|
|
rel_resnorm = resnorm / old_resnorm;
|
|
|
|
if (my_id == 0 && print_level > 1)
|
|
{
|
|
hypre_printf(" %e %e %e\n", iter, resnorm, rel_resnorm);
|
|
}
|
|
|
|
/* Exit if convergence tolerance has been achieved */
|
|
if (rel_resnorm >= tol)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Compute: x(k+1) = x(k) + omega*inv(M)*r */
|
|
hypre_FSAIApply(fsai_vdata, one, r_work, x);
|
|
}
|
|
|
|
if (logging > 1)
|
|
{
|
|
hypre_ParFSAIDataNumIterations(fsai_data) = iter;
|
|
hypre_ParFSAIDataRelResNorm(fsai_data) = rel_resnorm;
|
|
}
|
|
else
|
|
{
|
|
hypre_ParFSAIDataNumIterations(fsai_data) = 0;
|
|
hypre_ParFSAIDataRelResNorm(fsai_data) = 0.0;
|
|
}
|
|
|
|
hypre_GpuProfilingPopRange();
|
|
HYPRE_ANNOTATE_FUNC_END;
|
|
|
|
return hypre_error_flag;
|
|
}
|
|
|
|
/*--------------------------------------------------------------------
|
|
* hypre_FSAIApply
|
|
*
|
|
* Computes x(k+1) = alpha*x(k) + omega*G^T*G*b
|
|
*--------------------------------------------------------------------*/
|
|
|
|
HYPRE_Int
|
|
hypre_FSAIApply( void *fsai_vdata,
|
|
HYPRE_Complex alpha,
|
|
hypre_ParVector *b,
|
|
hypre_ParVector *x )
|
|
{
|
|
hypre_ParFSAIData *fsai_data = (hypre_ParFSAIData*) fsai_vdata;
|
|
|
|
/* Data structure variables */
|
|
hypre_ParCSRMatrix *G = hypre_ParFSAIDataGmat(fsai_data);
|
|
hypre_ParCSRMatrix *GT = hypre_ParFSAIDataGTmat(fsai_data);
|
|
hypre_ParVector *z_work = hypre_ParFSAIDataZWork(fsai_data);
|
|
HYPRE_Real omega = hypre_ParFSAIDataOmega(fsai_data);
|
|
|
|
HYPRE_Complex one = 1.0;
|
|
HYPRE_Complex zero = 0.0;
|
|
|
|
HYPRE_ANNOTATE_FUNC_BEGIN;
|
|
hypre_GpuProfilingPushRange("FSAIApply");
|
|
|
|
hypre_ParCSRMatrixMatvec(one, G, b, zero, z_work);
|
|
hypre_ParCSRMatrixMatvec(omega, GT, z_work, alpha, x);
|
|
|
|
hypre_GpuProfilingPopRange();
|
|
HYPRE_ANNOTATE_FUNC_END;
|
|
|
|
return hypre_error_flag;
|
|
}
|