hypre/sstruct_ls/hypre_MaxwellSolve.c
2009-11-05 21:21:19 +00:00

771 lines
36 KiB
C

/*BHEADER**********************************************************************
* Copyright (c) 2008, Lawrence Livermore National Security, LLC.
* Produced at the Lawrence Livermore National Laboratory.
* This file is part of HYPRE. See file COPYRIGHT for details.
*
* HYPRE is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License (as published by the Free
* Software Foundation) version 2.1 dated February 1999.
*
* $Revision$
***********************************************************************EHEADER*/
#include "headers.h"
/*--------------------------------------------------------------------------
* hypre_MaxwellSolve- note that there is no input operator Aee. We assume
* that maxwell_vdata has the exact operators. This prevents the need to
* to recompute Ann in the solve phase. However, we do allow the f_edge &
* u_edge to change per call.
*--------------------------------------------------------------------------*/
int
hypre_MaxwellSolve( void * maxwell_vdata,
hypre_SStructMatrix * A_in,
hypre_SStructVector * f,
hypre_SStructVector * u )
{
hypre_MaxwellData *maxwell_data = maxwell_vdata;
hypre_ParVector *f_edge;
hypre_ParVector *u_edge;
int max_iter = maxwell_data-> max_iter;
double tol = maxwell_data-> tol;
int rel_change = maxwell_data-> rel_change;
int zero_guess = maxwell_data-> zero_guess;
int npre_relax = maxwell_data-> num_pre_relax;
int npost_relax = maxwell_data-> num_post_relax;
hypre_ParCSRMatrix **Ann_l = maxwell_data-> Ann_l;
hypre_ParCSRMatrix **Pn_l = maxwell_data-> Pn_l;
hypre_ParCSRMatrix **RnT_l = maxwell_data-> RnT_l;
hypre_ParVector **bn_l = maxwell_data-> bn_l;
hypre_ParVector **xn_l = maxwell_data-> xn_l;
hypre_ParVector **resn_l = maxwell_data-> resn_l;
hypre_ParVector **en_l = maxwell_data-> en_l;
hypre_ParVector **nVtemp_l = maxwell_data-> nVtemp_l;
hypre_ParVector **nVtemp2_l = maxwell_data-> nVtemp2_l;
int **nCF_marker_l = maxwell_data-> nCF_marker_l;
double *nrelax_weight= maxwell_data-> nrelax_weight;
double *nomega = maxwell_data-> nomega;
int nrelax_type = maxwell_data-> nrelax_type;
int node_numlevs = maxwell_data-> node_numlevels;
hypre_ParCSRMatrix *Tgrad = maxwell_data-> Tgrad;
hypre_ParCSRMatrix *T_transpose = maxwell_data-> T_transpose;
hypre_ParCSRMatrix **Aen_l = maxwell_data-> Aen_l;
int en_numlevs = maxwell_data-> en_numlevels;
hypre_ParCSRMatrix **Aee_l = maxwell_data-> Aee_l;
hypre_IJMatrix **Pe_l = maxwell_data-> Pe_l;
hypre_IJMatrix **ReT_l = maxwell_data-> ReT_l;
hypre_ParVector **be_l = maxwell_data-> be_l;
hypre_ParVector **xe_l = maxwell_data-> xe_l;
hypre_ParVector **rese_l = maxwell_data-> rese_l;
hypre_ParVector **ee_l = maxwell_data-> ee_l;
hypre_ParVector **eVtemp_l = maxwell_data-> eVtemp_l;
hypre_ParVector **eVtemp2_l = maxwell_data-> eVtemp2_l;
int **eCF_marker_l = maxwell_data-> eCF_marker_l;
double *erelax_weight= maxwell_data-> erelax_weight;
double *eomega = maxwell_data-> eomega;
int erelax_type = maxwell_data-> erelax_type;
int edge_numlevs = maxwell_data-> edge_numlevels;
int **BdryRanks_l = maxwell_data-> BdryRanks_l;
int *BdryRanksCnts_l= maxwell_data-> BdryRanksCnts_l;
int logging = maxwell_data-> logging;
double *norms = maxwell_data-> norms;
double *rel_norms = maxwell_data-> rel_norms;
int Solve_err_flag;
int relax_local, cycle_param;
double b_dot_b, r_dot_r, eps;
double e_dot_e, x_dot_x;
int i, j;
int level;
int ierr= 0;
/* added for the relaxation routines */
hypre_ParVector *ze = NULL;
if (hypre_NumThreads() > 1)
{
/* Aee is always bigger than Ann */
ze = hypre_ParVectorCreate(hypre_ParCSRMatrixComm(Aee_l[0]),
hypre_ParCSRMatrixGlobalNumRows(Aee_l[0]),
hypre_ParCSRMatrixRowStarts(Aee_l[0]));
hypre_ParVectorInitialize(ze);
hypre_ParVectorSetPartitioningOwner(ze,0);
}
hypre_BeginTiming(maxwell_data-> time_index);
hypre_SStructVectorConvert(f, &f_edge);
hypre_SStructVectorConvert(u, &u_edge);
hypre_ParVectorZeroBCValues(f_edge, BdryRanks_l[0], BdryRanksCnts_l[0]);
hypre_ParVectorZeroBCValues(u_edge, BdryRanks_l[0], BdryRanksCnts_l[0]);
be_l[0]= f_edge;
xe_l[0]= u_edge;
/* the nodal fine vectors: bn= T'*be, xn= 0. */
hypre_ParCSRMatrixMatvec(1.0, T_transpose, f_edge, 0.0, bn_l[0]);
hypre_ParVectorSetConstantValues(xn_l[0], 0.0);
relax_local= 0;
cycle_param= 0;
(maxwell_data-> num_iterations) = 0;
/* if max_iter is zero, return */
if (max_iter == 0)
{
/* if using a zero initial guess, return zero */
if (zero_guess)
{
hypre_ParVectorSetConstantValues(xe_l[0], 0.0);
}
hypre_EndTiming(maxwell_data -> time_index);
return ierr;
}
/* part of convergence check */
if (tol > 0.0)
{
/* eps = (tol^2) */
b_dot_b= hypre_ParVectorInnerProd(be_l[0], be_l[0]);
eps = tol*tol;
/* if rhs is zero, return a zero solution */
if (b_dot_b == 0.0)
{
hypre_ParVectorSetConstantValues(xe_l[0], 0.0);
if (logging > 0)
{
norms[0] = 0.0;
rel_norms[0] = 0.0;
}
hypre_EndTiming(maxwell_data -> time_index);
return ierr;
}
}
/*-----------------------------------------------------
* Do V-cycles:
* For each index l, "fine" = (l-1), "coarse" = l
* down cycle:
* a) smooth nodes (Ann)
* b) update edge residual (Ane)
* c) smooth edges (Aee)
* d) restrict updated node and edge residuals
* up cycle:
* a) interpolate node and edges separately
* a) smooth nodes
* b) update edge residual
* c) smooth edges
*
* solution update:
* edge_sol= edge_sol + T*node_sol
*-----------------------------------------------------*/
for (i = 0; i < max_iter; i++)
{
/* fine grid pre_relaxation */
for (j= 0; j< npre_relax; j++)
{
hypre_ParVectorCopy(bn_l[0], nVtemp_l[0]);
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[0], xe_l[0],
1.0, nVtemp_l[0]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[0],
nVtemp_l[0],
nCF_marker_l[0],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[0],
nomega[0],
xn_l[0],
nVtemp2_l[0],
ze);
/* update edge right-hand fe_l= fe_l-Aen_l*xn_l[0] */
hypre_ParVectorCopy(be_l[0], eVtemp_l[0]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[0], xn_l[0],
1.0, eVtemp_l[0]);
hypre_ParVectorZeroBCValues(eVtemp_l[0], BdryRanks_l[0],
BdryRanksCnts_l[0]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[0],
eVtemp_l[0],
eCF_marker_l[0],
erelax_type,
relax_local,
cycle_param,
erelax_weight[0],
eomega[0],
xe_l[0],
eVtemp2_l[0],
ze);
} /* for (j= 0; j< npre_relax; j++) */
/* compute fine grid residual. Note the edge residual of
the block system is the residual of the actual edge equations
itself. */
hypre_ParVectorCopy(bn_l[0], resn_l[0]);
hypre_ParCSRMatrixMatvec(-1.0, Ann_l[0], xn_l[0], 1.0, resn_l[0]);
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[0], xe_l[0], 1.0, resn_l[0]);
hypre_ParVectorCopy(be_l[0], rese_l[0]);
hypre_ParCSRMatrixMatvec(-1.0, Aee_l[0], xe_l[0], 1.0, rese_l[0]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[0], xn_l[0], 1.0, rese_l[0]);
hypre_ParVectorZeroBCValues(rese_l[0], BdryRanks_l[0], BdryRanksCnts_l[0]);
/* convergence check */
if (tol > 0.0)
{
r_dot_r= hypre_ParVectorInnerProd(rese_l[0], rese_l[0]);
if (logging > 0)
{
norms[i] = sqrt(r_dot_r);
if (b_dot_b > 0)
rel_norms[i] = sqrt(r_dot_r/b_dot_b);
else
rel_norms[i] = 0.0;
}
/* always do at least 1 V-cycle */
if ((r_dot_r/b_dot_b < eps) && (i > 0))
{
if (rel_change)
{
if ((e_dot_e/x_dot_x) < eps)
break;
}
else
{
break;
}
}
}
if (en_numlevs > 1)
{
hypre_ParCSRMatrixMatvecT(1.0, RnT_l[0], resn_l[0], 0.0,
bn_l[1]);
hypre_ParCSRMatrixMatvecT(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(ReT_l[0]),
rese_l[0], 0.0, be_l[1]);
hypre_ParVectorZeroBCValues(be_l[1], BdryRanks_l[1],
BdryRanksCnts_l[1]);
/* zero off initial guess for the next level */
hypre_ParVectorSetConstantValues(xn_l[1], 0.0);
hypre_ParVectorSetConstantValues(xe_l[1], 0.0);
} /* if (en_numlevs > 1) */
for (level= 1; level<= en_numlevs-2; level++)
{
/*-----------------------------------------------
* Down cycle
*-----------------------------------------------*/
for (j= 0; j< npre_relax; j++)
{
hypre_ParVectorCopy(bn_l[level], nVtemp_l[level]);
if (j)
{
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[level],
xe_l[level], 1.0, nVtemp_l[level]);
}
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
nVtemp_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
/* update edge right-hand fe_l= fe_l-Aen_l*xn_l[level] */
hypre_ParVectorCopy(be_l[level], eVtemp_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[level],
xn_l[level], 1.0, eVtemp_l[level]);
hypre_ParVectorZeroBCValues(eVtemp_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
eVtemp_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
} /*for (j= 0; j< npre_relax; j++) */
/* compute residuals */
hypre_ParVectorCopy(bn_l[level], resn_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Ann_l[level], xn_l[level],
1.0, resn_l[level]);
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[level], xe_l[level],
1.0, resn_l[level]);
hypre_ParVectorCopy(be_l[level], rese_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aee_l[level], xe_l[level],
1.0, rese_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[level], xn_l[level],
1.0, rese_l[level]);
hypre_ParVectorZeroBCValues(rese_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
/* restrict residuals */
hypre_ParCSRMatrixMatvecT(1.0, RnT_l[level], resn_l[level],
0.0, bn_l[level+1]);
hypre_ParCSRMatrixMatvecT(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(ReT_l[level]),
rese_l[level], 0.0, be_l[level+1]);
hypre_ParVectorZeroBCValues(be_l[level+1], BdryRanks_l[level+1],
BdryRanksCnts_l[level+1]);
/* zero off initial guess for the next level */
hypre_ParVectorSetConstantValues(xn_l[level+1], 0.0);
hypre_ParVectorSetConstantValues(xe_l[level+1], 0.0);
} /* for (level= 0; level<= en_numlevels-2; level++) */
/*----------------------------------------------------------------
* For the lowest edge-node level, solve using relaxation or
* cycling down if there are more than en_numlevels levels for
* one of the node or edge dofs.
*----------------------------------------------------------------*/
level= en_numlevs-1;
/* npre_relax if not the coarsest level. Otherwise, relax once.*/
if ( (en_numlevs != edge_numlevs)
|| (en_numlevs != node_numlevs) )
{
for (j= 0; j< npre_relax; j++)
{
hypre_ParVectorCopy(bn_l[level], nVtemp_l[level]);
if (j)
{
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[level],
xe_l[level], 1.0, nVtemp_l[level]);
}
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
nVtemp_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
/* update edge right-hand fe_l= fe_l-Aen_l*xn_l[level] */
hypre_ParVectorCopy(be_l[level], eVtemp_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[level],
xn_l[level], 1.0, eVtemp_l[level]);
hypre_ParVectorZeroBCValues(eVtemp_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
eVtemp_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
} /*for (j= 0; j< npre_relax; j++) */
} /* if ( (en_numlevs != edge_numlevs) */
else
{
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
bn_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
hypre_ParVectorCopy(be_l[level], eVtemp_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[level], xn_l[level],
1.0, eVtemp_l[level]);
hypre_ParVectorZeroBCValues(eVtemp_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
eVtemp_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
}
/* Continue down the edge hierarchy if more edge levels. */
if (edge_numlevs > en_numlevs)
{
hypre_ParVectorCopy(be_l[level], rese_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aee_l[level], xe_l[level], 1.0,
rese_l[level]);
hypre_ParCSRMatrixMatvecT(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(ReT_l[level]),
rese_l[level], 0.0, be_l[level+1]);
hypre_ParVectorZeroBCValues(be_l[level+1], BdryRanks_l[level+1],
BdryRanksCnts_l[level+1]);
hypre_ParVectorSetConstantValues(xe_l[level+1], 0.0);
for (level= en_numlevs; level<= edge_numlevs-2; level++)
{
for (j= 0; j< npre_relax; j++)
{
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
be_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
}
/* compute residuals and restrict */
hypre_ParVectorCopy(be_l[level], rese_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aee_l[level], xe_l[level],
1.0, rese_l[level]);
hypre_ParCSRMatrixMatvecT(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(ReT_l[level]),
rese_l[level], 0.0, be_l[level+1]);
hypre_ParVectorZeroBCValues(be_l[level+1], BdryRanks_l[level+1],
BdryRanksCnts_l[level+1]);
hypre_ParVectorSetConstantValues(xe_l[level+1], 0.0);
} /* for (level= en_numlevs; level< edge_numlevs-2; level++) */
/* coarsest relaxation */
level= edge_numlevs-1;
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
be_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
} /* if (edge_numlevs > en_numlevs) */
/*-----------------------------------------------------------
* node hierarchy has more levels than the edge hierarchy:
* continue to march down the node hierarchy
*-----------------------------------------------------------*/
else if (node_numlevs > en_numlevs)
{
hypre_ParVectorCopy(bn_l[level], resn_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Ann_l[level], xn_l[level], 1.0,
resn_l[level]);
hypre_ParCSRMatrixMatvecT(1.0,
(hypre_ParCSRMatrix *) RnT_l[level],
resn_l[level], 0.0, bn_l[level+1]);
hypre_ParVectorSetConstantValues(xn_l[level+1], 0.0);
for (level= en_numlevs; level<= node_numlevs-2; level++)
{
for (j= 0; j< npre_relax; j++)
{
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
bn_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
}
/* compute residuals and restrict */
hypre_ParVectorCopy(bn_l[level], resn_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Ann_l[level], xn_l[level],
1.0, resn_l[level]);
hypre_ParCSRMatrixMatvecT(1.0, RnT_l[level], resn_l[level],
0.0, bn_l[level+1]);
hypre_ParVectorSetConstantValues(xn_l[level+1], 0.0);
} /* for (level= en_numlevs; level<= node_numlevs-2; level++) */
/* coarsest relaxation */
level= node_numlevs-1;
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
bn_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
} /* else if (node_numlevs > en_numlevs) */
/*---------------------------------------------------------------------
* Up cycle. First the extra hierarchy levels. Notice we relax on
* the coarsest en_numlevel.
*---------------------------------------------------------------------*/
if (edge_numlevs > en_numlevs)
{
for (level= (edge_numlevs - 2); level>= en_numlevs-1; level--)
{
hypre_ParCSRMatrixMatvec(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(Pe_l[level]),
xe_l[level+1], 0.0, ee_l[level]);
hypre_ParVectorZeroBCValues(ee_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
hypre_ParVectorAxpy(1.0, ee_l[level], xe_l[level]);
/* post smooth */
for (j= 0; j< npost_relax; j++)
{
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
be_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
}
} /* for (level= (edge_numlevs - 2); level>= en_numlevs; level--) */
} /* if (edge_numlevs > en_numlevs) */
else if (node_numlevs > en_numlevs)
{
for (level= (node_numlevs - 2); level>= en_numlevs-1; level--)
{
hypre_ParCSRMatrixMatvec(1.0, Pn_l[level], xn_l[level+1], 0.0,
en_l[level]);
hypre_ParVectorAxpy(1.0, en_l[level], xn_l[level]);
/* post smooth */
for (j= 0; j< npost_relax; j++)
{
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
bn_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp2_l[level],
ze);
}
} /* for (level= (node_numlevs - 2); level>= en_numlevs; level--) */
} /* else if (node_numlevs > en_numlevs) */
/*---------------------------------------------------------------------
* Cycle up the common levels.
*---------------------------------------------------------------------*/
for (level= (en_numlevs - 2); level>= 1; level--)
{
hypre_ParCSRMatrixMatvec(1.0, Pn_l[level], xn_l[level+1], 0.0,
en_l[level]);
hypre_ParVectorAxpy(1.0, en_l[level], xn_l[level]);
hypre_ParCSRMatrixMatvec(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(Pe_l[level]),
xe_l[level+1], 0.0, ee_l[level]);
hypre_ParVectorZeroBCValues(ee_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
hypre_ParVectorAxpy(1.0, ee_l[level], xe_l[level]);
/* post smooth */
for (j= 0; j< npost_relax; j++)
{
hypre_ParVectorCopy(bn_l[level], nVtemp_l[level]);
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[level], xe_l[level],
1.0, nVtemp_l[level]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[level],
nVtemp_l[level],
nCF_marker_l[level],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[level],
nomega[level],
xn_l[level],
nVtemp_l[level],
ze);
hypre_ParVectorCopy(be_l[level], eVtemp_l[level]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[level], xn_l[level],
1.0, eVtemp_l[level]);
hypre_ParVectorZeroBCValues(eVtemp_l[level], BdryRanks_l[level],
BdryRanksCnts_l[level]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[level],
eVtemp_l[level],
eCF_marker_l[level],
erelax_type,
relax_local,
cycle_param,
erelax_weight[level],
eomega[level],
xe_l[level],
eVtemp2_l[level],
ze);
}
} /* for (level= (en_numlevs - 2); level>= 1; level--) */
/* interpolate error and correct on finest grids */
hypre_ParCSRMatrixMatvec(1.0, Pn_l[0], xn_l[1], 0.0, en_l[0]);
hypre_ParVectorAxpy(1.0, en_l[0], xn_l[0]);
hypre_ParCSRMatrixMatvec(1.0,
(hypre_ParCSRMatrix *) hypre_IJMatrixObject(Pe_l[0]),
xe_l[1], 0.0, ee_l[0]);
hypre_ParVectorZeroBCValues(ee_l[0], BdryRanks_l[0],
BdryRanksCnts_l[0]);
hypre_ParVectorAxpy(1.0, ee_l[0], xe_l[0]);
/* part of convergence check. Will assume that if en_numlevels= 1,
then so would edge_numlevels and node_numlevels. Otherwise,
we measure the error of xe_l[0] + T*xn_l[0]. */
if ((tol > 0.0) && (rel_change))
{
if (en_numlevs > 1)
{
hypre_ParCSRMatrixMatvec(1.0, Tgrad, en_l[0], 1.0,
ee_l[0]);
hypre_ParVectorZeroBCValues(ee_l[0], BdryRanks_l[0],
BdryRanksCnts_l[0]);
e_dot_e= hypre_ParVectorInnerProd(ee_l[0], ee_l[0]);
hypre_ParVectorCopy(xe_l[0], eVtemp_l[0]);
hypre_ParCSRMatrixMatvec(1.0, Tgrad, xn_l[0], 1.0,
eVtemp_l[0]);
hypre_ParVectorZeroBCValues(eVtemp_l[0], BdryRanks_l[0],
BdryRanksCnts_l[0]);
x_dot_x= hypre_ParVectorInnerProd(eVtemp_l[0], eVtemp_l[0]);
}
else
{
e_dot_e = 0.0;
x_dot_x = 1.0;
}
}
/* check nodal convergence */
for (j= 0; j< npost_relax; j++)
{
hypre_ParVectorCopy(bn_l[0], nVtemp_l[0]);
hypre_ParCSRMatrixMatvecT(-1.0, Aen_l[0], xe_l[0],
1.0, nVtemp_l[0]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Ann_l[0],
nVtemp_l[0],
nCF_marker_l[0],
nrelax_type,
relax_local,
cycle_param,
nrelax_weight[0],
nomega[0],
xn_l[0],
nVtemp2_l[0],
ze);
hypre_ParVectorCopy(be_l[0], eVtemp_l[0]);
hypre_ParCSRMatrixMatvec(-1.0, Aen_l[0], xn_l[0], 1.0,
eVtemp_l[0]);
hypre_ParVectorZeroBCValues(eVtemp_l[0], BdryRanks_l[0],
BdryRanksCnts_l[0]);
Solve_err_flag = hypre_BoomerAMGRelaxIF(Aee_l[0],
eVtemp_l[0],
eCF_marker_l[0],
erelax_type,
relax_local,
cycle_param,
erelax_weight[0],
eomega[0],
xe_l[0],
eVtemp2_l[0],
ze);
} /* for (j= 0; j< npost_relax; j++) */
(maxwell_data -> num_iterations) = (i + 1);
}
/* add the gradient solution component to u_edge */
hypre_ParCSRMatrixMatvec(1.0, Tgrad, xn_l[0], 1.0, u_edge);
hypre_ParVectorZeroBCValues(u_edge, BdryRanks_l[0], BdryRanksCnts_l[0]);
hypre_EndTiming(maxwell_data -> time_index);
if (ze)
hypre_ParVectorDestroy(ze);
return ierr;
}