Skip to content

Commit e846f20

Browse files
improve coverage
1 parent 6800e10 commit e846f20

File tree

3 files changed

+208
-20
lines changed

3 files changed

+208
-20
lines changed

src/htool/solver/geneo/coarse_space_builder.hpp

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,25 @@
22
#define HTOOL_PYTHON_GENEO_COARSE_SPACE_BUILDER_HPP
33

44
#include <htool/hmatrix/linalg/add_hmatrix_vector_product.hpp>
5-
#include <htool/solvers/geneo/coarse_space_builder.hpp>
5+
#include <htool/solvers/interfaces/virtual_coarse_space_builder.hpp>
66
#include <pybind11/pybind11.h>
77
namespace py = pybind11;
88

9-
template <typename CoefficientPrecision, typename CoordinatePrecision = CoefficientPrecision>
10-
class VirtualGeneoCoarseSpaceBuilderPython : public VirtualGeneoCoarseSpaceBuilder<CoefficientPrecision, CoordinatePrecision> {
9+
template <typename CoefficientPrecision, typename CoordinatePrecision = htool::underlying_type<CoefficientPrecision>>
10+
class VirtualGeneoCoarseSpaceBuilderPython : public VirtualCoarseSpaceBuilder<CoefficientPrecision> {
1111
py::array_t<CoefficientPrecision, py::array::f_style> m_coarse_space;
1212

13+
int m_size_wo_overlap;
14+
int m_size_with_overlap;
15+
const HMatrix<CoefficientPrecision, CoordinatePrecision> &m_local_hmatrix;
16+
int m_geneo_nu = 2;
17+
htool::underlying_type<CoefficientPrecision> m_geneo_threshold = -1.;
18+
1319
public:
14-
char get_symmetry() { return this->m_symmetry; }
1520
int get_geneo_nu() { return this->m_geneo_nu; }
1621
htool::underlying_type<CoefficientPrecision> get_geneo_threshold() { return this->m_geneo_threshold; }
1722

18-
explicit VirtualGeneoCoarseSpaceBuilderPython(int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, char symmetry, char uplo, int geneo_nu, htool::underlying_type<CoefficientPrecision> geneo_threshold) : VirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>(size_wo_overlap, size_with_overlap, Ai, symmetry, uplo, geneo_nu, geneo_threshold) {}
23+
explicit VirtualGeneoCoarseSpaceBuilderPython(int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, int geneo_nu, htool::underlying_type<CoefficientPrecision> geneo_threshold) : m_size_wo_overlap(size_wo_overlap), m_size_with_overlap(size_with_overlap), m_local_hmatrix(Ai), m_geneo_nu(geneo_nu), m_geneo_threshold(geneo_threshold) {}
1924

2025
Matrix<CoefficientPrecision> build_coarse_space() override {
2126
std::function<py::array_t<CoefficientPrecision>(py::array_t<CoefficientPrecision>)> hmatrix_callback;
@@ -74,28 +79,23 @@ void declare_virtual_geneo_coarse_space_builder(py::module &m, const std::string
7479

7580
using Class = VirtualGeneoCoarseSpaceBuilderPython<CoefficientPrecision>;
7681
py::class_<Class, PyVirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>, VirtualCoarseSpaceBuilder<CoefficientPrecision>> py_class(m, className.c_str());
77-
py_class.def(py::init([](int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, char symmetry, char uplo, int geneo_nu) {
78-
return PyVirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>(size_wo_overlap, size_with_overlap, Ai, symmetry, uplo, geneo_nu, -1);
82+
py_class.def(py::init([](int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, int geneo_nu) {
83+
return PyVirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>(size_wo_overlap, size_with_overlap, Ai, geneo_nu, -1);
7984
}),
8085
py::arg("size_wo_overlap"),
8186
py::arg("size_with_overlap"),
8287
py::arg("Ai"),
83-
py::arg("symmetry"),
84-
py::arg("uplo"),
8588
py::kw_only(),
8689
py::arg("geneo_nu"));
87-
py_class.def(py::init([](int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, char symmetry, char uplo, double geneo_threshold) {
88-
return PyVirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>(size_wo_overlap, size_with_overlap, Ai, symmetry, uplo, 0, geneo_threshold);
90+
py_class.def(py::init([](int size_wo_overlap, int size_with_overlap, const HMatrix<CoefficientPrecision> &Ai, double geneo_threshold) {
91+
return PyVirtualGeneoCoarseSpaceBuilder<CoefficientPrecision>(size_wo_overlap, size_with_overlap, Ai, 0, geneo_threshold);
8992
}),
9093
py::arg("size_wo_overlap"),
9194
py::arg("size_with_overlap"),
9295
py::arg("Ai"),
93-
py::arg("symmetry"),
94-
py::arg("uplo"),
9596
py::kw_only(),
9697
py::arg("geneo_threshold"));
9798
py_class.def("set_coarse_space", &Class::set_coarse_space);
98-
py_class.def_property_readonly("symmetry", &Class::get_symmetry);
9999
py_class.def_property_readonly("geneo_nu", &Class::get_geneo_nu);
100100
py_class.def_property_readonly("geneo_threshold", &Class::get_geneo_threshold);
101101
}

tests/test_ddm_solver.py

Lines changed: 193 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,13 @@
66
import numpy as np
77
import pytest
88
from conftest import ComplexGeneratorFromMatrix, GeneratorFromMatrix
9-
from scipy.linalg import eig, eigh
9+
from scipy.linalg import eig, eigh, ldl, solve_triangular
10+
from scipy.sparse.linalg import LinearOperator, eigsh
1011

1112

12-
class CustomGeneoCoarseSpaceDenseBuilder(Htool.VirtualGeneoCoarseSpaceDenseBuilder):
13+
class CustomDenseGeneoCoarseSpaceDenseBuilder(
14+
Htool.VirtualGeneoCoarseSpaceDenseBuilder
15+
):
1316
def compute_coarse_space(self, Ai, Bi):
1417
coarse_space = None
1518
if self.symmetry == "S" or self.symmetry == "H":
@@ -30,6 +33,102 @@ def compute_coarse_space(self, Ai, Bi):
3033
self.set_coarse_space(coarse_space)
3134

3235

36+
class CustomGeneoCoarseSpaceBuilder(Htool.VirtualGeneoCoarseSpaceBuilder):
37+
class DirichletHMatrix(LinearOperator):
38+
def __init__(self, hmatrix_callback, size, dtype):
39+
self.hmatrix_callback = hmatrix_callback
40+
self.shape = (size, size)
41+
self.dtype = dtype
42+
43+
def _matvec(self, x):
44+
return self.hmatrix_callback(x)
45+
46+
class DenseNeumannMatrix(LinearOperator):
47+
def __init__(self, Bi):
48+
self.L, self.D, self.perm = ldl(Bi)
49+
self.shape = Bi.shape
50+
self.dtype = Bi.dtype
51+
52+
def _matvec(self, x):
53+
tmp = solve_triangular(self.L[self.perm, :], x[self.perm], lower=True)
54+
for index, coef in enumerate(self.D.diagonal()):
55+
# if coef>1e-4:
56+
tmp[index] /= coef
57+
# else :
58+
# tmp[index]=0
59+
res = np.empty_like(x)
60+
res[self.perm] = solve_triangular(
61+
self.L[self.perm, :], tmp, lower=True, trans="T"
62+
)
63+
return res
64+
65+
def __init__(
66+
self,
67+
size_wo_overlap,
68+
size_with_overlap,
69+
Ai,
70+
Bi,
71+
geneo_nu=2,
72+
geneo_threshold=None,
73+
):
74+
if not geneo_threshold:
75+
Htool.VirtualGeneoCoarseSpaceBuilder.__init__(
76+
self,
77+
size_wo_overlap,
78+
size_with_overlap,
79+
Ai,
80+
geneo_nu=geneo_nu,
81+
)
82+
else:
83+
Htool.VirtualGeneoCoarseSpaceBuilder.__init__(
84+
self,
85+
size_wo_overlap,
86+
size_with_overlap,
87+
Ai,
88+
geneo_threshold=geneo_threshold,
89+
)
90+
self.local_size = size_with_overlap
91+
self.Bi = Bi
92+
self.Ai = Ai
93+
94+
def compute_coarse_space(self, hmatrix_callback):
95+
self.coarse_space = None
96+
self.eigenvalues = None
97+
98+
if self.geneo_threshold > 0:
99+
[w, v] = eigsh(
100+
self.Bi,
101+
10,
102+
M=self.DirichletHMatrix(
103+
hmatrix_callback, self.local_size, np.dtype("float64")
104+
),
105+
OPinv=self.DenseNeumannMatrix(self.Bi),
106+
return_eigenvectors=True,
107+
sigma=0,
108+
)
109+
else:
110+
[w, v] = eigsh(
111+
self.Bi,
112+
self.geneo_nu,
113+
M=self.DirichletHMatrix(
114+
hmatrix_callback, self.local_size, np.dtype("float64")
115+
),
116+
OPinv=self.DenseNeumannMatrix(self.Bi),
117+
return_eigenvectors=True,
118+
sigma=0,
119+
)
120+
idx = w.argsort()
121+
if self.geneo_threshold > 0:
122+
nb_eig = (w < 1.0 / self.geneo_threshold).sum()
123+
self.coarse_space = v[:, idx[0:nb_eig]].real
124+
self.eigenvalues = 1.0 / w[idx[:]]
125+
else:
126+
self.coarse_space = v[:, idx[0 : self.geneo_nu]]
127+
self.eigenvalues = 1.0 / w[idx[:]]
128+
129+
self.set_coarse_space(self.coarse_space)
130+
131+
33132
@pytest.mark.parametrize("epsilon", [1e-6])
34133
@pytest.mark.parametrize("eta", [10])
35134
@pytest.mark.parametrize("tol", [1e-6])
@@ -96,6 +195,70 @@ def compute_coarse_space(self, Ai, Bi):
96195
"additive",
97196
"geneo_threshold",
98197
),
198+
(
199+
1,
200+
"S",
201+
"DDMWithHMatrixPlusOverlap",
202+
"asm",
203+
"additive",
204+
"custom_dense_geneo_nu",
205+
),
206+
(
207+
1,
208+
"S",
209+
"DDMWithHMatrixPlusOverlap",
210+
"ras",
211+
"additive",
212+
"custom_dense_geneo_nu",
213+
),
214+
(
215+
10,
216+
"S",
217+
"DDMWithHMatrixPlusOverlap",
218+
"asm",
219+
"additive",
220+
"custom_dense_geneo_nu",
221+
),
222+
(
223+
10,
224+
"S",
225+
"DDMWithHMatrixPlusOverlap",
226+
"ras",
227+
"additive",
228+
"custom_dense_geneo_nu",
229+
),
230+
(
231+
1,
232+
"S",
233+
"DDMWithHMatrixPlusOverlap",
234+
"asm",
235+
"additive",
236+
"custom_dense_geneo_threshold",
237+
),
238+
(
239+
1,
240+
"S",
241+
"DDMWithHMatrixPlusOverlap",
242+
"ras",
243+
"additive",
244+
"custom_dense_geneo_threshold",
245+
),
246+
(
247+
10,
248+
"S",
249+
"DDMWithHMatrixPlusOverlap",
250+
"asm",
251+
"additive",
252+
"custom_dense_geneo_threshold",
253+
),
254+
(
255+
10,
256+
"S",
257+
"DDMWithHMatrixPlusOverlap",
258+
"ras",
259+
"additive",
260+
"custom_dense_geneo_threshold",
261+
),
99262
(1, "S", "DDMWithHMatrixPlusOverlap", "asm", "additive", "custom_geneo_nu"),
100263
(1, "S", "DDMWithHMatrixPlusOverlap", "ras", "additive", "custom_geneo_nu"),
101264
(
@@ -156,6 +319,14 @@ def compute_coarse_space(self, Ai, Bi):
156319
(1, "S", "DDMWithHMatrix", "ras", "additive", "geneo_threshold"),
157320
(10, "S", "DDMWithHMatrix", "asm", "additive", "geneo_threshold"),
158321
(10, "S", "DDMWithHMatrix", "ras", "additive", "geneo_threshold"),
322+
(1, "S", "DDMWithHMatrix", "asm", "additive", "custom_dense_geneo_nu"),
323+
(1, "S", "DDMWithHMatrix", "ras", "additive", "custom_dense_geneo_nu"),
324+
(10, "S", "DDMWithHMatrix", "asm", "additive", "custom_dense_geneo_nu"),
325+
(10, "S", "DDMWithHMatrix", "ras", "additive", "custom_dense_geneo_nu"),
326+
(1, "S", "DDMWithHMatrix", "asm", "additive", "custom_dense_geneo_threshold"),
327+
(1, "S", "DDMWithHMatrix", "ras", "additive", "custom_dense_geneo_threshold"),
328+
(10, "S", "DDMWithHMatrix", "asm", "additive", "custom_dense_geneo_threshold"),
329+
(10, "S", "DDMWithHMatrix", "ras", "additive", "custom_dense_geneo_threshold"),
159330
(1, "S", "DDMWithHMatrix", "asm", "additive", "custom_geneo_nu"),
160331
(1, "S", "DDMWithHMatrix", "ras", "additive", "custom_geneo_nu"),
161332
(10, "S", "DDMWithHMatrix", "asm", "additive", "custom_geneo_nu"),
@@ -383,7 +554,24 @@ def test_ddm_solver(
383554
geneo_threshold=100,
384555
)
385556
elif geneo_type == "custom_geneo_nu":
386-
geneo_space_operator_builder = CustomGeneoCoarseSpaceDenseBuilder(
557+
print("ICI")
558+
geneo_space_operator_builder = CustomGeneoCoarseSpaceBuilder(
559+
local_size_wo_overlap,
560+
local_size_with_overlap,
561+
default_approximation.block_diagonal_hmatrix,
562+
local_neumann_matrix,
563+
geneo_nu=2,
564+
)
565+
elif geneo_type == "custom_geneo_threshold":
566+
geneo_space_operator_builder = CustomGeneoCoarseSpaceBuilder(
567+
local_size_wo_overlap,
568+
local_size_with_overlap,
569+
default_approximation.block_diagonal_hmatrix,
570+
local_neumann_matrix,
571+
geneo_threshold=100,
572+
)
573+
elif geneo_type == "custom_dense_geneo_nu":
574+
geneo_space_operator_builder = CustomDenseGeneoCoarseSpaceDenseBuilder(
387575
local_size_wo_overlap,
388576
local_size_with_overlap,
389577
default_approximation.block_diagonal_hmatrix.to_dense(),
@@ -392,8 +580,8 @@ def test_ddm_solver(
392580
UPLO,
393581
geneo_nu=2,
394582
)
395-
elif geneo_type == "custom_geneo_threshold":
396-
geneo_space_operator_builder = CustomGeneoCoarseSpaceDenseBuilder(
583+
elif geneo_type == "custom_dense_geneo_threshold":
584+
geneo_space_operator_builder = CustomDenseGeneoCoarseSpaceDenseBuilder(
397585
local_size_wo_overlap,
398586
local_size_with_overlap,
399587
default_approximation.block_diagonal_hmatrix.to_dense(),

0 commit comments

Comments
 (0)