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,106 @@
|
|
|
1
|
+
import pytest
|
|
2
|
+
import scipy.fft as scifft
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from feectools.ddm.mpi import mpi as MPI
|
|
6
|
+
from feectools.linalg.fft import *
|
|
7
|
+
from feectools.ddm.cart import DomainDecomposition, CartDecomposition
|
|
8
|
+
from feectools.linalg.stencil import StencilVector
|
|
9
|
+
#===============================================================================
|
|
10
|
+
def compute_global_starts_ends(domain_decomposition, npts):
|
|
11
|
+
ndims = len(npts)
|
|
12
|
+
global_starts = [None]*ndims
|
|
13
|
+
global_ends = [None]*ndims
|
|
14
|
+
|
|
15
|
+
for axis in range(ndims):
|
|
16
|
+
es = domain_decomposition.global_element_starts[axis]
|
|
17
|
+
ee = domain_decomposition.global_element_ends [axis]
|
|
18
|
+
|
|
19
|
+
global_ends [axis] = ee.copy()
|
|
20
|
+
global_ends [axis][-1] = npts[axis]-1
|
|
21
|
+
global_starts[axis] = np.array([0] + (global_ends[axis][:-1]+1).tolist())
|
|
22
|
+
|
|
23
|
+
return global_starts, global_ends
|
|
24
|
+
#===============================================================================
|
|
25
|
+
def decode_fft_type(ffttype):
|
|
26
|
+
if ffttype == 'fft':
|
|
27
|
+
return (complex, DistributedFFT, scifft.fftn)
|
|
28
|
+
elif ffttype == 'ifft':
|
|
29
|
+
return (complex, DistributedIFFT, scifft.ifftn)
|
|
30
|
+
elif ffttype == 'dct':
|
|
31
|
+
return (complex, DistributedDCT, scifft.dctn)
|
|
32
|
+
elif ffttype == 'idct':
|
|
33
|
+
return (complex, DistributedIDCT, scifft.idctn)
|
|
34
|
+
elif ffttype == 'dst':
|
|
35
|
+
return (complex, DistributedDST, scifft.dstn)
|
|
36
|
+
elif ffttype == 'idst':
|
|
37
|
+
return (complex, DistributedIDST, scifft.idstn)
|
|
38
|
+
else:
|
|
39
|
+
raise NotImplementedError()
|
|
40
|
+
|
|
41
|
+
def method_test(seed, comm, config, dtype, classtype, comparison, verbose=False):
|
|
42
|
+
np.random.seed(seed)
|
|
43
|
+
|
|
44
|
+
if comm is None:
|
|
45
|
+
rank = -1
|
|
46
|
+
else:
|
|
47
|
+
rank = comm.Get_rank()
|
|
48
|
+
|
|
49
|
+
npts, pads, periods = config
|
|
50
|
+
|
|
51
|
+
if verbose:
|
|
52
|
+
print(f'[{rank}] Test start', flush=True)
|
|
53
|
+
|
|
54
|
+
comm = MPI.COMM_WORLD
|
|
55
|
+
D = DomainDecomposition(npts, periods=periods, comm=comm)
|
|
56
|
+
|
|
57
|
+
# Partition the points
|
|
58
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
59
|
+
|
|
60
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=pads, shifts=[1]*len(pads))
|
|
61
|
+
|
|
62
|
+
# vector spaces
|
|
63
|
+
V = StencilVectorSpace(cart, dtype=dtype)
|
|
64
|
+
localslice = tuple([slice(s, e+1) for s, e in zip(V.starts, V.ends)])
|
|
65
|
+
|
|
66
|
+
if verbose:
|
|
67
|
+
print(f'[{rank}] Vector spaces built', flush=True)
|
|
68
|
+
|
|
69
|
+
if np.dtype(dtype).kind == 'c':
|
|
70
|
+
Y_glob = np.random.random(V.npts) + np.random.random(V.npts) * 1j
|
|
71
|
+
else:
|
|
72
|
+
Y_glob = np.random.random(V.npts)
|
|
73
|
+
|
|
74
|
+
# vector to solve for (Y)
|
|
75
|
+
Y = StencilVector(V)
|
|
76
|
+
Y[localslice] = Y_glob[localslice]
|
|
77
|
+
Y.update_ghost_regions()
|
|
78
|
+
|
|
79
|
+
if verbose:
|
|
80
|
+
print(f'[{rank}] Vector built', flush=True)
|
|
81
|
+
|
|
82
|
+
X_glob = comparison(Y_glob)
|
|
83
|
+
|
|
84
|
+
compare = classtype(V)
|
|
85
|
+
X = compare.dot(Y)
|
|
86
|
+
|
|
87
|
+
if verbose:
|
|
88
|
+
print(f'[{rank}] Functions have been run', flush=True)
|
|
89
|
+
|
|
90
|
+
assert np.allclose(X_glob[localslice], X[localslice], 1e-10, 1e-10)
|
|
91
|
+
|
|
92
|
+
@pytest.mark.parametrize( 'seed', [0, 2] )
|
|
93
|
+
@pytest.mark.parametrize( 'params', [([8], [2], [False]), ([8,9], [2,3], [False,True]), ([8,9,17], [2,3,7], [False,True,False])] )
|
|
94
|
+
@pytest.mark.parametrize( 'ffttype', ['fft', 'ifft', 'dct', 'idct', 'dst', 'idst'] )
|
|
95
|
+
def test_kron_fft_ser(seed, params, ffttype):
|
|
96
|
+
method_test(seed, None, params, *decode_fft_type(ffttype), verbose=False)
|
|
97
|
+
|
|
98
|
+
@pytest.mark.parametrize( 'seed', [0, 2] )
|
|
99
|
+
@pytest.mark.parametrize( 'params', [([16], [2], [False]), ([16,18], [2,3], [False,True]), ([16,18,37], [2,3,7], [False,True,False])] )
|
|
100
|
+
@pytest.mark.parametrize( 'ffttype', ['fft', 'ifft', 'dct', 'idct', 'dst', 'idst'] )
|
|
101
|
+
@pytest.mark.parallel
|
|
102
|
+
def test_kron_fft_par(seed, params, ffttype):
|
|
103
|
+
method_test(seed, MPI.COMM_WORLD, params, *decode_fft_type(ffttype), verbose=False)
|
|
104
|
+
|
|
105
|
+
if __name__ == '__main__':
|
|
106
|
+
method_test(0, MPI.COMM_WORLD, ([8,9,5], [2,3,7], [False,True,False]), *decode_fft_type('fft'), verbose=True)
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from functools import reduce
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
import numpy as np
|
|
5
|
+
from scipy.sparse import kron
|
|
6
|
+
|
|
7
|
+
from feectools.ddm.cart import DomainDecomposition, CartDecomposition
|
|
8
|
+
from feectools.linalg.stencil import StencilVectorSpace
|
|
9
|
+
from feectools.linalg.stencil import StencilVector
|
|
10
|
+
from feectools.linalg.stencil import StencilMatrix
|
|
11
|
+
from feectools.linalg.kron import KroneckerStencilMatrix
|
|
12
|
+
#===============================================================================
|
|
13
|
+
def compute_global_starts_ends(domain_decomposition, npts):
|
|
14
|
+
ndims = len(npts)
|
|
15
|
+
global_starts = [None]*ndims
|
|
16
|
+
global_ends = [None]*ndims
|
|
17
|
+
|
|
18
|
+
for axis in range(ndims):
|
|
19
|
+
ee = domain_decomposition.global_element_ends [axis]
|
|
20
|
+
|
|
21
|
+
global_ends [axis] = ee.copy()
|
|
22
|
+
global_ends [axis][-1] = npts[axis]-1
|
|
23
|
+
global_starts[axis] = np.array([0] + (global_ends[axis][:-1]+1).tolist())
|
|
24
|
+
|
|
25
|
+
return tuple(global_starts), tuple(global_ends)
|
|
26
|
+
|
|
27
|
+
#==============================================================================
|
|
28
|
+
@pytest.mark.parametrize('dtype', [float])
|
|
29
|
+
@pytest.mark.parametrize('npts', [(5, 7, 8)])
|
|
30
|
+
@pytest.mark.parametrize('pads', [(2, 3, 5)])
|
|
31
|
+
@pytest.mark.parametrize('periodic', [(True, False, False)])
|
|
32
|
+
|
|
33
|
+
def test_KroneckerStencilMatrix(dtype, npts, pads, periodic):
|
|
34
|
+
|
|
35
|
+
# Extract input parameters
|
|
36
|
+
n1, n2, n3 = npts
|
|
37
|
+
p1, p2, p3 = pads
|
|
38
|
+
P1, P2, P3 = periodic
|
|
39
|
+
|
|
40
|
+
# Define data type with a factor
|
|
41
|
+
if dtype==complex:
|
|
42
|
+
factor=1j
|
|
43
|
+
else:
|
|
44
|
+
factor=1
|
|
45
|
+
|
|
46
|
+
# Create domain decomposition
|
|
47
|
+
D = DomainDecomposition([n1-1,n2-1, n3-1], periods=[P1,P2,P3])
|
|
48
|
+
|
|
49
|
+
# Partition the points
|
|
50
|
+
global_starts, global_ends = compute_global_starts_ends(D, npts)
|
|
51
|
+
|
|
52
|
+
cart = CartDecomposition(D, npts, global_starts, global_ends, pads=[p1,p2,p3], shifts=[1,1,1])
|
|
53
|
+
|
|
54
|
+
# 3D vector space and element
|
|
55
|
+
W = StencilVectorSpace( cart, dtype=dtype)
|
|
56
|
+
w = StencilVector(W)
|
|
57
|
+
|
|
58
|
+
# 1D vector space
|
|
59
|
+
|
|
60
|
+
D1 = DomainDecomposition([n1-1], periods=[P1])
|
|
61
|
+
D2 = DomainDecomposition([n2-1], periods=[P2])
|
|
62
|
+
D3 = DomainDecomposition([n3-1], periods=[P3])
|
|
63
|
+
|
|
64
|
+
# Partition the points
|
|
65
|
+
global_starts1, global_ends1 = compute_global_starts_ends(D1, [n1])
|
|
66
|
+
global_starts2, global_ends2 = compute_global_starts_ends(D2, [n2])
|
|
67
|
+
global_starts3, global_ends3 = compute_global_starts_ends(D3, [n3])
|
|
68
|
+
|
|
69
|
+
cart1 = CartDecomposition(D1, [n1], global_starts1, global_ends1, pads=[p1], shifts=[1])
|
|
70
|
+
cart2 = CartDecomposition(D2, [n2], global_starts2, global_ends2, pads=[p2], shifts=[1])
|
|
71
|
+
cart3 = CartDecomposition(D3, [n3], global_starts3, global_ends3, pads=[p3], shifts=[1])
|
|
72
|
+
|
|
73
|
+
V1 = StencilVectorSpace( cart1, dtype=dtype )
|
|
74
|
+
V2 = StencilVectorSpace( cart2, dtype=dtype )
|
|
75
|
+
V3 = StencilVectorSpace( cart3, dtype=dtype )
|
|
76
|
+
|
|
77
|
+
# 1D stencil matrices
|
|
78
|
+
M1 = StencilMatrix(V1, V1)
|
|
79
|
+
M2 = StencilMatrix(V2, V2)
|
|
80
|
+
M3 = StencilMatrix(V3, V3)
|
|
81
|
+
|
|
82
|
+
# ...
|
|
83
|
+
# Fill in stencil matrix values
|
|
84
|
+
for k1 in range(-p1, p1+1):
|
|
85
|
+
M1[:, k1] = 10 + k1*factor
|
|
86
|
+
|
|
87
|
+
for k2 in range(-p2, p2+1):
|
|
88
|
+
M2[:, k2] = 20 + k2*factor
|
|
89
|
+
|
|
90
|
+
for k3 in range(-p3, p3+1):
|
|
91
|
+
M3[:, k3] = 40 + k3*factor
|
|
92
|
+
|
|
93
|
+
M1.remove_spurious_entries()
|
|
94
|
+
M2.remove_spurious_entries()
|
|
95
|
+
M3.remove_spurious_entries()
|
|
96
|
+
# ...
|
|
97
|
+
|
|
98
|
+
# Fill in vector values
|
|
99
|
+
w[:, :, :] = factor
|
|
100
|
+
|
|
101
|
+
# Create Kronecker matrix
|
|
102
|
+
M = KroneckerStencilMatrix(W, W, M1, M2, M3)
|
|
103
|
+
|
|
104
|
+
# Scipy sparse matrices used for comparison
|
|
105
|
+
M1_sp = M1.tosparse().tocsr()
|
|
106
|
+
M2_sp = M2.tosparse().tocsr()
|
|
107
|
+
M3_sp = M3.tosparse().tocsr()
|
|
108
|
+
M_sp = reduce(kron, (M1_sp, M2_sp, M3_sp)).tocsr()
|
|
109
|
+
|
|
110
|
+
# Test transpose
|
|
111
|
+
assert (M_sp.T - M.T.tosparse().tocsr()).count_nonzero() == 0
|
|
112
|
+
|
|
113
|
+
# Test dot product
|
|
114
|
+
assert np.array_equal(M_sp.dot(w.toarray()), M.dot(w).toarray())
|