feectools 0.1.0__py3-none-any.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.
- feectools/__init__.py +0 -0
- feectools/accelerate/__init__.py +0 -0
- feectools/accelerate/accelerate.py +220 -0
- feectools/accelerate/compile_psydac.mk +52 -0
- feectools/api/__init__.py +0 -0
- feectools/api/essential_bc.py +122 -0
- feectools/api/fem_bilinear_form.py +2226 -0
- feectools/api/fem_common.py +286 -0
- feectools/api/fem_sum_form.py +123 -0
- feectools/api/settings.py +82 -0
- feectools/core/__init__.py +11 -0
- feectools/core/bsplines.py +1107 -0
- feectools/core/bsplines_kernels.py +1349 -0
- feectools/core/field_evaluation_kernels.py +5015 -0
- feectools/core/tests/__init__.py +0 -0
- feectools/core/tests/test_bsplines.py +263 -0
- feectools/core/tests/test_bsplines_kernel.py +40 -0
- feectools/core/tests/test_bsplines_pyccel.py +752 -0
- feectools/ddm/__init__.py +3 -0
- feectools/ddm/basic.py +78 -0
- feectools/ddm/blocking_data_exchanger.py +348 -0
- feectools/ddm/cart.py +1835 -0
- feectools/ddm/interface_data_exchanger.py +122 -0
- feectools/ddm/mpi.py +109 -0
- feectools/ddm/nonblocking_data_exchanger.py +331 -0
- feectools/ddm/partition.py +207 -0
- feectools/ddm/petsc.py +112 -0
- feectools/ddm/tests/__init__.py +0 -0
- feectools/ddm/tests/test_cart_1d.py +138 -0
- feectools/ddm/tests/test_cart_2d.py +164 -0
- feectools/ddm/tests/test_cart_3d.py +158 -0
- feectools/ddm/tests/test_multicart_2d.py +173 -0
- feectools/ddm/tests/test_partition.py +124 -0
- feectools/ddm/utilities.py +24 -0
- feectools/feec/__init__.py +0 -0
- feectools/feec/derivatives.py +780 -0
- feectools/feec/dof_kernels.py +210 -0
- feectools/feec/global_geometric_projectors.py +1073 -0
- feectools/feec/hodge.py +148 -0
- feectools/fem/__init__.py +0 -0
- feectools/fem/basic.py +465 -0
- feectools/fem/grid.py +181 -0
- feectools/fem/partitioning.py +344 -0
- feectools/fem/projectors.py +160 -0
- feectools/fem/splines.py +559 -0
- feectools/fem/tensor.py +1393 -0
- feectools/fem/tests/__init__.py +0 -0
- feectools/fem/tests/analytical_profiles_1d.py +100 -0
- feectools/fem/tests/analytical_profiles_base.py +34 -0
- feectools/fem/tests/splines_error_bounds.py +155 -0
- feectools/fem/tests/test_spline_histopolation.py +120 -0
- feectools/fem/tests/test_spline_interpolation.py +182 -0
- feectools/fem/tests/test_splines.py +184 -0
- feectools/fem/tests/test_splines_par.py +46 -0
- feectools/fem/tests/test_vector_spaces.py +150 -0
- feectools/fem/tests/utilities.py +47 -0
- feectools/fem/vector.py +729 -0
- feectools/linalg/__init__.py +0 -0
- feectools/linalg/basic.py +1386 -0
- feectools/linalg/block.py +1451 -0
- feectools/linalg/direct_solvers.py +201 -0
- feectools/linalg/fft.py +258 -0
- feectools/linalg/kernels/__init__.py +0 -0
- feectools/linalg/kernels/axpy_kernels.py +57 -0
- feectools/linalg/kernels/inner_kernels.py +100 -0
- feectools/linalg/kernels/matvec_kernels.py +206 -0
- feectools/linalg/kernels/stencil2IJV_kernels.py +227 -0
- feectools/linalg/kernels/stencil2coo_kernels.py +179 -0
- feectools/linalg/kernels/transpose_kernels.py +263 -0
- feectools/linalg/kron.py +911 -0
- feectools/linalg/solvers.py +1914 -0
- feectools/linalg/sparse.py +114 -0
- feectools/linalg/stencil.py +2923 -0
- feectools/linalg/stencil_dot_kernels.py +317 -0
- feectools/linalg/stencil_transpose_kernels.py +372 -0
- feectools/linalg/tests/__init__.py +0 -0
- feectools/linalg/tests/test_block.py +1588 -0
- feectools/linalg/tests/test_fft.py +106 -0
- feectools/linalg/tests/test_kron_stencil_matrix.py +114 -0
- feectools/linalg/tests/test_linalg.py +1065 -0
- feectools/linalg/tests/test_matrix_free.py +128 -0
- feectools/linalg/tests/test_solvers.py +213 -0
- feectools/linalg/tests/test_stencil_interface_matrix.py +379 -0
- feectools/linalg/tests/test_stencil_vector.py +1036 -0
- feectools/linalg/tests/test_stencil_vector_space.py +440 -0
- feectools/linalg/topetsc.py +522 -0
- feectools/linalg/utilities.py +200 -0
- feectools/utilities/__init__.py +0 -0
- feectools/utilities/quadratures.py +113 -0
- feectools/utilities/utils.py +166 -0
- feectools/version.py +1 -0
- feectools-0.1.0.dist-info/METADATA +66 -0
- feectools-0.1.0.dist-info/RECORD +98 -0
- feectools-0.1.0.dist-info/WHEEL +5 -0
- feectools-0.1.0.dist-info/entry_points.txt +3 -0
- feectools-0.1.0.dist-info/licenses/AUTHORS +22 -0
- feectools-0.1.0.dist-info/licenses/LICENSE +21 -0
- feectools-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,1588 @@
|
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
|
2
|
+
#
|
|
3
|
+
import pytest
|
|
4
|
+
import numpy as np
|
|
5
|
+
from scipy.sparse import csr_matrix
|
|
6
|
+
from random import random, seed
|
|
7
|
+
|
|
8
|
+
from feectools.ddm.mpi import mpi as MPI
|
|
9
|
+
from feectools.linalg.direct_solvers import SparseSolver
|
|
10
|
+
from feectools.linalg.stencil import StencilVectorSpace, StencilVector, StencilMatrix
|
|
11
|
+
from feectools.linalg.block import BlockVectorSpace, BlockVector
|
|
12
|
+
from feectools.linalg.block import BlockLinearOperator
|
|
13
|
+
from feectools.linalg.utilities import array_to_psydac, petsc_to_psydac
|
|
14
|
+
from feectools.linalg.sparse import SparseMatrixLinearOperator
|
|
15
|
+
from feectools.api.settings import PSYDAC_BACKEND_GPYCCEL
|
|
16
|
+
from feectools.ddm.cart import DomainDecomposition, CartDecomposition
|
|
17
|
+
|
|
18
|
+
#===============================================================================
|
|
19
|
+
def compute_global_starts_ends(domain_decomposition, npts):
|
|
20
|
+
global_starts = [None]*len(npts)
|
|
21
|
+
global_ends = [None]*len(npts)
|
|
22
|
+
|
|
23
|
+
for axis in range(len(npts)):
|
|
24
|
+
es = domain_decomposition.global_element_starts[axis]
|
|
25
|
+
ee = domain_decomposition.global_element_ends [axis]
|
|
26
|
+
|
|
27
|
+
global_ends [axis] = ee.copy()
|
|
28
|
+
global_ends [axis][-1] = npts[axis]-1
|
|
29
|
+
global_starts[axis] = np.array([0] + (global_ends[axis][:-1]+1).tolist())
|
|
30
|
+
|
|
31
|
+
return global_starts, global_ends
|
|
32
|
+
|
|
33
|
+
#===============================================================================
|
|
34
|
+
# SERIAL TESTS
|
|
35
|
+
#===============================================================================
|
|
36
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
37
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
38
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
39
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
40
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
41
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
42
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
43
|
+
|
|
44
|
+
def test_2D_block_vector_space_serial_init( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
45
|
+
# set seed for reproducibility
|
|
46
|
+
seed(n1*n2*p1*p2)
|
|
47
|
+
|
|
48
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
49
|
+
|
|
50
|
+
# Partition the points
|
|
51
|
+
npts = [n1,n2]
|
|
52
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
53
|
+
|
|
54
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
55
|
+
|
|
56
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
57
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
58
|
+
W = BlockVectorSpace(V, V)
|
|
59
|
+
|
|
60
|
+
assert W.dimension == 2*n1*n2
|
|
61
|
+
assert W.dtype == dtype
|
|
62
|
+
assert W.spaces == (V,V)
|
|
63
|
+
assert W.parallel == False
|
|
64
|
+
assert W.starts == [(0,0),(0,0)]
|
|
65
|
+
assert W.ends == [(n1-1,n2-1),(n1-1,n2-1)]
|
|
66
|
+
assert W.pads == (p1,p2)
|
|
67
|
+
assert W.n_blocks == 2
|
|
68
|
+
assert W.connectivity== {}
|
|
69
|
+
#===============================================================================
|
|
70
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
71
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
72
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
73
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
74
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
75
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
76
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
77
|
+
|
|
78
|
+
def test_2D_block_vector_serial_init( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
79
|
+
# set seed for reproducibility
|
|
80
|
+
seed(n1*n2*p1*p2)
|
|
81
|
+
|
|
82
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
83
|
+
|
|
84
|
+
# Partition the points
|
|
85
|
+
npts = [n1,n2]
|
|
86
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
87
|
+
|
|
88
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
89
|
+
|
|
90
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
91
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
92
|
+
x1 = StencilVector( V )
|
|
93
|
+
x2 = StencilVector( V )
|
|
94
|
+
|
|
95
|
+
W = BlockVectorSpace(V, V)
|
|
96
|
+
x = BlockVector(W, blocks=[x1,x2])
|
|
97
|
+
assert x.dtype == dtype
|
|
98
|
+
assert x.space == W
|
|
99
|
+
assert x.n_blocks == 2
|
|
100
|
+
assert x.blocks == (x1, x2)
|
|
101
|
+
#===============================================================================
|
|
102
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
103
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
104
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
105
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
106
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
107
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
108
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
109
|
+
|
|
110
|
+
def test_2D_block_linear_operator_serial_init( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
111
|
+
# set seed for reproducibility
|
|
112
|
+
seed(n1*n2*p1*p2)
|
|
113
|
+
|
|
114
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
115
|
+
|
|
116
|
+
# Partition the points
|
|
117
|
+
npts = [n1,n2]
|
|
118
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
119
|
+
|
|
120
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
121
|
+
|
|
122
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
123
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
124
|
+
M1 = StencilMatrix( V, V)
|
|
125
|
+
M2 = StencilMatrix( V, V )
|
|
126
|
+
M3 = StencilMatrix( V, V )
|
|
127
|
+
x1 = StencilVector( V )
|
|
128
|
+
x2 = StencilVector( V )
|
|
129
|
+
|
|
130
|
+
# Fill in stencil matrices based on diagonal index
|
|
131
|
+
if dtype==complex:
|
|
132
|
+
f=lambda k1,k2: 10j*k1+k2
|
|
133
|
+
else:
|
|
134
|
+
f=lambda k1,k2: 10*k1+k2
|
|
135
|
+
|
|
136
|
+
for k1 in range(-p1,p1+1):
|
|
137
|
+
for k2 in range(-p2,p2+1):
|
|
138
|
+
M1[:,:,k1,k2] = f(k1,k2)
|
|
139
|
+
M2[:,:,k1,k2] = f(k1,k2)+2.
|
|
140
|
+
M3[:,:,k1,k2] = f(k1,k2)+5.
|
|
141
|
+
|
|
142
|
+
M1.remove_spurious_entries()
|
|
143
|
+
M2.remove_spurious_entries()
|
|
144
|
+
M3.remove_spurious_entries()
|
|
145
|
+
|
|
146
|
+
# Fill in vector with random values, then update ghost regions
|
|
147
|
+
for i1 in range(n1):
|
|
148
|
+
for i2 in range(n2):
|
|
149
|
+
x1[i1,i2] = 2.0*random() - 1.0
|
|
150
|
+
x2[i1,i2] = 5.0*random() - 1.0
|
|
151
|
+
x1.update_ghost_regions()
|
|
152
|
+
x2.update_ghost_regions()
|
|
153
|
+
|
|
154
|
+
W = BlockVectorSpace(V, V)
|
|
155
|
+
|
|
156
|
+
# Construct a BlockLinearOperator object containing M1, M2, M, using 3 ways
|
|
157
|
+
# |M1 M2|
|
|
158
|
+
# L = | |
|
|
159
|
+
# |M3 0 |
|
|
160
|
+
|
|
161
|
+
dict_blocks = {(0,0):M1, (0,1):M2, (1,0):M3}
|
|
162
|
+
list_blocks = [[M1, M2], [M3, None]]
|
|
163
|
+
|
|
164
|
+
L1 = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
165
|
+
assert L1.domain == W
|
|
166
|
+
assert L1.codomain == W
|
|
167
|
+
assert L1.dtype == dtype
|
|
168
|
+
assert L1.blocks == ((M1,M2),(M3,None))
|
|
169
|
+
assert L1.n_block_rows == 2
|
|
170
|
+
assert L1.n_block_cols == 2
|
|
171
|
+
assert L1.nonzero_block_indices == ((0,0),(0,1),(1,0))
|
|
172
|
+
assert L1.backend()==None
|
|
173
|
+
|
|
174
|
+
# Test copy method with an out
|
|
175
|
+
L4 = BlockLinearOperator( W, W )
|
|
176
|
+
L1.copy(out=L4)
|
|
177
|
+
assert L1.domain == W
|
|
178
|
+
assert L1.codomain == W
|
|
179
|
+
assert L1.dtype == dtype
|
|
180
|
+
assert L1.n_block_rows == 2
|
|
181
|
+
assert L1.n_block_cols == 2
|
|
182
|
+
assert L1.nonzero_block_indices == ((0,0),(0,1),(1,0))
|
|
183
|
+
assert L1.backend()==None
|
|
184
|
+
|
|
185
|
+
L2 = BlockLinearOperator( W, W, blocks=list_blocks )
|
|
186
|
+
L3 = BlockLinearOperator( W, W )
|
|
187
|
+
|
|
188
|
+
L3[0,0] = M1
|
|
189
|
+
L3[0,1] = M2
|
|
190
|
+
L3[1,0] = M3
|
|
191
|
+
|
|
192
|
+
# Convert L1, L2, L3 and L4 to COO form
|
|
193
|
+
coo1 = L1.tosparse().tocoo()
|
|
194
|
+
coo2 = L2.tosparse().tocoo()
|
|
195
|
+
coo3 = L3.tosparse().tocoo()
|
|
196
|
+
coo4 = L4.tosparse().tocoo()
|
|
197
|
+
|
|
198
|
+
# Check if the data are in the same place
|
|
199
|
+
assert np.array_equal( coo1.col , coo2.col )
|
|
200
|
+
assert np.array_equal( coo1.row , coo2.row )
|
|
201
|
+
assert np.array_equal( coo1.data, coo2.data )
|
|
202
|
+
|
|
203
|
+
assert np.array_equal( coo1.col , coo3.col )
|
|
204
|
+
assert np.array_equal( coo1.row , coo3.row )
|
|
205
|
+
assert np.array_equal( coo1.data, coo3.data )
|
|
206
|
+
|
|
207
|
+
assert np.array_equal( coo1.col , coo4.col )
|
|
208
|
+
assert np.array_equal( coo1.row , coo4.row )
|
|
209
|
+
assert np.array_equal( coo1.data, coo4.data )
|
|
210
|
+
|
|
211
|
+
dict_blocks = {(0,0):M1, (0,1):M2}
|
|
212
|
+
|
|
213
|
+
L1 = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
214
|
+
|
|
215
|
+
# Test transpose
|
|
216
|
+
LT1 = L1.transpose()
|
|
217
|
+
LT2 = BlockLinearOperator( W, W )
|
|
218
|
+
L1.transpose(out=LT2)
|
|
219
|
+
|
|
220
|
+
assert LT1.domain == W
|
|
221
|
+
assert LT1.codomain == W
|
|
222
|
+
assert LT1.dtype == dtype
|
|
223
|
+
assert LT1.n_block_rows == 2
|
|
224
|
+
assert LT1.n_block_cols == 2
|
|
225
|
+
assert LT1.nonzero_block_indices == ((0,0),(1,0))
|
|
226
|
+
assert LT1.backend()==None
|
|
227
|
+
|
|
228
|
+
assert LT2.domain == W
|
|
229
|
+
assert LT2.codomain == W
|
|
230
|
+
assert LT2.dtype == dtype
|
|
231
|
+
assert LT2.n_block_rows == 2
|
|
232
|
+
assert LT2.n_block_cols == 2
|
|
233
|
+
assert LT2.nonzero_block_indices == ((0,0),(1,0))
|
|
234
|
+
assert LT2.backend()==None
|
|
235
|
+
|
|
236
|
+
#convert to scipy for tests
|
|
237
|
+
LT1_sp = LT1.tosparse()
|
|
238
|
+
LT2_sp = LT2.tosparse()
|
|
239
|
+
L1_spT = L1.tosparse().T
|
|
240
|
+
|
|
241
|
+
# Check if the data are in the same place
|
|
242
|
+
assert abs(LT1_sp - L1_spT).max()< 1e-14
|
|
243
|
+
assert abs(LT2_sp - L1_spT).max()< 1e-14
|
|
244
|
+
|
|
245
|
+
#===============================================================================
|
|
246
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
247
|
+
@pytest.mark.parametrize( 'ndim', [1, 2, 3] )
|
|
248
|
+
@pytest.mark.parametrize( 'p', [1, 2] )
|
|
249
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
250
|
+
@pytest.mark.parametrize( 'P2', [True, False] )
|
|
251
|
+
@pytest.mark.parametrize( 'P3', [True] )
|
|
252
|
+
def test_block_serial_dimension( ndim, p, P1, P2, P3, dtype ):
|
|
253
|
+
|
|
254
|
+
if ndim == 1:
|
|
255
|
+
npts = [12]
|
|
256
|
+
ps = [p]
|
|
257
|
+
Ps = [P1]
|
|
258
|
+
shifts = [1]
|
|
259
|
+
|
|
260
|
+
elif ndim == 2:
|
|
261
|
+
npts =[12, 15]
|
|
262
|
+
ps = [p, p]
|
|
263
|
+
Ps = [P1, P2]
|
|
264
|
+
shifts = [1, 1]
|
|
265
|
+
|
|
266
|
+
else:
|
|
267
|
+
npts = [12, 15, 9]
|
|
268
|
+
ps = [p, p, p]
|
|
269
|
+
Ps = [P1, P2, P3]
|
|
270
|
+
shifts = [1, 1, 1]
|
|
271
|
+
|
|
272
|
+
# set seed for reproducibility
|
|
273
|
+
D = DomainDecomposition(npts, periods=Ps)
|
|
274
|
+
|
|
275
|
+
# Partition the points
|
|
276
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
277
|
+
|
|
278
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=ps, shifts=shifts)
|
|
279
|
+
|
|
280
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
281
|
+
V = StencilVectorSpace( cart, dtype=dtype)
|
|
282
|
+
if dtype==complex:
|
|
283
|
+
cst=1j
|
|
284
|
+
else:
|
|
285
|
+
cst=1
|
|
286
|
+
|
|
287
|
+
x1 = StencilVector( V )
|
|
288
|
+
x2 = StencilVector( V )
|
|
289
|
+
y1 = StencilVector( V )
|
|
290
|
+
y2 = StencilVector( V )
|
|
291
|
+
|
|
292
|
+
W = BlockVectorSpace(V, V)
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
# Fill in vector with random values, then update ghost regions
|
|
296
|
+
if ndim==1:
|
|
297
|
+
x1[:] = cst*2.0*np.random.random((npts[0]+2*p))
|
|
298
|
+
x2[:] = cst*5.0*np.random.random((npts[0]+2*p))
|
|
299
|
+
y1[:] = cst*2.0*np.random.random((npts[0]+2*p))
|
|
300
|
+
y2[:] = cst*3.0*np.random.random((npts[0]+2*p))
|
|
301
|
+
|
|
302
|
+
elif ndim==2:
|
|
303
|
+
x1[:,:] = cst*2.0*np.random.random((npts[0]+2*p,npts[1]+2*p))
|
|
304
|
+
x2[:,:] = cst*5.0*np.random.random((npts[0]+2*p,npts[1]+2*p))
|
|
305
|
+
y1[:,:] = cst*2.0*np.random.random((npts[0]+2*p,npts[1]+2*p))
|
|
306
|
+
y2[:,:] = cst*3.0*np.random.random((npts[0]+2*p,npts[1]+2*p))
|
|
307
|
+
|
|
308
|
+
else:
|
|
309
|
+
x1[:,:,:] = cst*2.0*np.random.random((npts[0]+2*p,npts[1]+2*p,npts[2]+2*p))
|
|
310
|
+
x2[:,:,:] = cst*5.0*np.random.random((npts[0]+2*p,npts[1]+2*p,npts[2]+2*p))
|
|
311
|
+
y1[:,:,:] = cst*2.0*np.random.random((npts[0]+2*p,npts[1]+2*p,npts[2]+2*p))
|
|
312
|
+
y2[:,:,:] = cst*3.0*np.random.random((npts[0]+2*p,npts[1]+2*p,npts[2]+2*p))
|
|
313
|
+
|
|
314
|
+
x1.update_ghost_regions()
|
|
315
|
+
x2.update_ghost_regions()
|
|
316
|
+
y1.update_ghost_regions()
|
|
317
|
+
y2.update_ghost_regions()
|
|
318
|
+
|
|
319
|
+
# Construct a BlockVector object containing x1 and x2
|
|
320
|
+
# |x1|
|
|
321
|
+
# X = | |
|
|
322
|
+
# |x2|
|
|
323
|
+
|
|
324
|
+
X = BlockVector(W)
|
|
325
|
+
X[0] = x1
|
|
326
|
+
X[1] = x2
|
|
327
|
+
|
|
328
|
+
Y = BlockVector(W)
|
|
329
|
+
Y[0] = y1
|
|
330
|
+
Y[1] = y2
|
|
331
|
+
|
|
332
|
+
# Test dot product
|
|
333
|
+
exact_inner = V.inner(x1, y1) + V.inner(x2, y2)
|
|
334
|
+
|
|
335
|
+
assert X.dtype == dtype
|
|
336
|
+
assert np.allclose(W.inner(X, Y), exact_inner, rtol=1e-14, atol=1e-14 )
|
|
337
|
+
|
|
338
|
+
# Test axpy product
|
|
339
|
+
axpy_exact = X + np.pi * cst * Y
|
|
340
|
+
X.mul_iadd(np.pi * cst, Y)
|
|
341
|
+
assert np.allclose(X[0]._data, axpy_exact[0]._data, rtol=1e-10, atol=1e-10 )
|
|
342
|
+
assert np.allclose(X[1]._data, axpy_exact[1]._data, rtol=1e-10, atol=1e-10 )
|
|
343
|
+
|
|
344
|
+
M1 = StencilMatrix(V, V)
|
|
345
|
+
M2 = StencilMatrix(V, V)
|
|
346
|
+
M3 = StencilMatrix(V, V)
|
|
347
|
+
|
|
348
|
+
# Fill in stencil matrices based on diagonal index
|
|
349
|
+
if ndim==1:
|
|
350
|
+
f = lambda k1: 10 * k1
|
|
351
|
+
for k1 in range(-ps[0], ps[0] + 1):
|
|
352
|
+
M1[:, k1] = f(k1)
|
|
353
|
+
M2[:, k1] = f(k1) + 2.
|
|
354
|
+
M3[:, k1] = f(k1) + 5.
|
|
355
|
+
if ndim==2:
|
|
356
|
+
f = lambda k1,k2: 10 * k1 + 100*k2
|
|
357
|
+
for k1 in range(-ps[0], ps[0] + 1):
|
|
358
|
+
for k2 in range(-ps[1], ps[1] + 1):
|
|
359
|
+
M1[:, k1] = f(k1,k2)
|
|
360
|
+
M2[:, k1] = f(k1,k2) + 2.
|
|
361
|
+
M3[:, k1] = f(k1,k2) + 5.
|
|
362
|
+
if ndim==3:
|
|
363
|
+
f = lambda k1, k2, k3: 10 * k1 + 100*k2+1000*k3
|
|
364
|
+
for k1 in range(-ps[0], ps[0] + 1):
|
|
365
|
+
for k2 in range(-ps[1], ps[1] + 1):
|
|
366
|
+
for k3 in range(-ps[1], ps[1] + 1):
|
|
367
|
+
M1[:, k1] = f(k1,k2,k3)
|
|
368
|
+
M2[:, k1] = f(k1,k2,k3) + 2.
|
|
369
|
+
M3[:, k1] = f(k1,k2,k3) + 5.
|
|
370
|
+
|
|
371
|
+
M1.remove_spurious_entries()
|
|
372
|
+
M2.remove_spurious_entries()
|
|
373
|
+
M3.remove_spurious_entries()
|
|
374
|
+
|
|
375
|
+
M = BlockLinearOperator(W, W, blocks=[[M1, M2], [M3, None]])
|
|
376
|
+
|
|
377
|
+
Y[0] = M1.dot(x1) + M2.dot(x2)
|
|
378
|
+
Y[1] = M3.dot(x1)
|
|
379
|
+
|
|
380
|
+
assert M.dtype == dtype
|
|
381
|
+
assert np.allclose((M.dot(X)).toarray(), Y.toarray(), rtol=1e-14, atol=1e-14 )
|
|
382
|
+
|
|
383
|
+
#===============================================================================
|
|
384
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
385
|
+
@pytest.mark.parametrize( 'npts', [[6, 8, 9]] )
|
|
386
|
+
@pytest.mark.parametrize( 'p', [[1,1,1], [2,3,4]] )
|
|
387
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
388
|
+
@pytest.mark.parametrize( 'P2', [True, False] )
|
|
389
|
+
@pytest.mark.parametrize( 'P3', [True] )
|
|
390
|
+
def test_3D_block_serial_basic_operator( dtype, npts, p, P1, P2, P3 ):
|
|
391
|
+
|
|
392
|
+
# set seed for reproducibility
|
|
393
|
+
D = DomainDecomposition(npts, periods=[P1,P2,P3])
|
|
394
|
+
|
|
395
|
+
# Partition the points
|
|
396
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
397
|
+
|
|
398
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=p, shifts=[1,1,1])
|
|
399
|
+
|
|
400
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
401
|
+
V = StencilVectorSpace( cart, dtype=dtype)
|
|
402
|
+
|
|
403
|
+
x1 = StencilVector( V )
|
|
404
|
+
x2 = StencilVector( V )
|
|
405
|
+
y1 = StencilVector( V )
|
|
406
|
+
y2 = StencilVector( V )
|
|
407
|
+
|
|
408
|
+
W = BlockVectorSpace(V, V)
|
|
409
|
+
if dtype==complex:
|
|
410
|
+
x1[:,:,:] = 2.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))+1j*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))
|
|
411
|
+
x2[:,:,:] = 5.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))+2j*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))
|
|
412
|
+
else:
|
|
413
|
+
x1[:,:,:] = 2.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))
|
|
414
|
+
x2[:,:,:] = 5.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1],npts[2]+2*p[2]))
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
x1.update_ghost_regions()
|
|
418
|
+
x2.update_ghost_regions()
|
|
419
|
+
y1.update_ghost_regions()
|
|
420
|
+
y2.update_ghost_regions()
|
|
421
|
+
|
|
422
|
+
# Construct a BlockVector object containing x1 and x2
|
|
423
|
+
# |x1|
|
|
424
|
+
# X = | |
|
|
425
|
+
# |x2|
|
|
426
|
+
|
|
427
|
+
X = BlockVector(W)
|
|
428
|
+
X[0] = x1
|
|
429
|
+
X[1] = x2
|
|
430
|
+
|
|
431
|
+
Y = BlockVector(W)
|
|
432
|
+
|
|
433
|
+
Y +=X
|
|
434
|
+
assert Y.dtype == dtype
|
|
435
|
+
assert np.allclose(Y.blocks[0]._data, (x1)._data, rtol=1e-14, atol=1e-14 )
|
|
436
|
+
assert np.allclose(Y.blocks[1]._data, (x2)._data, rtol=1e-14, atol=1e-14 )
|
|
437
|
+
|
|
438
|
+
Y -=2*X
|
|
439
|
+
assert np.allclose(Y.blocks[0]._data, -(x1)._data, rtol=1e-14, atol=1e-14 )
|
|
440
|
+
assert np.allclose(Y.blocks[1]._data, -(x2)._data, rtol=1e-14, atol=1e-14 )
|
|
441
|
+
|
|
442
|
+
Y *=6
|
|
443
|
+
assert np.allclose(Y.blocks[0]._data, -6*(x1)._data, rtol=1e-14, atol=1e-14 )
|
|
444
|
+
assert np.allclose(Y.blocks[1]._data, -6*(x2)._data, rtol=1e-14, atol=1e-14 )
|
|
445
|
+
|
|
446
|
+
Y /=-6
|
|
447
|
+
assert np.allclose(Y.blocks[0]._data, (x1)._data, rtol=1e-14, atol=1e-14 )
|
|
448
|
+
assert np.allclose(Y.blocks[1]._data, (x2)._data, rtol=1e-14, atol=1e-14 )
|
|
449
|
+
|
|
450
|
+
Y[0]=x2
|
|
451
|
+
Y[1]=-x1
|
|
452
|
+
|
|
453
|
+
Z1=Y+X
|
|
454
|
+
assert isinstance(Z1,BlockVector)
|
|
455
|
+
assert np.allclose(Z1.blocks[0]._data, (x1+x2)._data, rtol=1e-14, atol=1e-14 )
|
|
456
|
+
assert np.allclose(Z1.blocks[1]._data, (x2-x1)._data, rtol=1e-14, atol=1e-14 )
|
|
457
|
+
|
|
458
|
+
Z2=Y-X
|
|
459
|
+
assert isinstance(Z2,BlockVector)
|
|
460
|
+
assert np.allclose(Z2.blocks[0]._data, (x2-x1)._data, rtol=1e-14, atol=1e-14 )
|
|
461
|
+
assert np.allclose(Z2.blocks[1]._data, (-x2-x1)._data, rtol=1e-14, atol=1e-14 )
|
|
462
|
+
|
|
463
|
+
Z3=3*Y
|
|
464
|
+
assert isinstance(Z3,BlockVector)
|
|
465
|
+
assert np.allclose(Z3.blocks[0]._data, 3*(x2)._data, rtol=1e-14, atol=1e-14 )
|
|
466
|
+
assert np.allclose(Z3.blocks[1]._data, 3*(-x1)._data, rtol=1e-14, atol=1e-14 )
|
|
467
|
+
|
|
468
|
+
Z4=Y/4
|
|
469
|
+
assert isinstance(Z4,BlockVector)
|
|
470
|
+
assert np.allclose(Z4.blocks[0]._data, (x2)._data/4, rtol=1e-14, atol=1e-14 )
|
|
471
|
+
assert np.allclose(Z4.blocks[1]._data, (-x1)._data/4, rtol=1e-14, atol=1e-14 )
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
M1 = StencilMatrix(V, V)
|
|
475
|
+
M2 = StencilMatrix(V, V)
|
|
476
|
+
M3 = StencilMatrix(V, V)
|
|
477
|
+
|
|
478
|
+
if dtype==complex:
|
|
479
|
+
f = lambda k1, k2, k3: 10 * k1 + 100j*k2+1000*k3
|
|
480
|
+
else:
|
|
481
|
+
f = lambda k1, k2, k3: 10 * k1 + 100*k2+1000*k3
|
|
482
|
+
|
|
483
|
+
for k1 in range(-p[0], p[0] + 1):
|
|
484
|
+
for k2 in range(-p[1], p[1] + 1):
|
|
485
|
+
for k3 in range(-p[1], p[1] + 1):
|
|
486
|
+
M1[:, k1] = f(k1,k2,k3)
|
|
487
|
+
M2[:, k1] = f(k1,k2,k3) + 2.
|
|
488
|
+
M3[:, k1] = f(k1,k2,k3) + 5.
|
|
489
|
+
|
|
490
|
+
M1.remove_spurious_entries()
|
|
491
|
+
M2.remove_spurious_entries()
|
|
492
|
+
M3.remove_spurious_entries()
|
|
493
|
+
|
|
494
|
+
M = BlockLinearOperator(W, W, blocks=[[M1, M2], [M3, None]])
|
|
495
|
+
A = BlockLinearOperator(W, W)
|
|
496
|
+
|
|
497
|
+
A +=M
|
|
498
|
+
assert A.dtype == dtype
|
|
499
|
+
assert np.allclose(A.blocks[0][0]._data, (M1)._data, rtol=1e-14, atol=1e-14 )
|
|
500
|
+
assert np.allclose(A.blocks[0][1]._data, (M2)._data, rtol=1e-14, atol=1e-14 )
|
|
501
|
+
assert np.allclose(A.blocks[1][0]._data, (M3)._data, rtol=1e-14, atol=1e-14 )
|
|
502
|
+
assert A.blocks[1][1]==None
|
|
503
|
+
|
|
504
|
+
A -= 2*M
|
|
505
|
+
assert np.allclose(A.blocks[0][0]._data, -(M1)._data, rtol=1e-14, atol=1e-14 )
|
|
506
|
+
assert np.allclose(A.blocks[0][1]._data, -(M2)._data, rtol=1e-14, atol=1e-14 )
|
|
507
|
+
assert np.allclose(A.blocks[1][0]._data, -(M3)._data, rtol=1e-14, atol=1e-14 )
|
|
508
|
+
assert A.blocks[1][1]==None
|
|
509
|
+
|
|
510
|
+
A *= 5
|
|
511
|
+
assert np.allclose(A.blocks[0][0]._data, -5*(M1)._data, rtol=1e-14, atol=1e-14 )
|
|
512
|
+
assert np.allclose(A.blocks[0][1]._data, -5*(M2)._data, rtol=1e-14, atol=1e-14 )
|
|
513
|
+
assert np.allclose(A.blocks[1][0]._data, -5*(M3)._data, rtol=1e-14, atol=1e-14 )
|
|
514
|
+
assert A.blocks[1][1]==None
|
|
515
|
+
|
|
516
|
+
A /= -5
|
|
517
|
+
assert np.allclose(A.blocks[0][0]._data, (M1)._data, rtol=1e-14, atol=1e-14 )
|
|
518
|
+
assert np.allclose(A.blocks[0][1]._data, (M2)._data, rtol=1e-14, atol=1e-14 )
|
|
519
|
+
assert np.allclose(A.blocks[1][0]._data, (M3)._data, rtol=1e-14, atol=1e-14 )
|
|
520
|
+
assert A.blocks[1][1]==None
|
|
521
|
+
|
|
522
|
+
A= BlockLinearOperator(W, W, blocks=[[None, M3], [M2, M1]])
|
|
523
|
+
|
|
524
|
+
A1=A+M
|
|
525
|
+
assert isinstance(A1,BlockLinearOperator)
|
|
526
|
+
assert np.allclose(A1.blocks[0][0]._data, (M1)._data, rtol=1e-14, atol=1e-14 )
|
|
527
|
+
assert np.allclose(A1.blocks[0][1]._data, (M2+M3)._data, rtol=1e-14, atol=1e-14 )
|
|
528
|
+
assert np.allclose(A1.blocks[1][0]._data, (M3+M2)._data, rtol=1e-14, atol=1e-14 )
|
|
529
|
+
assert np.allclose(A1.blocks[1][1]._data, (M1)._data, rtol=1e-14, atol=1e-14 )
|
|
530
|
+
|
|
531
|
+
A2=A-M
|
|
532
|
+
assert isinstance(A2,BlockLinearOperator)
|
|
533
|
+
assert np.allclose(A2.blocks[0][0]._data, (-M1)._data, rtol=1e-14, atol=1e-14 )
|
|
534
|
+
assert np.allclose(A2.blocks[0][1]._data, (M3-M2)._data, rtol=1e-14, atol=1e-14 )
|
|
535
|
+
assert np.allclose(A2.blocks[1][0]._data, (M2-M3)._data, rtol=1e-14, atol=1e-14 )
|
|
536
|
+
assert np.allclose(A2.blocks[1][1]._data, (M1)._data, rtol=1e-14, atol=1e-14 )
|
|
537
|
+
|
|
538
|
+
A3=6*A
|
|
539
|
+
assert isinstance(A3,BlockLinearOperator)
|
|
540
|
+
assert np.allclose(A3.blocks[0][1]._data, 6*(M3)._data, rtol=1e-14, atol=1e-14 )
|
|
541
|
+
assert np.allclose(A3.blocks[1][0]._data, 6*(M2)._data, rtol=1e-14, atol=1e-14 )
|
|
542
|
+
assert np.allclose(A3.blocks[1][1]._data, 6*(M1)._data, rtol=1e-14, atol=1e-14 )
|
|
543
|
+
|
|
544
|
+
A4=A/5
|
|
545
|
+
assert isinstance(A4,BlockLinearOperator)
|
|
546
|
+
assert np.allclose(A4.blocks[0][1]._data, (M3)._data/5, rtol=1e-14, atol=1e-14 )
|
|
547
|
+
assert np.allclose(A4.blocks[1][0]._data, (M2)._data/5, rtol=1e-14, atol=1e-14 )
|
|
548
|
+
assert np.allclose(A4.blocks[1][1]._data, (M1)._data/5, rtol=1e-14, atol=1e-14 )
|
|
549
|
+
|
|
550
|
+
#===============================================================================
|
|
551
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
552
|
+
@pytest.mark.parametrize( 'npts', [[6, 8]] )
|
|
553
|
+
@pytest.mark.parametrize( 'p', [[1,1], [2,3]] )
|
|
554
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
555
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
556
|
+
def test_2D_block_serial_math( dtype, npts, p, P1, P2 ):
|
|
557
|
+
|
|
558
|
+
# set seed for reproducibility
|
|
559
|
+
D = DomainDecomposition(npts, periods=[P1,P2])
|
|
560
|
+
|
|
561
|
+
# Partition the points
|
|
562
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
563
|
+
|
|
564
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=p, shifts=[1,1])
|
|
565
|
+
|
|
566
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
567
|
+
V = StencilVectorSpace( cart, dtype=dtype)
|
|
568
|
+
|
|
569
|
+
x1 = StencilVector( V )
|
|
570
|
+
x2 = StencilVector( V )
|
|
571
|
+
|
|
572
|
+
W = BlockVectorSpace(V, V)
|
|
573
|
+
if dtype==complex:
|
|
574
|
+
x1[:,:,:] = 2.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))+1j*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))
|
|
575
|
+
x2[:,:,:] = 5.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))+2j*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))
|
|
576
|
+
else:
|
|
577
|
+
x1[:,:,:] = 2.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))
|
|
578
|
+
x2[:,:,:] = 5.0*np.random.random((npts[0]+2*p[0],npts[1]+2*p[1]))
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
x1.update_ghost_regions()
|
|
582
|
+
x2.update_ghost_regions()
|
|
583
|
+
|
|
584
|
+
x1a = x1.toarray().conj()
|
|
585
|
+
x2a = x2.toarray().conj()
|
|
586
|
+
|
|
587
|
+
# Construct a BlockVector object containing x1 and x2
|
|
588
|
+
# |x1|
|
|
589
|
+
# X = | |
|
|
590
|
+
# |x2|
|
|
591
|
+
|
|
592
|
+
X = BlockVector(W)
|
|
593
|
+
X[0] = x1
|
|
594
|
+
X[1] = x2
|
|
595
|
+
|
|
596
|
+
Xc=X.conjugate()
|
|
597
|
+
assert np.allclose(Xc.blocks[0].toarray(), x1a, rtol=1e-14, atol=1e-14 )
|
|
598
|
+
assert np.allclose(Xc.blocks[1].toarray(), x2a, rtol=1e-14, atol=1e-14 )
|
|
599
|
+
|
|
600
|
+
Xc=X.conj()
|
|
601
|
+
assert np.allclose(Xc.blocks[0].toarray(), x1a, rtol=1e-14, atol=1e-14 )
|
|
602
|
+
assert np.allclose(Xc.blocks[1].toarray(), x2a, rtol=1e-14, atol=1e-14 )
|
|
603
|
+
|
|
604
|
+
|
|
605
|
+
M1 = StencilMatrix(V, V)
|
|
606
|
+
M2 = StencilMatrix(V, V)
|
|
607
|
+
M3 = StencilMatrix(V, V)
|
|
608
|
+
|
|
609
|
+
if dtype==complex:
|
|
610
|
+
f = lambda k1, k2: 10 * k1 + 100j*k2
|
|
611
|
+
else:
|
|
612
|
+
f = lambda k1, k2: 10 * k1 + 100*k2
|
|
613
|
+
|
|
614
|
+
for k1 in range(-p[0], p[0] + 1):
|
|
615
|
+
for k2 in range(-p[1], p[1] + 1):
|
|
616
|
+
M1[:, k1] = f(k1,k2)
|
|
617
|
+
M2[:, k1] = f(k1,k2) + 2.
|
|
618
|
+
M3[:, k1] = f(k1,k2) + 5.
|
|
619
|
+
|
|
620
|
+
M1.remove_spurious_entries()
|
|
621
|
+
M2.remove_spurious_entries()
|
|
622
|
+
M3.remove_spurious_entries()
|
|
623
|
+
|
|
624
|
+
M1a = M1.toarray().conjugate()
|
|
625
|
+
M2a = M2.toarray().conjugate()
|
|
626
|
+
M3a = M3.toarray().conjugate()
|
|
627
|
+
|
|
628
|
+
# Construct a BlockLinearOperator object containing M1, M2, M3
|
|
629
|
+
# |M1 M2|
|
|
630
|
+
# M = | |
|
|
631
|
+
# |M3 0|
|
|
632
|
+
|
|
633
|
+
M = BlockLinearOperator(W, W, blocks=[[M1, M2], [M3, None]])
|
|
634
|
+
|
|
635
|
+
Mc = M.conjugate()
|
|
636
|
+
assert np.allclose(Mc.blocks[0][0].toarray(), M1a, rtol=1e-14, atol=1e-14 )
|
|
637
|
+
assert np.allclose(Mc.blocks[0][1].toarray(), M2a, rtol=1e-14, atol=1e-14 )
|
|
638
|
+
assert np.allclose(Mc.blocks[1][0].toarray(), M3a, rtol=1e-14, atol=1e-14 )
|
|
639
|
+
|
|
640
|
+
Mc = M.conj()
|
|
641
|
+
assert np.allclose(Mc.blocks[0][0].toarray(), M1a, rtol=1e-14, atol=1e-14 )
|
|
642
|
+
assert np.allclose(Mc.blocks[0][1].toarray(), M2a, rtol=1e-14, atol=1e-14 )
|
|
643
|
+
assert np.allclose(Mc.blocks[1][0].toarray(), M3a, rtol=1e-14, atol=1e-14 )
|
|
644
|
+
|
|
645
|
+
#===============================================================================
|
|
646
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
647
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
648
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
649
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
650
|
+
@pytest.mark.parametrize( 'p2', [1, 2] )
|
|
651
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
652
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
653
|
+
|
|
654
|
+
def test_block_linear_operator_serial_dot( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
655
|
+
# set seed for reproducibility
|
|
656
|
+
seed(n1*n2*p1*p2)
|
|
657
|
+
|
|
658
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
659
|
+
|
|
660
|
+
# Partition the points
|
|
661
|
+
npts = [n1,n2]
|
|
662
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
663
|
+
|
|
664
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
665
|
+
|
|
666
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
667
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
668
|
+
M1 = StencilMatrix( V, V)
|
|
669
|
+
M2 = StencilMatrix( V, V )
|
|
670
|
+
M3 = StencilMatrix( V, V )
|
|
671
|
+
x1 = StencilVector( V )
|
|
672
|
+
x2 = StencilVector( V )
|
|
673
|
+
|
|
674
|
+
# Fill in stencil matrices based on diagonal index
|
|
675
|
+
if dtype==complex:
|
|
676
|
+
f=lambda k1,k2: 10j*k1+k2
|
|
677
|
+
else:
|
|
678
|
+
f=lambda k1,k2: 10*k1+k2
|
|
679
|
+
|
|
680
|
+
for k1 in range(-p1,p1+1):
|
|
681
|
+
for k2 in range(-p2,p2+1):
|
|
682
|
+
M1[:,:,k1,k2] = f(k1,k2)
|
|
683
|
+
M2[:,:,k1,k2] = f(k1,k2)+2.
|
|
684
|
+
M3[:,:,k1,k2] = f(k1,k2)+5.
|
|
685
|
+
|
|
686
|
+
M1.remove_spurious_entries()
|
|
687
|
+
M2.remove_spurious_entries()
|
|
688
|
+
M3.remove_spurious_entries()
|
|
689
|
+
|
|
690
|
+
# Fill in vector with random values, then update ghost regions
|
|
691
|
+
for i1 in range(n1):
|
|
692
|
+
for i2 in range(n2):
|
|
693
|
+
x1[i1,i2] = 2.0*random() - 1.0
|
|
694
|
+
x2[i1,i2] = 5.0*random() - 1.0
|
|
695
|
+
x1.update_ghost_regions()
|
|
696
|
+
x2.update_ghost_regions()
|
|
697
|
+
|
|
698
|
+
W = BlockVectorSpace(V, V)
|
|
699
|
+
|
|
700
|
+
# Construct a BlockLinearOperator object containing M1, M2, M, using 3 ways
|
|
701
|
+
# |M1 M2|
|
|
702
|
+
# L = | |
|
|
703
|
+
# |M3 0 |
|
|
704
|
+
|
|
705
|
+
dict_blocks = {(0,0):M1, (0,1):M2, (1,0):M3}
|
|
706
|
+
|
|
707
|
+
L = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
708
|
+
|
|
709
|
+
# Construct a BlockVector object containing x1 and x2
|
|
710
|
+
# |x1|
|
|
711
|
+
# X = | |
|
|
712
|
+
# |x2|
|
|
713
|
+
|
|
714
|
+
X = BlockVector(W)
|
|
715
|
+
X[0] = x1
|
|
716
|
+
X[1] = x2
|
|
717
|
+
|
|
718
|
+
# Compute BlockLinearOperator product
|
|
719
|
+
Y = L.dot(X)
|
|
720
|
+
|
|
721
|
+
# Compute matrix-vector products for each block
|
|
722
|
+
y1 = M1.dot(x1) + M2.dot(x2)
|
|
723
|
+
y2 = M3.dot(x1)
|
|
724
|
+
|
|
725
|
+
# Check data in 1D array
|
|
726
|
+
assert np.allclose( Y.blocks[0].toarray(), y1.toarray(), rtol=1e-14, atol=1e-14 )
|
|
727
|
+
assert np.allclose( Y.blocks[1].toarray(), y2.toarray(), rtol=1e-14, atol=1e-14 )
|
|
728
|
+
#===============================================================================
|
|
729
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
730
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
731
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
732
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
733
|
+
@pytest.mark.parametrize( 'p2', [1, 2] )
|
|
734
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
735
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
736
|
+
|
|
737
|
+
def test_sparse_matrix_linear_operator_serial_dot( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
738
|
+
# set seed for reproducibility
|
|
739
|
+
seed(n1*n2*p1*p2)
|
|
740
|
+
|
|
741
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
742
|
+
|
|
743
|
+
# Partition the points
|
|
744
|
+
npts = [n1,n2]
|
|
745
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
746
|
+
|
|
747
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
748
|
+
|
|
749
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
750
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
751
|
+
M1 = StencilMatrix( V, V)
|
|
752
|
+
M2 = StencilMatrix( V, V )
|
|
753
|
+
M3 = StencilMatrix( V, V )
|
|
754
|
+
x1 = StencilVector( V )
|
|
755
|
+
x2 = StencilVector( V )
|
|
756
|
+
|
|
757
|
+
# Fill in stencil matrices based on diagonal index
|
|
758
|
+
if dtype==complex:
|
|
759
|
+
f=lambda k1,k2: 10j*k1+k2
|
|
760
|
+
else:
|
|
761
|
+
f=lambda k1,k2: 10*k1+k2
|
|
762
|
+
|
|
763
|
+
for k1 in range(-p1,p1+1):
|
|
764
|
+
for k2 in range(-p2,p2+1):
|
|
765
|
+
M1[:,:,k1,k2] = f(k1,k2)
|
|
766
|
+
M2[:,:,k1,k2] = f(k1,k2)+2.
|
|
767
|
+
M3[:,:,k1,k2] = f(k1,k2)+5.
|
|
768
|
+
|
|
769
|
+
M1.remove_spurious_entries()
|
|
770
|
+
M2.remove_spurious_entries()
|
|
771
|
+
M3.remove_spurious_entries()
|
|
772
|
+
|
|
773
|
+
# Fill in vector with random values, then update ghost regions
|
|
774
|
+
for i1 in range(n1):
|
|
775
|
+
for i2 in range(n2):
|
|
776
|
+
x1[i1,i2] = 2.0*random() - 1.0
|
|
777
|
+
x2[i1,i2] = 5.0*random() - 1.0
|
|
778
|
+
x1.update_ghost_regions()
|
|
779
|
+
x2.update_ghost_regions()
|
|
780
|
+
|
|
781
|
+
W = BlockVectorSpace(V, V)
|
|
782
|
+
|
|
783
|
+
# Construct a BlockLinearOperator object containing M1, M2, M, using 3 ways
|
|
784
|
+
# |M1 M2|
|
|
785
|
+
# L = | |
|
|
786
|
+
# |M3 0 |
|
|
787
|
+
|
|
788
|
+
dict_blocks = {(0,0):M1, (0,1):M2, (1,0):M3}
|
|
789
|
+
|
|
790
|
+
L = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
791
|
+
Lm = SparseMatrixLinearOperator(W, W, L.tosparse().tocsr())
|
|
792
|
+
|
|
793
|
+
# Construct a BlockVector object containing x1 and x2
|
|
794
|
+
# |x1|
|
|
795
|
+
# X = | |
|
|
796
|
+
# |x2|
|
|
797
|
+
|
|
798
|
+
X = BlockVector(W)
|
|
799
|
+
X[0] = x1
|
|
800
|
+
X[1] = x2
|
|
801
|
+
|
|
802
|
+
# Compute BlockLinearOperator product
|
|
803
|
+
Y = L.dot(X)
|
|
804
|
+
|
|
805
|
+
Ym = Lm.dot(X)
|
|
806
|
+
|
|
807
|
+
# Check data in 1D array
|
|
808
|
+
assert np.allclose( Ym.toarray(), Y.toarray(), rtol=1e-12, atol=1e-12 )
|
|
809
|
+
#===============================================================================
|
|
810
|
+
@pytest.mark.parametrize( 'dtype', [float, complex] )
|
|
811
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
812
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
813
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
814
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
815
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
816
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
817
|
+
|
|
818
|
+
def test_block_2d_serial_array_to_psydac( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
819
|
+
#Define a factor for the data
|
|
820
|
+
if dtype==complex:
|
|
821
|
+
factor=1j
|
|
822
|
+
else:
|
|
823
|
+
factor=1
|
|
824
|
+
# set seed for reproducibility
|
|
825
|
+
seed(n1*n2*p1*p2)
|
|
826
|
+
|
|
827
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
828
|
+
|
|
829
|
+
# Partition the points
|
|
830
|
+
npts = [n1,n2]
|
|
831
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
832
|
+
|
|
833
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
834
|
+
|
|
835
|
+
# Create vector spaces, and stencil vectors
|
|
836
|
+
V1 = StencilVectorSpace( cart ,dtype=dtype)
|
|
837
|
+
V2 = StencilVectorSpace( cart ,dtype=dtype)
|
|
838
|
+
|
|
839
|
+
W = BlockVectorSpace(V1, V2)
|
|
840
|
+
W2 = BlockVectorSpace(W, W)
|
|
841
|
+
|
|
842
|
+
x = BlockVector(W)
|
|
843
|
+
x2 = BlockVector(W2)
|
|
844
|
+
|
|
845
|
+
# Fill in vector with random values, then update ghost regions
|
|
846
|
+
for i1 in range(n1):
|
|
847
|
+
for i2 in range(n2):
|
|
848
|
+
x[0][i1,i2] = 2.0*factor*random() + 1.0
|
|
849
|
+
x[1][i1,i2] = 5.0*factor*random() - 1.0
|
|
850
|
+
x2[0][0][i1,i2] = 2.0*factor*random() + 1.0
|
|
851
|
+
x2[0][1][i1,i2] = 5.0*factor*random() - 1.0
|
|
852
|
+
x2[1][0][i1,i2] = 2.0*factor*random() + 1.0
|
|
853
|
+
x2[1][1][i1,i2] = 5.0*factor*random() - 1.0
|
|
854
|
+
x.update_ghost_regions()
|
|
855
|
+
x2.update_ghost_regions()
|
|
856
|
+
|
|
857
|
+
xa = x.toarray()
|
|
858
|
+
x2a = x2.toarray()
|
|
859
|
+
v = array_to_psydac(xa, W)
|
|
860
|
+
v2 = array_to_psydac(x2a, W2)
|
|
861
|
+
|
|
862
|
+
assert np.allclose( xa , v.toarray() )
|
|
863
|
+
assert np.allclose( x2a , v2.toarray() )
|
|
864
|
+
|
|
865
|
+
#===============================================================================
|
|
866
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
867
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
868
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
869
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
870
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
871
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
872
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
873
|
+
@pytest.mark.petsc
|
|
874
|
+
|
|
875
|
+
def test_block_vector_2d_serial_topetsc( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
876
|
+
#Define a factor for the data
|
|
877
|
+
if dtype==complex:
|
|
878
|
+
factor=1j
|
|
879
|
+
else:
|
|
880
|
+
factor=1
|
|
881
|
+
# set seed for reproducibility
|
|
882
|
+
seed(n1*n2*p1*p2)
|
|
883
|
+
|
|
884
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
885
|
+
|
|
886
|
+
# Partition the points
|
|
887
|
+
npts = [n1,n2]
|
|
888
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
889
|
+
|
|
890
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
891
|
+
|
|
892
|
+
# Create vector spaces, and stencil vectors
|
|
893
|
+
V1 = StencilVectorSpace( cart ,dtype=dtype)
|
|
894
|
+
V2 = StencilVectorSpace( cart ,dtype=dtype)
|
|
895
|
+
|
|
896
|
+
W = BlockVectorSpace(V1, V2)
|
|
897
|
+
|
|
898
|
+
x = BlockVector(W)
|
|
899
|
+
|
|
900
|
+
# Fill in vector with random values, then update ghost regions
|
|
901
|
+
for i1 in range(n1):
|
|
902
|
+
for i2 in range(n2):
|
|
903
|
+
x[0][i1,i2] = 2.0*factor*random() + 1.0
|
|
904
|
+
x[1][i1,i2] = 5.0*factor*random() - 1.0
|
|
905
|
+
|
|
906
|
+
x.update_ghost_regions()
|
|
907
|
+
|
|
908
|
+
v = x.topetsc()
|
|
909
|
+
v = petsc_to_psydac(v, W)
|
|
910
|
+
|
|
911
|
+
# The vectors can only be compared in the serial case
|
|
912
|
+
assert np.allclose( x.toarray() , v.toarray() )
|
|
913
|
+
|
|
914
|
+
#===============================================================================
|
|
915
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
916
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
917
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
918
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
919
|
+
@pytest.mark.parametrize( 'p2', [1, 2] )
|
|
920
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
921
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
922
|
+
@pytest.mark.petsc
|
|
923
|
+
|
|
924
|
+
def test_block_linear_operator_2d_serial_topetsc( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
925
|
+
# set seed for reproducibility
|
|
926
|
+
seed(n1*n2*p1*p2)
|
|
927
|
+
|
|
928
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
929
|
+
|
|
930
|
+
# Partition the points
|
|
931
|
+
npts = [n1,n2]
|
|
932
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
933
|
+
|
|
934
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
935
|
+
|
|
936
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
937
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
938
|
+
M1 = StencilMatrix( V, V)
|
|
939
|
+
M2 = StencilMatrix( V, V )
|
|
940
|
+
M3 = StencilMatrix( V, V )
|
|
941
|
+
|
|
942
|
+
# Fill in stencil matrices based on diagonal index
|
|
943
|
+
if dtype==complex:
|
|
944
|
+
f=lambda k1,k2: 10j*k1+k2
|
|
945
|
+
else:
|
|
946
|
+
f=lambda k1,k2: 10*k1+k2
|
|
947
|
+
|
|
948
|
+
for k1 in range(-p1,p1+1):
|
|
949
|
+
for k2 in range(-p2,p2+1):
|
|
950
|
+
M1[:,:,k1,k2] = f(k1,k2)
|
|
951
|
+
M2[:,:,k1,k2] = f(k1,k2)+2.
|
|
952
|
+
M3[:,:,k1,k2] = f(k1,k2)+5.
|
|
953
|
+
|
|
954
|
+
M1.remove_spurious_entries()
|
|
955
|
+
M2.remove_spurious_entries()
|
|
956
|
+
M3.remove_spurious_entries()
|
|
957
|
+
|
|
958
|
+
W = BlockVectorSpace(V, V)
|
|
959
|
+
|
|
960
|
+
# Construct a BlockLinearOperator object containing M1, M2, M, using 3 ways
|
|
961
|
+
# |M1 M2|
|
|
962
|
+
# L = | |
|
|
963
|
+
# |M3 0 |
|
|
964
|
+
|
|
965
|
+
dict_blocks = {(0,0):M1, (0,1):M2, (1,0):M3}
|
|
966
|
+
|
|
967
|
+
L = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
968
|
+
|
|
969
|
+
Lp = L.topetsc()
|
|
970
|
+
indptr, indices, data = Lp.getValuesCSR()
|
|
971
|
+
if dtype == float:
|
|
972
|
+
data = data.real #PETSc with installation complex configuration only handles complex dtype
|
|
973
|
+
Lp = csr_matrix((data, indices, indptr), shape=Lp.size)
|
|
974
|
+
L = L.tosparse().tocsr()
|
|
975
|
+
|
|
976
|
+
# The operators can only be compared in the serial case
|
|
977
|
+
assert (L-Lp).data.size == 0
|
|
978
|
+
|
|
979
|
+
#===============================================================================
|
|
980
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
981
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
982
|
+
@pytest.mark.parametrize( 'n2', [8, 32] )
|
|
983
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
984
|
+
@pytest.mark.parametrize( 'p2', [2] )
|
|
985
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
986
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
987
|
+
@pytest.mark.parametrize( 'backend', [None, PSYDAC_BACKEND_GPYCCEL] )
|
|
988
|
+
|
|
989
|
+
def test_block_linear_operator_dot_backend( dtype, n1, n2, p1, p2, P1, P2, backend ):
|
|
990
|
+
# Define a factor for the data
|
|
991
|
+
if dtype == complex:
|
|
992
|
+
factor = 1j
|
|
993
|
+
else:
|
|
994
|
+
factor = 1
|
|
995
|
+
|
|
996
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2])
|
|
997
|
+
|
|
998
|
+
# Partition the points
|
|
999
|
+
npts = [n1,n2]
|
|
1000
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1001
|
+
|
|
1002
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
1003
|
+
|
|
1004
|
+
# Create vector space, stencil matrix, and stencil vector
|
|
1005
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
1006
|
+
|
|
1007
|
+
M1 = StencilMatrix( V, V , backend=backend)
|
|
1008
|
+
M2 = StencilMatrix( V, V , backend=backend)
|
|
1009
|
+
M3 = StencilMatrix( V, V , backend=backend)
|
|
1010
|
+
M4 = StencilMatrix( V, V , backend=backend)
|
|
1011
|
+
x1 = StencilVector( V )
|
|
1012
|
+
x2 = StencilVector( V )
|
|
1013
|
+
|
|
1014
|
+
s1,s2 = V.starts
|
|
1015
|
+
e1,e2 = V.ends
|
|
1016
|
+
|
|
1017
|
+
# Fill in stencil matrix values based on diagonal index (periodic!)
|
|
1018
|
+
for k1 in range(-p1,p1+1):
|
|
1019
|
+
for k2 in range(-p2,p2+1):
|
|
1020
|
+
M1[:,:,k1,k2] = factor*k1+k2+10.
|
|
1021
|
+
M2[:,:,k1,k2] = factor*2.*k1+k2
|
|
1022
|
+
M3[:,:,k1,k2] = factor*5*k1+k2
|
|
1023
|
+
M4[:,:,k1,k2] = factor*10*k1+k2
|
|
1024
|
+
|
|
1025
|
+
# If any dimension is not periodic, set corresponding periodic corners to zero
|
|
1026
|
+
M1.remove_spurious_entries()
|
|
1027
|
+
M2.remove_spurious_entries()
|
|
1028
|
+
M3.remove_spurious_entries()
|
|
1029
|
+
M4.remove_spurious_entries()
|
|
1030
|
+
|
|
1031
|
+
# Fill in vector with random values, then update ghost regions
|
|
1032
|
+
for i1 in range(s1,e1+1):
|
|
1033
|
+
for i2 in range(s2,e2+1):
|
|
1034
|
+
x1[i1,i2] = 2.0*factor * i1 + i2
|
|
1035
|
+
x2[i1,i2] = 5.0*factor * i2 - i1
|
|
1036
|
+
x1.update_ghost_regions()
|
|
1037
|
+
x2.update_ghost_regions()
|
|
1038
|
+
|
|
1039
|
+
# Create and Fill Block objects
|
|
1040
|
+
W = BlockVectorSpace(V, V)
|
|
1041
|
+
L = BlockLinearOperator( W, W )
|
|
1042
|
+
L[0,0] = M1
|
|
1043
|
+
L[0,1] = M2
|
|
1044
|
+
L[1,0] = M3
|
|
1045
|
+
L[1,1] = M4
|
|
1046
|
+
|
|
1047
|
+
# L.set_backend(PSYDAC_BACKEND_GPYCCEL)
|
|
1048
|
+
|
|
1049
|
+
# X = BlockVector(W)
|
|
1050
|
+
# X[0] = x1
|
|
1051
|
+
# X[1] = x2
|
|
1052
|
+
|
|
1053
|
+
# # Compute Block-vector product
|
|
1054
|
+
# Y = L.dot(X)
|
|
1055
|
+
|
|
1056
|
+
# # Compute matrix-vector products for each block
|
|
1057
|
+
# y1 = M1.dot(x1) + M2.dot(x2)
|
|
1058
|
+
# y2 = M3.dot(x1) + M4.dot(x2)
|
|
1059
|
+
|
|
1060
|
+
# # Check data in 1D array
|
|
1061
|
+
# assert np.allclose( Y.blocks[0].toarray(), y1.toarray(), rtol=1e-13, atol=1e-13 )
|
|
1062
|
+
# assert np.allclose( Y.blocks[1].toarray(), y2.toarray(), rtol=1e-13, atol=1e-13 )
|
|
1063
|
+
#===============================================================================
|
|
1064
|
+
# PARALLEL TESTS
|
|
1065
|
+
#===============================================================================
|
|
1066
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
1067
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
1068
|
+
@pytest.mark.parametrize( 'n2', [8, 32] )
|
|
1069
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
1070
|
+
@pytest.mark.parametrize( 'p2', [2] )
|
|
1071
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
1072
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
1073
|
+
@pytest.mark.parallel
|
|
1074
|
+
|
|
1075
|
+
def test_block_linear_operator_parallel_dot( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
1076
|
+
# Define a factor for the data
|
|
1077
|
+
if dtype == complex:
|
|
1078
|
+
factor = 1j
|
|
1079
|
+
else:
|
|
1080
|
+
factor = 1
|
|
1081
|
+
|
|
1082
|
+
# set seed for reproducibility
|
|
1083
|
+
seed(n1*n2*p1*p2)
|
|
1084
|
+
|
|
1085
|
+
comm = MPI.COMM_WORLD
|
|
1086
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2], comm=comm)
|
|
1087
|
+
|
|
1088
|
+
# Partition the points
|
|
1089
|
+
npts = [n1,n2]
|
|
1090
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1091
|
+
|
|
1092
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
1093
|
+
|
|
1094
|
+
# Create vector space, stencil matrix, and stencil vector
|
|
1095
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
1096
|
+
M1 = StencilMatrix( V, V )
|
|
1097
|
+
M2 = StencilMatrix( V, V )
|
|
1098
|
+
M3 = StencilMatrix( V, V )
|
|
1099
|
+
M4 = StencilMatrix( V, V )
|
|
1100
|
+
x1 = StencilVector( V )
|
|
1101
|
+
x2 = StencilVector( V )
|
|
1102
|
+
|
|
1103
|
+
s1,s2 = V.starts
|
|
1104
|
+
e1,e2 = V.ends
|
|
1105
|
+
|
|
1106
|
+
# Fill in stencil matrix values based on diagonal index (periodic!)
|
|
1107
|
+
for k1 in range(-p1,p1+1):
|
|
1108
|
+
for k2 in range(-p2,p2+1):
|
|
1109
|
+
M1[:,:,k1,k2] = factor*k1+k2+10.
|
|
1110
|
+
M2[:,:,k1,k2] = factor*2.*k1+k2
|
|
1111
|
+
M3[:,:,k1,k2] = factor*5*k1+k2
|
|
1112
|
+
M4[:,:,k1,k2] = factor*10*k1+k2
|
|
1113
|
+
|
|
1114
|
+
# If any dimension is not periodic, set corresponding periodic corners to zero
|
|
1115
|
+
M1.remove_spurious_entries()
|
|
1116
|
+
M2.remove_spurious_entries()
|
|
1117
|
+
M3.remove_spurious_entries()
|
|
1118
|
+
M4.remove_spurious_entries()
|
|
1119
|
+
|
|
1120
|
+
# Fill in vector with random values, then update ghost regions
|
|
1121
|
+
for i1 in range(s1,e1+1):
|
|
1122
|
+
for i2 in range(s2,e2+1):
|
|
1123
|
+
x1[i1,i2] = 2.0*factor*random() + 1.0
|
|
1124
|
+
x2[i1,i2] = 5.0*factor*random() - 1.0
|
|
1125
|
+
x1.update_ghost_regions()
|
|
1126
|
+
x2.update_ghost_regions()
|
|
1127
|
+
|
|
1128
|
+
# Create and Fill Block objects
|
|
1129
|
+
W = BlockVectorSpace(V, V)
|
|
1130
|
+
L = BlockLinearOperator( W, W )
|
|
1131
|
+
L[0,0] = M1
|
|
1132
|
+
L[0,1] = M2
|
|
1133
|
+
L[1,0] = M3
|
|
1134
|
+
L[1,1] = M4
|
|
1135
|
+
|
|
1136
|
+
X = BlockVector(W)
|
|
1137
|
+
X[0] = x1
|
|
1138
|
+
X[1] = x2
|
|
1139
|
+
|
|
1140
|
+
# Compute Block-vector product
|
|
1141
|
+
Y = L.dot(X)
|
|
1142
|
+
|
|
1143
|
+
# Compute matrix-vector products for each block
|
|
1144
|
+
y1 = M1.dot(x1) + M2.dot(x2)
|
|
1145
|
+
y2 = M3.dot(x1) + M4.dot(x2)
|
|
1146
|
+
|
|
1147
|
+
# Check data in 1D array
|
|
1148
|
+
assert np.allclose( Y.blocks[0].toarray(), y1.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1149
|
+
assert np.allclose( Y.blocks[1].toarray(), y2.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1150
|
+
|
|
1151
|
+
# Test copy with an out
|
|
1152
|
+
# Create random matrix
|
|
1153
|
+
N1 = StencilMatrix( V, V )
|
|
1154
|
+
N2 = StencilMatrix( V, V )
|
|
1155
|
+
N3 = StencilMatrix( V, V )
|
|
1156
|
+
N4 = StencilMatrix( V, V )
|
|
1157
|
+
|
|
1158
|
+
for k1 in range(-p1,p1+1):
|
|
1159
|
+
for k2 in range(-p2,p2+1):
|
|
1160
|
+
N1[:,:,k1,k2] = factor*random()
|
|
1161
|
+
N2[:,:,k1,k2] = factor*random()
|
|
1162
|
+
N3[:,:,k1,k2] = factor*random()
|
|
1163
|
+
N4[:,:,k1,k2] = factor*random()
|
|
1164
|
+
|
|
1165
|
+
K = BlockLinearOperator( W, W )
|
|
1166
|
+
N = BlockLinearOperator( W, W )
|
|
1167
|
+
|
|
1168
|
+
|
|
1169
|
+
K[0,0] = N1
|
|
1170
|
+
K[0,1] = N2
|
|
1171
|
+
K[1,0] = N3
|
|
1172
|
+
K[1,1] = N4
|
|
1173
|
+
|
|
1174
|
+
#replace the random entries to check they are really overwritten
|
|
1175
|
+
K.copy(out=N)
|
|
1176
|
+
L.copy(out=K)
|
|
1177
|
+
|
|
1178
|
+
# Compute Block-vector product
|
|
1179
|
+
K.dot(X, out= Y)
|
|
1180
|
+
|
|
1181
|
+
# Check data in 1D array
|
|
1182
|
+
assert np.allclose( Y.blocks[0].toarray(), y1.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1183
|
+
assert np.allclose( Y.blocks[1].toarray(), y2.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1184
|
+
|
|
1185
|
+
# Test transpose with an out, check that we overwrite the random entries
|
|
1186
|
+
L.transpose(out = N)
|
|
1187
|
+
|
|
1188
|
+
# Compute Block-vector product
|
|
1189
|
+
Z = N.dot(X)
|
|
1190
|
+
|
|
1191
|
+
# Compute matrix-vector products for each block
|
|
1192
|
+
y1 = M1.T.dot(x1) + M3.T.dot(x2)
|
|
1193
|
+
y2 = M2.T.dot(x1) + M4.T.dot(x2)
|
|
1194
|
+
|
|
1195
|
+
# Check data in 1D array
|
|
1196
|
+
assert np.allclose( Z.blocks[0].toarray(), y1.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1197
|
+
assert np.allclose( Z.blocks[1].toarray(), y2.toarray(), rtol=1e-14, atol=1e-14 )
|
|
1198
|
+
|
|
1199
|
+
# ===============================================================================
|
|
1200
|
+
@pytest.mark.parametrize('dtype', [float])
|
|
1201
|
+
@pytest.mark.parametrize('n1', [10, 17])
|
|
1202
|
+
@pytest.mark.parametrize('n2', [13, 7])
|
|
1203
|
+
@pytest.mark.parametrize('p1', [1, 2])
|
|
1204
|
+
@pytest.mark.parametrize('p2', [1])
|
|
1205
|
+
@pytest.mark.parametrize('s1', [1, 2])
|
|
1206
|
+
@pytest.mark.parametrize('s2', [1])
|
|
1207
|
+
@pytest.mark.parametrize('P1', [True, False])
|
|
1208
|
+
@pytest.mark.parametrize('P2', [True])
|
|
1209
|
+
@pytest.mark.parallel
|
|
1210
|
+
|
|
1211
|
+
def test_block_vector_2d_parallel_array_to_psydac(dtype, n1, n2, p1, p2, s1, s2, P1, P2):
|
|
1212
|
+
npts = [n1, n2]
|
|
1213
|
+
|
|
1214
|
+
comm = MPI.COMM_WORLD
|
|
1215
|
+
|
|
1216
|
+
# Create domain decomposition
|
|
1217
|
+
D = DomainDecomposition(npts, periods=[P1, P2], comm=comm)
|
|
1218
|
+
|
|
1219
|
+
# Partition the points
|
|
1220
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1221
|
+
C = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1, p2], shifts=[s1, s2])
|
|
1222
|
+
|
|
1223
|
+
# Create Vector spaces and Vectors
|
|
1224
|
+
V = StencilVectorSpace(C, dtype=dtype)
|
|
1225
|
+
W = BlockVectorSpace(V, V)
|
|
1226
|
+
W2 = BlockVectorSpace(W, W, V)
|
|
1227
|
+
x = W.zeros()
|
|
1228
|
+
x2 = W2.zeros()
|
|
1229
|
+
|
|
1230
|
+
# Fill the vector with data
|
|
1231
|
+
if dtype == complex:
|
|
1232
|
+
f = lambda i1, i2: 10j * i1 + i2
|
|
1233
|
+
else:
|
|
1234
|
+
f = lambda i1, i2: 10 * i1 + i2
|
|
1235
|
+
for i1 in range(V.starts[0], V.ends[0]+1):
|
|
1236
|
+
for i2 in range(V.starts[1], V.ends[1]+1):
|
|
1237
|
+
x[0][i1, i2] = f(i1, i2)
|
|
1238
|
+
x[1][i1, i2] = -13*f(i1, i2)
|
|
1239
|
+
x2[0] = x
|
|
1240
|
+
x2[1] = 2*x
|
|
1241
|
+
x2[2][i1, i2] = 7*f(i1, i2)
|
|
1242
|
+
|
|
1243
|
+
x.update_ghost_regions()
|
|
1244
|
+
x2.update_ghost_regions()
|
|
1245
|
+
|
|
1246
|
+
# Convert vectors to arrays
|
|
1247
|
+
xa = x.toarray()
|
|
1248
|
+
x2a = x2.toarray()
|
|
1249
|
+
|
|
1250
|
+
# Apply array_to_psydac as left inverse of toarray
|
|
1251
|
+
w = array_to_psydac(xa, W)
|
|
1252
|
+
w2 = array_to_psydac(x2a, W2)
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
# Apply array_to_psydac first, and toarray next
|
|
1256
|
+
xa_r_inv = np.array(np.random.rand(xa.size), dtype=dtype)*xa # the vector must be distributed as xa
|
|
1257
|
+
x_r_inv = array_to_psydac(xa_r_inv, W)
|
|
1258
|
+
x_r_inv.update_ghost_regions()
|
|
1259
|
+
va_r_inv = x_r_inv.toarray()
|
|
1260
|
+
|
|
1261
|
+
x2a_r_inv = np.array(np.random.rand(x2a.size), dtype=dtype)*x2a # the vector must be distributed as xa
|
|
1262
|
+
x2_r_inv = array_to_psydac(x2a_r_inv, W2)
|
|
1263
|
+
x2_r_inv.update_ghost_regions()
|
|
1264
|
+
v2a_r_inv = x2_r_inv.toarray()
|
|
1265
|
+
|
|
1266
|
+
## Check that array_to_psydac is the inverse of .toarray():
|
|
1267
|
+
# left inverse:
|
|
1268
|
+
assert isinstance(w, BlockVector)
|
|
1269
|
+
assert w.space is W
|
|
1270
|
+
assert isinstance(w2, BlockVector)
|
|
1271
|
+
assert w2.space is W2
|
|
1272
|
+
for i in range(2):
|
|
1273
|
+
assert np.array_equal(x[i]._data, w[i]._data)
|
|
1274
|
+
for j in range(2):
|
|
1275
|
+
assert np.array_equal(x2[i][j]._data, w2[i][j]._data)
|
|
1276
|
+
assert np.array_equal(x2[i][j]._data, w2[i][j]._data)
|
|
1277
|
+
|
|
1278
|
+
assert np.array_equal(x2[2]._data, w2[2]._data)
|
|
1279
|
+
|
|
1280
|
+
# right inverse:
|
|
1281
|
+
assert np.array_equal(xa_r_inv, va_r_inv)
|
|
1282
|
+
assert np.array_equal(x2a_r_inv, v2a_r_inv)
|
|
1283
|
+
|
|
1284
|
+
#===============================================================================
|
|
1285
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
1286
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
1287
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
1288
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
1289
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
1290
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
1291
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
1292
|
+
@pytest.mark.parallel
|
|
1293
|
+
@pytest.mark.petsc
|
|
1294
|
+
|
|
1295
|
+
def test_block_vector_2d_parallel_topetsc( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
1296
|
+
#Define a factor for the data
|
|
1297
|
+
if dtype==complex:
|
|
1298
|
+
factor=1j
|
|
1299
|
+
else:
|
|
1300
|
+
factor=1
|
|
1301
|
+
# set seed for reproducibility
|
|
1302
|
+
seed(n1*n2*p1*p2)
|
|
1303
|
+
|
|
1304
|
+
comm = MPI.COMM_WORLD
|
|
1305
|
+
|
|
1306
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2], comm=comm)
|
|
1307
|
+
|
|
1308
|
+
# Partition the points
|
|
1309
|
+
npts = [n1,n2]
|
|
1310
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1311
|
+
|
|
1312
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
1313
|
+
|
|
1314
|
+
D2 = DomainDecomposition([n1+1,n2+1], periods=[P1,P2], comm=comm)
|
|
1315
|
+
npts2 = [n1+1,n2+1]
|
|
1316
|
+
global_starts2, global_ends2 = compute_global_starts_ends(D2, npts2)
|
|
1317
|
+
cart2 = CartDecomposition(D2, npts2, global_starts2, global_ends2, pads=[p1+1,p2+1], shifts=[1,1])
|
|
1318
|
+
|
|
1319
|
+
# Create vector spaces, and stencil vectors
|
|
1320
|
+
V1 = StencilVectorSpace( cart ,dtype=dtype)
|
|
1321
|
+
V2 = StencilVectorSpace( cart2 ,dtype=dtype)
|
|
1322
|
+
|
|
1323
|
+
W = BlockVectorSpace(V1, V2)
|
|
1324
|
+
#TODO: implement conversion to PETSc recursively to treat case of block of blocks
|
|
1325
|
+
|
|
1326
|
+
x = BlockVector(W)
|
|
1327
|
+
|
|
1328
|
+
# Fill in vector with random values, then update ghost regions
|
|
1329
|
+
for i0 in range(len(W.starts)):
|
|
1330
|
+
for i1 in range(W.starts[i0][0], W.ends[i0][0] + 1):
|
|
1331
|
+
for i2 in range(W.starts[i0][1], W.ends[i0][1] + 1):
|
|
1332
|
+
x[i0][i1,i2] = 2.0*factor*random() + 1.0
|
|
1333
|
+
|
|
1334
|
+
x.update_ghost_regions()
|
|
1335
|
+
|
|
1336
|
+
v = petsc_to_psydac(x.topetsc(), W)
|
|
1337
|
+
|
|
1338
|
+
assert np.allclose( x.toarray() , v.toarray(), rtol=1e-12, atol=1e-12 )
|
|
1339
|
+
|
|
1340
|
+
#===============================================================================
|
|
1341
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
1342
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
1343
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
1344
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
1345
|
+
@pytest.mark.parallel
|
|
1346
|
+
@pytest.mark.petsc
|
|
1347
|
+
|
|
1348
|
+
def test_block_linear_operator_1d_parallel_topetsc( dtype, n1, p1, P1):
|
|
1349
|
+
# set seed for reproducibility
|
|
1350
|
+
seed(n1*p1)
|
|
1351
|
+
|
|
1352
|
+
D = DomainDecomposition([n1], periods=[P1], comm=MPI.COMM_WORLD)
|
|
1353
|
+
|
|
1354
|
+
# Partition the points
|
|
1355
|
+
npts = [n1]
|
|
1356
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1357
|
+
|
|
1358
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1], shifts=[1])
|
|
1359
|
+
|
|
1360
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
1361
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
1362
|
+
M1 = StencilMatrix( V, V )
|
|
1363
|
+
M2 = StencilMatrix( V, V )
|
|
1364
|
+
|
|
1365
|
+
# Fill in stencil matrices based on diagonal index
|
|
1366
|
+
if dtype==complex:
|
|
1367
|
+
f=lambda k1: 10j*k1
|
|
1368
|
+
else:
|
|
1369
|
+
f=lambda k1: 10*k1
|
|
1370
|
+
|
|
1371
|
+
for k1 in range(-p1, p1+1):
|
|
1372
|
+
M1[:,k1] = f(k1)
|
|
1373
|
+
M2[:,k1] = f(k1)+2.
|
|
1374
|
+
|
|
1375
|
+
M1.remove_spurious_entries()
|
|
1376
|
+
M2.remove_spurious_entries()
|
|
1377
|
+
|
|
1378
|
+
W = BlockVectorSpace(V, V)
|
|
1379
|
+
|
|
1380
|
+
# Construct a BlockLinearOperator object containing M1, M2, M3:
|
|
1381
|
+
# |M1 M2|
|
|
1382
|
+
# L = | |
|
|
1383
|
+
# |M3 0 |
|
|
1384
|
+
|
|
1385
|
+
dict_blocks = {(0,0):M1, (0,1):M2}
|
|
1386
|
+
|
|
1387
|
+
L = BlockLinearOperator( W, V, blocks=dict_blocks )
|
|
1388
|
+
x = BlockVector(W)
|
|
1389
|
+
|
|
1390
|
+
# Fill in vector with random values, then update ghost regions
|
|
1391
|
+
for i0 in range(len(W.starts)):
|
|
1392
|
+
for i1 in range(W.starts[i0][0], W.ends[i0][0] + 1):
|
|
1393
|
+
x[i0][i1] = 2.0*random() + (1j if dtype==complex else 1.)
|
|
1394
|
+
x.update_ghost_regions()
|
|
1395
|
+
|
|
1396
|
+
y = L.dot(x)
|
|
1397
|
+
|
|
1398
|
+
# Cast operator to PETSc Mat format
|
|
1399
|
+
Lp = L.topetsc()
|
|
1400
|
+
|
|
1401
|
+
# Create Vec to allocate the result of the dot product
|
|
1402
|
+
y_petsc = Lp.createVecLeft()
|
|
1403
|
+
# Compute dot product
|
|
1404
|
+
Lp.mult(x.topetsc(), y_petsc)
|
|
1405
|
+
# Cast result back to Psydac BlockVector format
|
|
1406
|
+
y_p = petsc_to_psydac(y_petsc, V)
|
|
1407
|
+
|
|
1408
|
+
assert np.allclose(y_p.toarray(), y.toarray(), rtol=1e-12, atol=1e-12)
|
|
1409
|
+
|
|
1410
|
+
#===============================================================================
|
|
1411
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
1412
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
1413
|
+
@pytest.mark.parametrize( 'n2', [8, 12] )
|
|
1414
|
+
@pytest.mark.parametrize( 'p1', [1, 2] )
|
|
1415
|
+
@pytest.mark.parametrize( 'p2', [1, 3] )
|
|
1416
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
1417
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
1418
|
+
@pytest.mark.parallel
|
|
1419
|
+
@pytest.mark.petsc
|
|
1420
|
+
|
|
1421
|
+
def test_block_linear_operator_2d_parallel_topetsc( dtype, n1, n2, p1, p2, P1, P2):
|
|
1422
|
+
# set seed for reproducibility
|
|
1423
|
+
seed(n1*n2*p1*p2)
|
|
1424
|
+
comm = MPI.COMM_WORLD
|
|
1425
|
+
|
|
1426
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2], comm=comm)
|
|
1427
|
+
|
|
1428
|
+
# Partition the points
|
|
1429
|
+
npts = [n1,n2]
|
|
1430
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1431
|
+
|
|
1432
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
1433
|
+
|
|
1434
|
+
# Create vector spaces, stencil matrices, and stencil vectors
|
|
1435
|
+
V = StencilVectorSpace( cart, dtype=dtype )
|
|
1436
|
+
M1 = StencilMatrix( V, V )
|
|
1437
|
+
M2 = StencilMatrix( V, V )
|
|
1438
|
+
M3 = StencilMatrix( V, V )
|
|
1439
|
+
|
|
1440
|
+
# Fill in stencil matrices based on diagonal index
|
|
1441
|
+
if dtype==complex:
|
|
1442
|
+
f=lambda k1,k2: 10j*k1+k2
|
|
1443
|
+
else:
|
|
1444
|
+
f=lambda k1,k2: 10*k1+k2
|
|
1445
|
+
|
|
1446
|
+
for k1 in range(-p1,p1+1):
|
|
1447
|
+
for k2 in range(-p2,p2+1):
|
|
1448
|
+
M1[:,:,k1,k2] = f(k1,k2)
|
|
1449
|
+
M2[:,:,k1,k2] = f(k1,k2)+2.
|
|
1450
|
+
M3[:,:,k1,k2] = -f(k1,k2)+1.
|
|
1451
|
+
|
|
1452
|
+
M1.remove_spurious_entries()
|
|
1453
|
+
M2.remove_spurious_entries()
|
|
1454
|
+
M3.remove_spurious_entries()
|
|
1455
|
+
|
|
1456
|
+
W = BlockVectorSpace(V, V)
|
|
1457
|
+
|
|
1458
|
+
# Construct a BlockLinearOperator object containing M1, M2, M3:
|
|
1459
|
+
#
|
|
1460
|
+
# L = |M1 M2|
|
|
1461
|
+
# |M3 0 |
|
|
1462
|
+
|
|
1463
|
+
dict_blocks = {(0,0):M1, (0,1):M2, (1,0):M3}
|
|
1464
|
+
|
|
1465
|
+
L = BlockLinearOperator( W, W, blocks=dict_blocks )
|
|
1466
|
+
x = BlockVector(W)
|
|
1467
|
+
|
|
1468
|
+
# Fill in vector with random values, then update ghost regions
|
|
1469
|
+
for i0 in range(len(W.starts)):
|
|
1470
|
+
for i1 in range(W.starts[i0][0], W.ends[i0][0] + 1):
|
|
1471
|
+
for i2 in range(W.starts[i0][1], W.ends[i0][1] + 1):
|
|
1472
|
+
x[i0][i1,i2] = 2.0*random() + (1j if dtype==complex else 1.)
|
|
1473
|
+
x.update_ghost_regions()
|
|
1474
|
+
|
|
1475
|
+
y = L.dot(x)
|
|
1476
|
+
|
|
1477
|
+
# Cast operator to PETSc Mat format
|
|
1478
|
+
Lp = L.topetsc()
|
|
1479
|
+
|
|
1480
|
+
# Create Vec to allocate the result of the dot product
|
|
1481
|
+
y_petsc = Lp.createVecLeft()
|
|
1482
|
+
# Compute dot product
|
|
1483
|
+
Lp.mult(x.topetsc(), y_petsc)
|
|
1484
|
+
# Cast result back to Psydac BlockVector format
|
|
1485
|
+
y_p = petsc_to_psydac(y_petsc, L.codomain)
|
|
1486
|
+
|
|
1487
|
+
assert np.allclose(y_p.toarray(), y.toarray(), rtol=1e-12, atol=1e-12)
|
|
1488
|
+
|
|
1489
|
+
#===============================================================================
|
|
1490
|
+
|
|
1491
|
+
@pytest.mark.parametrize( 'dtype', [float] )
|
|
1492
|
+
@pytest.mark.parametrize( 'n1', [8, 16] )
|
|
1493
|
+
@pytest.mark.parametrize( 'n2', [8, 32] )
|
|
1494
|
+
@pytest.mark.parametrize( 'p1', [1, 3] )
|
|
1495
|
+
@pytest.mark.parametrize( 'p2', [2] )
|
|
1496
|
+
@pytest.mark.parametrize( 'P1', [True, False] )
|
|
1497
|
+
@pytest.mark.parametrize( 'P2', [True] )
|
|
1498
|
+
@pytest.mark.parallel
|
|
1499
|
+
|
|
1500
|
+
def test_block_matrix_operator_parallel_dot_backend( dtype, n1, n2, p1, p2, P1, P2 ):
|
|
1501
|
+
# Define a factor for the data
|
|
1502
|
+
if dtype == complex:
|
|
1503
|
+
factor = 1j
|
|
1504
|
+
else:
|
|
1505
|
+
factor = 1
|
|
1506
|
+
# set seed for reproducibility
|
|
1507
|
+
|
|
1508
|
+
comm = MPI.COMM_WORLD
|
|
1509
|
+
D = DomainDecomposition([n1,n2], periods=[P1,P2], comm=comm)
|
|
1510
|
+
|
|
1511
|
+
# Partition the points
|
|
1512
|
+
npts = [n1,n2]
|
|
1513
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
1514
|
+
|
|
1515
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2], shifts=[1,1])
|
|
1516
|
+
|
|
1517
|
+
# Create vector space, stencil matrix, and stencil vector
|
|
1518
|
+
V = StencilVectorSpace( cart, dtype=dtype)
|
|
1519
|
+
M1 = StencilMatrix( V, V , backend=PSYDAC_BACKEND_GPYCCEL)
|
|
1520
|
+
M2 = StencilMatrix( V, V , backend=PSYDAC_BACKEND_GPYCCEL)
|
|
1521
|
+
M3 = StencilMatrix( V, V , backend=PSYDAC_BACKEND_GPYCCEL)
|
|
1522
|
+
M4 = StencilMatrix( V, V , backend=PSYDAC_BACKEND_GPYCCEL)
|
|
1523
|
+
x1 = StencilVector( V )
|
|
1524
|
+
x2 = StencilVector( V )
|
|
1525
|
+
|
|
1526
|
+
s1,s2 = V.starts
|
|
1527
|
+
e1,e2 = V.ends
|
|
1528
|
+
|
|
1529
|
+
# Fill in stencil matrix values based on diagonal index (periodic!)
|
|
1530
|
+
for k1 in range(-p1,p1+1):
|
|
1531
|
+
for k2 in range(-p2,p2+1):
|
|
1532
|
+
M1[:,:,k1,k2] = k1*factor+k2+10.
|
|
1533
|
+
M2[:,:,k1,k2] = 2.*factor*k1+k2
|
|
1534
|
+
M3[:,:,k1,k2] = 5*factor*k1+k2
|
|
1535
|
+
M4[:,:,k1,k2] = 10*factor*k1+k2
|
|
1536
|
+
|
|
1537
|
+
# If any dimension is not periodic, set corresponding periodic corners to zero
|
|
1538
|
+
M1.remove_spurious_entries()
|
|
1539
|
+
M2.remove_spurious_entries()
|
|
1540
|
+
M3.remove_spurious_entries()
|
|
1541
|
+
M4.remove_spurious_entries()
|
|
1542
|
+
|
|
1543
|
+
# Fill in vector with random values, then update ghost regions
|
|
1544
|
+
for i1 in range(s1,e1+1):
|
|
1545
|
+
for i2 in range(s2,e2+1):
|
|
1546
|
+
x1[i1,i2] = 2.0*factor*random() + 1.0
|
|
1547
|
+
x2[i1,i2] = 5.0*factor*random() - 1.0
|
|
1548
|
+
x1.update_ghost_regions()
|
|
1549
|
+
x2.update_ghost_regions()
|
|
1550
|
+
|
|
1551
|
+
# Create and Fill Block objects
|
|
1552
|
+
W = BlockVectorSpace(V, V)
|
|
1553
|
+
L = BlockLinearOperator( W, W )
|
|
1554
|
+
L[0,0] = M1
|
|
1555
|
+
L[0,1] = M2
|
|
1556
|
+
L[1,0] = M3
|
|
1557
|
+
L[1,1] = M4
|
|
1558
|
+
|
|
1559
|
+
# L.set_backend(PSYDAC_BACKEND_GPYCCEL)
|
|
1560
|
+
|
|
1561
|
+
# X = BlockVector(W)
|
|
1562
|
+
# X[0] = x1
|
|
1563
|
+
# X[1] = x2
|
|
1564
|
+
|
|
1565
|
+
# # Compute Block-vector product
|
|
1566
|
+
# Y = L.dot(X)
|
|
1567
|
+
|
|
1568
|
+
# # Compute matrix-vector products for each block
|
|
1569
|
+
# y1 = M1.dot(x1) + M2.dot(x2)
|
|
1570
|
+
# y2 = M3.dot(x1) + M4.dot(x2)
|
|
1571
|
+
|
|
1572
|
+
# #Test axpy method in parallel
|
|
1573
|
+
# z3 = X + 5 * factor * Y
|
|
1574
|
+
# X.mul_iadd(5 * factor, Y)
|
|
1575
|
+
|
|
1576
|
+
# # Test exact value and symetry of the scalar product
|
|
1577
|
+
# assert np.allclose(X[0]._data, z3[0]._data)
|
|
1578
|
+
|
|
1579
|
+
# # Check data in 1D array
|
|
1580
|
+
# assert np.allclose( Y.blocks[0].toarray(), y1.toarray(), rtol=1e-13, atol=1e-13 )
|
|
1581
|
+
# assert np.allclose( Y.blocks[1].toarray(), y2.toarray(), rtol=1e-13, atol=1e-13 )
|
|
1582
|
+
|
|
1583
|
+
#===============================================================================
|
|
1584
|
+
# SCRIPT FUNCTIONALITY
|
|
1585
|
+
#===============================================================================
|
|
1586
|
+
if __name__ == "__main__":
|
|
1587
|
+
import sys
|
|
1588
|
+
pytest.main( sys.argv )
|