feectools 0.5.0__tar.gz → 0.7.0__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.5.0/feectools.egg-info → feectools-0.7.0}/PKG-INFO +1 -1
- {feectools-0.5.0 → feectools-0.7.0}/feectools/accelerate/compile_psydac.mk +1 -1
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/fem_bilinear_form.py +2 -2
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/fem_common.py +1 -1
- {feectools-0.5.0 → feectools-0.7.0}/feectools/feec/derivatives.py +15 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/basic.py +29 -19
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/block.py +5 -2
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/direct_solvers.py +110 -22
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/fft.py +3 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_1d/stencil_dot_1d_cuda.cu +10 -7
- feectools-0.7.0/feectools/linalg/kernels/stencil_dot_1d/stencil_dot_1d_kernels.py +38 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_2d/stencil_dot_2d_cuda.cu +12 -9
- feectools-0.7.0/feectools/linalg/kernels/stencil_dot_2d/stencil_dot_2d_kernels.py +47 -0
- feectools-0.7.0/feectools/linalg/kernels/stencil_dot_3d/stencil_dot_3d_cuda.cu +52 -0
- feectools-0.7.0/feectools/linalg/kernels/stencil_dot_3d/stencil_dot_3d_kernels.py +63 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_transpose_1d/stencil_transpose_1d_cuda.cu +12 -12
- feectools-0.7.0/feectools/linalg/kernels/stencil_transpose_1d/stencil_transpose_1d_kernels.py +38 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_transpose_2d/stencil_transpose_2d_cuda.cu +11 -12
- feectools-0.7.0/feectools/linalg/kernels/stencil_transpose_2d/stencil_transpose_2d_kernels.py +52 -0
- feectools-0.7.0/feectools/linalg/kernels/stencil_transpose_3d/stencil_transpose_3d_cuda.cu +57 -0
- feectools-0.7.0/feectools/linalg/kernels/stencil_transpose_3d/stencil_transpose_3d_kernels.py +69 -0
- feectools-0.7.0/feectools/linalg/kron.py +1578 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/solvers.py +62 -32
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/stencil.py +48 -27
- feectools-0.7.0/feectools/linalg/tests/inner_on_device_child.py +149 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/kernel_test_args.py +34 -17
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_cuda_parity.py +1 -1
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_device_matvec.py +63 -20
- feectools-0.7.0/feectools/linalg/tests/test_inner_on_device.py +160 -0
- feectools-0.7.0/feectools/linalg/tests/test_kron_device_solve.py +284 -0
- feectools-0.7.0/feectools/linalg/tests/test_kron_stencil_matrix.py +526 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_mpi_device.py +62 -0
- {feectools-0.5.0 → feectools-0.7.0/feectools.egg-info}/PKG-INFO +1 -1
- {feectools-0.5.0 → feectools-0.7.0}/feectools.egg-info/SOURCES.txt +3 -0
- {feectools-0.5.0 → feectools-0.7.0}/pyproject.toml +1 -1
- feectools-0.5.0/feectools/linalg/kernels/stencil_dot_1d/stencil_dot_1d_kernels.py +0 -35
- feectools-0.5.0/feectools/linalg/kernels/stencil_dot_2d/stencil_dot_2d_kernels.py +0 -99
- feectools-0.5.0/feectools/linalg/kernels/stencil_dot_3d/stencil_dot_3d_cuda.cu +0 -64
- feectools-0.5.0/feectools/linalg/kernels/stencil_dot_3d/stencil_dot_3d_kernels.py +0 -206
- feectools-0.5.0/feectools/linalg/kernels/stencil_transpose_1d/stencil_transpose_1d_kernels.py +0 -37
- feectools-0.5.0/feectools/linalg/kernels/stencil_transpose_2d/stencil_transpose_2d_kernels.py +0 -116
- feectools-0.5.0/feectools/linalg/kernels/stencil_transpose_3d/stencil_transpose_3d_cuda.cu +0 -76
- feectools-0.5.0/feectools/linalg/kernels/stencil_transpose_3d/stencil_transpose_3d_kernels.py +0 -252
- feectools-0.5.0/feectools/linalg/kron.py +0 -933
- feectools-0.5.0/feectools/linalg/tests/test_kron_stencil_matrix.py +0 -115
- {feectools-0.5.0 → feectools-0.7.0}/AUTHORS +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/LICENSE +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/README.md +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/accelerate/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/accelerate/accelerate.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/essential_bc.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/fem_sum_form.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/api/settings.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/bsplines.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/bsplines_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/field_evaluation_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/tests/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/tests/test_bsplines.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/tests/test_bsplines_kernel.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/core/tests/test_bsplines_pyccel.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/basic.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/blocking_data_exchanger.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/cart.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/interface_data_exchanger.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/nonblocking_data_exchanger.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/partition.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/petsc.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_cart_1d.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_cart_2d.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_cart_3d.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_coarsen.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_device_binding.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_multicart_2d.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/tests/test_partition.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/ddm/utilities.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/feec/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/feec/dof_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/feec/global_geometric_projectors.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/feec/hodge.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/basic.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/grid.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/lst_preconditioner.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/partitioning.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/projectors.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/splines.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tensor.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/analytical_profiles_1d.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/analytical_profiles_base.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/splines_error_bounds.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_dirichlet_projectors.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_spline_histopolation.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_spline_interpolation.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_splines.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_splines_par.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_tensor.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/test_vector_spaces.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/tests/utilities.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/fem/vector.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/matvec_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil2IJV_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil2coo_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_1d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_1d/stencil_axpy_1d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_1d/stencil_axpy_1d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_2d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_2d/stencil_axpy_2d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_2d/stencil_axpy_2d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_3d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_3d/stencil_axpy_3d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_axpy_3d/stencil_axpy_3d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_1d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_2d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_3d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_1d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_1d/stencil_inner_1d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_1d/stencil_inner_1d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_2d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_2d/stencil_inner_2d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_2d/stencil_inner_2d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_3d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_3d/stencil_inner_3d_cuda.cu +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_inner_3d/stencil_inner_3d_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_transpose_1d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_transpose_2d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_transpose_3d/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/transpose_kernels.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/memory.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/sparse.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/cuda_parity_cases.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_axpy_ghost_sync.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_block.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_cuda_emulation.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_fft.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_linalg.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_matrix_free.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_solvers.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_stencil_interface_matrix.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_stencil_vector.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_stencil_vector_space.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/test_toarray.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/tests/utilities.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/topetsc.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/utilities.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/utilities/__init__.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/utilities/quadratures.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/utilities/utils.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools/version.py +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools.egg-info/dependency_links.txt +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools.egg-info/entry_points.txt +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools.egg-info/requires.txt +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/feectools.egg-info/top_level.txt +0 -0
- {feectools-0.5.0 → feectools-0.7.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: feectools
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
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>
|
|
@@ -594,9 +594,9 @@ class DiscreteBilinearForm:
|
|
|
594
594
|
if is_conformal:
|
|
595
595
|
matrix[k1, k2] = global_mats[k1, k2]
|
|
596
596
|
elif use_restriction:
|
|
597
|
-
matrix.
|
|
597
|
+
matrix.multiplicands[-1][k1, k2] = global_mats[k1, k2]
|
|
598
598
|
elif use_prolongation:
|
|
599
|
-
matrix.
|
|
599
|
+
matrix.multiplicands[0][k1, k2] = global_mats[k1, k2]
|
|
600
600
|
|
|
601
601
|
else: # case of scalar equation
|
|
602
602
|
if is_broken: # multi-patch
|
|
@@ -277,7 +277,7 @@ def extract_stencil_mats(mats):
|
|
|
277
277
|
if isinstance(M, (StencilInterfaceMatrix, StencilMatrix)):
|
|
278
278
|
new_mats.append(M)
|
|
279
279
|
elif isinstance(M, ComposedLinearOperator):
|
|
280
|
-
new_mats += [i for i in M.
|
|
280
|
+
new_mats += [i for i in M.multiplicands if isinstance(i, (StencilInterfaceMatrix, StencilMatrix))]
|
|
281
281
|
return new_mats
|
|
282
282
|
|
|
283
283
|
#==============================================================================
|
|
@@ -136,6 +136,21 @@ class DirectionalDerivativeOperator(LinearOperator):
|
|
|
136
136
|
def dtype( self ):
|
|
137
137
|
return self.domain.dtype
|
|
138
138
|
|
|
139
|
+
@property
|
|
140
|
+
def diffdir(self) -> int:
|
|
141
|
+
"""Direction (axis) of the derivative."""
|
|
142
|
+
return self._diffdir
|
|
143
|
+
|
|
144
|
+
@property
|
|
145
|
+
def negative(self) -> bool:
|
|
146
|
+
"""Whether the operator is the negative derivative."""
|
|
147
|
+
return self._negative
|
|
148
|
+
|
|
149
|
+
@property
|
|
150
|
+
def transposed(self) -> bool:
|
|
151
|
+
"""Whether the operator is the transposed derivative."""
|
|
152
|
+
return self._transposed
|
|
153
|
+
|
|
139
154
|
def __truediv__(self, a):
|
|
140
155
|
""" Divide by scalar. """
|
|
141
156
|
return self * (1.0 / a)
|
|
@@ -8,6 +8,7 @@ provides the fundamental classes for linear algebra operations.
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
import itertools
|
|
11
|
+
import warnings
|
|
11
12
|
from abc import ABC, abstractmethod
|
|
12
13
|
from types import LambdaType
|
|
13
14
|
from inspect import signature
|
|
@@ -93,9 +94,11 @@ class VectorSpace(ABC):
|
|
|
93
94
|
|
|
94
95
|
Returns
|
|
95
96
|
-------
|
|
96
|
-
float | complex
|
|
97
|
+
float | complex | cupy.ndarray
|
|
97
98
|
The scalar product of the two vectors. Note that inner(x, x) is
|
|
98
99
|
a non-negative real number which is zero if and only if x = 0.
|
|
100
|
+
For vectors with device (CuPy) data, a 0-d device array: the
|
|
101
|
+
result stays on the device.
|
|
99
102
|
|
|
100
103
|
"""
|
|
101
104
|
|
|
@@ -1055,27 +1058,27 @@ class ComposedLinearOperator(LinearOperator):
|
|
|
1055
1058
|
for i in range(len(args)-1):
|
|
1056
1059
|
assert args[i].domain == args[i+1].codomain
|
|
1057
1060
|
|
|
1058
|
-
|
|
1061
|
+
multiplicands = ()
|
|
1059
1062
|
tmp_vectors = []
|
|
1060
1063
|
for a in args[:-1]:
|
|
1061
1064
|
if isinstance(a, ComposedLinearOperator):
|
|
1062
|
-
|
|
1065
|
+
multiplicands = (*multiplicands, *a.multiplicands)
|
|
1063
1066
|
tmp_vectors.extend(a.tmp_vectors)
|
|
1064
1067
|
tmp_vectors.append(a.domain.zeros())
|
|
1065
1068
|
else:
|
|
1066
|
-
|
|
1069
|
+
multiplicands = (*multiplicands, a)
|
|
1067
1070
|
tmp_vectors.append(a.domain.zeros())
|
|
1068
1071
|
|
|
1069
1072
|
last = args[-1]
|
|
1070
1073
|
if isinstance(last, ComposedLinearOperator):
|
|
1071
|
-
|
|
1074
|
+
multiplicands = (*multiplicands, *last.multiplicands)
|
|
1072
1075
|
tmp_vectors.extend(last.tmp_vectors)
|
|
1073
1076
|
else:
|
|
1074
|
-
|
|
1077
|
+
multiplicands = (*multiplicands, last)
|
|
1075
1078
|
|
|
1076
1079
|
self._domain = domain
|
|
1077
1080
|
self._codomain = codomain
|
|
1078
|
-
self.
|
|
1081
|
+
self._multiplicands = multiplicands
|
|
1079
1082
|
self._tmp_vectors = tuple(tmp_vectors)
|
|
1080
1083
|
|
|
1081
1084
|
@property
|
|
@@ -1096,34 +1099,41 @@ class ComposedLinearOperator(LinearOperator):
|
|
|
1096
1099
|
return self._codomain
|
|
1097
1100
|
|
|
1098
1101
|
@property
|
|
1099
|
-
def
|
|
1102
|
+
def multiplicands(self):
|
|
1100
1103
|
r"""
|
|
1101
|
-
A tuple $(A_1,\dots,A_n)$ containing the
|
|
1104
|
+
A tuple $(A_1,\dots,A_n)$ containing the multiplicands of the linear operator
|
|
1102
1105
|
$self = A_n\circ\dots\circ A_1$.
|
|
1103
1106
|
|
|
1104
1107
|
"""
|
|
1105
|
-
return self.
|
|
1108
|
+
return self._multiplicands
|
|
1109
|
+
|
|
1110
|
+
@property
|
|
1111
|
+
def multiplicants(self):
|
|
1112
|
+
"""Deprecated alias of ``multiplicands``."""
|
|
1113
|
+
warnings.warn("ComposedLinearOperator.multiplicants is deprecated, use multiplicands instead.",
|
|
1114
|
+
DeprecationWarning, stacklevel=2)
|
|
1115
|
+
return self._multiplicands
|
|
1106
1116
|
|
|
1107
1117
|
@property
|
|
1108
1118
|
def dtype(self):
|
|
1109
1119
|
return None
|
|
1110
1120
|
|
|
1111
1121
|
def tosparse(self):
|
|
1112
|
-
mats = [M.tosparse() for M in self.
|
|
1122
|
+
mats = [M.tosparse() for M in self._multiplicands]
|
|
1113
1123
|
M = mats[0]
|
|
1114
1124
|
for Mi in mats[1:]:
|
|
1115
1125
|
M = M @ Mi
|
|
1116
1126
|
return coo_matrix(M)
|
|
1117
1127
|
|
|
1118
1128
|
def transpose(self, conjugate=False):
|
|
1119
|
-
|
|
1120
|
-
for a in self.
|
|
1121
|
-
|
|
1129
|
+
t_multiplicands = ()
|
|
1130
|
+
for a in self._multiplicands:
|
|
1131
|
+
t_multiplicands = (a.transpose(conjugate=conjugate), *t_multiplicands)
|
|
1122
1132
|
new_dom = self.codomain
|
|
1123
1133
|
new_cod = self.domain
|
|
1124
1134
|
assert isinstance(new_dom, VectorSpace)
|
|
1125
1135
|
assert isinstance(new_cod, VectorSpace)
|
|
1126
|
-
return ComposedLinearOperator(self.codomain, self.domain, *
|
|
1136
|
+
return ComposedLinearOperator(self.codomain, self.domain, *t_multiplicands)
|
|
1127
1137
|
|
|
1128
1138
|
def dot(self, v, out=None):
|
|
1129
1139
|
assert isinstance(v, Vector)
|
|
@@ -1135,11 +1145,11 @@ class ComposedLinearOperator(LinearOperator):
|
|
|
1135
1145
|
x = v
|
|
1136
1146
|
for i in range(len(self._tmp_vectors)):
|
|
1137
1147
|
y = self._tmp_vectors[-1-i]
|
|
1138
|
-
A = self.
|
|
1148
|
+
A = self._multiplicands[-1-i]
|
|
1139
1149
|
A.dot(x, out=y)
|
|
1140
1150
|
x = y
|
|
1141
1151
|
|
|
1142
|
-
A = self.
|
|
1152
|
+
A = self._multiplicands[0]
|
|
1143
1153
|
if out is not None:
|
|
1144
1154
|
|
|
1145
1155
|
A.dot(x, out=out)
|
|
@@ -1148,11 +1158,11 @@ class ComposedLinearOperator(LinearOperator):
|
|
|
1148
1158
|
return out
|
|
1149
1159
|
|
|
1150
1160
|
def exchange_assembly_data(self):
|
|
1151
|
-
for op in self.
|
|
1161
|
+
for op in self._multiplicands:
|
|
1152
1162
|
op.exchange_assembly_data()
|
|
1153
1163
|
|
|
1154
1164
|
def set_backend(self, backend, precompiled=False):
|
|
1155
|
-
for op in self.
|
|
1165
|
+
for op in self._multiplicands:
|
|
1156
1166
|
op.set_backend(backend)
|
|
1157
1167
|
|
|
1158
1168
|
#===============================================================================
|
|
@@ -112,9 +112,11 @@ class BlockVectorSpace(VectorSpace):
|
|
|
112
112
|
|
|
113
113
|
Returns
|
|
114
114
|
-------
|
|
115
|
-
float | complex
|
|
115
|
+
float | complex | cupy.ndarray
|
|
116
116
|
The scalar product of the two vectors. Note that inner(x, x) is
|
|
117
117
|
a non-negative real number which is zero if and only if x = 0.
|
|
118
|
+
For vectors with device (CuPy) data, a 0-d device array: the
|
|
119
|
+
result stays on the device.
|
|
118
120
|
|
|
119
121
|
"""
|
|
120
122
|
|
|
@@ -134,7 +136,8 @@ class BlockVectorSpace(VectorSpace):
|
|
|
134
136
|
Parameters
|
|
135
137
|
----------
|
|
136
138
|
a : scalar
|
|
137
|
-
The scaling coefficient needed for the operation
|
|
139
|
+
The scaling coefficient needed for the operation (a 0-d device
|
|
140
|
+
array is accepted, see `StencilVectorSpace.axpy`).
|
|
138
141
|
|
|
139
142
|
x : BlockVector
|
|
140
143
|
The vector which is not modified by this function.
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
# for full license details. #
|
|
5
5
|
#---------------------------------------------------------------------------#
|
|
6
6
|
from abc import abstractmethod
|
|
7
|
+
import numpy as np
|
|
7
8
|
import cunumpy as xp
|
|
8
9
|
from cunumpy.xp import array_backend
|
|
9
10
|
from scipy.sparse import spmatrix, dia_matrix
|
|
10
11
|
|
|
11
12
|
from feectools.linalg.basic import LinearSolver
|
|
12
13
|
|
|
13
|
-
__all__ = ('to_bnd', 'BandedSolver', 'SparseSolver')
|
|
14
|
+
__all__ = ('to_bnd', 'DenseInverse', 'BandedSolver', 'SparseSolver')
|
|
14
15
|
|
|
15
16
|
#===============================================================================
|
|
16
17
|
def to_bnd(A):
|
|
@@ -28,6 +29,89 @@ def to_bnd(A):
|
|
|
28
29
|
|
|
29
30
|
return A_bnd, la, ua
|
|
30
31
|
|
|
32
|
+
#===============================================================================
|
|
33
|
+
class DenseInverse:
|
|
34
|
+
"""
|
|
35
|
+
The inverse of a 1D solver's matrix as a dense matrix, for solves on the device.
|
|
36
|
+
|
|
37
|
+
LAPACK and SuperLU run on the host only. For device data the matrix is inverted
|
|
38
|
+
once on the host, by the solver itself (it solves for the identity), and the inverse
|
|
39
|
+
is applied with one matrix product per solve (a cuBLAS GEMM on CuPy). A device solve
|
|
40
|
+
then makes no host/device copy. The 1D matrices of Kronecker solvers are small
|
|
41
|
+
(n ~ tens to hundreds), so the n x n inverse is cheap to store, and one GEMM over all
|
|
42
|
+
right-hand sides is faster on a GPU than banded triangular solves.
|
|
43
|
+
|
|
44
|
+
Right-hand sides are rows, as in `BandedSolver.solve`: for ``rhs`` of shape
|
|
45
|
+
``(m, n)`` the solution is ``rhs @ M`` with ``M = solver.solve(I)``, whose row k is
|
|
46
|
+
the solution for the k-th unit vector, i.e. ``M = op(A)^{-T}``. This holds for any
|
|
47
|
+
linear 1D solver with the row convention, transposed or not.
|
|
48
|
+
|
|
49
|
+
Parameters
|
|
50
|
+
----------
|
|
51
|
+
solver : LinearSolver
|
|
52
|
+
A 1D solver whose ``solve`` accepts host (NumPy) arrays of shape ``(m, n)``.
|
|
53
|
+
|
|
54
|
+
n : int
|
|
55
|
+
The size of the 1D matrix.
|
|
56
|
+
|
|
57
|
+
dtype : dtype
|
|
58
|
+
The dtype of the right-hand sides.
|
|
59
|
+
"""
|
|
60
|
+
def __init__(self, solver, n, dtype):
|
|
61
|
+
eye = np.eye(int(n), dtype=dtype)
|
|
62
|
+
# host bookkeeping at setup: the host solver applied to the identity
|
|
63
|
+
self._host = np.ascontiguousarray(xp.to_numpy(solver.solve(eye)))
|
|
64
|
+
self._device = None
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def shape(self):
|
|
68
|
+
return self._host.shape
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def host_matrix(self):
|
|
72
|
+
"""``M`` on the host."""
|
|
73
|
+
return self._host
|
|
74
|
+
|
|
75
|
+
def device_matrix(self):
|
|
76
|
+
"""``M`` on the device, copied there once (on the first call)."""
|
|
77
|
+
if self._device is None:
|
|
78
|
+
self._device = xp.to_cupy(self._host)
|
|
79
|
+
return self._device
|
|
80
|
+
|
|
81
|
+
def matrix_for(self, array):
|
|
82
|
+
"""``M`` on the device for a device array, on the host otherwise."""
|
|
83
|
+
return self.device_matrix() if xp.is_gpu(array) else self._host
|
|
84
|
+
|
|
85
|
+
def solve(self, rhs, out=None):
|
|
86
|
+
"""
|
|
87
|
+
Solves for the right-hand sides ``rhs`` (rows) where they live, with one matrix product.
|
|
88
|
+
|
|
89
|
+
The right-hand sides are the rows of ``rhs``, as in `BandedSolver.solve`, so the
|
|
90
|
+
solutions are the rows of ``rhs @ op(A)^{-T}``; ``M`` stores ``op(A)^{-T}`` (no
|
|
91
|
+
symmetry is assumed). Multiplying from the right keeps the row-contiguous work
|
|
92
|
+
arrays of `KroneckerLinearSolver` as they are: one GEMM, no transpose copy.
|
|
93
|
+
|
|
94
|
+
``out`` may be ``rhs`` (in-place solve).
|
|
95
|
+
"""
|
|
96
|
+
assert rhs.shape[-1] == self._host.shape[0]
|
|
97
|
+
result = rhs @ self.matrix_for(rhs)
|
|
98
|
+
if out is None:
|
|
99
|
+
return result
|
|
100
|
+
assert out.shape == rhs.shape
|
|
101
|
+
out[...] = result
|
|
102
|
+
return out
|
|
103
|
+
|
|
104
|
+
#===============================================================================
|
|
105
|
+
def _device_inverse(solver, n, dtype):
|
|
106
|
+
"""The `DenseInverse` of a 1D solver for device solves, built on first use and cached per dtype."""
|
|
107
|
+
cache = getattr(solver, '_dense_inverses', None)
|
|
108
|
+
if cache is None:
|
|
109
|
+
cache = solver._dense_inverses = {}
|
|
110
|
+
key = np.dtype(dtype)
|
|
111
|
+
if key not in cache:
|
|
112
|
+
cache[key] = DenseInverse(solver, n, key)
|
|
113
|
+
return cache[key]
|
|
114
|
+
|
|
31
115
|
#===============================================================================
|
|
32
116
|
class BandedSolver(LinearSolver):
|
|
33
117
|
"""
|
|
@@ -117,6 +201,7 @@ class BandedSolver(LinearSolver):
|
|
|
117
201
|
obj._space = self._space
|
|
118
202
|
obj._dtype = self._dtype
|
|
119
203
|
obj._transposed = not self._transposed
|
|
204
|
+
obj._dense_inverses = {}
|
|
120
205
|
|
|
121
206
|
return obj
|
|
122
207
|
|
|
@@ -140,11 +225,19 @@ class BandedSolver(LinearSolver):
|
|
|
140
225
|
|
|
141
226
|
transposed = self._transposed
|
|
142
227
|
|
|
228
|
+
# LAPACK is host-only: device data is solved with the dense inverse on the
|
|
229
|
+
# device (see DenseInverse). Decided by the array itself, not the global
|
|
230
|
+
# backend, since host arrays may be passed on the CuPy backend too.
|
|
231
|
+
if xp.is_gpu(rhs):
|
|
232
|
+
if out is not None:
|
|
233
|
+
assert out.shape == rhs.shape
|
|
234
|
+
assert out.dtype == rhs.dtype
|
|
235
|
+
return _device_inverse(self, self._bmat.shape[1], rhs.dtype).solve(rhs, out=out)
|
|
236
|
+
|
|
143
237
|
if out is None:
|
|
144
|
-
|
|
145
|
-
preout, self._sinfo = self._solver_function(self._bmat, self._l, self._u, xp.to_numpy(rhs).T,
|
|
238
|
+
preout, self._sinfo = self._solver_function(self._bmat, self._l, self._u, rhs.T,
|
|
146
239
|
self._ipiv, trans=transposed)
|
|
147
|
-
out =
|
|
240
|
+
out = preout.T
|
|
148
241
|
|
|
149
242
|
else:
|
|
150
243
|
assert out.shape == rhs.shape
|
|
@@ -157,16 +250,7 @@ class BandedSolver(LinearSolver):
|
|
|
157
250
|
# TODO: handle non-contiguous views?
|
|
158
251
|
|
|
159
252
|
# we want FORTRAN-contiguous data (default is assumed to be C contiguous).
|
|
160
|
-
|
|
161
|
-
# the array itself, not the global backend, since host arrays may be passed
|
|
162
|
-
# on the CuPy backend too.
|
|
163
|
-
if xp.is_gpu(out):
|
|
164
|
-
out_cpu = xp.to_numpy(out)
|
|
165
|
-
_, self._sinfo = self._solver_function(self._bmat, self._l, self._u, out_cpu.T, self._ipiv, overwrite_b=True,
|
|
166
|
-
trans=transposed)
|
|
167
|
-
out[...] = xp.asarray(out_cpu)
|
|
168
|
-
else:
|
|
169
|
-
_, self._sinfo = self._solver_function(self._bmat, self._l, self._u, out.T, self._ipiv, overwrite_b=True,
|
|
253
|
+
_, self._sinfo = self._solver_function(self._bmat, self._l, self._u, out.T, self._ipiv, overwrite_b=True,
|
|
170
254
|
trans=transposed)
|
|
171
255
|
|
|
172
256
|
return out
|
|
@@ -206,6 +290,7 @@ class SparseSolver (LinearSolver):
|
|
|
206
290
|
obj._space = self._space
|
|
207
291
|
obj._splu = self._splu
|
|
208
292
|
obj._transposed = not self._transposed
|
|
293
|
+
obj._dense_inverses = {}
|
|
209
294
|
|
|
210
295
|
return obj
|
|
211
296
|
|
|
@@ -229,19 +314,22 @@ class SparseSolver (LinearSolver):
|
|
|
229
314
|
assert rhs.T.shape[0] == self._splu.shape[1]
|
|
230
315
|
transposed = self._transposed
|
|
231
316
|
|
|
317
|
+
# SuperLU is host-only: device data is solved with the dense inverse on the
|
|
318
|
+
# device (see DenseInverse); decided by the array, not the global backend.
|
|
319
|
+
if xp.is_gpu(rhs):
|
|
320
|
+
if out is not None:
|
|
321
|
+
assert out.shape == rhs.shape
|
|
322
|
+
assert out.dtype == rhs.dtype
|
|
323
|
+
return _device_inverse(self, self._splu.shape[1], rhs.dtype).solve(rhs, out=out)
|
|
324
|
+
|
|
232
325
|
if out is None:
|
|
233
|
-
|
|
234
|
-
out = self._splu.solve(xp.to_numpy(rhs).T, trans='T' if transposed else 'N').T
|
|
235
|
-
if xp.is_gpu(rhs):
|
|
236
|
-
out = xp.asarray(out)
|
|
326
|
+
out = self._splu.solve(rhs.T, trans='T' if transposed else 'N').T
|
|
237
327
|
|
|
238
328
|
else:
|
|
239
329
|
assert out.shape == rhs.shape
|
|
240
330
|
assert out.dtype == rhs.dtype
|
|
241
331
|
|
|
242
|
-
# currently no in-place solve exposed.
|
|
243
|
-
|
|
244
|
-
result = self._splu.solve(xp.to_numpy(rhs).T, trans='T' if transposed else 'N').T
|
|
245
|
-
out[:] = xp.asarray(result) if xp.is_gpu(out) else result
|
|
332
|
+
# currently no in-place solve exposed.
|
|
333
|
+
out[:] = self._splu.solve(rhs.T, trans='T' if transposed else 'N').T
|
|
246
334
|
|
|
247
335
|
return out
|
|
@@ -36,6 +36,9 @@ class DistributedFFTBase(LinearOperator):
|
|
|
36
36
|
function : Callable
|
|
37
37
|
The given function.
|
|
38
38
|
"""
|
|
39
|
+
# KroneckerLinearSolver: keep applying the function (not its dense matrix) to device data
|
|
40
|
+
dense_on_device = False
|
|
41
|
+
|
|
39
42
|
def __init__(self, function):
|
|
40
43
|
self._function = function
|
|
41
44
|
|
{feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_1d/stencil_dot_1d_cuda.cu
RENAMED
|
@@ -7,15 +7,16 @@
|
|
|
7
7
|
*
|
|
8
8
|
* One thread per entry of `out` (n_threads = out.size, see __init__.py). A thread outside the owned rows
|
|
9
9
|
* (local row index i1_loc outside [0, e_out - s_out]) returns without writing, so the padding of `out` is
|
|
10
|
-
* left as it is, as in pyccel.
|
|
11
|
-
*
|
|
10
|
+
* left as it is, as in pyccel. The matrix has n = mat.shape[1] diagonals (its pads are q = (n - 1) / 2) and
|
|
11
|
+
* diagonal d1 of row i1 is the column i1 - q + d1. Interior rows use all n diagonals, the last owned row
|
|
12
|
+
* (i1 == e_out) uses n - 1 + add, which is how a rectangular matrix is handled.
|
|
12
13
|
*
|
|
13
|
-
* @param mat matrix data, shape (rows of `out`,
|
|
14
|
+
* @param mat matrix data, shape (rows of `out`, diagonals)
|
|
14
15
|
* @param x data of the domain vector, ghost regions included
|
|
15
16
|
* @param out data of the codomain vector; the owned rows are written
|
|
16
17
|
* @param s_in global start of the domain of this process
|
|
17
18
|
* @param p_in padding of the domain
|
|
18
|
-
* @param add 1 if the last row uses all
|
|
19
|
+
* @param add 1 if the last row uses all diagonals, else 0
|
|
19
20
|
* @param s_out global start of the codomain of this process
|
|
20
21
|
* @param e_out global end (inclusive) of the codomain of this process
|
|
21
22
|
* @param p_out padding of the codomain: the owned rows start at index p_out of `mat` and `out`
|
|
@@ -30,11 +31,13 @@ extern "C" __global__ void stencil_dot_1d(Array2D<double> mat, Array1D<double> x
|
|
|
30
31
|
if (i1_loc < 0 || i1_loc > e_out - s_out) return;
|
|
31
32
|
const long long i1 = s_out + i1_loc; // global row index
|
|
32
33
|
|
|
33
|
-
const long long n_diags1 =
|
|
34
|
+
const long long n_diags1 = mat.shape[1];
|
|
35
|
+
const long long nd1 = (i1 == e_out) ? n_diags1 - 1 + add : n_diags1;
|
|
36
|
+
const long long off1 = p_in - (n_diags1 - 1) / 2 - s_in; // x index of diagonal 0 minus i1
|
|
34
37
|
|
|
35
38
|
double val = 0.;
|
|
36
|
-
for (long long d1 = 0; d1 <
|
|
37
|
-
val += mat(p_out + i1_loc, d1) * x(i1 + d1
|
|
39
|
+
for (long long d1 = 0; d1 < nd1; ++d1)
|
|
40
|
+
val += mat(p_out + i1_loc, d1) * x(i1 + d1 + off1);
|
|
38
41
|
|
|
39
42
|
out(p_out + i1_loc) = val;
|
|
40
43
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Stencil matrix-vector product ``out = mat @ x`` on the owned rows (1D).
|
|
2
|
+
|
|
3
|
+
The host version of ``stencil_dot_1d``.
|
|
4
|
+
|
|
5
|
+
Moved from ``feectools.linalg.stencil_dot_kernels.matvec_1d_kernel``. The CUDA version in ``stencil_dot_1d_cuda.cu``
|
|
6
|
+
takes the same arguments in the same order.
|
|
7
|
+
|
|
8
|
+
The number of diagonals is read from ``mat``: ``n = mat.shape[1]`` diagonals, the pads of the matrix are
|
|
9
|
+
``q = (n - 1) // 2`` (at most the pads ``p_in`` of the domain), and diagonal ``d`` of row ``i`` is the column
|
|
10
|
+
``i - q + d``. Interior rows use all ``n`` diagonals, the last owned row ``n - 1 + add``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def stencil_dot_1d(mat: 'float[:, :]',
|
|
15
|
+
x: 'float[:]',
|
|
16
|
+
out: 'float[:]',
|
|
17
|
+
s_in: int,
|
|
18
|
+
p_in: int,
|
|
19
|
+
add: int,
|
|
20
|
+
s_out: int,
|
|
21
|
+
e_out: int,
|
|
22
|
+
p_out: int):
|
|
23
|
+
|
|
24
|
+
n_diags1 = mat.shape[1]
|
|
25
|
+
# x index of diagonal 0 minus the global row index: column i1 - q + d1 is at x[i1 - q + d1 - s_in + p_in]
|
|
26
|
+
off1 = p_in - (n_diags1 - 1) // 2 - s_in
|
|
27
|
+
|
|
28
|
+
for i1 in range(s_out, e_out + 1): # global row index
|
|
29
|
+
i1_loc = i1 - s_out # local row index
|
|
30
|
+
nd1 = n_diags1
|
|
31
|
+
if i1 == e_out:
|
|
32
|
+
nd1 = n_diags1 - 1 + add
|
|
33
|
+
|
|
34
|
+
val = 0.
|
|
35
|
+
for d1 in range(nd1):
|
|
36
|
+
val += mat[p_out + i1_loc, d1] * x[i1 + d1 + off1]
|
|
37
|
+
|
|
38
|
+
out[p_out + i1_loc] = val
|
{feectools-0.5.0 → feectools-0.7.0}/feectools/linalg/kernels/stencil_dot_2d/stencil_dot_2d_cuda.cu
RENAMED
|
@@ -7,11 +7,11 @@
|
|
|
7
7
|
*
|
|
8
8
|
* One thread per entry of `out` (n_threads = out.size, see __init__.py), the last axis varying fastest. A
|
|
9
9
|
* thread outside the owned rows returns without writing, so the padding of `out` is left as it is, as in
|
|
10
|
-
* pyccel. Along each direction k
|
|
11
|
-
* (i_k == e_out[k]) uses
|
|
12
|
-
*
|
|
10
|
+
* pyccel. Along each direction k the matrix has n_k = mat.shape[2 + k] diagonals; interior rows use all of
|
|
11
|
+
* them, the last owned row (i_k == e_out[k]) uses n_k - 1 + add[k], as in the 1D kernel. The diagonals are
|
|
12
|
+
* summed in the same order as in pyccel (d1 outer, d2 inner).
|
|
13
13
|
*
|
|
14
|
-
* @param mat matrix data, shape (rows of `out`...,
|
|
14
|
+
* @param mat matrix data, shape (rows of `out`..., diagonals...)
|
|
15
15
|
* @param x data of the domain vector, ghost regions included
|
|
16
16
|
* @param out data of the codomain vector; the owned rows are written
|
|
17
17
|
* @param s_in, p_in, add, s_out, e_out, p_out per direction (length 2), as in the 1D kernel
|
|
@@ -30,13 +30,16 @@ extern "C" __global__ void stencil_dot_2d(Array4D<double> mat, Array2D<double> x
|
|
|
30
30
|
const long long i1 = s_out[0] + i1_loc; // global row indices
|
|
31
31
|
const long long i2 = s_out[1] + i2_loc;
|
|
32
32
|
|
|
33
|
-
const long long
|
|
34
|
-
const long long
|
|
33
|
+
const long long nd1 = (i1 == e_out[0]) ? mat.shape[2] - 1 + add[0] : mat.shape[2];
|
|
34
|
+
const long long nd2 = (i2 == e_out[1]) ? mat.shape[3] - 1 + add[1] : mat.shape[3];
|
|
35
|
+
// x index of diagonal 0 minus the global row index, per direction
|
|
36
|
+
const long long off1 = p_in[0] - (mat.shape[2] - 1) / 2 - s_in[0];
|
|
37
|
+
const long long off2 = p_in[1] - (mat.shape[3] - 1) / 2 - s_in[1];
|
|
35
38
|
|
|
36
39
|
double val = 0.;
|
|
37
|
-
for (long long d1 = 0; d1 <
|
|
38
|
-
for (long long d2 = 0; d2 <
|
|
39
|
-
val += mat(p_out[0] + i1_loc, p_out[1] + i2_loc, d1, d2) * x(i1 + d1
|
|
40
|
+
for (long long d1 = 0; d1 < nd1; ++d1)
|
|
41
|
+
for (long long d2 = 0; d2 < nd2; ++d2)
|
|
42
|
+
val += mat(p_out[0] + i1_loc, p_out[1] + i2_loc, d1, d2) * x(i1 + d1 + off1, i2 + d2 + off2);
|
|
40
43
|
|
|
41
44
|
out(p_out[0] + i1_loc, p_out[1] + i2_loc) = val;
|
|
42
45
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""Stencil matrix-vector product ``out = mat @ x`` on the owned rows (2D).
|
|
2
|
+
|
|
3
|
+
The host version of ``stencil_dot_2d``.
|
|
4
|
+
|
|
5
|
+
Moved from ``feectools.linalg.stencil_dot_kernels.matvec_2d_kernel``. The CUDA version in ``stencil_dot_2d_cuda.cu``
|
|
6
|
+
takes the same arguments in the same order.
|
|
7
|
+
|
|
8
|
+
The number of diagonals is read from ``mat``, per direction as in ``stencil_dot_1d``: ``n_k = mat.shape[2 + k]``,
|
|
9
|
+
the pads of the matrix are ``q_k = (n_k - 1) // 2`` and diagonal ``d_k`` of row ``i_k`` is the column
|
|
10
|
+
``i_k - q_k + d_k``. Interior rows use all ``n_k`` diagonals, the last owned row ``n_k - 1 + add[k]``.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def stencil_dot_2d(mat: 'float[:, :, :, :]',
|
|
15
|
+
x: 'float[:, :]',
|
|
16
|
+
out: 'float[:, :]',
|
|
17
|
+
s_in: 'int[:]',
|
|
18
|
+
p_in: 'int[:]',
|
|
19
|
+
add: 'int[:]',
|
|
20
|
+
s_out: 'int[:]',
|
|
21
|
+
e_out: 'int[:]',
|
|
22
|
+
p_out: 'int[:]'):
|
|
23
|
+
|
|
24
|
+
n_diags1 = mat.shape[2]
|
|
25
|
+
n_diags2 = mat.shape[3]
|
|
26
|
+
# x index of diagonal 0 minus the global row index, per direction
|
|
27
|
+
off1 = p_in[0] - (n_diags1 - 1) // 2 - s_in[0]
|
|
28
|
+
off2 = p_in[1] - (n_diags2 - 1) // 2 - s_in[1]
|
|
29
|
+
|
|
30
|
+
for i1 in range(s_out[0], e_out[0] + 1): # global row indices
|
|
31
|
+
i1_loc = i1 - s_out[0] # local row indices
|
|
32
|
+
nd1 = n_diags1
|
|
33
|
+
if i1 == e_out[0]:
|
|
34
|
+
nd1 = n_diags1 - 1 + add[0]
|
|
35
|
+
|
|
36
|
+
for i2 in range(s_out[1], e_out[1] + 1):
|
|
37
|
+
i2_loc = i2 - s_out[1]
|
|
38
|
+
nd2 = n_diags2
|
|
39
|
+
if i2 == e_out[1]:
|
|
40
|
+
nd2 = n_diags2 - 1 + add[1]
|
|
41
|
+
|
|
42
|
+
val = 0.
|
|
43
|
+
for d1 in range(nd1):
|
|
44
|
+
for d2 in range(nd2):
|
|
45
|
+
val += mat[p_out[0] + i1_loc, p_out[1] + i2_loc, d1, d2] * x[i1 + d1 + off1, i2 + d2 + off2]
|
|
46
|
+
|
|
47
|
+
out[p_out[0] + i1_loc, p_out[1] + i2_loc] = val
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// CUDA version of stencil_dot_3d (stencil_dot_3d_kernels.py), with the same arguments in the same order.
|
|
2
|
+
#include "cunumpy/array_view.cuh"
|
|
3
|
+
#include "cunumpy/index.cuh"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Stencil matrix-vector product out = mat @ x on the owned rows, as the pyccel kernel stencil_dot_3d.
|
|
7
|
+
*
|
|
8
|
+
* One thread per entry of `out` (n_threads = out.size, see __init__.py), the last axis varying fastest. A
|
|
9
|
+
* thread outside the owned rows returns without writing, so the padding of `out` is left as it is, as in
|
|
10
|
+
* pyccel. Along each direction k the matrix has n_k = mat.shape[3 + k] diagonals; interior rows use all of
|
|
11
|
+
* them, the last owned row (i_k == e_out[k]) uses n_k - 1 + add[k], as in the 1D kernel. The diagonals are
|
|
12
|
+
* summed in the same order as in pyccel (d1, d2, d3 innermost).
|
|
13
|
+
*
|
|
14
|
+
* @param mat matrix data (a 6D view), shape (rows of `out`..., diagonals...)
|
|
15
|
+
* @param x data of the domain vector, ghost regions included
|
|
16
|
+
* @param out data of the codomain vector; the owned rows are written
|
|
17
|
+
* @param s_in, p_in, add, s_out, e_out, p_out per direction (length 3), as in the 1D kernel
|
|
18
|
+
*/
|
|
19
|
+
extern "C" __global__ void stencil_dot_3d(Array6D<double> mat, Array3D<double> x, Array3D<double> out,
|
|
20
|
+
const long long* s_in, const long long* p_in, const long long* add,
|
|
21
|
+
const long long* s_out, const long long* e_out,
|
|
22
|
+
const long long* p_out)
|
|
23
|
+
{
|
|
24
|
+
CUNUMPY_THREAD_1D(thread, out.size());
|
|
25
|
+
|
|
26
|
+
const long long i1_loc = thread / (out.shape[1] * out.shape[2]) - p_out[0]; // local row indices
|
|
27
|
+
const long long i2_loc = (thread / out.shape[2]) % out.shape[1] - p_out[1];
|
|
28
|
+
const long long i3_loc = thread % out.shape[2] - p_out[2];
|
|
29
|
+
if (i1_loc < 0 || i1_loc > e_out[0] - s_out[0]) return;
|
|
30
|
+
if (i2_loc < 0 || i2_loc > e_out[1] - s_out[1]) return;
|
|
31
|
+
if (i3_loc < 0 || i3_loc > e_out[2] - s_out[2]) return;
|
|
32
|
+
const long long i1 = s_out[0] + i1_loc; // global row indices
|
|
33
|
+
const long long i2 = s_out[1] + i2_loc;
|
|
34
|
+
const long long i3 = s_out[2] + i3_loc;
|
|
35
|
+
|
|
36
|
+
const long long nd1 = (i1 == e_out[0]) ? mat.shape[3] - 1 + add[0] : mat.shape[3];
|
|
37
|
+
const long long nd2 = (i2 == e_out[1]) ? mat.shape[4] - 1 + add[1] : mat.shape[4];
|
|
38
|
+
const long long nd3 = (i3 == e_out[2]) ? mat.shape[5] - 1 + add[2] : mat.shape[5];
|
|
39
|
+
// x index of diagonal 0 minus the global row index, per direction
|
|
40
|
+
const long long off1 = p_in[0] - (mat.shape[3] - 1) / 2 - s_in[0];
|
|
41
|
+
const long long off2 = p_in[1] - (mat.shape[4] - 1) / 2 - s_in[1];
|
|
42
|
+
const long long off3 = p_in[2] - (mat.shape[5] - 1) / 2 - s_in[2];
|
|
43
|
+
|
|
44
|
+
double val = 0.;
|
|
45
|
+
for (long long d1 = 0; d1 < nd1; ++d1)
|
|
46
|
+
for (long long d2 = 0; d2 < nd2; ++d2)
|
|
47
|
+
for (long long d3 = 0; d3 < nd3; ++d3)
|
|
48
|
+
val += mat(p_out[0] + i1_loc, p_out[1] + i2_loc, p_out[2] + i3_loc, d1, d2, d3) *
|
|
49
|
+
x(i1 + d1 + off1, i2 + d2 + off2, i3 + d3 + off3);
|
|
50
|
+
|
|
51
|
+
out(p_out[0] + i1_loc, p_out[1] + i2_loc, p_out[2] + i3_loc) = val;
|
|
52
|
+
}
|