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.
Files changed (108) hide show
  1. {feectools-0.1.6/feectools.egg-info → feectools-0.1.7}/PKG-INFO +1 -1
  2. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/block.py +8 -0
  3. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/direct_solvers.py +1 -1
  4. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kron.py +6 -0
  5. feectools-0.1.7/feectools/linalg/memory.py +41 -0
  6. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil.py +69 -10
  7. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_linalg.py +55 -0
  8. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/utilities.py +16 -4
  9. {feectools-0.1.6 → feectools-0.1.7/feectools.egg-info}/PKG-INFO +1 -1
  10. {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/SOURCES.txt +1 -0
  11. {feectools-0.1.6 → feectools-0.1.7}/pyproject.toml +1 -1
  12. {feectools-0.1.6 → feectools-0.1.7}/AUTHORS +0 -0
  13. {feectools-0.1.6 → feectools-0.1.7}/LICENSE +0 -0
  14. {feectools-0.1.6 → feectools-0.1.7}/README.md +0 -0
  15. {feectools-0.1.6 → feectools-0.1.7}/feectools/__init__.py +0 -0
  16. {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/__init__.py +0 -0
  17. {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/accelerate.py +0 -0
  18. {feectools-0.1.6 → feectools-0.1.7}/feectools/accelerate/compile_psydac.mk +0 -0
  19. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/__init__.py +0 -0
  20. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/essential_bc.py +0 -0
  21. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_bilinear_form.py +0 -0
  22. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_common.py +0 -0
  23. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/fem_sum_form.py +0 -0
  24. {feectools-0.1.6 → feectools-0.1.7}/feectools/api/settings.py +0 -0
  25. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/__init__.py +0 -0
  26. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/bsplines.py +0 -0
  27. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/bsplines_kernels.py +0 -0
  28. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/field_evaluation_kernels.py +0 -0
  29. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/__init__.py +0 -0
  30. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines.py +0 -0
  31. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines_kernel.py +0 -0
  32. {feectools-0.1.6 → feectools-0.1.7}/feectools/core/tests/test_bsplines_pyccel.py +0 -0
  33. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/__init__.py +0 -0
  34. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/basic.py +0 -0
  35. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/blocking_data_exchanger.py +0 -0
  36. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/cart.py +0 -0
  37. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/interface_data_exchanger.py +0 -0
  38. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/mpi.py +0 -0
  39. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/nonblocking_data_exchanger.py +0 -0
  40. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/partition.py +0 -0
  41. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/petsc.py +0 -0
  42. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/__init__.py +0 -0
  43. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_1d.py +0 -0
  44. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_2d.py +0 -0
  45. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_cart_3d.py +0 -0
  46. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_multicart_2d.py +0 -0
  47. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/tests/test_partition.py +0 -0
  48. {feectools-0.1.6 → feectools-0.1.7}/feectools/ddm/utilities.py +0 -0
  49. {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/__init__.py +0 -0
  50. {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/derivatives.py +0 -0
  51. {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/dof_kernels.py +0 -0
  52. {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/global_geometric_projectors.py +0 -0
  53. {feectools-0.1.6 → feectools-0.1.7}/feectools/feec/hodge.py +0 -0
  54. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/__init__.py +0 -0
  55. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/basic.py +0 -0
  56. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/grid.py +0 -0
  57. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/lst_preconditioner.py +0 -0
  58. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/partitioning.py +0 -0
  59. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/projectors.py +0 -0
  60. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/splines.py +0 -0
  61. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tensor.py +0 -0
  62. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/__init__.py +0 -0
  63. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/analytical_profiles_1d.py +0 -0
  64. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/analytical_profiles_base.py +0 -0
  65. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/splines_error_bounds.py +0 -0
  66. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_dirichlet_projectors.py +0 -0
  67. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_spline_histopolation.py +0 -0
  68. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_spline_interpolation.py +0 -0
  69. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_splines.py +0 -0
  70. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_splines_par.py +0 -0
  71. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_tensor.py +0 -0
  72. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/test_vector_spaces.py +0 -0
  73. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/tests/utilities.py +0 -0
  74. {feectools-0.1.6 → feectools-0.1.7}/feectools/fem/vector.py +0 -0
  75. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/__init__.py +0 -0
  76. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/basic.py +0 -0
  77. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/fft.py +0 -0
  78. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/__init__.py +0 -0
  79. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/axpy_kernels.py +0 -0
  80. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/inner_kernels.py +0 -0
  81. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/matvec_kernels.py +0 -0
  82. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/stencil2IJV_kernels.py +0 -0
  83. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/stencil2coo_kernels.py +0 -0
  84. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/kernels/transpose_kernels.py +0 -0
  85. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/solvers.py +0 -0
  86. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/sparse.py +0 -0
  87. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil_dot_kernels.py +0 -0
  88. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/stencil_transpose_kernels.py +0 -0
  89. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/__init__.py +0 -0
  90. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_block.py +0 -0
  91. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_fft.py +0 -0
  92. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_kron_stencil_matrix.py +0 -0
  93. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_matrix_free.py +0 -0
  94. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_solvers.py +0 -0
  95. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_interface_matrix.py +0 -0
  96. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_vector.py +0 -0
  97. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/test_stencil_vector_space.py +0 -0
  98. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/tests/utilities.py +0 -0
  99. {feectools-0.1.6 → feectools-0.1.7}/feectools/linalg/topetsc.py +0 -0
  100. {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/__init__.py +0 -0
  101. {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/quadratures.py +0 -0
  102. {feectools-0.1.6 → feectools-0.1.7}/feectools/utilities/utils.py +0 -0
  103. {feectools-0.1.6 → feectools-0.1.7}/feectools/version.py +0 -0
  104. {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/dependency_links.txt +0 -0
  105. {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/entry_points.txt +0 -0
  106. {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/requires.txt +0 -0
  107. {feectools-0.1.6 → feectools-0.1.7}/feectools.egg-info/top_level.txt +0 -0
  108. {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.6
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 = pads or tuple(V.pads)
922
- dims = list(W.shape)
923
- diags = [compute_diag_len(p, md, mc) for p,md,mc in zip(self._pads, V.shifts, W.shifts)]
924
- self._data = xp.zeros(tuple(int(d) for d in (dims + diags)), dtype=W.dtype)
925
- self._domain = V
926
- self._codomain = W
927
- self._ndim = len(dims)
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 xp.sign(a), 0, abs(a)
187
+ return _scalar_sign(a), 0, abs(a)
188
188
  elif a == 0:
189
- return 0, xp.sign(b), abs(b)
189
+ return 0, _scalar_sign(b), abs(b)
190
190
  elif abs(b) > abs(a):
191
191
  tau = a / b
192
- s = xp.sign(b) / sqrt(1 + tau * tau)
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 = xp.sign(a) / sqrt(1+tau*tau)
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.6
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>
@@ -75,6 +75,7 @@ feectools/linalg/block.py
75
75
  feectools/linalg/direct_solvers.py
76
76
  feectools/linalg/fft.py
77
77
  feectools/linalg/kron.py
78
+ feectools/linalg/memory.py
78
79
  feectools/linalg/solvers.py
79
80
  feectools/linalg/sparse.py
80
81
  feectools/linalg/stencil.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "feectools"
7
- version = "0.1.6"
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