capytaine 2.0__cp310-cp310-macosx_10_9_x86_64.whl → 2.2__cp310-cp310-macosx_10_9_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capytaine/.dylibs/libgcc_s.1.1.dylib +0 -0
- capytaine/.dylibs/libgfortran.5.dylib +0 -0
- capytaine/.dylibs/libquadmath.0.dylib +0 -0
- capytaine/__about__.py +3 -3
- capytaine/__init__.py +5 -3
- capytaine/bem/airy_waves.py +4 -6
- capytaine/bem/engines.py +146 -25
- capytaine/bem/problems_and_results.py +217 -106
- capytaine/bem/solver.py +179 -47
- capytaine/bodies/__init__.py +1 -1
- capytaine/bodies/bodies.py +207 -39
- capytaine/bodies/predefined/__init__.py +0 -2
- capytaine/bodies/predefined/cylinders.py +0 -2
- capytaine/bodies/predefined/rectangles.py +0 -2
- capytaine/bodies/predefined/spheres.py +0 -2
- capytaine/green_functions/abstract_green_function.py +0 -3
- capytaine/green_functions/delhommeau.py +225 -63
- capytaine/green_functions/libs/Delhommeau_float32.cpython-310-darwin.so +0 -0
- capytaine/green_functions/libs/Delhommeau_float64.cpython-310-darwin.so +0 -0
- capytaine/io/bemio.py +17 -16
- capytaine/io/legacy.py +52 -20
- capytaine/io/mesh_loaders.py +49 -27
- capytaine/io/mesh_writers.py +1 -3
- capytaine/io/meshio.py +4 -1
- capytaine/io/xarray.py +73 -35
- capytaine/matrices/__init__.py +0 -2
- capytaine/matrices/block.py +23 -2
- capytaine/matrices/block_toeplitz.py +0 -2
- capytaine/matrices/builders.py +2 -4
- capytaine/matrices/linear_solvers.py +84 -7
- capytaine/matrices/low_rank.py +0 -2
- capytaine/meshes/__init__.py +0 -2
- capytaine/meshes/clipper.py +0 -3
- capytaine/meshes/collections.py +49 -20
- capytaine/meshes/geometry.py +3 -6
- capytaine/meshes/meshes.py +170 -81
- capytaine/meshes/predefined/__init__.py +0 -1
- capytaine/meshes/predefined/cylinders.py +48 -7
- capytaine/meshes/predefined/rectangles.py +43 -10
- capytaine/meshes/predefined/spheres.py +15 -4
- capytaine/meshes/properties.py +43 -2
- capytaine/meshes/quadratures.py +80 -0
- capytaine/meshes/quality.py +1 -3
- capytaine/meshes/surface_integrals.py +0 -1
- capytaine/meshes/symmetric.py +55 -14
- capytaine/post_pro/free_surfaces.py +4 -7
- capytaine/post_pro/impedance.py +12 -10
- capytaine/post_pro/kochin.py +5 -3
- capytaine/post_pro/rao.py +16 -22
- capytaine/tools/cache_on_disk.py +26 -0
- capytaine/tools/deprecation_handling.py +2 -2
- capytaine/tools/lists_of_points.py +13 -3
- capytaine/tools/lru_cache.py +23 -29
- capytaine/tools/optional_imports.py +0 -2
- capytaine/tools/prony_decomposition.py +0 -3
- capytaine/tools/symbolic_multiplication.py +107 -0
- capytaine/ui/cli.py +7 -27
- capytaine/ui/rich.py +5 -0
- capytaine/ui/vtk/__init__.py +0 -3
- capytaine/ui/vtk/animation.py +28 -8
- capytaine/ui/vtk/body_viewer.py +2 -2
- capytaine/ui/vtk/helpers.py +0 -3
- capytaine/ui/vtk/mesh_viewer.py +0 -3
- {capytaine-2.0.dist-info → capytaine-2.2.dist-info}/METADATA +32 -14
- capytaine-2.2.dist-info/RECORD +76 -0
- capytaine/green_functions/libDelhommeau/.gitignore +0 -5
- capytaine/green_functions/libDelhommeau/LICENSE +0 -203
- capytaine/green_functions/libDelhommeau/Makefile +0 -123
- capytaine/green_functions/libDelhommeau/README.md +0 -15
- capytaine/green_functions/libDelhommeau/benchmarks/openmp/benchmark_omp.f90 +0 -212
- capytaine/green_functions/libDelhommeau/benchmarks/openmp/display_mesh.py +0 -7
- capytaine/green_functions/libDelhommeau/benchmarks/openmp/read_output.py +0 -82
- capytaine/green_functions/libDelhommeau/benchmarks/profiling/benchmark_profiling.f90 +0 -201
- capytaine/green_functions/libDelhommeau/benchmarks/tabulations/benchmark_tabulation.f90 +0 -87
- capytaine/green_functions/libDelhommeau/examples/minimal/minimal_example.f90 +0 -213
- capytaine/green_functions/libDelhommeau/examples/minimal/minimal_example.py +0 -60
- capytaine/green_functions/libDelhommeau/src/Delhommeau_integrals.f90 +0 -311
- capytaine/green_functions/libDelhommeau/src/Green_Rankine.f90 +0 -148
- capytaine/green_functions/libDelhommeau/src/Green_wave.f90 +0 -303
- capytaine/green_functions/libDelhommeau/src/constants.f90 +0 -16
- capytaine/green_functions/libDelhommeau/src/float32.f90 +0 -7
- capytaine/green_functions/libDelhommeau/src/float64.f90 +0 -7
- capytaine/green_functions/libDelhommeau/src/matrices.f90 +0 -274
- capytaine/green_functions/libDelhommeau/src/old_Prony_decomposition.f90 +0 -636
- capytaine/green_functions/libs/XieDelhommeau_float32.cpython-310-darwin.so +0 -0
- capytaine/green_functions/libs/XieDelhommeau_float64.cpython-310-darwin.so +0 -0
- capytaine-2.0.dist-info/RECORD +0 -93
- {capytaine-2.0.dist-info → capytaine-2.2.dist-info}/LICENSE +0 -0
- {capytaine-2.0.dist-info → capytaine-2.2.dist-info}/WHEEL +0 -0
- {capytaine-2.0.dist-info → capytaine-2.2.dist-info}/entry_points.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
capytaine/__about__.py
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
2
|
|
|
3
3
|
__all__ = ["__title__", "__description__", "__version__", "__author__", "__uri__", "__license__"]
|
|
4
4
|
|
|
5
5
|
__title__ = "capytaine"
|
|
6
6
|
__description__ = """Python BEM solver for linear potential flow, based on Nemoh"""
|
|
7
7
|
|
|
8
|
-
__version__ = "2.
|
|
8
|
+
__version__ = "2.2"
|
|
9
9
|
|
|
10
10
|
__author__ = "Matthieu Ancellin"
|
|
11
|
-
__uri__ = "https://github.com/
|
|
11
|
+
__uri__ = "https://github.com/capytaine/capytaine"
|
|
12
12
|
__license__ = "GPL-3.0"
|
|
13
13
|
|
|
14
14
|
|
capytaine/__init__.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# coding: utf-8
|
|
3
1
|
# Copyright (C) 2017-2019 Matthieu Ancellin
|
|
4
2
|
# See LICENSE file at <https://github.com/mancellin/capytaine>
|
|
5
3
|
|
|
@@ -24,10 +22,14 @@ from capytaine.bodies.predefined.rectangles import Rectangle, RectangularParalle
|
|
|
24
22
|
|
|
25
23
|
from capytaine.bem.problems_and_results import RadiationProblem, DiffractionProblem
|
|
26
24
|
from capytaine.bem.solver import BEMSolver
|
|
27
|
-
from capytaine.bem.engines import BasicMatrixEngine, HierarchicalToeplitzMatrixEngine
|
|
25
|
+
from capytaine.bem.engines import BasicMatrixEngine, HierarchicalToeplitzMatrixEngine, HierarchicalPrecondMatrixEngine
|
|
28
26
|
from capytaine.green_functions.delhommeau import Delhommeau, XieDelhommeau
|
|
29
27
|
|
|
30
28
|
from capytaine.post_pro.free_surfaces import FreeSurface
|
|
31
29
|
|
|
32
30
|
from capytaine.io.mesh_loaders import load_mesh
|
|
33
31
|
from capytaine.io.xarray import assemble_dataset
|
|
32
|
+
|
|
33
|
+
from capytaine.ui.rich import set_logging
|
|
34
|
+
|
|
35
|
+
set_logging(level="WARNING")
|
capytaine/bem/airy_waves.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# coding: utf-8
|
|
3
1
|
"""Computing the potential and velocity of Airy wave."""
|
|
4
2
|
# Copyright (C) 2017-2019 Matthieu Ancellin
|
|
5
3
|
# See LICENSE file at <https://github.com/mancellin/capytaine>
|
|
@@ -27,7 +25,8 @@ def airy_waves_potential(points, pb):
|
|
|
27
25
|
x, y, z = points.T
|
|
28
26
|
k = pb.wavenumber
|
|
29
27
|
h = pb.water_depth
|
|
30
|
-
|
|
28
|
+
beta = pb.encounter_wave_direction
|
|
29
|
+
wbar = x * np.cos(beta) + y * np.sin(beta)
|
|
31
30
|
|
|
32
31
|
if 0 <= k*h < 20:
|
|
33
32
|
cih = np.cosh(k*(z+h))/np.cosh(k*h)
|
|
@@ -61,8 +60,9 @@ def airy_waves_velocity(points, pb):
|
|
|
61
60
|
x, y, z = points.T
|
|
62
61
|
k = pb.wavenumber
|
|
63
62
|
h = pb.water_depth
|
|
63
|
+
beta = pb.encounter_wave_direction
|
|
64
64
|
|
|
65
|
-
wbar = x * np.cos(
|
|
65
|
+
wbar = x * np.cos(beta) + y * np.sin(beta)
|
|
66
66
|
|
|
67
67
|
if 0 <= k*h < 20:
|
|
68
68
|
cih = np.cosh(k*(z+h))/np.cosh(k*h)
|
|
@@ -104,5 +104,3 @@ def airy_waves_free_surface_elevation(points, pb):
|
|
|
104
104
|
"""
|
|
105
105
|
points, output_shape = _normalize_free_surface_points(points)
|
|
106
106
|
return 1j * pb.omega / pb.g * airy_waves_potential(points, pb).reshape(output_shape)
|
|
107
|
-
|
|
108
|
-
|
capytaine/bem/engines.py
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
#!/usr/bin/env python
|
|
2
|
-
# coding: utf-8
|
|
3
1
|
"""Definition of the methods to build influence matrices, using possibly some sparse structures."""
|
|
4
2
|
# Copyright (C) 2017-2019 Matthieu Ancellin
|
|
5
3
|
# See LICENSE file at <https://github.com/mancellin/capytaine>
|
|
@@ -8,6 +6,9 @@ import logging
|
|
|
8
6
|
from abc import ABC, abstractmethod
|
|
9
7
|
|
|
10
8
|
import numpy as np
|
|
9
|
+
from scipy.linalg import lu_factor
|
|
10
|
+
from scipy.sparse import coo_matrix
|
|
11
|
+
from scipy.sparse import linalg as ssl
|
|
11
12
|
|
|
12
13
|
from capytaine.meshes.collections import CollectionOfMeshes
|
|
13
14
|
from capytaine.meshes.symmetric import ReflectionSymmetricMesh, TranslationalSymmetricMesh, AxialSymmetricMesh
|
|
@@ -16,7 +17,7 @@ from capytaine.matrices import linear_solvers
|
|
|
16
17
|
from capytaine.matrices.block import BlockMatrix
|
|
17
18
|
from capytaine.matrices.low_rank import LowRankMatrix, NoConvergenceOfACA
|
|
18
19
|
from capytaine.matrices.block_toeplitz import BlockSymmetricToeplitzMatrix, BlockToeplitzMatrix, BlockCirculantMatrix
|
|
19
|
-
from capytaine.tools.lru_cache import
|
|
20
|
+
from capytaine.tools.lru_cache import lru_cache_with_strict_maxsize
|
|
20
21
|
|
|
21
22
|
LOG = logging.getLogger(__name__)
|
|
22
23
|
|
|
@@ -29,7 +30,7 @@ class MatrixEngine(ABC):
|
|
|
29
30
|
"""Abstract method to build a matrix."""
|
|
30
31
|
|
|
31
32
|
@abstractmethod
|
|
32
|
-
def build_matrices(self, mesh1, mesh2, free_surface, water_depth, wavenumber, green_function):
|
|
33
|
+
def build_matrices(self, mesh1, mesh2, free_surface, water_depth, wavenumber, green_function, adjoint_double_layer):
|
|
33
34
|
pass
|
|
34
35
|
|
|
35
36
|
def build_S_matrix(self, *args, **kwargs):
|
|
@@ -71,7 +72,7 @@ class BasicMatrixEngine(MatrixEngine):
|
|
|
71
72
|
self.linear_solver = linear_solver
|
|
72
73
|
|
|
73
74
|
if matrix_cache_size > 0:
|
|
74
|
-
self.build_matrices =
|
|
75
|
+
self.build_matrices = lru_cache_with_strict_maxsize(maxsize=matrix_cache_size)(self.build_matrices)
|
|
75
76
|
|
|
76
77
|
self.exportable_settings = {
|
|
77
78
|
'engine': 'BasicMatrixEngine',
|
|
@@ -90,7 +91,7 @@ class BasicMatrixEngine(MatrixEngine):
|
|
|
90
91
|
def _repr_pretty_(self, p, cycle):
|
|
91
92
|
p.text(self.__str__())
|
|
92
93
|
|
|
93
|
-
def build_matrices(self, mesh1, mesh2, free_surface, water_depth, wavenumber, green_function):
|
|
94
|
+
def build_matrices(self, mesh1, mesh2, free_surface, water_depth, wavenumber, green_function, adjoint_double_layer=True):
|
|
94
95
|
r"""Build the influence matrices between mesh1 and mesh2.
|
|
95
96
|
|
|
96
97
|
Parameters
|
|
@@ -107,6 +108,8 @@ class BasicMatrixEngine(MatrixEngine):
|
|
|
107
108
|
wavenumber (default: 1.0)
|
|
108
109
|
green_function: AbstractGreenFunction
|
|
109
110
|
object with an "evaluate" method that computes the Green function.
|
|
111
|
+
adjoint_double_layer: bool, optional
|
|
112
|
+
compute double layer for direct method (F) or adjoint double layer for indirect method (T) matrices (default: True)
|
|
110
113
|
|
|
111
114
|
Returns
|
|
112
115
|
-------
|
|
@@ -129,7 +132,7 @@ class BasicMatrixEngine(MatrixEngine):
|
|
|
129
132
|
|
|
130
133
|
else:
|
|
131
134
|
return green_function.evaluate(
|
|
132
|
-
mesh1, mesh2, free_surface, water_depth, wavenumber,
|
|
135
|
+
mesh1, mesh2, free_surface, water_depth, wavenumber, adjoint_double_layer=adjoint_double_layer
|
|
133
136
|
)
|
|
134
137
|
|
|
135
138
|
###################################
|
|
@@ -153,7 +156,7 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
153
156
|
def __init__(self, *, ACA_distance=8.0, ACA_tol=1e-2, matrix_cache_size=1):
|
|
154
157
|
|
|
155
158
|
if matrix_cache_size > 0:
|
|
156
|
-
self.build_matrices =
|
|
159
|
+
self.build_matrices = lru_cache_with_strict_maxsize(maxsize=matrix_cache_size)(self.build_matrices)
|
|
157
160
|
|
|
158
161
|
self.ACA_distance = ACA_distance
|
|
159
162
|
self.ACA_tol = ACA_tol
|
|
@@ -179,9 +182,18 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
179
182
|
|
|
180
183
|
def build_matrices(self,
|
|
181
184
|
mesh1, mesh2, free_surface, water_depth, wavenumber, green_function,
|
|
182
|
-
|
|
185
|
+
adjoint_double_layer=True):
|
|
186
|
+
|
|
187
|
+
return self._build_matrices(
|
|
188
|
+
mesh1, mesh2, free_surface, water_depth, wavenumber, green_function,
|
|
189
|
+
adjoint_double_layer, _rec_depth=1)
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _build_matrices(self,
|
|
193
|
+
mesh1, mesh2, free_surface, water_depth, wavenumber, green_function,
|
|
194
|
+
adjoint_double_layer, _rec_depth=1):
|
|
183
195
|
"""Recursively builds a hierarchical matrix between mesh1 and mesh2.
|
|
184
|
-
|
|
196
|
+
|
|
185
197
|
Same arguments as :func:`BasicMatrixEngine.build_matrices`.
|
|
186
198
|
|
|
187
199
|
:code:`_rec_depth` keeps track of the recursion depth only for pretty log printing.
|
|
@@ -208,12 +220,12 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
208
220
|
|
|
209
221
|
LOG.debug(log_entry + " using mirror symmetry.")
|
|
210
222
|
|
|
211
|
-
S_a, V_a = self.
|
|
223
|
+
S_a, V_a = self._build_matrices(
|
|
212
224
|
mesh1[0], mesh2[0], free_surface, water_depth, wavenumber, green_function,
|
|
213
|
-
_rec_depth=_rec_depth+1)
|
|
214
|
-
S_b, V_b = self.
|
|
225
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
226
|
+
S_b, V_b = self._build_matrices(
|
|
215
227
|
mesh1[0], mesh2[1], free_surface, water_depth, wavenumber, green_function,
|
|
216
|
-
_rec_depth=_rec_depth+1)
|
|
228
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
217
229
|
|
|
218
230
|
return BlockSymmetricToeplitzMatrix([[S_a, S_b]]), BlockSymmetricToeplitzMatrix([[V_a, V_b]])
|
|
219
231
|
|
|
@@ -226,15 +238,15 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
226
238
|
|
|
227
239
|
S_list, V_list = [], []
|
|
228
240
|
for submesh in mesh2:
|
|
229
|
-
S, V = self.
|
|
241
|
+
S, V = self._build_matrices(
|
|
230
242
|
mesh1[0], submesh, free_surface, water_depth, wavenumber, green_function,
|
|
231
|
-
_rec_depth=_rec_depth+1)
|
|
243
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
232
244
|
S_list.append(S)
|
|
233
245
|
V_list.append(V)
|
|
234
246
|
for submesh in mesh1[1:][::-1]:
|
|
235
|
-
S, V = self.
|
|
247
|
+
S, V = self._build_matrices(
|
|
236
248
|
submesh, mesh2[0], free_surface, water_depth, wavenumber, green_function,
|
|
237
|
-
_rec_depth=_rec_depth+1)
|
|
249
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
238
250
|
S_list.append(S)
|
|
239
251
|
V_list.append(V)
|
|
240
252
|
|
|
@@ -249,9 +261,9 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
249
261
|
|
|
250
262
|
S_line, V_line = [], []
|
|
251
263
|
for submesh in mesh2[:mesh2.nb_submeshes]:
|
|
252
|
-
S, V = self.
|
|
264
|
+
S, V = self._build_matrices(
|
|
253
265
|
mesh1[0], submesh, free_surface, water_depth, wavenumber, green_function,
|
|
254
|
-
_rec_depth=_rec_depth+1)
|
|
266
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
255
267
|
S_line.append(S)
|
|
256
268
|
V_line.append(V)
|
|
257
269
|
|
|
@@ -266,14 +278,16 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
266
278
|
def get_row_func(i):
|
|
267
279
|
s, v = green_function.evaluate(
|
|
268
280
|
mesh1.extract_one_face(i), mesh2,
|
|
269
|
-
free_surface, water_depth, wavenumber
|
|
281
|
+
free_surface, water_depth, wavenumber,
|
|
282
|
+
adjoint_double_layer=adjoint_double_layer
|
|
270
283
|
)
|
|
271
284
|
return s.flatten(), v.flatten()
|
|
272
285
|
|
|
273
286
|
def get_col_func(j):
|
|
274
287
|
s, v = green_function.evaluate(
|
|
275
288
|
mesh1, mesh2.extract_one_face(j),
|
|
276
|
-
free_surface, water_depth, wavenumber
|
|
289
|
+
free_surface, water_depth, wavenumber,
|
|
290
|
+
adjoint_double_layer=adjoint_double_layer
|
|
277
291
|
)
|
|
278
292
|
return s.flatten(), v.flatten()
|
|
279
293
|
|
|
@@ -297,9 +311,9 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
297
311
|
for submesh1 in mesh1:
|
|
298
312
|
S_line, V_line = [], []
|
|
299
313
|
for submesh2 in mesh2:
|
|
300
|
-
S, V = self.
|
|
314
|
+
S, V = self._build_matrices(
|
|
301
315
|
submesh1, submesh2, free_surface, water_depth, wavenumber, green_function,
|
|
302
|
-
_rec_depth=_rec_depth+1)
|
|
316
|
+
adjoint_double_layer=adjoint_double_layer, _rec_depth=_rec_depth+1)
|
|
303
317
|
|
|
304
318
|
S_line.append(S)
|
|
305
319
|
V_line.append(V)
|
|
@@ -314,7 +328,114 @@ class HierarchicalToeplitzMatrixEngine(MatrixEngine):
|
|
|
314
328
|
LOG.debug(log_entry)
|
|
315
329
|
|
|
316
330
|
S, V = green_function.evaluate(
|
|
317
|
-
mesh1, mesh2, free_surface, water_depth, wavenumber,
|
|
331
|
+
mesh1, mesh2, free_surface, water_depth, wavenumber, adjoint_double_layer=adjoint_double_layer
|
|
318
332
|
)
|
|
319
333
|
return S, V
|
|
320
334
|
|
|
335
|
+
class HierarchicalPrecondMatrixEngine(HierarchicalToeplitzMatrixEngine):
|
|
336
|
+
"""An experimental matrix engine that build a hierarchical matrix with
|
|
337
|
+
some block-Toeplitz structure.
|
|
338
|
+
|
|
339
|
+
Parameters
|
|
340
|
+
----------
|
|
341
|
+
ACA_distance: float, optional
|
|
342
|
+
Above this distance, the ACA is used to approximate the matrix with a low-rank block.
|
|
343
|
+
ACA_tol: float, optional
|
|
344
|
+
The tolerance of the ACA when building a low-rank matrix.
|
|
345
|
+
matrix_cache_size: int, optional
|
|
346
|
+
number of matrices to keep in cache
|
|
347
|
+
"""
|
|
348
|
+
|
|
349
|
+
def __init__(self, *, ACA_distance=8.0, ACA_tol=1e-2, matrix_cache_size=1):
|
|
350
|
+
super().__init__(ACA_distance=ACA_distance, ACA_tol=ACA_tol, matrix_cache_size=matrix_cache_size)
|
|
351
|
+
self.linear_solver = linear_solvers.solve_precond_gmres
|
|
352
|
+
|
|
353
|
+
def build_matrices(self,
|
|
354
|
+
mesh1, mesh2, free_surface, water_depth, wavenumber,
|
|
355
|
+
green_function, adjoint_double_layer=True):
|
|
356
|
+
"""Recursively builds a hierarchical matrix between mesh1 and mesh2,
|
|
357
|
+
and precomputes some of the quantities needed for the preconditioner.
|
|
358
|
+
|
|
359
|
+
Same arguments as :func:`BasicMatrixEngine.build_matrices`, except for rec_depth
|
|
360
|
+
"""
|
|
361
|
+
# Build the matrices using the method of the parent class
|
|
362
|
+
S, K = super().build_matrices(mesh1, mesh2, free_surface, water_depth,
|
|
363
|
+
wavenumber, green_function,
|
|
364
|
+
adjoint_double_layer=adjoint_double_layer)
|
|
365
|
+
|
|
366
|
+
path_to_leaf = mesh1.path_to_leaf()
|
|
367
|
+
|
|
368
|
+
n = len(path_to_leaf)
|
|
369
|
+
N = K.shape[0]
|
|
370
|
+
|
|
371
|
+
# Navigate to the diagonal blocks and compute their LU decompositions
|
|
372
|
+
DLU = []
|
|
373
|
+
diag_shapes = []
|
|
374
|
+
for leaf in range(n):
|
|
375
|
+
# Navigate to the block containing the one we need
|
|
376
|
+
# (one layer above in the dendrogram)
|
|
377
|
+
#upper_block = self.access_block_by_path(K, path_to_leaf[leaf][:-1])
|
|
378
|
+
upper_block = K.access_block_by_path(path_to_leaf[leaf][:-1])
|
|
379
|
+
# find the local index in the full path
|
|
380
|
+
ind = path_to_leaf[leaf][-1]
|
|
381
|
+
# compute the LU decomposition and add to the list
|
|
382
|
+
DLU.append(lu_factor(upper_block.all_blocks[ind, ind]))
|
|
383
|
+
diag_shapes.append(upper_block.all_blocks[ind, ind].shape[0])
|
|
384
|
+
|
|
385
|
+
# Build the restriction and precompute its multiplication by K
|
|
386
|
+
R = np.zeros((n, N), dtype=complex)
|
|
387
|
+
RA = np.zeros((n, N), dtype=complex)
|
|
388
|
+
for ii in range(n):
|
|
389
|
+
row_slice = slice(sum(diag_shapes[:ii]), sum(diag_shapes[:ii+1]))
|
|
390
|
+
R[ii, row_slice] = 1
|
|
391
|
+
# Compute the multiplication using only the relevant slices of K
|
|
392
|
+
# The slices are found by navigating the tree
|
|
393
|
+
#RA[ii, :] = self.slice_rmatvec(R[ii, :], ii)
|
|
394
|
+
Aloc = K
|
|
395
|
+
v = R[ii, :]
|
|
396
|
+
va = np.zeros(N, dtype=complex)
|
|
397
|
+
free = [0, N]
|
|
398
|
+
|
|
399
|
+
for lvl, jj in enumerate(path_to_leaf[ii]):
|
|
400
|
+
|
|
401
|
+
Nrows = Aloc.all_blocks[jj, jj].shape[0]
|
|
402
|
+
|
|
403
|
+
if jj==0:
|
|
404
|
+
v = v[:Nrows]
|
|
405
|
+
w = v @ Aloc.all_blocks[0,1]
|
|
406
|
+
va[free[1]-len(w) : free[1]] = w
|
|
407
|
+
free[1] = free[1] - len(w)
|
|
408
|
+
else:
|
|
409
|
+
v = v[-Nrows:]
|
|
410
|
+
w = v @ Aloc.all_blocks[1, 0]
|
|
411
|
+
va[free[0] : free[0]+len(w)] = w
|
|
412
|
+
free[0] = free[0] + len(w)
|
|
413
|
+
|
|
414
|
+
Aloc = Aloc.all_blocks[jj, jj]
|
|
415
|
+
|
|
416
|
+
if lvl == len(path_to_leaf[ii])-1:
|
|
417
|
+
w = v@Aloc
|
|
418
|
+
va[free[0] : free[1]] = w
|
|
419
|
+
free[0] = free[0] + len(w)
|
|
420
|
+
|
|
421
|
+
RA[ii, :] = va
|
|
422
|
+
|
|
423
|
+
Ac = RA @ R.T
|
|
424
|
+
AcLU = lu_factor(Ac)
|
|
425
|
+
|
|
426
|
+
# Now navigate again to the diagonal blocks and set them to zero
|
|
427
|
+
for leaf in range(n):
|
|
428
|
+
upper_block = K.access_block_by_path(path_to_leaf[leaf][:-1])
|
|
429
|
+
ind = path_to_leaf[leaf][-1]
|
|
430
|
+
# turn the diagonal block into a zero sparse matrix
|
|
431
|
+
upper_block.all_blocks[ind, ind] = coo_matrix(upper_block.all_blocks[ind, ind].shape)
|
|
432
|
+
|
|
433
|
+
def PinvA_mv(v):
|
|
434
|
+
v = v + 1j*np.zeros(N)
|
|
435
|
+
return v - linear_solvers._block_Jacobi_coarse_corr(
|
|
436
|
+
K, np.zeros(N, dtype=complex), v,
|
|
437
|
+
R, RA, AcLU, DLU, diag_shapes, n)
|
|
438
|
+
|
|
439
|
+
PinvA = ssl.LinearOperator((N, N), matvec=PinvA_mv)
|
|
440
|
+
|
|
441
|
+
return S, (K, R, RA, AcLU, DLU, diag_shapes, n, PinvA)
|