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
|
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
|
+
|