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.
Files changed (98) hide show
  1. feectools/__init__.py +0 -0
  2. feectools/accelerate/__init__.py +0 -0
  3. feectools/accelerate/accelerate.py +220 -0
  4. feectools/accelerate/compile_psydac.mk +52 -0
  5. feectools/api/__init__.py +0 -0
  6. feectools/api/essential_bc.py +122 -0
  7. feectools/api/fem_bilinear_form.py +2226 -0
  8. feectools/api/fem_common.py +286 -0
  9. feectools/api/fem_sum_form.py +123 -0
  10. feectools/api/settings.py +82 -0
  11. feectools/core/__init__.py +11 -0
  12. feectools/core/bsplines.py +1107 -0
  13. feectools/core/bsplines_kernels.py +1349 -0
  14. feectools/core/field_evaluation_kernels.py +5015 -0
  15. feectools/core/tests/__init__.py +0 -0
  16. feectools/core/tests/test_bsplines.py +263 -0
  17. feectools/core/tests/test_bsplines_kernel.py +40 -0
  18. feectools/core/tests/test_bsplines_pyccel.py +752 -0
  19. feectools/ddm/__init__.py +3 -0
  20. feectools/ddm/basic.py +78 -0
  21. feectools/ddm/blocking_data_exchanger.py +348 -0
  22. feectools/ddm/cart.py +1835 -0
  23. feectools/ddm/interface_data_exchanger.py +122 -0
  24. feectools/ddm/mpi.py +109 -0
  25. feectools/ddm/nonblocking_data_exchanger.py +331 -0
  26. feectools/ddm/partition.py +207 -0
  27. feectools/ddm/petsc.py +112 -0
  28. feectools/ddm/tests/__init__.py +0 -0
  29. feectools/ddm/tests/test_cart_1d.py +138 -0
  30. feectools/ddm/tests/test_cart_2d.py +164 -0
  31. feectools/ddm/tests/test_cart_3d.py +158 -0
  32. feectools/ddm/tests/test_multicart_2d.py +173 -0
  33. feectools/ddm/tests/test_partition.py +124 -0
  34. feectools/ddm/utilities.py +24 -0
  35. feectools/feec/__init__.py +0 -0
  36. feectools/feec/derivatives.py +780 -0
  37. feectools/feec/dof_kernels.py +210 -0
  38. feectools/feec/global_geometric_projectors.py +1073 -0
  39. feectools/feec/hodge.py +148 -0
  40. feectools/fem/__init__.py +0 -0
  41. feectools/fem/basic.py +465 -0
  42. feectools/fem/grid.py +181 -0
  43. feectools/fem/partitioning.py +344 -0
  44. feectools/fem/projectors.py +160 -0
  45. feectools/fem/splines.py +559 -0
  46. feectools/fem/tensor.py +1393 -0
  47. feectools/fem/tests/__init__.py +0 -0
  48. feectools/fem/tests/analytical_profiles_1d.py +100 -0
  49. feectools/fem/tests/analytical_profiles_base.py +34 -0
  50. feectools/fem/tests/splines_error_bounds.py +155 -0
  51. feectools/fem/tests/test_spline_histopolation.py +120 -0
  52. feectools/fem/tests/test_spline_interpolation.py +182 -0
  53. feectools/fem/tests/test_splines.py +184 -0
  54. feectools/fem/tests/test_splines_par.py +46 -0
  55. feectools/fem/tests/test_vector_spaces.py +150 -0
  56. feectools/fem/tests/utilities.py +47 -0
  57. feectools/fem/vector.py +729 -0
  58. feectools/linalg/__init__.py +0 -0
  59. feectools/linalg/basic.py +1386 -0
  60. feectools/linalg/block.py +1451 -0
  61. feectools/linalg/direct_solvers.py +201 -0
  62. feectools/linalg/fft.py +258 -0
  63. feectools/linalg/kernels/__init__.py +0 -0
  64. feectools/linalg/kernels/axpy_kernels.py +57 -0
  65. feectools/linalg/kernels/inner_kernels.py +100 -0
  66. feectools/linalg/kernels/matvec_kernels.py +206 -0
  67. feectools/linalg/kernels/stencil2IJV_kernels.py +227 -0
  68. feectools/linalg/kernels/stencil2coo_kernels.py +179 -0
  69. feectools/linalg/kernels/transpose_kernels.py +263 -0
  70. feectools/linalg/kron.py +911 -0
  71. feectools/linalg/solvers.py +1914 -0
  72. feectools/linalg/sparse.py +114 -0
  73. feectools/linalg/stencil.py +2923 -0
  74. feectools/linalg/stencil_dot_kernels.py +317 -0
  75. feectools/linalg/stencil_transpose_kernels.py +372 -0
  76. feectools/linalg/tests/__init__.py +0 -0
  77. feectools/linalg/tests/test_block.py +1588 -0
  78. feectools/linalg/tests/test_fft.py +106 -0
  79. feectools/linalg/tests/test_kron_stencil_matrix.py +114 -0
  80. feectools/linalg/tests/test_linalg.py +1065 -0
  81. feectools/linalg/tests/test_matrix_free.py +128 -0
  82. feectools/linalg/tests/test_solvers.py +213 -0
  83. feectools/linalg/tests/test_stencil_interface_matrix.py +379 -0
  84. feectools/linalg/tests/test_stencil_vector.py +1036 -0
  85. feectools/linalg/tests/test_stencil_vector_space.py +440 -0
  86. feectools/linalg/topetsc.py +522 -0
  87. feectools/linalg/utilities.py +200 -0
  88. feectools/utilities/__init__.py +0 -0
  89. feectools/utilities/quadratures.py +113 -0
  90. feectools/utilities/utils.py +166 -0
  91. feectools/version.py +1 -0
  92. feectools-0.1.0.dist-info/METADATA +66 -0
  93. feectools-0.1.0.dist-info/RECORD +98 -0
  94. feectools-0.1.0.dist-info/WHEEL +5 -0
  95. feectools-0.1.0.dist-info/entry_points.txt +3 -0
  96. feectools-0.1.0.dist-info/licenses/AUTHORS +22 -0
  97. feectools-0.1.0.dist-info/licenses/LICENSE +21 -0
  98. feectools-0.1.0.dist-info/top_level.txt +1 -0
File without changes
@@ -0,0 +1,263 @@
1
+ #coding: utf-8
2
+
3
+ import pytest
4
+ import numpy as np
5
+
6
+ from feectools.core.bsplines import ( find_span,
7
+ basis_funs,
8
+ basis_funs_1st_der,
9
+ basis_funs_all_ders,
10
+ make_knots,
11
+ elevate_knots,
12
+ greville,
13
+ collocation_matrix,
14
+ histopolation_matrix,
15
+ cell_index)
16
+
17
+ from feectools.fem.tests.utilities import random_grid
18
+
19
+ # TODO: add unit tests for
20
+ # - make_knots
21
+ # - elevate_knots
22
+ # - greville
23
+
24
+ #==============================================================================
25
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
26
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
27
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,7,10) )
28
+
29
+ def test_find_span( lims, nc, p, eps=1e-12 ):
30
+
31
+ grid = np.linspace( *lims, num=nc+1 )
32
+ knots = np.r_[ [grid[0]]*p, grid, [grid[-1]]*p ]
33
+
34
+ for i,xi in enumerate( grid ):
35
+ assert find_span( knots, p, x=xi-eps ) == p + max( 0, i-1 )
36
+ assert find_span( knots, p, x=xi ) == p + min( i, nc-1 )
37
+ assert find_span( knots, p, x=xi+eps ) == p + min( i, nc-1 )
38
+
39
+ #==============================================================================
40
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
41
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
42
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,7,10) )
43
+
44
+ def test_basis_funs( lims, nc, p, tol=1e-14 ):
45
+
46
+ grid = np.linspace( *lims, num=nc+1 )
47
+ knots = np.r_[ [grid[0]]*p, grid, [grid[-1]]*p ]
48
+
49
+ xx = np.linspace( *lims, num=101 )
50
+ for x in xx:
51
+ span = find_span( knots, p, x )
52
+ basis = basis_funs( knots, p, x, span )
53
+ assert len( basis ) == p+1
54
+ assert np.all( basis >= 0 )
55
+ assert abs( sum( basis ) - 1.0 ) < tol
56
+
57
+ #==============================================================================
58
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
59
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
60
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,7,10) )
61
+
62
+ def test_basis_funs_1st_der( lims, nc, p, tol=1e-14 ):
63
+
64
+ grid = np.linspace( *lims, num=nc+1 )
65
+ knots = np.r_[ [grid[0]]*p, grid, [grid[-1]]*p ]
66
+
67
+ xx = np.linspace( *lims, num=101 )
68
+ for x in xx:
69
+ span = find_span( knots, p, x )
70
+ ders = basis_funs_1st_der( knots, p, x, span )
71
+ assert len( ders ) == p+1
72
+ assert abs( sum( ders ) ) < tol
73
+
74
+ #==============================================================================
75
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
76
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
77
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,7,10) )
78
+
79
+ def test_basis_funs_all_ders( lims, nc, p, tol=1e-14 ):
80
+
81
+ # Maximum derivative required
82
+ n = p+2
83
+
84
+ grid, dx = np.linspace( *lims, num=nc+1, retstep=True )
85
+ knots = np.r_[ [grid[0]]*p, grid, [grid[-1]]*p ]
86
+
87
+ xx = np.linspace( *lims, num=101 )
88
+ for x in xx:
89
+ span = find_span( knots, p, x )
90
+ ders = basis_funs_all_ders( knots, p, x, span, n )
91
+
92
+ # Test output array
93
+ assert ders.shape == (1+n,1+p)
94
+ assert ders.dtype == np.dtype( float )
95
+
96
+ # Test 0th derivative
97
+ der0 = basis_funs( knots, p, x, span )
98
+ assert np.allclose( ders[0,:], der0, rtol=1e-15, atol=1e-15 )
99
+ assert np.all( ders[0,:] >= 0.0 )
100
+
101
+ # Test 1st derivative
102
+ der1 = basis_funs_1st_der( knots, p, x, span )
103
+ assert np.allclose( ders[1,:], der1, rtol=1e-15, atol=1e-15/dx )
104
+
105
+ # Test 2nd to n-th derivatives
106
+ for i in range(2,n+1):
107
+ assert abs( ders[i,:].sum() ) <= tol * abs( ders[i,:] ).max()
108
+
109
+ # Test that all derivatives of degree > p are zero
110
+ assert np.all( ders[p+1:,:] == 0.0 )
111
+
112
+ #==============================================================================
113
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
114
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
115
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,7,8) )
116
+ @pytest.mark.parametrize( 'periodic' , (True, False) )
117
+
118
+ # TODO: improve checks
119
+ def test_collocation_matrix(lims, nc, p, periodic, tol=1e-13):
120
+
121
+ breaks = random_grid(domain=lims, ncells=nc, random_fraction=0.3)
122
+ knots = make_knots(breaks, p, periodic)
123
+ xgrid = greville(knots, p, periodic)
124
+ mat = collocation_matrix(knots, p, periodic, normalization='B', xgrid=xgrid)
125
+
126
+ acceptable_nonzeros_in_row = [p, p+1] if periodic else [1, p, p+1]
127
+
128
+ for row in mat:
129
+ assert all( row >= 0.0 )
130
+ assert abs( sum( row ) - 1.0 ) < tol
131
+ assert (abs(row) > tol).sum() in acceptable_nonzeros_in_row
132
+
133
+ #==============================================================================
134
+ @pytest.mark.parametrize( 'lims', ([0,1], [-2,3]) )
135
+ @pytest.mark.parametrize( 'nc', (10, 18, 33) )
136
+ @pytest.mark.parametrize( 'p' , (0,1,2,3,4,5,6) )
137
+ @pytest.mark.parametrize( 'periodic' , (True, False) )
138
+
139
+ # TODO: improve checks
140
+ def test_histopolation_matrix(lims, nc, p, periodic, tol=1e-13):
141
+
142
+ breaks = random_grid(domain=lims, ncells=nc, random_fraction=0.3)
143
+ knots = make_knots(breaks, p, periodic)
144
+ xgrid = greville(elevate_knots(knots, p, periodic), p+1, periodic)
145
+ mat = histopolation_matrix(knots, p, periodic, normalization='M', xgrid=xgrid)
146
+
147
+ for col in mat.T:
148
+ assert all( col >= 0.0 )
149
+ assert abs( sum( col ) - 1.0 ) < tol
150
+ # assert (abs(col) > tol).sum() <= 2*p + 1
151
+
152
+ #==============================================================================
153
+ @pytest.mark.parametrize("i_grid, expected", [([0.05, 0.15, 0.21, 0.05, 0.55],[0, 1, 2, 0, 5]),
154
+ ([0.1, 0.1, 0.0, 0.4, 0.4, 0.9, 0.9], [0, 1, 0, 3, 4, 8, 9]),
155
+ ([0., 0.1, 0.1, 1], [0, 0, 1, 9])])
156
+ def test_cell_index(i_grid, expected):
157
+ breaks = np.array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.])
158
+ out = cell_index(breaks, np.asarray(i_grid))
159
+ assert np.array_equal(expected, out)
160
+
161
+ #==============================================================================
162
+ # SCRIPT FUNCTIONALITY: PLOT BASIS FUNCTIONS
163
+ #==============================================================================
164
+ if __name__ == '__main__':
165
+
166
+ import matplotlib.pyplot as plt
167
+ np.set_printoptions(linewidth=130)
168
+
169
+ # Domain limits, number of cells and spline degree
170
+ lims = [0, 1]
171
+ nc = 4
172
+ p = 3
173
+
174
+ # Repeat internal knot with index 'k' for 'm' times
175
+ k = 5
176
+ m = 2
177
+
178
+ # Grid (breakpoints) and clamped knot sequence
179
+ grid = np.linspace( *lims, num=nc+1 )
180
+ grid[1:-1] += 0.1*np.random.random_sample(nc-1) - 0.05 # Perturb internal breakpoints
181
+ knots = np.r_[ [grid[0]]*p, grid, [grid[-1]]*p ]
182
+
183
+ # Insert repeated internal knot
184
+ knots = list( knots )
185
+ knots = knots[:k] + [knots[k]]*m + knots[k+1:]
186
+ knots = np.array( knots )
187
+
188
+ # Number of basis functions
189
+ nb = len(knots)-p-1
190
+
191
+ # Evaluation grid
192
+ xx = np.linspace( *lims, num=501 )
193
+
194
+ # Compute values of each basis function on evaluation grid
195
+ yy = np.zeros( (len(xx), nb) )
196
+ zz = np.zeros( (len(xx), nb) )
197
+ for i,x in enumerate( xx ):
198
+ span = find_span( knots, p, x )
199
+ yy[i,span-p:span+1] = basis_funs ( knots, p, x, span )
200
+ zz[i,span-p:span+1] = basis_funs_1st_der( knots, p, x, span )
201
+
202
+ # Check partition of unity on evaluation grid
203
+ unity = yy.sum(axis=1)
204
+ print("\nPartition of unity on evaluation grid:")
205
+ print(unity)
206
+
207
+ # ...
208
+ # Integrals of each B-spline over domain (theoretical values)
209
+ #
210
+ # \int B(i) dx = length(support(B)) / (p + 1) = (T[i + p + 1] - T[i]) / (p + 1)
211
+ #
212
+ integrals_theory = np.array([(knots[i+p+1] - knots[i]) / (p+1) for i in range(nb)])
213
+
214
+ # Integrals of each B-spline over domain (Gaussian quadrature)
215
+ from feectools.utilities.quadratures import gauss_legendre
216
+ from feectools.core.bsplines import quadrature_grid, basis_ders_on_quad_grid
217
+ from feectools.core.bsplines import elements_spans
218
+
219
+ u, w = gauss_legendre(p + 1)
220
+ quad_x, quad_w = quadrature_grid(grid, u, w)
221
+ quad_basis = basis_ders_on_quad_grid(knots, p, quad_x, nders=0, normalization='B')
222
+ integrals = np.zeros(nb)
223
+ for ie, span in enumerate(elements_spans(knots, p)):
224
+ integrals[span-p:span+1] += np.dot(quad_basis[ie, :, 0, :], quad_w[ie, :])
225
+
226
+ # Compare theory results with computed integrals
227
+ print("\nIntegrals of basis functions over domain:")
228
+ print("Theory :", integrals_theory)
229
+ print("Computed:", integrals)
230
+ # ...
231
+
232
+ # Create figure
233
+ fig, axes = plt.subplots( 2, 1, sharex=True )
234
+
235
+ # Plot basis functions
236
+ axes[0].plot( xx, yy )
237
+ axes[0].set_title( "Basis functions y=B(x)" )
238
+ axes[0].set_xlabel( 'x' )
239
+ axes[0].set_ylabel( 'y', rotation='horizontal' )
240
+
241
+ # Plot first derivative of basis functions
242
+ axes[1].plot( xx, zz )
243
+ axes[1].set_title( "First derivative z=B'(x)" )
244
+ axes[1].set_xlabel( 'x' )
245
+ axes[1].set_ylabel( 'z', rotation='horizontal' )
246
+
247
+ # Plot knot sequence and add grid
248
+ values, counts = np.unique( knots, return_counts=True )
249
+ y = np.concatenate( [np.linspace(0,1,c,endpoint=True) for c in counts] )
250
+ for ax in axes:
251
+ ax.plot( knots, y, 'ko', mew=1.0, mfc='None' )
252
+ ax.grid()
253
+
254
+ # Show figure and keep it open if necessary
255
+ fig.tight_layout()
256
+ fig.show()
257
+
258
+ import __main__ as main
259
+ if hasattr( main, '__file__' ):
260
+ try:
261
+ __IPYTHON__
262
+ except NameError:
263
+ plt.show()
@@ -0,0 +1,40 @@
1
+ #coding: utf-8
2
+
3
+ import pytest
4
+ import numpy as np
5
+
6
+
7
+ from feectools.core.bsplines_kernels import cell_index_p
8
+
9
+ def test_cell_index_p():
10
+ breaks = np.array([0. , 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.])
11
+ breaks = np.ascontiguousarray(breaks, dtype=float)
12
+ out = np.zeros_like(breaks, dtype=np.int64)
13
+ tol = 1e-15
14
+
15
+ # limit case: code should decide wether point is in or out, not fall in infinite loop
16
+ i_grid = breaks.copy()
17
+ i_grid[:] += tol
18
+ status = cell_index_p(breaks, i_grid, tol, out)
19
+ assert status in [0,-1]
20
+
21
+ # usual cases: points inside or outside domain
22
+ for offset, expected_status in [(0, 0), (tol/2, 0), (2*tol, -1)]:
23
+ i_grid = breaks.copy()
24
+ i_grid[:] += offset
25
+ status = cell_index_p(breaks, i_grid, tol, out)
26
+ assert status == expected_status
27
+
28
+ # checking that the values match those of searchsorted (-1) for arbitrary grid points
29
+ i_grid = np.array([0.14320482, 0.86569833, 0.77775327, 0.00895956, 0.074629 ,
30
+ 0.45682646, 0.5384352 , 0.20915311, 0.73121977, 0.01057414,
31
+ 0.33756086, 0.17839759, 0.14023414, 0.09846206, 0.79970392,
32
+ 0.65330406, 0.82716552, 0.24185731, 0.24054685, 0.72466651,
33
+ 0.69125033, 0.3136558 , 0.64794089, 0.47975527, 0.99802844,
34
+ 0.64402598, 0.41263526, 0.28178414, 0.57274384, 0.73218562])
35
+ out = np.zeros_like(i_grid, dtype=np.int64)
36
+ status = cell_index_p(breaks, i_grid, tol, out)
37
+ assert status == 0
38
+ nps = np.searchsorted(breaks, i_grid)-1
39
+ assert np.allclose(out, nps)
40
+