hypre/parcsr_ls/par_coarsen.c
2013-01-07 23:57:24 +00:00

2608 lines
80 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*/
/******************************************************************************
*
*****************************************************************************/
/* following should be in a header file */
#include "_hypre_parcsr_ls.h"
/*==========================================================================*/
/*==========================================================================*/
/**
Selects a coarse "grid" based on the graph of a matrix.
Notes:
\begin{itemize}
\item The underlying matrix storage scheme is a hypre_ParCSR matrix.
\item The routine returns the following:
\begin{itemize}
\item S - a ParCSR matrix representing the "strength matrix". This is
used in the "build interpolation" routine.
\item CF\_marker - an array indicating both C-pts (value = 1) and
F-pts (value = -1)
\end{itemize}
\item We define the following temporary storage:
\begin{itemize}
\item measure\_array - an array containing the "measures" for each
of the fine-grid points
\item graph\_array - an array containing the list of points in the
"current subgraph" being considered in the coarsening process.
\end{itemize}
\item The graph of the "strength matrix" for A is a subgraph of the
graph of A, but requires nonsymmetric storage even if A is
symmetric. This is because of the directional nature of the
"strengh of dependence" notion (see below). Since we are using
nonsymmetric storage for A right now, this is not a problem. If we
ever add the ability to store A symmetrically, then we could store
the strength graph as floats instead of doubles to save space.
\item This routine currently "compresses" the strength matrix. We
should consider the possibility of defining this matrix to have the
same "nonzero structure" as A. To do this, we could use the same
A\_i and A\_j arrays, and would need only define the S\_data array.
There are several pros and cons to discuss.
\end{itemize}
Terminology:
\begin{itemize}
\item Ruge's terminology: A point is "strongly connected to" $j$, or
"strongly depends on" $j$, if $-a_ij >= \theta max_{l != j} \{-a_il\}$.
\item Here, we retain some of this terminology, but with a more
generalized notion of "strength". We also retain the "natural"
graph notation for representing the directed graph of a matrix.
That is, the nonzero entry $a_ij$ is represented as: i --> j. In
the strength matrix, S, the entry $s_ij$ is also graphically denoted
as above, and means both of the following:
\begin{itemize}
\item $i$ "depends on" $j$ with "strength" $s_ij$
\item $j$ "influences" $i$ with "strength" $s_ij$
\end{itemize}
\end{itemize}
{\bf Input files:}
_hypre_parcsr_ls.h
@return Error code.
@param A [IN]
coefficient matrix
@param strength_threshold [IN]
threshold parameter used to define strength
@param S_ptr [OUT]
strength matrix
@param CF_marker_ptr [OUT]
array indicating C/F points
@see */
/*--------------------------------------------------------------------------*/
#define C_PT 1
#define F_PT -1
#define SF_PT -3
#define COMMON_C_PT 2
#define Z_PT -2
HYPRE_Int
hypre_BoomerAMGCoarsen( hypre_ParCSRMatrix *S,
hypre_ParCSRMatrix *A,
HYPRE_Int CF_init,
HYPRE_Int debug_flag,
HYPRE_Int **CF_marker_ptr)
{
MPI_Comm comm = hypre_ParCSRMatrixComm(S);
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(S);
hypre_ParCSRCommHandle *comm_handle;
hypre_CSRMatrix *S_diag = hypre_ParCSRMatrixDiag(S);
HYPRE_Int *S_diag_i = hypre_CSRMatrixI(S_diag);
HYPRE_Int *S_diag_j = hypre_CSRMatrixJ(S_diag);
hypre_CSRMatrix *S_offd = hypre_ParCSRMatrixOffd(S);
HYPRE_Int *S_offd_i = hypre_CSRMatrixI(S_offd);
HYPRE_Int *S_offd_j = NULL;
HYPRE_Int *col_map_offd = hypre_ParCSRMatrixColMapOffd(S);
HYPRE_Int num_variables = hypre_CSRMatrixNumRows(S_diag);
HYPRE_Int col_1 = hypre_ParCSRMatrixFirstColDiag(S);
HYPRE_Int col_n = col_1 + hypre_CSRMatrixNumCols(S_diag);
HYPRE_Int num_cols_offd = 0;
hypre_CSRMatrix *S_ext;
HYPRE_Int *S_ext_i = NULL;
HYPRE_Int *S_ext_j = NULL;
HYPRE_Int num_sends = 0;
HYPRE_Int *int_buf_data;
double *buf_data;
HYPRE_Int *CF_marker;
HYPRE_Int *CF_marker_offd;
double *measure_array;
HYPRE_Int *graph_array;
HYPRE_Int *graph_array_offd;
HYPRE_Int graph_size;
HYPRE_Int graph_offd_size;
HYPRE_Int global_graph_size;
HYPRE_Int i, j, k, kc, jS, kS, ig, elmt;
HYPRE_Int index, start, my_id, num_procs, jrow, cnt;
HYPRE_Int ierr = 0;
HYPRE_Int use_commpkg_A = 0;
HYPRE_Int break_var = 1;
double wall_time;
HYPRE_Int iter = 0;
#if 0 /* debugging */
char filename[256];
FILE *fp;
HYPRE_Int iter = 0;
#endif
/*--------------------------------------------------------------
* Compute a ParCSR strength matrix, S.
*
* For now, the "strength" of dependence/influence is defined in
* the following way: i depends on j if
* aij > hypre_max (k != i) aik, aii < 0
* or
* aij < hypre_min (k != i) aik, aii >= 0
* Then S_ij = 1, else S_ij = 0.
*
* NOTE: the entries are negative initially, corresponding
* to "unaccounted-for" dependence.
*----------------------------------------------------------------*/
S_ext = NULL;
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
hypre_MPI_Comm_size(comm,&num_procs);
hypre_MPI_Comm_rank(comm,&my_id);
if (!comm_pkg)
{
use_commpkg_A = 1;
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A);
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
int_buf_data = hypre_CTAlloc(HYPRE_Int, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
buf_data = hypre_CTAlloc(double, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
num_cols_offd = hypre_CSRMatrixNumCols(S_offd);
S_diag_j = hypre_CSRMatrixJ(S_diag);
if (num_cols_offd)
{
S_offd_j = hypre_CSRMatrixJ(S_offd);
}
/*----------------------------------------------------------
* Compute the measures
*
* The measures are currently given by the column sums of S.
* Hence, measure_array[i] is the number of influences
* of variable i.
*
* The measures are augmented by a random number
* between 0 and 1.
*----------------------------------------------------------*/
measure_array = hypre_CTAlloc(double, num_variables+num_cols_offd);
for (i=0; i < S_offd_i[num_variables]; i++)
{
measure_array[num_variables + S_offd_j[i]] += 1.0;
}
if (num_procs > 1)
comm_handle = hypre_ParCSRCommHandleCreate(2, comm_pkg,
&measure_array[num_variables], buf_data);
for (i=0; i < S_diag_i[num_variables]; i++)
{
measure_array[S_diag_j[i]] += 1.0;
}
if (num_procs > 1)
hypre_ParCSRCommHandleDestroy(comm_handle);
index = 0;
for (i=0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j=start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
measure_array[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)]
+= buf_data[index++];
}
for (i=num_variables; i < num_variables+num_cols_offd; i++)
{
measure_array[i] = 0;
}
/* this augments the measures */
if (CF_init == 2)
hypre_BoomerAMGIndepSetInit(S, measure_array, 1);
else
hypre_BoomerAMGIndepSetInit(S, measure_array, 0);
/*---------------------------------------------------
* Initialize the graph array
* graph_array contains interior points in elements 0 ... num_variables-1
* followed by boundary values
*---------------------------------------------------*/
graph_array = hypre_CTAlloc(HYPRE_Int, num_variables);
if (num_cols_offd)
graph_array_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
else
graph_array_offd = NULL;
/* initialize measure array and graph array */
for (ig = 0; ig < num_cols_offd; ig++)
graph_array_offd[ig] = ig;
/*---------------------------------------------------
* Initialize the C/F marker array
* C/F marker array contains interior points in elements 0 ...
* num_variables-1 followed by boundary values
*---------------------------------------------------*/
graph_offd_size = num_cols_offd;
if (CF_init==1)
{
CF_marker = *CF_marker_ptr;
cnt = 0;
for (i=0; i < num_variables; i++)
{
if ( (S_offd_i[i+1]-S_offd_i[i]) > 0
|| CF_marker[i] == -1)
{
CF_marker[i] = 0;
}
if ( CF_marker[i] == Z_PT)
{
if (measure_array[i] >= 1.0 ||
(S_diag_i[i+1]-S_diag_i[i]) > 0)
{
CF_marker[i] = 0;
graph_array[cnt++] = i;
}
else
{
CF_marker[i] = F_PT;
}
}
else if (CF_marker[i] == SF_PT)
measure_array[i] = 0;
else
graph_array[cnt++] = i;
}
}
else
{
CF_marker = hypre_CTAlloc(HYPRE_Int, num_variables);
cnt = 0;
for (i=0; i < num_variables; i++)
{
CF_marker[i] = 0;
if ( (S_diag_i[i+1]-S_diag_i[i]) == 0
&& (S_offd_i[i+1]-S_offd_i[i]) == 0)
{
CF_marker[i] = SF_PT;
measure_array[i] = 0;
}
else
graph_array[cnt++] = i;
}
}
graph_size = cnt;
if (num_cols_offd)
CF_marker_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
else
CF_marker_offd = NULL;
for (i=0; i < num_cols_offd; i++)
CF_marker_offd[i] = 0;
/*---------------------------------------------------
* Loop until all points are either fine or coarse.
*---------------------------------------------------*/
if (num_procs > 1)
{
if (use_commpkg_A)
S_ext = hypre_ParCSRMatrixExtractBExt(S,A,0);
else
S_ext = hypre_ParCSRMatrixExtractBExt(S,S,0);
S_ext_i = hypre_CSRMatrixI(S_ext);
S_ext_j = hypre_CSRMatrixJ(S_ext);
}
/* compress S_ext and convert column numbers*/
index = 0;
for (i=0; i < num_cols_offd; i++)
{
for (j=S_ext_i[i]; j < S_ext_i[i+1]; j++)
{
k = S_ext_j[j];
if (k >= col_1 && k < col_n)
{
S_ext_j[index++] = k - col_1;
}
else
{
kc = hypre_BinarySearch(col_map_offd,k,num_cols_offd);
if (kc > -1) S_ext_j[index++] = -kc-1;
}
}
S_ext_i[i] = index;
}
for (i = num_cols_offd; i > 0; i--)
S_ext_i[i] = S_ext_i[i-1];
if (num_procs > 1) S_ext_i[0] = 0;
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d Initialize CLJP phase = %f\n",
my_id, wall_time);
}
while (1)
{
/*------------------------------------------------
* Exchange boundary data, i.i. get measures and S_ext_data
*------------------------------------------------*/
if (num_procs > 1)
comm_handle = hypre_ParCSRCommHandleCreate(2, comm_pkg,
&measure_array[num_variables], buf_data);
if (num_procs > 1)
hypre_ParCSRCommHandleDestroy(comm_handle);
index = 0;
for (i=0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j=start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
measure_array[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)]
+= buf_data[index++];
}
/*------------------------------------------------
* Set F-pts and update subgraph
*------------------------------------------------*/
if (iter || (CF_init != 1))
{
for (ig = 0; ig < graph_size; ig++)
{
i = graph_array[ig];
if ( (CF_marker[i] != C_PT) && (measure_array[i] < 1) )
{
/* set to be an F-pt */
CF_marker[i] = F_PT;
/* make sure all dependencies have been accounted for */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++)
{
if (S_diag_j[jS] > -1)
{
CF_marker[i] = 0;
}
}
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++)
{
if (S_offd_j[jS] > -1)
{
CF_marker[i] = 0;
}
}
}
if (CF_marker[i])
{
measure_array[i] = 0;
/* take point out of the subgraph */
graph_size--;
graph_array[ig] = graph_array[graph_size];
graph_array[graph_size] = i;
ig--;
}
}
}
/*------------------------------------------------
* Exchange boundary data, i.i. get measures
*------------------------------------------------*/
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
jrow = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
buf_data[index++] = measure_array[jrow];
}
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(1, comm_pkg, buf_data,
&measure_array[num_variables]);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
/*------------------------------------------------
* Debugging:
*
* Uncomment the sections of code labeled
* "debugging" to generate several files that
* can be visualized using the `coarsen.m'
* matlab routine.
*------------------------------------------------*/
#if 0 /* debugging */
/* print out measures */
hypre_sprintf(filename, "coarsen.out.measures.%04d", iter);
fp = fopen(filename, "w");
for (i = 0; i < num_variables; i++)
{
hypre_fprintf(fp, "%f\n", measure_array[i]);
}
fclose(fp);
/* print out strength matrix */
hypre_sprintf(filename, "coarsen.out.strength.%04d", iter);
hypre_CSRMatrixPrint(S, filename);
/* print out C/F marker */
hypre_sprintf(filename, "coarsen.out.CF.%04d", iter);
fp = fopen(filename, "w");
for (i = 0; i < num_variables; i++)
{
hypre_fprintf(fp, "%d\n", CF_marker[i]);
}
fclose(fp);
iter++;
#endif
/*------------------------------------------------
* Test for convergence
*------------------------------------------------*/
hypre_MPI_Allreduce(&graph_size,&global_graph_size,1,HYPRE_MPI_INT,hypre_MPI_SUM,comm);
if (global_graph_size == 0)
break;
/*------------------------------------------------
* Pick an independent set of points with
* maximal measure.
*------------------------------------------------*/
if (iter || (CF_init != 1))
{
hypre_BoomerAMGIndepSet(S, measure_array, graph_array,
graph_size,
graph_array_offd, graph_offd_size,
CF_marker, CF_marker_offd);
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(12, comm_pkg,
CF_marker_offd, int_buf_data);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j=start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg,i+1);j++) {
elmt = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
if (!int_buf_data[index++] && CF_marker[elmt] > 0)
{
CF_marker[elmt] = 0;
}
}
}
}
iter++;
/*------------------------------------------------
* Exchange boundary data for CF_marker
*------------------------------------------------*/
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
elmt = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
int_buf_data[index++] = CF_marker[elmt];
}
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
for (ig = 0; ig < graph_offd_size; ig++)
{
i = graph_array_offd[ig];
if (CF_marker_offd[i] < 0)
{
/* take point out of the subgraph */
graph_offd_size--;
graph_array_offd[ig] = graph_array_offd[graph_offd_size];
graph_array_offd[graph_offd_size] = i;
ig--;
}
}
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d iter %d comm. and subgraph update = %f\n",
my_id, iter, wall_time);
}
/*------------------------------------------------
* Set C_pts and apply heuristics.
*------------------------------------------------*/
for (i=num_variables; i < num_variables+num_cols_offd; i++)
{
measure_array[i] = 0;
}
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
for (ig = 0; ig < graph_size; ig++)
{
i = graph_array[ig];
/*---------------------------------------------
* Heuristic: C-pts don't interpolate from
* neighbors that influence them.
*---------------------------------------------*/
if (CF_marker[i] > 0)
{
/* set to be a C-pt */
CF_marker[i] = C_PT;
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++)
{
j = S_diag_j[jS];
if (j > -1)
{
/* "remove" edge from S */
S_diag_j[jS] = -S_diag_j[jS]-1;
/* decrement measures of unmarked neighbors */
if (!CF_marker[j])
{
measure_array[j]--;
}
}
}
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++)
{
j = S_offd_j[jS];
if (j > -1)
{
/* "remove" edge from S */
S_offd_j[jS] = -S_offd_j[jS]-1;
/* decrement measures of unmarked neighbors */
if (!CF_marker_offd[j])
{
measure_array[j+num_variables]--;
}
}
}
}
else
{
/* marked dependencies */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++)
{
j = S_diag_j[jS];
if (j < 0) j = -j-1;
if (CF_marker[j] > 0)
{
if (S_diag_j[jS] > -1)
{
/* "remove" edge from S */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
/* IMPORTANT: consider all dependencies */
/* temporarily modify CF_marker */
CF_marker[j] = COMMON_C_PT;
}
else if (CF_marker[j] == SF_PT)
{
if (S_diag_j[jS] > -1)
{
/* "remove" edge from S */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
}
}
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++)
{
j = S_offd_j[jS];
if (j < 0) j = -j-1;
if (CF_marker_offd[j] > 0)
{
if (S_offd_j[jS] > -1)
{
/* "remove" edge from S */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
/* IMPORTANT: consider all dependencies */
/* temporarily modify CF_marker */
CF_marker_offd[j] = COMMON_C_PT;
}
else if (CF_marker_offd[j] == SF_PT)
{
if (S_offd_j[jS] > -1)
{
/* "remove" edge from S */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
}
}
/* unmarked dependencies */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++)
{
if (S_diag_j[jS] > -1)
{
j = S_diag_j[jS];
break_var = 1;
/* check for common C-pt */
for (kS = S_diag_i[j]; kS < S_diag_i[j+1]; kS++)
{
k = S_diag_j[kS];
if (k < 0) k = -k-1;
/* IMPORTANT: consider all dependencies */
if (CF_marker[k] == COMMON_C_PT)
{
/* "remove" edge from S and update measure*/
S_diag_j[jS] = -S_diag_j[jS]-1;
measure_array[j]--;
break_var = 0;
break;
}
}
if (break_var)
{
for (kS = S_offd_i[j]; kS < S_offd_i[j+1]; kS++)
{
k = S_offd_j[kS];
if (k < 0) k = -k-1;
/* IMPORTANT: consider all dependencies */
if ( CF_marker_offd[k] == COMMON_C_PT)
{
/* "remove" edge from S and update measure*/
S_diag_j[jS] = -S_diag_j[jS]-1;
measure_array[j]--;
break;
}
}
}
}
}
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++)
{
if (S_offd_j[jS] > -1)
{
j = S_offd_j[jS];
/* check for common C-pt */
for (kS = S_ext_i[j]; kS < S_ext_i[j+1]; kS++)
{
k = S_ext_j[kS];
if (k >= 0)
{
/* IMPORTANT: consider all dependencies */
if (CF_marker[k] == COMMON_C_PT)
{
/* "remove" edge from S and update measure*/
S_offd_j[jS] = -S_offd_j[jS]-1;
measure_array[j+num_variables]--;
break;
}
}
else
{
kc = -k-1;
if (kc > -1 && CF_marker_offd[kc] == COMMON_C_PT)
{
/* "remove" edge from S and update measure*/
S_offd_j[jS] = -S_offd_j[jS]-1;
measure_array[j+num_variables]--;
break;
}
}
}
}
}
}
/* reset CF_marker */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++)
{
j = S_diag_j[jS];
if (j < 0) j = -j-1;
if (CF_marker[j] == COMMON_C_PT)
{
CF_marker[j] = C_PT;
}
}
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++)
{
j = S_offd_j[jS];
if (j < 0) j = -j-1;
if (CF_marker_offd[j] == COMMON_C_PT)
{
CF_marker_offd[j] = C_PT;
}
}
}
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d CLJP phase = %f graph_size = %d nc_offd = %d\n",
my_id, wall_time, graph_size, num_cols_offd);
}
}
/*---------------------------------------------------
* Clean up and return
*---------------------------------------------------*/
/* Reset S_matrix */
for (i=0; i < S_diag_i[num_variables]; i++)
{
if (S_diag_j[i] < 0)
S_diag_j[i] = -S_diag_j[i]-1;
}
for (i=0; i < S_offd_i[num_variables]; i++)
{
if (S_offd_j[i] < 0)
S_offd_j[i] = -S_offd_j[i]-1;
}
/*for (i=0; i < num_variables; i++)
if (CF_marker[i] == SF_PT) CF_marker[i] = F_PT;*/
hypre_TFree(measure_array);
hypre_TFree(graph_array);
if (num_cols_offd) hypre_TFree(graph_array_offd);
hypre_TFree(buf_data);
hypre_TFree(int_buf_data);
hypre_TFree(CF_marker_offd);
if (num_procs > 1) hypre_CSRMatrixDestroy(S_ext);
*CF_marker_ptr = CF_marker;
return (ierr);
}
/*==========================================================================
* Ruge's coarsening algorithm
*==========================================================================*/
#define C_PT 1
#define F_PT -1
#define Z_PT -2
#define SF_PT -3 /* special fine points */
#define SC_PT 3 /* special coarse points */
#define UNDECIDED 0
/**************************************************************
*
* Ruge Coarsening routine
*
**************************************************************/
HYPRE_Int
hypre_BoomerAMGCoarsenRuge( hypre_ParCSRMatrix *S,
hypre_ParCSRMatrix *A,
HYPRE_Int measure_type,
HYPRE_Int coarsen_type,
HYPRE_Int debug_flag,
HYPRE_Int **CF_marker_ptr)
{
MPI_Comm comm = hypre_ParCSRMatrixComm(S);
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(S);
hypre_ParCSRCommHandle *comm_handle;
hypre_CSRMatrix *S_diag = hypre_ParCSRMatrixDiag(S);
hypre_CSRMatrix *S_offd = hypre_ParCSRMatrixOffd(S);
HYPRE_Int *S_i = hypre_CSRMatrixI(S_diag);
HYPRE_Int *S_j = hypre_CSRMatrixJ(S_diag);
HYPRE_Int *S_offd_i = hypre_CSRMatrixI(S_offd);
HYPRE_Int *S_offd_j = NULL;
HYPRE_Int num_variables = hypre_CSRMatrixNumRows(S_diag);
HYPRE_Int num_cols_offd = hypre_CSRMatrixNumCols(S_offd);
HYPRE_Int *col_map_offd = hypre_ParCSRMatrixColMapOffd(S);
hypre_CSRMatrix *S_ext = NULL;
HYPRE_Int *S_ext_i = NULL;
HYPRE_Int *S_ext_j = NULL;
hypre_CSRMatrix *ST;
HYPRE_Int *ST_i;
HYPRE_Int *ST_j;
HYPRE_Int *CF_marker;
HYPRE_Int *CF_marker_offd = NULL;
HYPRE_Int ci_tilde = -1;
HYPRE_Int ci_tilde_mark = -1;
HYPRE_Int ci_tilde_offd = -1;
HYPRE_Int ci_tilde_offd_mark = -1;
HYPRE_Int *measure_array;
HYPRE_Int *graph_array;
HYPRE_Int *int_buf_data = NULL;
HYPRE_Int *ci_array = NULL;
HYPRE_Int i, j, k, jS;
HYPRE_Int ji, jj, jk, jm, index;
HYPRE_Int set_empty = 1;
HYPRE_Int C_i_nonempty = 0;
HYPRE_Int num_nonzeros;
HYPRE_Int num_procs, my_id;
HYPRE_Int num_sends = 0;
HYPRE_Int first_col, start;
HYPRE_Int col_0, col_n;
hypre_LinkList LoL_head;
hypre_LinkList LoL_tail;
HYPRE_Int *lists, *where;
HYPRE_Int measure, new_meas;
HYPRE_Int meas_type = 0;
HYPRE_Int agg_2 = 0;
HYPRE_Int num_left, elmt;
HYPRE_Int nabor, nabor_two;
HYPRE_Int ierr = 0;
HYPRE_Int use_commpkg_A = 0;
HYPRE_Int break_var = 0;
HYPRE_Int f_pnt = F_PT;
double wall_time;
if (coarsen_type < 0) coarsen_type = -coarsen_type;
if (measure_type == 1 || measure_type == 4) meas_type = 1;
if (measure_type == 4 || measure_type == 3) agg_2 = 1;
/*-------------------------------------------------------
* Initialize the C/F marker, LoL_head, LoL_tail arrays
*-------------------------------------------------------*/
LoL_head = NULL;
LoL_tail = NULL;
lists = hypre_CTAlloc(HYPRE_Int, num_variables);
where = hypre_CTAlloc(HYPRE_Int, num_variables);
#if 0 /* debugging */
char filename[256];
FILE *fp;
HYPRE_Int iter = 0;
#endif
/*--------------------------------------------------------------
* Compute a CSR strength matrix, S.
*
* For now, the "strength" of dependence/influence is defined in
* the following way: i depends on j if
* aij > hypre_max (k != i) aik, aii < 0
* or
* aij < hypre_min (k != i) aik, aii >= 0
* Then S_ij = 1, else S_ij = 0.
*
* NOTE: the entries are negative initially, corresponding
* to "unaccounted-for" dependence.
*----------------------------------------------------------------*/
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
first_col = hypre_ParCSRMatrixFirstColDiag(S);
col_0 = first_col-1;
col_n = col_0+num_variables;
hypre_MPI_Comm_size(comm,&num_procs);
hypre_MPI_Comm_rank(comm,&my_id);
if (!comm_pkg)
{
use_commpkg_A = 1;
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A);
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
if (num_cols_offd) S_offd_j = hypre_CSRMatrixJ(S_offd);
jS = S_i[num_variables];
ST = hypre_CSRMatrixCreate(num_variables, num_variables, jS);
ST_i = hypre_CTAlloc(HYPRE_Int,num_variables+1);
ST_j = hypre_CTAlloc(HYPRE_Int,jS);
hypre_CSRMatrixI(ST) = ST_i;
hypre_CSRMatrixJ(ST) = ST_j;
/*----------------------------------------------------------
* generate transpose of S, ST
*----------------------------------------------------------*/
for (i=0; i <= num_variables; i++)
ST_i[i] = 0;
for (i=0; i < jS; i++)
{
ST_i[S_j[i]+1]++;
}
for (i=0; i < num_variables; i++)
{
ST_i[i+1] += ST_i[i];
}
for (i=0; i < num_variables; i++)
{
for (j=S_i[i]; j < S_i[i+1]; j++)
{
index = S_j[j];
ST_j[ST_i[index]] = i;
ST_i[index]++;
}
}
for (i = num_variables; i > 0; i--)
{
ST_i[i] = ST_i[i-1];
}
ST_i[0] = 0;
/*----------------------------------------------------------
* Compute the measures
*
* The measures are given by the row sums of ST.
* Hence, measure_array[i] is the number of influences
* of variable i.
* correct actual measures through adding influences from
* neighbor processors
*----------------------------------------------------------*/
measure_array = hypre_CTAlloc(HYPRE_Int, num_variables);
for (i = 0; i < num_variables; i++)
{
measure_array[i] = ST_i[i+1]-ST_i[i];
}
/* special case for Falgout coarsening */
if (coarsen_type == 6)
{
f_pnt = Z_PT;
coarsen_type = 1;
}
if (coarsen_type == 10)
{
f_pnt = Z_PT;
coarsen_type = 11;
}
if ((meas_type || (coarsen_type != 1 && coarsen_type != 11))
&& num_procs > 1)
{
if (use_commpkg_A)
S_ext = hypre_ParCSRMatrixExtractBExt(S,A,0);
else
S_ext = hypre_ParCSRMatrixExtractBExt(S,S,0);
S_ext_i = hypre_CSRMatrixI(S_ext);
S_ext_j = hypre_CSRMatrixJ(S_ext);
num_nonzeros = S_ext_i[num_cols_offd];
/*first_col = hypre_ParCSRMatrixFirstColDiag(S);
col_0 = first_col-1;
col_n = col_0+num_variables; */
if (meas_type)
{
for (i=0; i < num_nonzeros; i++)
{
index = S_ext_j[i] - first_col;
if (index > -1 && index < num_variables)
measure_array[index]++;
}
}
}
/*---------------------------------------------------
* Loop until all points are either fine or coarse.
*---------------------------------------------------*/
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
/* first coarsening phase */
/*************************************************************
*
* Initialize the lists
*
*************************************************************/
CF_marker = hypre_CTAlloc(HYPRE_Int, num_variables);
num_left = 0;
for (j = 0; j < num_variables; j++)
{
if ((S_i[j+1]-S_i[j])== 0 &&
(S_offd_i[j+1]-S_offd_i[j]) == 0)
{
CF_marker[j] = SF_PT;
if (agg_2) CF_marker[j] = SC_PT;
measure_array[j] = 0;
}
else
{
CF_marker[j] = UNDECIDED;
num_left++;
}
}
for (j = 0; j < num_variables; j++)
{
measure = measure_array[j];
if (CF_marker[j] != SF_PT && CF_marker[j] != SC_PT)
{
if (measure > 0)
{
enter_on_lists(&LoL_head, &LoL_tail, measure, j, lists, where);
}
else
{
if (measure < 0) hypre_printf("negative measure!\n");
CF_marker[j] = f_pnt;
for (k = S_i[j]; k < S_i[j+1]; k++)
{
nabor = S_j[k];
if (CF_marker[nabor] != SF_PT && CF_marker[nabor] != SC_PT)
{
if (nabor < j)
{
new_meas = measure_array[nabor];
if (new_meas > 0)
remove_point(&LoL_head, &LoL_tail, new_meas,
nabor, lists, where);
new_meas = ++(measure_array[nabor]);
enter_on_lists(&LoL_head, &LoL_tail, new_meas,
nabor, lists, where);
}
else
{
new_meas = ++(measure_array[nabor]);
}
}
}
--num_left;
}
}
}
/****************************************************************
*
* Main loop of Ruge-Stueben first coloring pass.
*
* WHILE there are still points to classify DO:
* 1) find first point, i, on list with max_measure
* make i a C-point, remove it from the lists
* 2) For each point, j, in S_i^T,
* a) Set j to be an F-point
* b) For each point, k, in S_j
* move k to the list in LoL with measure one
* greater than it occupies (creating new LoL
* entry if necessary)
* 3) For each point, j, in S_i,
* move j to the list in LoL with measure one
* smaller than it occupies (creating new LoL
* entry if necessary)
*
****************************************************************/
while (num_left > 0)
{
index = LoL_head -> head;
CF_marker[index] = C_PT;
measure = measure_array[index];
measure_array[index] = 0;
--num_left;
remove_point(&LoL_head, &LoL_tail, measure, index, lists, where);
for (j = ST_i[index]; j < ST_i[index+1]; j++)
{
nabor = ST_j[j];
if (CF_marker[nabor] == UNDECIDED)
{
CF_marker[nabor] = F_PT;
measure = measure_array[nabor];
remove_point(&LoL_head, &LoL_tail, measure, nabor, lists, where);
--num_left;
for (k = S_i[nabor]; k < S_i[nabor+1]; k++)
{
nabor_two = S_j[k];
if (CF_marker[nabor_two] == UNDECIDED)
{
measure = measure_array[nabor_two];
remove_point(&LoL_head, &LoL_tail, measure,
nabor_two, lists, where);
new_meas = ++(measure_array[nabor_two]);
enter_on_lists(&LoL_head, &LoL_tail, new_meas,
nabor_two, lists, where);
}
}
}
}
for (j = S_i[index]; j < S_i[index+1]; j++)
{
nabor = S_j[j];
if (CF_marker[nabor] == UNDECIDED)
{
measure = measure_array[nabor];
remove_point(&LoL_head, &LoL_tail, measure, nabor, lists, where);
measure_array[nabor] = --measure;
if (measure > 0)
enter_on_lists(&LoL_head, &LoL_tail, measure, nabor,
lists, where);
else
{
CF_marker[nabor] = F_PT;
--num_left;
for (k = S_i[nabor]; k < S_i[nabor+1]; k++)
{
nabor_two = S_j[k];
if (CF_marker[nabor_two] == UNDECIDED)
{
new_meas = measure_array[nabor_two];
remove_point(&LoL_head, &LoL_tail, new_meas,
nabor_two, lists, where);
new_meas = ++(measure_array[nabor_two]);
enter_on_lists(&LoL_head, &LoL_tail, new_meas,
nabor_two, lists, where);
}
}
}
}
}
}
hypre_TFree(measure_array);
hypre_CSRMatrixDestroy(ST);
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d Coarsen 1st pass = %f\n",
my_id, wall_time);
}
hypre_TFree(lists);
hypre_TFree(where);
hypre_TFree(LoL_head);
hypre_TFree(LoL_tail);
for (i=0; i < num_variables; i++)
if (CF_marker[i] == SC_PT) CF_marker[i] = C_PT;
if (coarsen_type == 11)
{
*CF_marker_ptr = CF_marker;
return 0;
}
/* second pass, check fine points for coarse neighbors
for coarsen_type = 2, the second pass includes
off-processore boundary points */
/*---------------------------------------------------
* Initialize the graph array
*---------------------------------------------------*/
graph_array = hypre_CTAlloc(HYPRE_Int, num_variables);
for (i = 0; i < num_variables; i++)
{
graph_array[i] = -1;
}
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
if (coarsen_type == 2)
{
/*------------------------------------------------
* Exchange boundary data for CF_marker
*------------------------------------------------*/
CF_marker_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
int_buf_data = hypre_CTAlloc(HYPRE_Int, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
int_buf_data[index++]
= CF_marker[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)];
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
ci_array = hypre_CTAlloc(HYPRE_Int,num_cols_offd);
for (i=0; i < num_cols_offd; i++)
ci_array[i] = -1;
for (i=0; i < num_variables; i++)
{
if (ci_tilde_mark != i) ci_tilde = -1;
if (ci_tilde_offd_mark != i) ci_tilde_offd = -1;
if (CF_marker[i] == -1)
{
break_var = 1;
for (ji = S_i[i]; ji < S_i[i+1]; ji++)
{
j = S_j[ji];
if (CF_marker[j] > 0)
graph_array[j] = i;
}
for (ji = S_offd_i[i]; ji < S_offd_i[i+1]; ji++)
{
j = S_offd_j[ji];
if (CF_marker_offd[j] > 0)
ci_array[j] = i;
}
for (ji = S_i[i]; ji < S_i[i+1]; ji++)
{
j = S_j[ji];
if (CF_marker[j] == -1)
{
set_empty = 1;
for (jj = S_i[j]; jj < S_i[j+1]; jj++)
{
index = S_j[jj];
if (graph_array[index] == i)
{
set_empty = 0;
break;
}
}
if (set_empty)
{
for (jj = S_offd_i[j]; jj < S_offd_i[j+1]; jj++)
{
index = S_offd_j[jj];
if (ci_array[index] == i)
{
set_empty = 0;
break;
}
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker[i] = 1;
if (ci_tilde > -1)
{
CF_marker[ci_tilde] = -1;
ci_tilde = -1;
}
if (ci_tilde_offd > -1)
{
CF_marker_offd[ci_tilde_offd] = -1;
ci_tilde_offd = -1;
}
C_i_nonempty = 0;
break_var = 0;
break;
}
else
{
ci_tilde = j;
ci_tilde_mark = i;
CF_marker[j] = 1;
C_i_nonempty = 1;
i--;
break_var = 0;
break;
}
}
}
}
if (break_var)
{
for (ji = S_offd_i[i]; ji < S_offd_i[i+1]; ji++)
{
j = S_offd_j[ji];
if (CF_marker_offd[j] == -1)
{
set_empty = 1;
for (jj = S_ext_i[j]; jj < S_ext_i[j+1]; jj++)
{
index = S_ext_j[jj];
if (index > col_0 && index < col_n) /* index interior */
{
if (graph_array[index-first_col] == i)
{
set_empty = 0;
break;
}
}
else
{
jk = hypre_BinarySearch(col_map_offd,index,num_cols_offd);
if (jk != -1)
{
if (ci_array[jk] == i)
{
set_empty = 0;
break;
}
}
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker[i] = 1;
if (ci_tilde > -1)
{
CF_marker[ci_tilde] = -1;
ci_tilde = -1;
}
if (ci_tilde_offd > -1)
{
CF_marker_offd[ci_tilde_offd] = -1;
ci_tilde_offd = -1;
}
C_i_nonempty = 0;
break;
}
else
{
ci_tilde_offd = j;
ci_tilde_offd_mark = i;
CF_marker_offd[j] = 1;
C_i_nonempty = 1;
i--;
break;
}
}
}
}
}
}
}
}
else
{
for (i=0; i < num_variables; i++)
{
if (ci_tilde_mark != i) ci_tilde = -1;
if (CF_marker[i] == -1)
{
for (ji = S_i[i]; ji < S_i[i+1]; ji++)
{
j = S_j[ji];
if (CF_marker[j] > 0)
graph_array[j] = i;
}
for (ji = S_i[i]; ji < S_i[i+1]; ji++)
{
j = S_j[ji];
if (CF_marker[j] == -1)
{
set_empty = 1;
for (jj = S_i[j]; jj < S_i[j+1]; jj++)
{
index = S_j[jj];
if (graph_array[index] == i)
{
set_empty = 0;
break;
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker[i] = 1;
if (ci_tilde > -1)
{
CF_marker[ci_tilde] = -1;
ci_tilde = -1;
}
C_i_nonempty = 0;
break;
}
else
{
ci_tilde = j;
ci_tilde_mark = i;
CF_marker[j] = 1;
C_i_nonempty = 1;
i--;
break;
}
}
}
}
}
}
}
if (debug_flag == 3 && coarsen_type != 2)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d Coarsen 2nd pass = %f\n",
my_id, wall_time);
}
/* third pass, check boundary fine points for coarse neighbors */
if (coarsen_type == 3 || coarsen_type == 4)
{
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
CF_marker_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
int_buf_data = hypre_CTAlloc(HYPRE_Int, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
/*------------------------------------------------
* Exchange boundary data for CF_marker
*------------------------------------------------*/
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
int_buf_data[index++]
= CF_marker[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)];
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
ci_array = hypre_CTAlloc(HYPRE_Int,num_cols_offd);
for (i=0; i < num_cols_offd; i++)
ci_array[i] = -1;
}
if (coarsen_type > 1 && coarsen_type < 5)
{
for (i=0; i < num_variables; i++)
graph_array[i] = -1;
for (i=0; i < num_cols_offd; i++)
{
if (ci_tilde_mark != i) ci_tilde = -1;
if (ci_tilde_offd_mark != i) ci_tilde_offd = -1;
if (CF_marker_offd[i] == -1)
{
for (ji = S_ext_i[i]; ji < S_ext_i[i+1]; ji++)
{
j = S_ext_j[ji];
if (j > col_0 && j < col_n)
{
j = j - first_col;
if (CF_marker[j] > 0)
graph_array[j] = i;
}
else
{
jj = hypre_BinarySearch(col_map_offd,j,num_cols_offd);
if (jj != -1 && CF_marker_offd[jj] > 0)
ci_array[jj] = i;
}
}
for (ji = S_ext_i[i]; ji < S_ext_i[i+1]; ji++)
{
j = S_ext_j[ji];
if (j > col_0 && j < col_n)
{
j = j - first_col;
if ( CF_marker[j] == -1)
{
set_empty = 1;
for (jj = S_i[j]; jj < S_i[j+1]; jj++)
{
index = S_j[jj];
if (graph_array[index] == i)
{
set_empty = 0;
break;
}
}
for (jj = S_offd_i[j]; jj < S_offd_i[j+1]; jj++)
{
index = S_offd_j[jj];
if (ci_array[index] == i)
{
set_empty = 0;
break;
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker_offd[i] = 1;
if (ci_tilde > -1)
{
CF_marker[ci_tilde] = -1;
ci_tilde = -1;
}
if (ci_tilde_offd > -1)
{
CF_marker_offd[ci_tilde_offd] = -1;
ci_tilde_offd = -1;
}
C_i_nonempty = 0;
break;
}
else
{
ci_tilde = j;
ci_tilde_mark = i;
CF_marker[j] = 1;
C_i_nonempty = 1;
i--;
break;
}
}
}
}
else
{
jm = hypre_BinarySearch(col_map_offd,j,num_cols_offd);
if (jm != -1 && CF_marker_offd[jm] == -1)
{
set_empty = 1;
for (jj = S_ext_i[jm]; jj < S_ext_i[jm+1]; jj++)
{
index = S_ext_j[jj];
if (index > col_0 && index < col_n)
{
if (graph_array[index-first_col] == i)
{
set_empty = 0;
break;
}
}
else
{
jk = hypre_BinarySearch(col_map_offd,index,num_cols_offd);
if (jk != -1)
{
if (ci_array[jk] == i)
{
set_empty = 0;
break;
}
}
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker_offd[i] = 1;
if (ci_tilde > -1)
{
CF_marker[ci_tilde] = -1;
ci_tilde = -1;
}
if (ci_tilde_offd > -1)
{
CF_marker_offd[ci_tilde_offd] = -1;
ci_tilde_offd = -1;
}
C_i_nonempty = 0;
break;
}
else
{
ci_tilde_offd = jm;
ci_tilde_offd_mark = i;
CF_marker_offd[jm] = 1;
C_i_nonempty = 1;
i--;
break;
}
}
}
}
}
}
}
/*------------------------------------------------
* Send boundary data for CF_marker back
*------------------------------------------------*/
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(12, comm_pkg, CF_marker_offd,
int_buf_data);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
/* only CF_marker entries from larger procs are accepted
if coarsen_type = 4 coarse points are not overwritten */
index = 0;
if (coarsen_type != 4)
{
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
if (hypre_ParCSRCommPkgSendProc(comm_pkg,i) > my_id)
{
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
CF_marker[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)] =
int_buf_data[index++];
}
else
{
index += hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1) - start;
}
}
}
else
{
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
if (hypre_ParCSRCommPkgSendProc(comm_pkg,i) > my_id)
{
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
elmt = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
if (CF_marker[elmt] != 1)
CF_marker[elmt] = int_buf_data[index];
index++;
}
}
else
{
index += hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1) - start;
}
}
}
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
if (coarsen_type == 4)
hypre_printf("Proc = %d Coarsen 3rd pass = %f\n",
my_id, wall_time);
if (coarsen_type == 3)
hypre_printf("Proc = %d Coarsen 3rd pass = %f\n",
my_id, wall_time);
if (coarsen_type == 2)
hypre_printf("Proc = %d Coarsen 2nd pass = %f\n",
my_id, wall_time);
}
}
if (coarsen_type == 5)
{
/*------------------------------------------------
* Exchange boundary data for CF_marker
*------------------------------------------------*/
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
CF_marker_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
int_buf_data = hypre_CTAlloc(HYPRE_Int, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
int_buf_data[index++]
= CF_marker[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)];
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
ci_array = hypre_CTAlloc(HYPRE_Int,num_cols_offd);
for (i=0; i < num_cols_offd; i++)
ci_array[i] = -1;
for (i=0; i < num_variables; i++)
graph_array[i] = -1;
for (i=0; i < num_variables; i++)
{
if (CF_marker[i] == -1 && (S_offd_i[i+1]-S_offd_i[i]) > 0)
{
break_var = 1;
for (ji = S_i[i]; ji < S_i[i+1]; ji++)
{
j = S_j[ji];
if (CF_marker[j] > 0)
graph_array[j] = i;
}
for (ji = S_offd_i[i]; ji < S_offd_i[i+1]; ji++)
{
j = S_offd_j[ji];
if (CF_marker_offd[j] > 0)
ci_array[j] = i;
}
for (ji = S_offd_i[i]; ji < S_offd_i[i+1]; ji++)
{
j = S_offd_j[ji];
if (CF_marker_offd[j] == -1)
{
set_empty = 1;
for (jj = S_ext_i[j]; jj < S_ext_i[j+1]; jj++)
{
index = S_ext_j[jj];
if (index > col_0 && index < col_n) /* index interior */
{
if (graph_array[index-first_col] == i)
{
set_empty = 0;
break;
}
}
else
{
jk = hypre_BinarySearch(col_map_offd,index,num_cols_offd);
if (jk != -1)
{
if (ci_array[jk] == i)
{
set_empty = 0;
break;
}
}
}
}
if (set_empty)
{
if (C_i_nonempty)
{
CF_marker[i] = -2;
C_i_nonempty = 0;
break;
}
else
{
C_i_nonempty = 1;
i--;
break;
}
}
}
}
}
}
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d Coarsen special points = %f\n",
my_id, wall_time);
}
}
/*---------------------------------------------------
* Clean up and return
*---------------------------------------------------*/
/*if (coarsen_type != 1)
{ */
hypre_TFree(CF_marker_offd);
hypre_TFree(int_buf_data);
hypre_TFree(ci_array);
/*} */
hypre_TFree(graph_array);
if ((meas_type || (coarsen_type != 1 && coarsen_type != 11))
&& num_procs > 1)
hypre_CSRMatrixDestroy(S_ext);
*CF_marker_ptr = CF_marker;
return (ierr);
}
HYPRE_Int
hypre_BoomerAMGCoarsenFalgout( hypre_ParCSRMatrix *S,
hypre_ParCSRMatrix *A,
HYPRE_Int measure_type,
HYPRE_Int debug_flag,
HYPRE_Int **CF_marker_ptr)
{
HYPRE_Int ierr = 0;
/*-------------------------------------------------------
* Perform Ruge coarsening followed by CLJP coarsening
*-------------------------------------------------------*/
ierr += hypre_BoomerAMGCoarsenRuge (S, A, measure_type, 6, debug_flag,
CF_marker_ptr);
ierr += hypre_BoomerAMGCoarsen (S, A, 1, debug_flag,
CF_marker_ptr);
return (ierr);
}
HYPRE_Int
hypre_BoomerAMGCoarsenHMIS( hypre_ParCSRMatrix *S,
hypre_ParCSRMatrix *A,
HYPRE_Int measure_type,
HYPRE_Int debug_flag,
HYPRE_Int **CF_marker_ptr)
{
HYPRE_Int ierr = 0;
/*-------------------------------------------------------
* Perform Ruge coarsening followed by CLJP coarsening
*-------------------------------------------------------*/
ierr += hypre_BoomerAMGCoarsenRuge (S, A, measure_type, 10, debug_flag,
CF_marker_ptr);
ierr += hypre_BoomerAMGCoarsenPMIS (S, A, 1, debug_flag,
CF_marker_ptr);
return (ierr);
}
/*--------------------------------------------------------------------------*/
#define C_PT 1
#define F_PT -1
#define SF_PT -3
#define COMMON_C_PT 2
#define Z_PT -2
/* begin HANS added */
/**************************************************************
*
* Modified Independent Set Coarsening routine
* (don't worry about strong F-F connections
* without a common C point)
*
**************************************************************/
HYPRE_Int
hypre_BoomerAMGCoarsenPMIS( hypre_ParCSRMatrix *S,
hypre_ParCSRMatrix *A,
HYPRE_Int CF_init,
HYPRE_Int debug_flag,
HYPRE_Int **CF_marker_ptr)
{
MPI_Comm comm = hypre_ParCSRMatrixComm(S);
hypre_ParCSRCommPkg *comm_pkg = hypre_ParCSRMatrixCommPkg(S);
hypre_ParCSRCommHandle *comm_handle;
hypre_CSRMatrix *S_diag = hypre_ParCSRMatrixDiag(S);
HYPRE_Int *S_diag_i = hypre_CSRMatrixI(S_diag);
HYPRE_Int *S_diag_j = hypre_CSRMatrixJ(S_diag);
hypre_CSRMatrix *S_offd = hypre_ParCSRMatrixOffd(S);
HYPRE_Int *S_offd_i = hypre_CSRMatrixI(S_offd);
HYPRE_Int *S_offd_j;
HYPRE_Int num_variables = hypre_CSRMatrixNumRows(S_diag);
HYPRE_Int num_cols_offd = 0;
/* hypre_CSRMatrix *S_ext;
HYPRE_Int *S_ext_i;
HYPRE_Int *S_ext_j; */
HYPRE_Int num_sends = 0;
HYPRE_Int *int_buf_data;
double *buf_data;
HYPRE_Int *CF_marker;
HYPRE_Int *CF_marker_offd;
double *measure_array;
HYPRE_Int *graph_array;
HYPRE_Int *graph_array_offd;
HYPRE_Int graph_size;
HYPRE_Int graph_offd_size;
HYPRE_Int global_graph_size;
HYPRE_Int i, j, jS, ig;
HYPRE_Int index, start, my_id, num_procs, jrow, cnt, elmt;
HYPRE_Int ierr = 0;
double wall_time;
HYPRE_Int iter = 0;
#if 0 /* debugging */
char filename[256];
FILE *fp;
HYPRE_Int iter = 0;
#endif
/*******************************************************************************
BEFORE THE INDEPENDENT SET COARSENING LOOP:
measure_array: calculate the measures, and communicate them
(this array contains measures for both local and external nodes)
CF_marker, CF_marker_offd: initialize CF_marker
(separate arrays for local and external; 0=unassigned, negative=F point, positive=C point)
******************************************************************************/
/*--------------------------------------------------------------
* Use the ParCSR strength matrix, S.
*
* For now, the "strength" of dependence/influence is defined in
* the following way: i depends on j if
* aij > hypre_max (k != i) aik, aii < 0
* or
* aij < hypre_min (k != i) aik, aii >= 0
* Then S_ij = 1, else S_ij = 0.
*
* NOTE: S_data is not used; in stead, only strong columns are retained
* in S_j, which can then be used like S_data
*----------------------------------------------------------------*/
/*S_ext = NULL; */
if (debug_flag == 3) wall_time = time_getWallclockSeconds();
hypre_MPI_Comm_size(comm,&num_procs);
hypre_MPI_Comm_rank(comm,&my_id);
if (!comm_pkg)
{
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
if (!comm_pkg)
{
hypre_MatvecCommPkgCreate(A);
comm_pkg = hypre_ParCSRMatrixCommPkg(A);
}
num_sends = hypre_ParCSRCommPkgNumSends(comm_pkg);
int_buf_data = hypre_CTAlloc(HYPRE_Int, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
buf_data = hypre_CTAlloc(double, hypre_ParCSRCommPkgSendMapStart(comm_pkg,
num_sends));
num_cols_offd = hypre_CSRMatrixNumCols(S_offd);
S_diag_j = hypre_CSRMatrixJ(S_diag);
if (num_cols_offd)
{
S_offd_j = hypre_CSRMatrixJ(S_offd);
}
/*----------------------------------------------------------
* Compute the measures
*
* The measures are currently given by the column sums of S.
* Hence, measure_array[i] is the number of influences
* of variable i.
*
* The measures are augmented by a random number
* between 0 and 1.
*----------------------------------------------------------*/
measure_array = hypre_CTAlloc(double, num_variables+num_cols_offd);
/* first calculate the local part of the sums for the external nodes */
for (i=0; i < S_offd_i[num_variables]; i++)
{
measure_array[num_variables + S_offd_j[i]] += 1.0;
}
/* now send those locally calculated values for the external nodes to the neighboring processors */
if (num_procs > 1)
comm_handle = hypre_ParCSRCommHandleCreate(2, comm_pkg,
&measure_array[num_variables], buf_data);
/* calculate the local part for the local nodes */
for (i=0; i < S_diag_i[num_variables]; i++)
{
measure_array[S_diag_j[i]] += 1.0;
}
/* finish the communication */
if (num_procs > 1)
hypre_ParCSRCommHandleDestroy(comm_handle);
/* now add the externally calculated part of the local nodes to the local nodes */
index = 0;
for (i=0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j=start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
measure_array[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)]
+= buf_data[index++];
}
/* set the measures of the external nodes to zero */
for (i=num_variables; i < num_variables+num_cols_offd; i++)
{
measure_array[i] = 0;
}
/* this augments the measures with a random number between 0 and 1 */
/* (only for the local part) */
/* this augments the measures */
if (CF_init == 2 || CF_init == 4)
hypre_BoomerAMGIndepSetInit(S, measure_array, 1);
else
hypre_BoomerAMGIndepSetInit(S, measure_array, 0);
/*---------------------------------------------------
* Initialize the graph arrays, and CF_marker arrays
*---------------------------------------------------*/
/* first the off-diagonal part of the graph array */
if (num_cols_offd)
graph_array_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
else
graph_array_offd = NULL;
for (ig = 0; ig < num_cols_offd; ig++)
graph_array_offd[ig] = ig;
graph_offd_size = num_cols_offd;
/* now the local part of the graph array, and the local CF_marker array */
graph_array = hypre_CTAlloc(HYPRE_Int, num_variables);
if (CF_init==1)
{
CF_marker = *CF_marker_ptr;
cnt = 0;
for (i=0; i < num_variables; i++)
{
if ( (S_offd_i[i+1]-S_offd_i[i]) > 0 || CF_marker[i] == -1)
{
CF_marker[i] = 0;
}
if ( CF_marker[i] == Z_PT)
{
if (measure_array[i] >= 1.0 ||
(S_diag_i[i+1]-S_diag_i[i]) > 0)
{
CF_marker[i] = 0;
graph_array[cnt++] = i;
}
else
{
CF_marker[i] = F_PT;
}
}
else if (CF_marker[i] == SF_PT)
measure_array[i] = 0;
else
graph_array[cnt++] = i;
}
}
else
{
CF_marker = hypre_CTAlloc(HYPRE_Int, num_variables);
cnt = 0;
for (i=0; i < num_variables; i++)
{
CF_marker[i] = 0;
if ( (S_diag_i[i+1]-S_diag_i[i]) == 0
&& (S_offd_i[i+1]-S_offd_i[i]) == 0)
{
CF_marker[i] = SF_PT;
if (CF_init == 3 || CF_init == 4) CF_marker[i] = C_PT;
measure_array[i] = 0;
}
else
graph_array[cnt++] = i;
}
}
graph_size = cnt;
/* now the off-diagonal part of CF_marker */
if (num_cols_offd)
CF_marker_offd = hypre_CTAlloc(HYPRE_Int, num_cols_offd);
else
CF_marker_offd = NULL;
for (i=0; i < num_cols_offd; i++)
CF_marker_offd[i] = 0;
/*------------------------------------------------
* Communicate the local measures, which are complete,
to the external nodes
*------------------------------------------------*/
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
jrow = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
buf_data[index++] = measure_array[jrow];
}
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(1, comm_pkg, buf_data,
&measure_array[num_variables]);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
/* we need S_ext: the columns of the S matrix for the local nodes */
/* we need this because the independent set routine can only decide
which local nodes are in it when it knows both the rows and columns
of S */
/* if (num_procs > 1)
{
S_ext = hypre_ParCSRMatrixExtractBExt(S,A,0);
S_ext_i = hypre_CSRMatrixI(S_ext);
S_ext_j = hypre_CSRMatrixJ(S_ext);
} */
/* compress S_ext and convert column numbers*/
/* index = 0;
for (i=0; i < num_cols_offd; i++)
{
for (j=S_ext_i[i]; j < S_ext_i[i+1]; j++)
{
k = S_ext_j[j];
if (k >= col_1 && k < col_n)
{
S_ext_j[index++] = k - col_1;
}
else
{
kc = hypre_BinarySearch(col_map_offd,k,num_cols_offd);
if (kc > -1) S_ext_j[index++] = -kc-1;
}
}
S_ext_i[i] = index;
}
for (i = num_cols_offd; i > 0; i--)
S_ext_i[i] = S_ext_i[i-1];
if (num_procs > 1) S_ext_i[0] = 0; */
if (debug_flag == 3)
{
wall_time = time_getWallclockSeconds() - wall_time;
hypre_printf("Proc = %d Initialize CLJP phase = %f\n",
my_id, wall_time);
}
/*******************************************************************************
THE INDEPENDENT SET COARSENING LOOP:
******************************************************************************/
/*---------------------------------------------------
* Loop until all points are either fine or coarse.
*---------------------------------------------------*/
while (1)
{
/* stop the coarsening if nothing left to be coarsened */
hypre_MPI_Allreduce(&graph_size,&global_graph_size,1,HYPRE_MPI_INT,hypre_MPI_SUM,comm);
if (global_graph_size == 0)
break;
/* hypre_printf("\n");
hypre_printf("*** MIS iteration %d\n",iter);
hypre_printf("graph_size remaining %d\n",graph_size);*/
/*------------------------------------------------
* Pick an independent set of points with
* maximal measure.
At the end, CF_marker is complete, but still needs to be
communicated to CF_marker_offd
*------------------------------------------------*/
if (!CF_init || iter)
{
hypre_BoomerAMGIndepSet(S, measure_array, graph_array,
graph_size,
graph_array_offd, graph_offd_size,
CF_marker, CF_marker_offd);
/*------------------------------------------------
* Exchange boundary data for CF_marker: send internal
points to external points
*------------------------------------------------*/
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(12, comm_pkg,
CF_marker_offd, int_buf_data);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j=start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
{
elmt = hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j);
if (!int_buf_data[index] && CF_marker[elmt] > 0)
{
CF_marker[elmt] = 0;
index++;
}
else
{
int_buf_data[index++] = CF_marker[elmt];
}
}
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
}
iter++;
/*------------------------------------------------
* Set C-pts and F-pts.
*------------------------------------------------*/
for (ig = 0; ig < graph_size; ig++) {
i = graph_array[ig];
/*---------------------------------------------
* If the measure of i is smaller than 1, then
* make i and F point (because it does not influence
* any other point), and remove all edges of
* equation i.
*---------------------------------------------*/
if(measure_array[i]<1.){
/* make point i an F point*/
CF_marker[i]= F_PT;
/* remove the edges in equation i */
/* first the local part */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++) {
j = S_diag_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
}
/* now the external part */
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++) {
j = S_offd_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
}
}
/*---------------------------------------------
* First treat the case where point i is in the
* independent set: make i a C point,
* take out all the graph edges for
* equation i.
*---------------------------------------------*/
if (CF_marker[i] > 0) {
/* set to be a C-pt */
CF_marker[i] = C_PT;
/* remove the edges in equation i */
/* first the local part */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++) {
j = S_diag_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
}
/* now the external part */
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++) {
j = S_offd_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
}
}
/*---------------------------------------------
* Now treat the case where point i is not in the
* independent set: loop over
* all the points j that influence equation i; if
* j is a C point, then make i an F point.
* If i is a new F point, then remove all the edges
* from the graph for equation i.
*---------------------------------------------*/
else {
/* first the local part */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++) {
/* j is the column number, or the local number of the point influencing i */
j = S_diag_j[jS];
if(j<0) j=-j-1;
if (CF_marker[j] > 0){ /* j is a C-point */
CF_marker[i] = F_PT;
}
}
/* now the external part */
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++) {
j = S_offd_j[jS];
if(j<0) j=-j-1;
if (CF_marker_offd[j] > 0){ /* j is a C-point */
CF_marker[i] = F_PT;
}
}
/* remove all the edges for equation i if i is a new F point */
if (CF_marker[i] == F_PT){
/* first the local part */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++) {
j = S_diag_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
}
/* now the external part */
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++) {
j = S_offd_j[jS];
if (j > -1){ /* column number is still positive; not accounted for yet */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
}
}
} /* end else */
} /* end first loop over graph */
/* now communicate CF_marker to CF_marker_offd, to make
sure that new external F points are known on this processor */
/*------------------------------------------------
* Exchange boundary data for CF_marker: send internal
points to external points
*------------------------------------------------*/
index = 0;
for (i = 0; i < num_sends; i++)
{
start = hypre_ParCSRCommPkgSendMapStart(comm_pkg, i);
for (j = start; j < hypre_ParCSRCommPkgSendMapStart(comm_pkg, i+1); j++)
int_buf_data[index++]
= CF_marker[hypre_ParCSRCommPkgSendMapElmt(comm_pkg,j)];
}
if (num_procs > 1)
{
comm_handle = hypre_ParCSRCommHandleCreate(11, comm_pkg, int_buf_data,
CF_marker_offd);
hypre_ParCSRCommHandleDestroy(comm_handle);
}
/*---------------------------------------------
* Now loop over the points i in the unassigned
* graph again. For all points i that are no new C or
* F points, remove the edges in equation i that
* connect to C or F points.
* (We have removed the rows for the new C and F
* points above; now remove the columns.)
*---------------------------------------------*/
for (ig = 0; ig < graph_size; ig++) {
i = graph_array[ig];
if(CF_marker[i]==0) {
/* first the local part */
for (jS = S_diag_i[i]; jS < S_diag_i[i+1]; jS++) {
j = S_diag_j[jS];
if(j<0) j=-j-1;
if (!CF_marker[j]==0 && S_diag_j[jS] > -1){ /* connection to C or F point, and
column number is still positive; not accounted for yet */
S_diag_j[jS] = -S_diag_j[jS]-1;
}
}
/* now the external part */
for (jS = S_offd_i[i]; jS < S_offd_i[i+1]; jS++) {
j = S_offd_j[jS];
if(j<0) j=-j-1;
if (!CF_marker_offd[j]==0 && S_offd_j[jS] > -1){ /* connection to C or F point, and
column number is still positive; not accounted for yet */
S_offd_j[jS] = -S_offd_j[jS]-1;
}
}
}
} /* end second loop over graph */
/*------------------------------------------------
* Update subgraph
*------------------------------------------------*/
for (ig = 0; ig < graph_size; ig++) {
i = graph_array[ig];
if (!CF_marker[i]==0) /* C or F point */
{
/* the independent set subroutine needs measure 0 for
removed nodes */
measure_array[i] = 0;
/* take point out of the subgraph */
graph_size--;
graph_array[ig] = graph_array[graph_size];
graph_array[graph_size] = i;
ig--;
}
}
for (ig = 0; ig < graph_offd_size; ig++) {
i = graph_array_offd[ig];
if (!CF_marker_offd[i]==0) /* C or F point */
{
/* the independent set subroutine needs measure 0 for
removed nodes */
measure_array[i+num_variables] = 0;
/* take point out of the subgraph */
graph_offd_size--;
graph_array_offd[ig] = graph_array_offd[graph_offd_size];
graph_array_offd[graph_offd_size] = i;
ig--;
}
}
} /* end while */
/* hypre_printf("*** MIS iteration %d\n",iter);
hypre_printf("graph_size remaining %d\n",graph_size);
hypre_printf("num_cols_offd %d\n",num_cols_offd);
for (i=0;i<num_variables;i++)
{
if(CF_marker[i]==1)
hypre_printf("node %d CF %d\n",i,CF_marker[i]);
}*/
/*---------------------------------------------------
* Clean up and return
*---------------------------------------------------*/
/* Reset S_matrix */
for (i=0; i < S_diag_i[num_variables]; i++)
{
if (S_diag_j[i] < 0)
S_diag_j[i] = -S_diag_j[i]-1;
}
for (i=0; i < S_offd_i[num_variables]; i++)
{
if (S_offd_j[i] < 0)
S_offd_j[i] = -S_offd_j[i]-1;
}
/*for (i=0; i < num_variables; i++)
if (CF_marker[i] == SF_PT) CF_marker[i] = F_PT;*/
hypre_TFree(measure_array);
hypre_TFree(graph_array);
if (num_cols_offd) hypre_TFree(graph_array_offd);
hypre_TFree(buf_data);
hypre_TFree(int_buf_data);
hypre_TFree(CF_marker_offd);
/*if (num_procs > 1) hypre_CSRMatrixDestroy(S_ext);*/
*CF_marker_ptr = CF_marker;
return (ierr);
}