feectools 0.1.6__tar.gz → 0.1.7__tar.gz
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-0.1.6/feectools.egg-info → feectools-0.1.7}/PKG-INFO +1 -1
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/block.py +8 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/direct_solvers.py +1 -1
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kron.py +6 -0
- feectools-0.1.7/feectools/linalg/memory.py +41 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil.py +69 -10
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_linalg.py +55 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/utilities.py +16 -4
- {feectools-0.1.6 → feectools-0.1.7/feectools.egg-info}/PKG-INFO +1 -1
- {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/SOURCES.txt +1 -0
- {feectools-0.1.6 → feectools-0.1.7}/pyproject.toml +1 -1
- {feectools-0.1.6 → feectools-0.1.7}/AUTHORS +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/LICENSE +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/README.md +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/accelerate.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/compile_psydac.mk +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/essential_bc.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_bilinear_form.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_common.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_sum_form.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/api/settings.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/bsplines.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/bsplines_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/field_evaluation_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines_kernel.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines_pyccel.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/basic.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/blocking_data_exchanger.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/cart.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/interface_data_exchanger.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/mpi.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/nonblocking_data_exchanger.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/partition.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/petsc.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_1d.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_2d.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_3d.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_multicart_2d.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_partition.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/utilities.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/derivatives.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/dof_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/global_geometric_projectors.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/hodge.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/basic.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/grid.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/lst_preconditioner.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/partitioning.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/projectors.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/splines.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tensor.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/analytical_profiles_1d.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/analytical_profiles_base.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/splines_error_bounds.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_dirichlet_projectors.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_spline_histopolation.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_spline_interpolation.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_splines.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_splines_par.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_tensor.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_vector_spaces.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/utilities.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/vector.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/basic.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/fft.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/axpy_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/inner_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/matvec_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/stencil2IJV_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/stencil2coo_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/transpose_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/solvers.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/sparse.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil_dot_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil_transpose_kernels.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_block.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_fft.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_kron_stencil_matrix.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_matrix_free.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_solvers.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_interface_matrix.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_vector.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_vector_space.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/utilities.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/topetsc.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/__init__.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/quadratures.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/utils.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools/version.py +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/dependency_links.txt +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/entry_points.txt +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/requires.txt +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/top_level.txt +0 -0
- {feectools-0.1.6 → feectools-0.1.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feectools
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Slimmed-down fork of Psydac (https://github.com/pyccel/psydac) with less functionality and fewer dependencies.
|
|
5
5
|
Author-email: Psydac development team <psydac@googlegroups.com>
|
|
6
6
|
Maintainer-email: Stefan Possanner <stefan.possanner@ipp.mpg.de>, Max Lindqvist <max.lindqvist@ipp.mpg.de>, Yaman Güçlü <yaman.guclu@gmail.com>, Martin Campos Pinto <martin.campos-pinto@ipp.mpg.de>, Ahmed Ratnani <ratnaniahmed@gmail.com>
|
|
@@ -886,6 +886,14 @@ class BlockLinearOperator(LinearOperator):
|
|
|
886
886
|
"""
|
|
887
887
|
return tuple(self._blocks)
|
|
888
888
|
|
|
889
|
+
# ...
|
|
890
|
+
@property
|
|
891
|
+
def nbytes(self):
|
|
892
|
+
"""Local (per-MPI-rank) memory footprint of all non-zero blocks, in bytes.
|
|
893
|
+
Blocks which do not expose an 'nbytes' attribute (e.g. matrix-free operators)
|
|
894
|
+
are counted as zero."""
|
|
895
|
+
return int(sum(getattr(Lij, 'nbytes', 0) for Lij in self._blocks.values()))
|
|
896
|
+
|
|
889
897
|
# ...
|
|
890
898
|
def update_ghost_regions(self):
|
|
891
899
|
for Lij in self._blocks.values():
|
|
@@ -23,7 +23,7 @@ def to_bnd(A):
|
|
|
23
23
|
ua = dmat.offsets.max()
|
|
24
24
|
cmat = dmat.tocsr()
|
|
25
25
|
|
|
26
|
-
A_bnd = xp.zeros((1+ua+2*la, cmat.shape[1]), A.dtype)
|
|
26
|
+
A_bnd = xp.zeros((1+ua+2*la, cmat.shape[1]), dtype=A.dtype)
|
|
27
27
|
|
|
28
28
|
for i,j in zip(*cmat.nonzero()):
|
|
29
29
|
A_bnd[la+ua+i-j, j] = cmat[i,j]
|
|
@@ -73,6 +73,12 @@ class KroneckerStencilMatrix(LinearOperator):
|
|
|
73
73
|
def mats( self ):
|
|
74
74
|
return self._mats
|
|
75
75
|
|
|
76
|
+
# ...
|
|
77
|
+
@property
|
|
78
|
+
def nbytes( self ):
|
|
79
|
+
"""Local (per-MPI-rank) memory footprint of the 1d factor matrices, in bytes."""
|
|
80
|
+
return int(sum(getattr(mat, 'nbytes', 0) for mat in self._mats))
|
|
81
|
+
|
|
76
82
|
# ...
|
|
77
83
|
def dot(self, x, out=None):
|
|
78
84
|
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
"""
|
|
3
|
+
Bookkeeping of the memory occupied by the stencil matrices that are currently alive.
|
|
4
|
+
|
|
5
|
+
Every :class:`~feectools.linalg.stencil.StencilMatrix` that allocates its data array registers
|
|
6
|
+
itself (weakly) in the module-level :data:`stencil_matrix_memory` tracker, so that an application
|
|
7
|
+
can report how much memory its matrices actually take, without having to walk its own data
|
|
8
|
+
structures. Matrices created with ``dry_run=True`` do not allocate anything and are not registered.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import weakref
|
|
12
|
+
|
|
13
|
+
__all__ = ('MatrixMemoryTracker', 'stencil_matrix_memory')
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class MatrixMemoryTracker:
|
|
17
|
+
"""Weak registry of allocated matrices; matrices that are garbage collected drop out of it."""
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
self._matrices = weakref.WeakSet()
|
|
21
|
+
|
|
22
|
+
def register(self, matrix):
|
|
23
|
+
"""Add a matrix to the registry (does not keep it alive)."""
|
|
24
|
+
self._matrices.add(matrix)
|
|
25
|
+
|
|
26
|
+
def clear(self):
|
|
27
|
+
"""Forget all registered matrices."""
|
|
28
|
+
self._matrices.clear()
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def n_matrices(self):
|
|
32
|
+
"""Number of currently alive registered matrices."""
|
|
33
|
+
return len(self._matrices)
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def nbytes(self):
|
|
37
|
+
"""Local (per-MPI-rank) memory footprint, in bytes, of all currently alive registered matrices."""
|
|
38
|
+
return int(sum(matrix.nbytes for matrix in tuple(self._matrices)))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
stencil_matrix_memory = MatrixMemoryTracker()
|
|
@@ -14,6 +14,7 @@ from scipy.sparse import coo_matrix, diags as sp_diags
|
|
|
14
14
|
|
|
15
15
|
from feectools.ddm.mpi import mpi as MPI
|
|
16
16
|
from feectools.linalg.basic import VectorSpace, Vector, LinearOperator
|
|
17
|
+
from feectools.linalg.memory import stencil_matrix_memory
|
|
17
18
|
from feectools.ddm.cart import find_mpi_type, CartDecomposition, InterfaceCartDecomposition
|
|
18
19
|
from feectools.ddm.utilities import get_data_exchanger
|
|
19
20
|
from feectools.api.settings import PSYDAC_BACKENDS
|
|
@@ -637,7 +638,7 @@ class StencilVector(Vector):
|
|
|
637
638
|
|
|
638
639
|
# ...
|
|
639
640
|
def _toarray_parallel_no_pads(self, order='C'):
|
|
640
|
-
a = xp.zeros( self.space.npts, self.dtype )
|
|
641
|
+
a = xp.zeros( self.space.npts, dtype=self.dtype )
|
|
641
642
|
idx_from = tuple( slice(m*p,-m*p) if p != 0 else slice(0, None) for p,m in zip(self.pads, self.space.shifts) )
|
|
642
643
|
idx_to = tuple( slice(s,e+1) for s,e in zip(self.starts,self.ends) )
|
|
643
644
|
a[idx_to] = self._data[idx_from]
|
|
@@ -649,7 +650,7 @@ class StencilVector(Vector):
|
|
|
649
650
|
pads = [m*p for m,p in zip(self.space.shifts, self.pads)]
|
|
650
651
|
# Step 0: create extended n-dimensional array with zero values
|
|
651
652
|
shape = tuple( n+2*p for n,p in zip( self.space.npts, pads ) )
|
|
652
|
-
a = xp.zeros( shape, self.dtype )
|
|
653
|
+
a = xp.zeros( shape, dtype=self.dtype )
|
|
653
654
|
|
|
654
655
|
# Step 1: write extended data chunk (local to process) onto array
|
|
655
656
|
idx = tuple( slice(s,e+2*p+1) for s,e,p in
|
|
@@ -905,8 +906,14 @@ class StencilMatrix(LinearOperator):
|
|
|
905
906
|
|
|
906
907
|
precompiled : bool
|
|
907
908
|
Whether to use precompiled kernels for .dot() and .transpose()
|
|
909
|
+
|
|
910
|
+
dry_run : bool
|
|
911
|
+
If True, only compute the shape of the data array (:attr:`data_shape`) and return early,
|
|
912
|
+
without allocating the (potentially large) data array and without setting up the
|
|
913
|
+
dot/transpose kernels. The resulting object is *not* usable as a linear operator; its only
|
|
914
|
+
purpose is to report the memory footprint the matrix would have via :attr:`nbytes`.
|
|
908
915
|
"""
|
|
909
|
-
def __init__( self, V, W, pads=None , backend=None, precompiled=True):
|
|
916
|
+
def __init__( self, V, W, pads=None , backend=None, precompiled=True, dry_run=False):
|
|
910
917
|
|
|
911
918
|
assert isinstance(V, StencilVectorSpace)
|
|
912
919
|
assert isinstance(W, StencilVectorSpace)
|
|
@@ -918,13 +925,21 @@ class StencilMatrix(LinearOperator):
|
|
|
918
925
|
for p,vp in zip(pads, V.pads):
|
|
919
926
|
assert p<=vp
|
|
920
927
|
|
|
921
|
-
self._pads
|
|
922
|
-
dims
|
|
923
|
-
diags
|
|
924
|
-
self.
|
|
925
|
-
self._domain
|
|
926
|
-
self._codomain
|
|
927
|
-
self._ndim
|
|
928
|
+
self._pads = pads or tuple(V.pads)
|
|
929
|
+
dims = list(W.shape)
|
|
930
|
+
diags = [compute_diag_len(p, md, mc) for p,md,mc in zip(self._pads, V.shifts, W.shifts)]
|
|
931
|
+
self._data_shape = tuple(int(d) for d in (dims + diags))
|
|
932
|
+
self._domain = V
|
|
933
|
+
self._codomain = W
|
|
934
|
+
self._ndim = len(dims)
|
|
935
|
+
self._dry_run = dry_run
|
|
936
|
+
|
|
937
|
+
# memory estimation only: do not allocate the data array, see the nbytes property
|
|
938
|
+
if dry_run:
|
|
939
|
+
return
|
|
940
|
+
|
|
941
|
+
self._data = xp.zeros(self._data_shape, dtype=W.dtype)
|
|
942
|
+
stencil_matrix_memory.register(self)
|
|
928
943
|
self._backend = backend
|
|
929
944
|
self._precompiled = precompiled
|
|
930
945
|
self._is_T = False
|
|
@@ -975,6 +990,17 @@ class StencilMatrix(LinearOperator):
|
|
|
975
990
|
backend = PSYDAC_BACKENDS.get(os.environ.get('PSYDAC_BACKEND')) or PSYDAC_BACKENDS['python']
|
|
976
991
|
self.set_backend(backend, precompiled)
|
|
977
992
|
|
|
993
|
+
# ...
|
|
994
|
+
def __getattr__(self, name):
|
|
995
|
+
# only called when the attribute was not found the usual way; give a helpful
|
|
996
|
+
# message for the attributes that are missing on a dry-run matrix
|
|
997
|
+
if self.__dict__.get('_dry_run', False):
|
|
998
|
+
raise AttributeError(
|
|
999
|
+
f"'{type(self).__name__}.{name}' is not available because the matrix was created with "
|
|
1000
|
+
"dry_run=True (memory estimation only, no data allocated)."
|
|
1001
|
+
)
|
|
1002
|
+
raise AttributeError(f"'{type(self).__name__}' object has no attribute '{name}'")
|
|
1003
|
+
|
|
978
1004
|
#--------------------------------------
|
|
979
1005
|
# Abstract interface
|
|
980
1006
|
#--------------------------------------
|
|
@@ -992,6 +1018,28 @@ class StencilMatrix(LinearOperator):
|
|
|
992
1018
|
def dtype(self):
|
|
993
1019
|
return self._domain.dtype
|
|
994
1020
|
|
|
1021
|
+
# ...
|
|
1022
|
+
@property
|
|
1023
|
+
def dry_run(self):
|
|
1024
|
+
"""Whether the matrix was created for memory estimation only, i.e. without allocating data."""
|
|
1025
|
+
return self._dry_run
|
|
1026
|
+
|
|
1027
|
+
# ...
|
|
1028
|
+
@property
|
|
1029
|
+
def data_shape(self):
|
|
1030
|
+
"""Shape of the local data array (n_rows in each direction + n_diagonals in each direction)."""
|
|
1031
|
+
return self._data_shape
|
|
1032
|
+
|
|
1033
|
+
# ...
|
|
1034
|
+
@property
|
|
1035
|
+
def nbytes(self):
|
|
1036
|
+
"""Local (per-MPI-rank) memory footprint of the data array, in bytes. Also available
|
|
1037
|
+
for matrices created with ``dry_run=True``, i.e. before/without allocating the data."""
|
|
1038
|
+
nbytes = xp.dtype(self._codomain.dtype).itemsize
|
|
1039
|
+
for n in self._data_shape:
|
|
1040
|
+
nbytes *= n
|
|
1041
|
+
return int(nbytes)
|
|
1042
|
+
|
|
995
1043
|
# ...
|
|
996
1044
|
def dot(self, v, out=None):
|
|
997
1045
|
"""
|
|
@@ -2076,6 +2124,11 @@ class StencilDiagonalMatrix(LinearOperator):
|
|
|
2076
2124
|
def dtype(self):
|
|
2077
2125
|
return self._data.dtype
|
|
2078
2126
|
|
|
2127
|
+
@property
|
|
2128
|
+
def nbytes(self):
|
|
2129
|
+
"""Local (per-MPI-rank) memory footprint of the data array, in bytes."""
|
|
2130
|
+
return int(self._data.nbytes)
|
|
2131
|
+
|
|
2079
2132
|
def tosparse(self):
|
|
2080
2133
|
return sp_diags(self._data.ravel())
|
|
2081
2134
|
|
|
@@ -2369,6 +2422,12 @@ class StencilInterfaceMatrix(LinearOperator):
|
|
|
2369
2422
|
def dtype(self):
|
|
2370
2423
|
return self.domain.dtype
|
|
2371
2424
|
|
|
2425
|
+
# ...
|
|
2426
|
+
@property
|
|
2427
|
+
def nbytes(self):
|
|
2428
|
+
"""Local (per-MPI-rank) memory footprint of the data array, in bytes."""
|
|
2429
|
+
return int(self._data.nbytes)
|
|
2430
|
+
|
|
2372
2431
|
# ...
|
|
2373
2432
|
def dot(self, v, out=None):
|
|
2374
2433
|
|
|
@@ -4,6 +4,7 @@ import cunumpy as xp
|
|
|
4
4
|
from feectools.linalg.block import BlockLinearOperator, BlockVector, BlockVectorSpace
|
|
5
5
|
from feectools.linalg.basic import LinearOperator, ZeroOperator, IdentityOperator, ComposedLinearOperator, SumLinearOperator, PowerLinearOperator, ScaledLinearOperator
|
|
6
6
|
from feectools.linalg.stencil import StencilVectorSpace, StencilVector, StencilMatrix
|
|
7
|
+
from feectools.linalg.memory import stencil_matrix_memory
|
|
7
8
|
from feectools.linalg.solvers import ConjugateGradient, inverse
|
|
8
9
|
from feectools.ddm.cart import DomainDecomposition, CartDecomposition
|
|
9
10
|
|
|
@@ -1057,6 +1058,60 @@ def test_dot_inner():
|
|
|
1057
1058
|
assert r0 == r2
|
|
1058
1059
|
assert r0 == r3
|
|
1059
1060
|
|
|
1061
|
+
#===============================================================================
|
|
1062
|
+
# DRY-RUN / MEMORY REGISTRATION TESTS
|
|
1063
|
+
#===============================================================================
|
|
1064
|
+
|
|
1065
|
+
def test_stencil_matrix_dry_run_no_data_no_register():
|
|
1066
|
+
"""A dry-run StencilMatrix must not allocate _data and must not register."""
|
|
1067
|
+
V = get_StencilVectorSpace(npts=[4, 5], pads=[1, 2], periods=[False, False])
|
|
1068
|
+
stencil_matrix_memory.clear()
|
|
1069
|
+
|
|
1070
|
+
m = StencilMatrix(V, V, dry_run=True)
|
|
1071
|
+
|
|
1072
|
+
assert m.dry_run
|
|
1073
|
+
assert not hasattr(m, '_data'), "dry_run matrix must not allocate _data"
|
|
1074
|
+
assert stencil_matrix_memory.n_matrices == 0, "dry_run matrix must not register in tracker"
|
|
1075
|
+
|
|
1076
|
+
|
|
1077
|
+
def test_stencil_matrix_dry_run_data_shape_and_nbytes():
|
|
1078
|
+
"""data_shape and nbytes must be usable on a dry-run matrix without error."""
|
|
1079
|
+
V = get_StencilVectorSpace(npts=[4, 5], pads=[1, 2], periods=[False, False])
|
|
1080
|
+
|
|
1081
|
+
m = StencilMatrix(V, V, dry_run=True)
|
|
1082
|
+
|
|
1083
|
+
assert isinstance(m.data_shape, tuple)
|
|
1084
|
+
assert len(m.data_shape) > 0
|
|
1085
|
+
assert isinstance(m.nbytes, int)
|
|
1086
|
+
assert m.nbytes > 0
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
def test_stencil_matrix_allocated_registers_and_contributes_nbytes():
|
|
1090
|
+
"""An allocated StencilMatrix must register and contribute to tracker nbytes."""
|
|
1091
|
+
import gc
|
|
1092
|
+
stencil_matrix_memory.clear()
|
|
1093
|
+
gc.collect()
|
|
1094
|
+
|
|
1095
|
+
V = get_StencilVectorSpace(npts=[4, 5], pads=[1, 2], periods=[False, False])
|
|
1096
|
+
m = StencilMatrix(V, V)
|
|
1097
|
+
|
|
1098
|
+
assert not m.dry_run
|
|
1099
|
+
assert hasattr(m, '_data'), "allocated matrix must have _data"
|
|
1100
|
+
assert stencil_matrix_memory.n_matrices >= 1
|
|
1101
|
+
assert stencil_matrix_memory.nbytes >= m.nbytes
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
def test_stencil_matrix_dry_run_nbytes_matches_allocated():
|
|
1105
|
+
"""nbytes reported by a dry-run matrix must equal the nbytes of the equivalent allocated one."""
|
|
1106
|
+
V = get_StencilVectorSpace(npts=[4, 5], pads=[1, 2], periods=[False, False])
|
|
1107
|
+
|
|
1108
|
+
m_dry = StencilMatrix(V, V, dry_run=True)
|
|
1109
|
+
m_alloc = StencilMatrix(V, V)
|
|
1110
|
+
|
|
1111
|
+
assert m_dry.nbytes == m_alloc.nbytes
|
|
1112
|
+
assert m_dry.data_shape == m_alloc.data_shape
|
|
1113
|
+
|
|
1114
|
+
|
|
1060
1115
|
#===============================================================================
|
|
1061
1116
|
# SCRIPT FUNCTIONALITY
|
|
1062
1117
|
#===============================================================================
|
|
@@ -184,17 +184,29 @@ def _sym_ortho(a, b):
|
|
|
184
184
|
http://www.stanford.edu/group/SOL/dissertations/sou-cheng-choi-thesis.pdf
|
|
185
185
|
"""
|
|
186
186
|
if b == 0:
|
|
187
|
-
return
|
|
187
|
+
return _scalar_sign(a), 0, abs(a)
|
|
188
188
|
elif a == 0:
|
|
189
|
-
return 0,
|
|
189
|
+
return 0, _scalar_sign(b), abs(b)
|
|
190
190
|
elif abs(b) > abs(a):
|
|
191
191
|
tau = a / b
|
|
192
|
-
s =
|
|
192
|
+
s = _scalar_sign(b) / sqrt(1 + tau * tau)
|
|
193
193
|
c = s * tau
|
|
194
194
|
r = b / s
|
|
195
195
|
else:
|
|
196
196
|
tau = b / a
|
|
197
|
-
c =
|
|
197
|
+
c = _scalar_sign(a) / sqrt(1+tau*tau)
|
|
198
198
|
s = c * tau
|
|
199
199
|
r = a / c
|
|
200
200
|
return c, s, r
|
|
201
|
+
|
|
202
|
+
#==============================================================================
|
|
203
|
+
def _scalar_sign(x):
|
|
204
|
+
"""
|
|
205
|
+
Sign of a real Python scalar. `xp.sign` (array_api_compat) requires its
|
|
206
|
+
argument to expose a `.dtype` attribute, which plain Python floats don't have.
|
|
207
|
+
"""
|
|
208
|
+
if x > 0:
|
|
209
|
+
return 1.0
|
|
210
|
+
elif x < 0:
|
|
211
|
+
return -1.0
|
|
212
|
+
return 0.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feectools
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Summary: Slimmed-down fork of Psydac (https://github.com/pyccel/psydac) with less functionality and fewer dependencies.
|
|
5
5
|
Author-email: Psydac development team <psydac@googlegroups.com>
|
|
6
6
|
Maintainer-email: Stefan Possanner <stefan.possanner@ipp.mpg.de>, Max Lindqvist <max.lindqvist@ipp.mpg.de>, Yaman Güçlü <yaman.guclu@gmail.com>, Martin Campos Pinto <martin.campos-pinto@ipp.mpg.de>, Ahmed Ratnani <ratnaniahmed@gmail.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "feectools"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.7"
|
|
8
8
|
description = "Slimmed-down fork of Psydac (https://github.com/pyccel/psydac) with less functionality and fewer dependencies."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">= 3.10"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|