Skip to content

Commit f59566b

Browse files
committed
Add/Enable METIS
Add submodules for METIS, patch METIS build system to work nicely with ours, patch superlu to use METIS when available.
1 parent fe9e59f commit f59566b

6 files changed

Lines changed: 304 additions & 2 deletions

File tree

.gitmodules

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
ignore = all
1212
update = checkout
1313
branch = master
14-
[submodule "METIS"]
15-
path = METIS
14+
[submodule "metis/GKlib"]
15+
path = metis/GKlib
16+
url = https://github.com/KarypisLab/GKlib.git
17+
[submodule "metis/METIS"]
18+
path = metis/METIS
1619
url = https://github.com/KarypisLab/METIS.git

CMakeLists.txt

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ if(NOT DEFINED CMAKE_SUPPRESS_DEVELOPER_WARNINGS)
4545
set(CMAKE_SUPPRESS_DEVELOPER_WARNINGS 1 CACHE INTERNAL "No dev warnings")
4646
endif()
4747

48+
# build static libraries throughout this tree
49+
set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build static libraries" FORCE)
50+
4851
# recommend the appropriate make command
4952
if(WIN32)
5053
set(RECOMMENDED_MAKE "mingw32-make")
@@ -78,6 +81,48 @@ endif()
7881
set(SUPERLU_DIR "${PROJECT_SOURCE_DIR}/superlu")
7982
set(SUPERLU_MT_DIR "${PROJECT_SOURCE_DIR}/superlu_mt")
8083
set(SUPERLU_PATCHES_DIR "${PROJECT_SOURCE_DIR}/superlu_mt_patches")
84+
set(METIS_DIR "${PROJECT_SOURCE_DIR}/metis/METIS")
85+
set(GKLIB_DIR "${PROJECT_SOURCE_DIR}/metis/GKlib")
86+
set(METIS_PATCHES_DIR "${PROJECT_SOURCE_DIR}/metis/metis_patches")
87+
88+
if(NOT DEFINED TPL_ENABLE_METISLIB)
89+
set(TPL_ENABLE_METISLIB ON CACHE BOOL "Enable METIS for SuperLU")
90+
endif()
91+
if(TPL_ENABLE_METISLIB)
92+
if(NOT EXISTS "${GKLIB_DIR}/CMakeLists.txt")
93+
message(FATAL_ERROR "The GKlib submodule was not downloaded.")
94+
endif()
95+
if(NOT EXISTS "${METIS_DIR}/CMakeLists.txt")
96+
message(FATAL_ERROR "The METIS submodule was not downloaded.")
97+
endif()
98+
99+
message(STATUS "Applying patches to METIS...")
100+
file(GLOB_RECURSE METIS_PATCH_FILES RELATIVE "${METIS_PATCHES_DIR}" "${METIS_PATCHES_DIR}/*")
101+
102+
foreach(file IN LISTS METIS_PATCH_FILES)
103+
set(src "${METIS_PATCHES_DIR}/${file}")
104+
set(dst "${METIS_DIR}/${file}")
105+
106+
get_filename_component(dst_dir "${dst}" DIRECTORY)
107+
file(MAKE_DIRECTORY "${dst_dir}")
108+
109+
message(STATUS " Patching: ${file}")
110+
file(COPY "${src}" DESTINATION "${dst_dir}")
111+
endforeach()
112+
113+
message(STATUS "METIS patched.")
114+
115+
set(SHARED OFF CACHE BOOL "Build vendored GKlib/METIS as static libraries" FORCE)
116+
set(GKLIB_BUILD_APPS OFF CACHE BOOL "Build GKlib applications" FORCE)
117+
set(METIS_BUILD_PROGRAMS OFF CACHE BOOL "Build METIS command line programs" FORCE)
118+
set(GKLIB_PATH "${GKLIB_DIR}" CACHE PATH "GKlib source directory" FORCE)
119+
120+
add_subdirectory("${GKLIB_DIR}" "${CMAKE_BINARY_DIR}/metis/GKlib")
121+
add_subdirectory("${METIS_DIR}" "${CMAKE_BINARY_DIR}/metis/METIS")
122+
123+
set(TPL_METIS_LIBRARIES "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/libmetis.a;${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/libGKlib.a" CACHE STRING "METIS static libraries" FORCE)
124+
set(TPL_METIS_INCLUDE_DIRS "${CMAKE_BINARY_DIR}/metis/METIS/include" CACHE PATH "METIS include directory" FORCE)
125+
endif()
81126

82127
set(enable_examples OFF FORCE)
83128
set(enable_tests OFF FORCE)
@@ -150,6 +195,9 @@ else()
150195

151196
include_directories("${SUPERLU_DIR}/SRC")
152197
add_subdirectory(${SUPERLU_DIR})
198+
if(TPL_ENABLE_METISLIB)
199+
add_dependencies(superlu metis GKlib)
200+
endif()
153201
set(SLU_DRIVER "${SUPERLU_DIR}/FORTRAN/c_fortran_dgssv.c")
154202
endif()
155203

metis/GKlib

Submodule GKlib added at e2856c2
Submodule METIS updated from 0000000 to dfded64

metis/metis_patches/CMakeLists.txt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
cmake_minimum_required(VERSION 3.10)
2+
project(METIS C)
3+
4+
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
5+
set(SHARED FALSE CACHE BOOL "build a shared library")
6+
option(METIS_BUILD_PROGRAMS "Build METIS command line programs" OFF)
7+
8+
if(MSVC)
9+
set(METIS_INSTALL FALSE)
10+
else()
11+
set(METIS_INSTALL TRUE)
12+
endif()
13+
14+
# Configure libmetis library.
15+
if(SHARED)
16+
set(METIS_LIBRARY_TYPE SHARED)
17+
else()
18+
set(METIS_LIBRARY_TYPE STATIC)
19+
endif(SHARED)
20+
21+
include(./conf/gkbuild.cmake)
22+
23+
# METIS' custom options
24+
#option(IDX64 "enable 64 bit ints" OFF)
25+
#option(REAL64 "enable 64 bit floats (i.e., double)" OFF)
26+
#if(IDX64)
27+
# set(METIS_COPTIONS "${METIS_COPTIONS} -DIDXTYPEWIDTH=64")
28+
#else()
29+
# set(METIS_COPTIONS "${METIS_COPTIONS} -DIDXTYPEWIDTH=32")
30+
#endif(IDX64)
31+
#if(REAL64)
32+
# set(METIS_COPTIONS "${METIS_COPTIONS} -DREALTYPEWIDTH=64")
33+
#else()
34+
# set(METIS_COPTIONS "${METIS_COPTIONS} -DREALTYPEWIDTH=32")
35+
#endif(REAL64)
36+
#
37+
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${METIS_COPTIONS}")
38+
39+
40+
set(METIS_GENERATED_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/include")
41+
file(MAKE_DIRECTORY "${METIS_GENERATED_INCLUDE_DIR}")
42+
file(WRITE "${METIS_GENERATED_INCLUDE_DIR}/metis.h" "#define IDXTYPEWIDTH 32\n#define REALTYPEWIDTH 32\n")
43+
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/include/metis.h" METIS_PUBLIC_HEADER)
44+
file(APPEND "${METIS_GENERATED_INCLUDE_DIR}/metis.h" "${METIS_PUBLIC_HEADER}")
45+
46+
# Add include directories.
47+
# i.e., the -I equivalent
48+
include_directories("${METIS_GENERATED_INCLUDE_DIR}")
49+
include_directories(${GKLIB_PATH}/include)
50+
include_directories(${CMAKE_INSTALL_PREFIX}/include)
51+
52+
# List of paths that the compiler will search for library files.
53+
# i.e., the -L equivalent
54+
link_directories(${GKLIB_PATH}/lib)
55+
link_directories(${CMAKE_INSTALL_PREFIX}/lib)
56+
57+
# Recursively look for CMakeLists.txt in subdirs.
58+
add_subdirectory("libmetis")
59+
if(METIS_BUILD_PROGRAMS)
60+
add_subdirectory("programs")
61+
endif()
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
2+
/*
3+
* -- SuperLU routine (version 6.0) --
4+
* Univ. of California Berkeley, Xerox Palo Alto Research Center,
5+
* and Lawrence Berkeley National Lab.
6+
* October 15, 2003
7+
*
8+
* March 26, 2023 Add 64-bit indexing and METIS ordering
9+
*/
10+
11+
#include "slu_ddefs.h"
12+
13+
#define HANDLE_SIZE 8
14+
15+
/* kind of integer to hold a pointer. Use 64-bit. */
16+
typedef long long int fptr;
17+
18+
typedef struct {
19+
SuperMatrix *L;
20+
SuperMatrix *U;
21+
int *perm_c;
22+
int *perm_r;
23+
} factors_t;
24+
25+
/*!
26+
* This routine can be called from Fortran.
27+
*
28+
* iopt (input) int
29+
* Specifies the operation:
30+
* = 1, performs LU decomposition for the first time
31+
* = 2, performs triangular solve
32+
* = 3, free all the storage in the end
33+
*
34+
* f_factors (input/output) fptr*
35+
* If iopt == 1, it is an output and contains the pointer pointing to
36+
* the structure of the factored matrices.
37+
* Otherwise, it it an input.
38+
*/
39+
void c_fortran_dgssv_(int *iopt, int *n, int_t *nnz, int *nrhs, double *values,
40+
int_t *rowind, int_t *colptr, double *b, int *ldb,
41+
fptr *f_factors, /* a handle containing the address
42+
pointing to the factored matrices */
43+
int_t *info) {
44+
SuperMatrix A, AC, B;
45+
SuperMatrix *L, *U;
46+
int *perm_r; /* row permutations from partial pivoting */
47+
int *perm_c; /* column permutation vector */
48+
int *etree; /* column elimination tree */
49+
SCformat *Lstore;
50+
NCformat *Ustore;
51+
int i, panel_size, permc_spec, relax;
52+
trans_t trans;
53+
mem_usage_t mem_usage;
54+
superlu_options_t options;
55+
SuperLUStat_t stat;
56+
factors_t *LUfactors;
57+
GlobalLU_t Glu; /* Not needed on return. */
58+
int_t *rowind0; /* counter 1-based indexing from Fortran arrays. */
59+
int_t *colptr0;
60+
61+
trans = NOTRANS;
62+
63+
if (*iopt == 1) { /* LU decomposition */
64+
65+
/* Set the default input options. */
66+
set_default_options(&options);
67+
68+
/* Initialize the statistics variables. */
69+
StatInit(&stat);
70+
71+
/* Adjust to 0-based indexing */
72+
if (!(rowind0 = intMalloc(*nnz)))
73+
ABORT("Malloc fails for rowind0[].");
74+
if (!(colptr0 = intMalloc(*n + 1)))
75+
ABORT("Malloc fails for colptr0[].");
76+
for (i = 0; i < *nnz; ++i)
77+
rowind0[i] = rowind[i] - 1;
78+
for (i = 0; i <= *n; ++i)
79+
colptr0[i] = colptr[i] - 1;
80+
81+
dCreate_CompCol_Matrix(&A, *n, *n, *nnz, values, rowind0, colptr0, SLU_NC,
82+
SLU_D, SLU_GE);
83+
L = (SuperMatrix *)SUPERLU_MALLOC(sizeof(SuperMatrix));
84+
U = (SuperMatrix *)SUPERLU_MALLOC(sizeof(SuperMatrix));
85+
if (!(perm_r = int32Malloc(*n)))
86+
ABORT("Malloc fails for perm_r[].");
87+
if (!(perm_c = int32Malloc(*n)))
88+
ABORT("Malloc fails for perm_c[].");
89+
if (!(etree = int32Malloc(*n)))
90+
ABORT("Malloc fails for etree[].");
91+
/*
92+
* Get column permutation vector perm_c[], according to permc_spec:
93+
* permc_spec = 0: natural ordering
94+
* permc_spec = 1: minimum degree on structure of A'*A
95+
* permc_spec = 2: minimum degree on structure of A'+A
96+
* permc_spec = 3: approximate minimum degree for unsymmetric matrices
97+
* permc_spec = 6: METIS ordering on structure of A'*A
98+
*/
99+
#if (HAVE_METIS)
100+
printf("USING METIS ORDERING\r\n");
101+
permc_spec = 6;
102+
#else
103+
permc_spec = options.ColPerm;
104+
#endif
105+
// permc_spec = 0;
106+
// printf("before get_perm_c: permc_spec %d, *n %d\n", permc_spec, *n);
107+
get_perm_c(permc_spec, &A, perm_c);
108+
// printf("after get_perm_c: permc_spec %d\n", permc_spec);
109+
110+
sp_preorder(&options, &A, perm_c, etree, &AC);
111+
112+
panel_size = sp_ienv(1);
113+
relax = sp_ienv(2);
114+
115+
dgstrf(&options, &AC, relax, panel_size, etree, NULL, 0, perm_c, perm_r, L,
116+
U, &Glu, &stat, info);
117+
118+
if (*info == 0) {
119+
Lstore = (SCformat *)L->Store;
120+
Ustore = (NCformat *)U->Store;
121+
printf("No of nonzeros in factor L = %lld\n", (long long)Lstore->nnz);
122+
printf("No of nonzeros in factor U = %lld\n", (long long)Ustore->nnz);
123+
printf("No of nonzeros in L+U = %lld\n",
124+
(long long)Lstore->nnz + Ustore->nnz);
125+
dQuerySpace(L, U, &mem_usage);
126+
printf("L\\U MB %.3f\ttotal MB needed %.3f\n", mem_usage.for_lu / 1e6,
127+
mem_usage.total_needed / 1e6);
128+
} else {
129+
printf("dgstrf() error returns INFO= %lld\n", (long long)*info);
130+
if (*info <= *n) { /* factorization completes */
131+
dQuerySpace(L, U, &mem_usage);
132+
printf("L\\U MB %.3f\ttotal MB needed %.3f\n", mem_usage.for_lu / 1e6,
133+
mem_usage.total_needed / 1e6);
134+
}
135+
}
136+
137+
/* Save the LU factors in the factors handle */
138+
LUfactors = (factors_t *)SUPERLU_MALLOC(sizeof(factors_t));
139+
LUfactors->L = L;
140+
LUfactors->U = U;
141+
LUfactors->perm_c = perm_c;
142+
LUfactors->perm_r = perm_r;
143+
*f_factors = (fptr)LUfactors;
144+
145+
/* Free un-wanted storage */
146+
SUPERLU_FREE(etree);
147+
Destroy_SuperMatrix_Store(&A);
148+
Destroy_CompCol_Permuted(&AC);
149+
SUPERLU_FREE(rowind0);
150+
SUPERLU_FREE(colptr0);
151+
StatFree(&stat);
152+
153+
} else if (*iopt == 2) { /* Triangular solve */
154+
int iinfo;
155+
156+
/* Initialize the statistics variables. */
157+
StatInit(&stat);
158+
159+
/* Extract the LU factors in the factors handle */
160+
LUfactors = (factors_t *)*f_factors;
161+
L = LUfactors->L;
162+
U = LUfactors->U;
163+
perm_c = LUfactors->perm_c;
164+
perm_r = LUfactors->perm_r;
165+
166+
dCreate_Dense_Matrix(&B, *n, *nrhs, b, *ldb, SLU_DN, SLU_D, SLU_GE);
167+
168+
/* Solve the system A*X=B, overwriting B with X. */
169+
dgstrs(trans, L, U, perm_c, perm_r, &B, &stat, &iinfo);
170+
*info = iinfo;
171+
172+
Destroy_SuperMatrix_Store(&B);
173+
StatFree(&stat);
174+
175+
} else if (*iopt == 3) { /* Free storage */
176+
/* Free the LU factors in the factors handle */
177+
LUfactors = (factors_t *)*f_factors;
178+
SUPERLU_FREE(LUfactors->perm_r);
179+
SUPERLU_FREE(LUfactors->perm_c);
180+
Destroy_SuperNode_Matrix(LUfactors->L);
181+
Destroy_CompCol_Matrix(LUfactors->U);
182+
SUPERLU_FREE(LUfactors->L);
183+
SUPERLU_FREE(LUfactors->U);
184+
SUPERLU_FREE(LUfactors);
185+
} else {
186+
fprintf(stderr, "Invalid iopt=%d passed to c_fortran_dgssv()\n", *iopt);
187+
exit(-1);
188+
}
189+
}

0 commit comments

Comments
 (0)