feectools 0.1.7__tar.gz → 0.1.9__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.7/feectools.egg-info → feectools-0.1.9}/PKG-INFO +1 -1
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/bsplines.py +47 -24
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/bsplines_kernels.py +22 -4
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/blocking_data_exchanger.py +2 -5
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/cart.py +36 -7
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/mpi.py +5 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/partition.py +1 -5
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/petsc.py +3 -6
- {feectools-0.1.7 → feectools-0.1.9}/feectools/feec/global_geometric_projectors.py +81 -13
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/grid.py +4 -5
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/partitioning.py +11 -2
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/splines.py +3 -3
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tensor.py +1 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/utilities.py +3 -5
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/solvers.py +2 -2
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/stencil.py +127 -17
- {feectools-0.1.7 → feectools-0.1.9}/feectools/utilities/quadratures.py +1 -2
- {feectools-0.1.7 → feectools-0.1.9}/feectools/utilities/utils.py +40 -11
- {feectools-0.1.7 → feectools-0.1.9/feectools.egg-info}/PKG-INFO +1 -1
- {feectools-0.1.7 → feectools-0.1.9}/pyproject.toml +1 -1
- {feectools-0.1.7 → feectools-0.1.9}/AUTHORS +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/LICENSE +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/README.md +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/accelerate/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/accelerate/accelerate.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/accelerate/compile_psydac.mk +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/essential_bc.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/fem_bilinear_form.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/fem_common.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/fem_sum_form.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/api/settings.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/field_evaluation_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/tests/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/tests/test_bsplines.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/tests/test_bsplines_kernel.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/core/tests/test_bsplines_pyccel.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/basic.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/interface_data_exchanger.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/nonblocking_data_exchanger.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/test_cart_1d.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/test_cart_2d.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/test_cart_3d.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/test_multicart_2d.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/tests/test_partition.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/ddm/utilities.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/feec/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/feec/derivatives.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/feec/dof_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/feec/hodge.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/basic.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/lst_preconditioner.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/projectors.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/analytical_profiles_1d.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/analytical_profiles_base.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/splines_error_bounds.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_dirichlet_projectors.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_spline_histopolation.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_spline_interpolation.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_splines.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_splines_par.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_tensor.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/tests/test_vector_spaces.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/fem/vector.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/basic.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/block.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/direct_solvers.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/fft.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/axpy_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/inner_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/matvec_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/stencil2IJV_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/stencil2coo_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kernels/transpose_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/kron.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/memory.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/sparse.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/stencil_dot_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/stencil_transpose_kernels.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_block.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_fft.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_kron_stencil_matrix.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_linalg.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_matrix_free.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_solvers.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_stencil_interface_matrix.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_stencil_vector.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/test_stencil_vector_space.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/tests/utilities.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/topetsc.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/linalg/utilities.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/utilities/__init__.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools/version.py +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools.egg-info/SOURCES.txt +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools.egg-info/dependency_links.txt +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools.egg-info/entry_points.txt +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools.egg-info/requires.txt +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/feectools.egg-info/top_level.txt +0 -0
- {feectools-0.1.7 → feectools-0.1.9}/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.9
|
|
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>
|
|
@@ -17,6 +17,7 @@ References:
|
|
|
17
17
|
"""
|
|
18
18
|
import cunumpy as xp
|
|
19
19
|
from cunumpy.xp import array_backend
|
|
20
|
+
import numpy as np
|
|
20
21
|
|
|
21
22
|
from feectools.core.bsplines_kernels import (find_span_p,
|
|
22
23
|
find_spans_p,
|
|
@@ -352,9 +353,9 @@ def collocation_matrix(knots, degree, periodic, normalization, xgrid, out=None,
|
|
|
352
353
|
if periodic:
|
|
353
354
|
nb -= degree + 1 - multiplicity
|
|
354
355
|
|
|
355
|
-
out =
|
|
356
|
+
out = np.zeros((int(xgrid.shape[0]), int(nb)), dtype=float)
|
|
356
357
|
else:
|
|
357
|
-
assert out.shape == ((int(xgrid.shape[0]), int(nb))) and out.dtype ==
|
|
358
|
+
assert out.shape == ((int(xgrid.shape[0]), int(nb))) and out.dtype == np.dtype('float')
|
|
358
359
|
|
|
359
360
|
bool_normalization = normalization == "M"
|
|
360
361
|
multiplicity = int(multiplicity)
|
|
@@ -437,9 +438,9 @@ def histopolation_matrix(knots, degree, periodic, normalization, xgrid, multipli
|
|
|
437
438
|
|
|
438
439
|
if out is None:
|
|
439
440
|
if periodic:
|
|
440
|
-
out =
|
|
441
|
+
out = np.zeros((len(xgrid), len(knots) - 2 * int(degree) - 2 + int(multiplicity)), dtype=float)
|
|
441
442
|
else:
|
|
442
|
-
out =
|
|
443
|
+
out = np.zeros((len(xgrid) - 1, len(elevated_knots) - (int(degree) + 1) - 1 - 1), dtype=float)
|
|
443
444
|
else:
|
|
444
445
|
if periodic:
|
|
445
446
|
assert out.shape == (len(xgrid), len(knots) - 2 * degree - 2 + multiplicity)
|
|
@@ -514,10 +515,15 @@ def greville(knots, degree, periodic, out=None, multiplicity=1):
|
|
|
514
515
|
Abscissas of all Greville points.
|
|
515
516
|
|
|
516
517
|
"""
|
|
517
|
-
|
|
518
|
+
# Greville points are index arrays, keep on NumPy
|
|
519
|
+
if isinstance(knots, (list, tuple)):
|
|
520
|
+
knots = np.asarray(knots, dtype=float)
|
|
521
|
+
if hasattr(knots, 'get'):
|
|
522
|
+
knots = knots.get() # Convert CuPy to NumPy
|
|
523
|
+
knots = np.ascontiguousarray(knots, dtype=float)
|
|
518
524
|
if out is None:
|
|
519
525
|
n = len(knots) - 2 * degree - 2 + multiplicity if periodic else len(knots) - degree - 1
|
|
520
|
-
out =
|
|
526
|
+
out = np.zeros(int(n))
|
|
521
527
|
multiplicity = int(multiplicity)
|
|
522
528
|
greville_p(knots, degree, periodic, out, multiplicity)
|
|
523
529
|
return out
|
|
@@ -568,7 +574,7 @@ def elements_spans(knots, degree, out=None):
|
|
|
568
574
|
"""
|
|
569
575
|
knots = xp.ascontiguousarray(knots, dtype=float)
|
|
570
576
|
if out is None:
|
|
571
|
-
out =
|
|
577
|
+
out = np.zeros(len(knots), dtype=xp.int64)
|
|
572
578
|
else:
|
|
573
579
|
assert out.shape == knots.shape and out.dtype == xp.dtype('int64')
|
|
574
580
|
i_final = elements_spans_p(knots, degree, out)
|
|
@@ -617,7 +623,11 @@ def make_knots(breaks, degree, periodic, multiplicity=1, out=None):
|
|
|
617
623
|
|
|
618
624
|
# Consistency checks
|
|
619
625
|
assert len(breaks) > 1
|
|
620
|
-
|
|
626
|
+
# Convert to numpy for comparison since assertion needs Python bool
|
|
627
|
+
breaks_np = breaks.get() if hasattr(breaks, 'get') else breaks
|
|
628
|
+
if isinstance(breaks_np, (list, tuple)):
|
|
629
|
+
breaks_np = np.asarray(breaks_np)
|
|
630
|
+
assert all( np.diff(breaks_np) > 0 )
|
|
621
631
|
assert degree >= 0
|
|
622
632
|
assert 1 <= multiplicity and multiplicity <= degree + 1
|
|
623
633
|
# Cast potential numpy.int64 into python native int
|
|
@@ -626,9 +636,14 @@ def make_knots(breaks, degree, periodic, multiplicity=1, out=None):
|
|
|
626
636
|
if periodic:
|
|
627
637
|
assert len(breaks) > degree
|
|
628
638
|
|
|
629
|
-
|
|
639
|
+
# Keep breaks on NumPy for initialization - knots are index arrays needed for CPU operations
|
|
640
|
+
breaks = np.asarray(breaks, dtype=float) if isinstance(breaks, (list, tuple)) else breaks
|
|
641
|
+
if hasattr(breaks, 'get'):
|
|
642
|
+
breaks = breaks.get() # Convert CuPy to NumPy
|
|
643
|
+
breaks = np.ascontiguousarray(breaks, dtype=float)
|
|
630
644
|
if out is None:
|
|
631
|
-
|
|
645
|
+
# Knots are index arrays, keep them on NumPy
|
|
646
|
+
out = np.zeros(multiplicity * len(breaks[1:-1]) + 2 + 2 * degree)
|
|
632
647
|
else:
|
|
633
648
|
assert out.shape == (multiplicity * len(breaks[1:-1]) + 2 + 2 * degree,) \
|
|
634
649
|
and out.dtype == xp.dtype('float')
|
|
@@ -676,25 +691,29 @@ def elevate_knots(knots, degree, periodic, multiplicity=1, tol=1e-15, out=None):
|
|
|
676
691
|
Knots sequence of spline space of degree p+1.
|
|
677
692
|
"""
|
|
678
693
|
multiplicity = int(multiplicity)
|
|
679
|
-
|
|
694
|
+
if isinstance(knots, (list, tuple)):
|
|
695
|
+
knots = np.asarray(knots, dtype=float)
|
|
696
|
+
if hasattr(knots, 'get'):
|
|
697
|
+
knots = knots.get() # Convert CuPy to NumPy
|
|
698
|
+
knots = np.ascontiguousarray(knots, dtype=float)
|
|
680
699
|
if out is None:
|
|
681
700
|
if periodic:
|
|
682
|
-
out =
|
|
701
|
+
out = np.zeros(knots.shape[0] + 2, dtype=float)
|
|
683
702
|
else:
|
|
684
703
|
shape = 2*(degree + 2)
|
|
685
704
|
if len(knots) - 2 * (degree + 1) > 0:
|
|
686
|
-
uniques = (
|
|
705
|
+
uniques = (np.diff(knots[degree + 1:-degree - 1]) > tol).nonzero()
|
|
687
706
|
shape += multiplicity * (1 + uniques[0].shape[0])
|
|
688
|
-
out =
|
|
707
|
+
out = np.zeros(shape, dtype=float)
|
|
689
708
|
else:
|
|
690
709
|
if periodic:
|
|
691
|
-
assert out.shape == (knots.shape[0] + 2,) and out.dtype ==
|
|
710
|
+
assert out.shape == (knots.shape[0] + 2,) and out.dtype == np.dtype('float')
|
|
692
711
|
else:
|
|
693
712
|
shape = 2*(degree + 2)
|
|
694
713
|
if len(knots) - 2 * (degree + 1) > 0:
|
|
695
|
-
uniques = (
|
|
714
|
+
uniques = (np.diff(knots[degree + 1:-degree - 1]) > tol).nonzero()
|
|
696
715
|
shape += multiplicity * (1 + uniques[0].shape[0])
|
|
697
|
-
assert out.shape == shape and out.dtype ==
|
|
716
|
+
assert out.shape == shape and out.dtype == np.dtype('float')
|
|
698
717
|
|
|
699
718
|
elevate_knots_p(knots, degree, periodic, out, multiplicity, tol)
|
|
700
719
|
return out
|
|
@@ -751,14 +770,18 @@ def quadrature_grid(breaks, quad_rule_x, quad_rule_w):
|
|
|
751
770
|
assert min(quad_rule_x) >= -1
|
|
752
771
|
assert max(quad_rule_x) <= +1
|
|
753
772
|
|
|
754
|
-
breaks
|
|
773
|
+
# Convert breaks to numpy if CuPy (breaks/grids should stay on CPU)
|
|
774
|
+
if hasattr(breaks, 'get'):
|
|
775
|
+
breaks = breaks.get()
|
|
776
|
+
breaks = np.ascontiguousarray(breaks, dtype=float)
|
|
755
777
|
|
|
756
778
|
if array_backend.backend == "cupy":
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
779
|
+
# Convert CuPy arrays to NumPy
|
|
780
|
+
quad_rule_x = quad_rule_x.get() if hasattr(quad_rule_x, 'get') else quad_rule_x
|
|
781
|
+
quad_rule_w = quad_rule_w.get() if hasattr(quad_rule_w, 'get') else quad_rule_w
|
|
782
|
+
|
|
783
|
+
quad_rule_x = np.ascontiguousarray(quad_rule_x, dtype=float)
|
|
784
|
+
quad_rule_w = np.ascontiguousarray(quad_rule_w, dtype=float)
|
|
762
785
|
|
|
763
786
|
|
|
764
787
|
out1 = xp.zeros((len(breaks) - 1, len(quad_rule_x)))
|
|
@@ -914,7 +937,7 @@ def cell_index(breaks, i_grid, tol=1e-15, out=None):
|
|
|
914
937
|
breaks = xp.ascontiguousarray(breaks, dtype=float)
|
|
915
938
|
i_grid = xp.ascontiguousarray(i_grid, dtype=float)
|
|
916
939
|
if out is None:
|
|
917
|
-
out =
|
|
940
|
+
out = np.zeros_like(i_grid, dtype=xp.int64)
|
|
918
941
|
else:
|
|
919
942
|
assert out.shape == i_grid.shape and out.dtype == xp.dtype('int64')
|
|
920
943
|
status = cell_index_p(breaks, i_grid, tol, out)
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
# This file holds the pyccelisable versions of the functions in bsplines.py
|
|
8
8
|
# This will be changed once pyccel can return arrays and can get out=None arguments
|
|
9
9
|
# like Numpy functions.
|
|
10
|
+
# NOTE: This file must use ONLY numpy for pyccel compilation compatibility.
|
|
11
|
+
# Backend conversion (NumPy/CuPy) happens at the Python wrapper level.
|
|
10
12
|
|
|
11
13
|
from pyccel.decorators import pure
|
|
12
14
|
from numpy import shape, abs
|
|
@@ -401,6 +403,9 @@ def basis_funs_all_ders_p(knots: 'float[:]', degree: int, x: float, span: int, n
|
|
|
401
403
|
.. [1] L. Piegl and W. Tiller. The NURBS Book, 2nd ed.,
|
|
402
404
|
Springer-Verlag Berlin Heidelberg GmbH, 1997.
|
|
403
405
|
"""
|
|
406
|
+
# Detect backend from output array
|
|
407
|
+
# Backend array operations removed - always use numpy
|
|
408
|
+
|
|
404
409
|
sh_a = np.empty(2)
|
|
405
410
|
sh_b = np.empty(2)
|
|
406
411
|
left = np.empty(degree)
|
|
@@ -556,6 +561,9 @@ def collocation_matrix_p(knots: 'float[:]', degree: int, periodic: bool, normali
|
|
|
556
561
|
multiplicity applies to each interior knot.
|
|
557
562
|
|
|
558
563
|
"""
|
|
564
|
+
# Detect backend from output array
|
|
565
|
+
# Backend array operations removed - always use numpy
|
|
566
|
+
|
|
559
567
|
# Number of basis functions (in periodic case remove degree repeated elements)
|
|
560
568
|
nb = len(knots)-degree-1
|
|
561
569
|
if periodic:
|
|
@@ -565,7 +573,7 @@ def collocation_matrix_p(knots: 'float[:]', degree: int, periodic: bool, normali
|
|
|
565
573
|
nx = len(xgrid)
|
|
566
574
|
|
|
567
575
|
basis = np.zeros((nx, degree + 1))
|
|
568
|
-
spans = np.zeros(nx, dtype=int)
|
|
576
|
+
spans = np.zeros(nx, dtype=int) # Keep indices on CPU
|
|
569
577
|
find_spans_p(knots, degree, xgrid, spans)
|
|
570
578
|
basis_funs_array_p(knots, degree, xgrid, spans, basis)
|
|
571
579
|
|
|
@@ -644,6 +652,9 @@ def histopolation_matrix_p(knots: 'float[:]', degree: int, periodic: bool, norma
|
|
|
644
652
|
contains the integrals of each B-spline basis function :math:`B_j` between
|
|
645
653
|
two successive grid points.
|
|
646
654
|
"""
|
|
655
|
+
# Detect backend from output array
|
|
656
|
+
# Backend array operations removed - always use numpy
|
|
657
|
+
|
|
647
658
|
nb = len(knots) - degree - 1
|
|
648
659
|
if periodic:
|
|
649
660
|
nb -= degree + 1 - multiplicity
|
|
@@ -700,7 +711,7 @@ def histopolation_matrix_p(knots: 'float[:]', degree: int, periodic: bool, norma
|
|
|
700
711
|
m = colloc.shape[0] - 1
|
|
701
712
|
n = colloc.shape[1] - 1
|
|
702
713
|
|
|
703
|
-
spans = np.zeros(colloc.shape[0], dtype=int)
|
|
714
|
+
spans = np.zeros(colloc.shape[0], dtype=int) # Keep indices on CPU
|
|
704
715
|
for i in range(colloc.shape[0]):
|
|
705
716
|
local_span = 0
|
|
706
717
|
for j in range(colloc.shape[1]):
|
|
@@ -767,7 +778,10 @@ def merge_sort(a: 'float[:]'):
|
|
|
767
778
|
"""
|
|
768
779
|
if len(a) != 1 and len(a) != 0:
|
|
769
780
|
n = len(a)
|
|
770
|
-
|
|
781
|
+
|
|
782
|
+
# Detect backend and use the appropriate array module
|
|
783
|
+
# Backend array operations removed - always use numpy
|
|
784
|
+
|
|
771
785
|
a1 = np.zeros(n // 2)
|
|
772
786
|
a1[:] = a[:n // 2]
|
|
773
787
|
a2 = np.zeros(n - n // 2)
|
|
@@ -1167,12 +1181,16 @@ def basis_ders_on_quad_grid_p(knots: 'float[:]', degree: int, quad_grid: 'float[
|
|
|
1167
1181
|
"""
|
|
1168
1182
|
ne = quad_grid.shape[0]
|
|
1169
1183
|
nq = quad_grid.shape[1]
|
|
1184
|
+
|
|
1185
|
+
# Detect backend from output array
|
|
1186
|
+
# Backend array operations removed - always use numpy
|
|
1187
|
+
|
|
1170
1188
|
if normalization:
|
|
1171
1189
|
integrals = np.zeros(knots.shape[0] - degree - 1)
|
|
1172
1190
|
basis_integrals_p(knots, degree, integrals)
|
|
1173
1191
|
scaling = 1.0 /integrals
|
|
1174
1192
|
|
|
1175
|
-
temp_spans = np.zeros(len(knots), dtype=int)
|
|
1193
|
+
temp_spans = np.zeros(len(knots), dtype=int) # Keep indices on CPU
|
|
1176
1194
|
actual_index = elements_spans_p(knots, degree, temp_spans)
|
|
1177
1195
|
spans = temp_spans[:actual_index]
|
|
1178
1196
|
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
# LICENSE file or go to https://github.com/pyccel/psydac/blob/devel/LICENSE #
|
|
4
|
-
# for full license details. #
|
|
5
|
-
#---------------------------------------------------------------------------#
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
6
3
|
import cunumpy as xp
|
|
7
4
|
import numpy as np
|
|
8
5
|
from feectools.ddm.mpi import mpi as MPI
|
|
@@ -1,9 +1,20 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
3
|
import os
|
|
4
|
+
import numpy as np
|
|
4
5
|
import cunumpy as xp
|
|
6
|
+
from cunumpy.xp import array_backend
|
|
5
7
|
from itertools import product
|
|
6
8
|
|
|
9
|
+
# Initialize CUDA context before MPI if using CuPy backend
|
|
10
|
+
if array_backend.backend == "cupy":
|
|
11
|
+
try:
|
|
12
|
+
import cupy as cp
|
|
13
|
+
cp.cuda.Device(0).use()
|
|
14
|
+
cp.cuda.Stream.null.synchronize()
|
|
15
|
+
except Exception:
|
|
16
|
+
pass
|
|
17
|
+
|
|
7
18
|
from feectools.ddm.mpi import mpi as MPI
|
|
8
19
|
from feectools.ddm.mpi import MockMPI
|
|
9
20
|
from feectools.ddm.partition import compute_dims, partition_procs_per_patch
|
|
@@ -43,6 +54,17 @@ def find_mpi_type( dtype ):
|
|
|
43
54
|
|
|
44
55
|
return mpi_type
|
|
45
56
|
|
|
57
|
+
#===============================================================================
|
|
58
|
+
def _cuda_sync_before_mpi():
|
|
59
|
+
"""Synchronize CUDA before MPI operations to avoid conflicts."""
|
|
60
|
+
if array_backend.backend == "cupy":
|
|
61
|
+
try:
|
|
62
|
+
import cupy as cp
|
|
63
|
+
cp.cuda.Stream.null.synchronize()
|
|
64
|
+
except Exception:
|
|
65
|
+
pass
|
|
66
|
+
|
|
67
|
+
#===============================================================================
|
|
46
68
|
class MultiPatchDomainDecomposition:
|
|
47
69
|
"""
|
|
48
70
|
Cartesian decomposition of multiple N-Cube grids.
|
|
@@ -260,11 +282,14 @@ class DomainDecomposition:
|
|
|
260
282
|
|
|
261
283
|
if comm is None:
|
|
262
284
|
# compute the coords for all processes
|
|
263
|
-
self._global_coords =
|
|
285
|
+
self._global_coords = np.array([np.unravel_index(int(rank), nprocs) for rank in range(self._size)])
|
|
264
286
|
self._coords = self._global_coords[self._rank]
|
|
265
287
|
self._rank_in_topo = 0
|
|
266
288
|
self._ranks_in_topo = xp.array([0])
|
|
267
289
|
else:
|
|
290
|
+
# Synchronize CUDA before MPI operations
|
|
291
|
+
_cuda_sync_before_mpi()
|
|
292
|
+
|
|
268
293
|
# Create a MPI cart
|
|
269
294
|
self._comm_cart = comm.Create_cart(
|
|
270
295
|
dims = self._nprocs,
|
|
@@ -288,6 +313,7 @@ class DomainDecomposition:
|
|
|
288
313
|
# Create (N-1)-dimensional communicators within the Cartesian topology
|
|
289
314
|
self._subcomm = [None]*self._ndims
|
|
290
315
|
for i in range(self._ndims):
|
|
316
|
+
_cuda_sync_before_mpi() # Synchronize before each Sub() call
|
|
291
317
|
remain_dims = [i==j for j in range( self._ndims )]
|
|
292
318
|
self._subcomm[i] = self._comm_cart.Sub( remain_dims )
|
|
293
319
|
|
|
@@ -467,8 +493,9 @@ class CartDecomposition():
|
|
|
467
493
|
# Store input arguments
|
|
468
494
|
self._domain_decomposition = domain_decomposition
|
|
469
495
|
self._npts = tuple( npts )
|
|
470
|
-
|
|
471
|
-
self.
|
|
496
|
+
# Convert to NumPy arrays for MPI compatibility (MPI can't handle CuPy arrays)
|
|
497
|
+
self._global_starts = tuple( [ np.asarray(gs.get() if hasattr(gs, 'get') else gs) for gs in global_starts] )
|
|
498
|
+
self._global_ends = tuple( [ np.asarray(ge.get() if hasattr(ge, 'get') else ge) for ge in global_ends] )
|
|
472
499
|
self._pads = tuple( pads )
|
|
473
500
|
self._shifts = tuple( shifts )
|
|
474
501
|
self._periods = domain_decomposition.periods
|
|
@@ -494,10 +521,12 @@ class CartDecomposition():
|
|
|
494
521
|
|
|
495
522
|
# Know my coordinates in the topology
|
|
496
523
|
self._coords = domain_decomposition.coords
|
|
524
|
+
# Convert coords to NumPy for indexing (MPI coords should be on CPU)
|
|
525
|
+
coords_np = [c.get() if hasattr(c, 'get') else c for c in self._coords]
|
|
497
526
|
|
|
498
527
|
# Start/end values of global indices (without ghost regions)
|
|
499
|
-
self._starts = tuple( self._global_starts[axis][c] for axis,c in zip(range(self._ndims),
|
|
500
|
-
self._ends = tuple( self._global_ends [axis][c] for axis,c in zip(range(self._ndims),
|
|
528
|
+
self._starts = tuple( self._global_starts[axis][c] for axis,c in zip(range(self._ndims), coords_np) )
|
|
529
|
+
self._ends = tuple( self._global_ends [axis][c] for axis,c in zip(range(self._ndims), coords_np) )
|
|
501
530
|
|
|
502
531
|
# List of 1D global indices (without ghost regions)
|
|
503
532
|
# self._grids = tuple( range(s,e+1) for s,e in zip( self._starts, self._ends ) )
|
|
@@ -906,7 +935,7 @@ class CartDecomposition():
|
|
|
906
935
|
if len([i for i in shift if i==0]) == 2 and rank_dest != MPI.PROC_NULL:
|
|
907
936
|
direction = [i for i,s in enumerate(shift) if s != 0][0]
|
|
908
937
|
comm = self._subcomm[direction]
|
|
909
|
-
# local_dest_rank = self._comm_cart.group.Translate_ranks(
|
|
938
|
+
# local_dest_rank = self._comm_cart.group.Translate_ranks(np.array([rank_dest]), comm.group)[0]
|
|
910
939
|
local_dest_rank = self._comm_cart.group.Translate_ranks([int(rank_dest)], comm.group)[0]
|
|
911
940
|
|
|
912
941
|
else:
|
|
@@ -921,7 +950,7 @@ class CartDecomposition():
|
|
|
921
950
|
if len([i for i in shift if i==0]) == 2 and rank_source != MPI.PROC_NULL:
|
|
922
951
|
direction = [i for i,s in enumerate(shift) if s != 0][0]
|
|
923
952
|
comm = self._subcomm[direction]
|
|
924
|
-
# local_source_rank = self._comm_cart.group.Translate_ranks(
|
|
953
|
+
# local_source_rank = self._comm_cart.group.Translate_ranks(np.array([rank_source]), comm.group)[0]
|
|
925
954
|
local_source_rank = self._comm_cart.group.Translate_ranks([int(rank_source)], comm.group)[0]
|
|
926
955
|
else:
|
|
927
956
|
local_source_rank = rank_source
|
|
@@ -81,6 +81,11 @@ class MockMPI:
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
try:
|
|
84
|
+
# Disable MPI when using CuPy due to known segfault issues with OpenMPI + CUDA
|
|
85
|
+
import os
|
|
86
|
+
if os.environ.get('ARRAY_BACKEND') == 'cupy':
|
|
87
|
+
raise ImportError("MPI disabled when using CuPy backend")
|
|
88
|
+
|
|
84
89
|
from mpi4py import MPI
|
|
85
90
|
|
|
86
91
|
_comm = MPI.COMM_WORLD
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
#---------------------------------------------------------------------------#
|
|
2
|
-
# This file is part of PSYDAC which is released under MIT License. See the #
|
|
3
|
-
# LICENSE file or go to https://github.com/pyccel/psydac/blob/devel/LICENSE #
|
|
4
|
-
# for full license details. #
|
|
5
|
-
#---------------------------------------------------------------------------#
|
|
6
1
|
import cunumpy as xp
|
|
2
|
+
import numpy as np
|
|
7
3
|
import numpy.ma as ma
|
|
8
4
|
|
|
9
5
|
from sympy.ntheory import factorint
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
# for full license details. #
|
|
5
|
-
#---------------------------------------------------------------------------#
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
|
|
3
|
+
import cunumpy as xp
|
|
6
4
|
from itertools import product
|
|
7
5
|
|
|
8
6
|
import cunumpy as xp
|
|
@@ -113,4 +111,3 @@ class PetscCart:
|
|
|
113
111
|
to_is = self.petsc.IS().createGeneral(indices, comm=cart.comm)
|
|
114
112
|
|
|
115
113
|
return self.petsc.Scatter().create(gvec, from_is, natural, to_is)
|
|
116
|
-
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import cunumpy as xp
|
|
4
4
|
from cunumpy.xp import array_backend
|
|
5
|
+
import numpy as np
|
|
5
6
|
|
|
6
7
|
from feectools.linalg.kron import KroneckerLinearSolver, KroneckerStencilMatrix
|
|
7
8
|
from feectools.linalg.stencil import StencilMatrix, StencilVectorSpace
|
|
@@ -25,6 +26,18 @@ __all__ = ('GlobalGeometricProjector', 'GlobalGeometricProjectorH1', 'GlobalGeom
|
|
|
25
26
|
'evaluate_dofs_2d_0form', 'evaluate_dofs_2d_1form_hcurl', 'evaluate_dofs_2d_1form_hdiv', 'evaluate_dofs_2d_2form',
|
|
26
27
|
'evaluate_dofs_3d_0form', 'evaluate_dofs_3d_1form', 'evaluate_dofs_3d_2form', 'evaluate_dofs_3d_3form')
|
|
27
28
|
|
|
29
|
+
|
|
30
|
+
def _to_numpy_for_kernel(*args):
|
|
31
|
+
"""Convert CuPy arrays to NumPy for compiled kernel calls."""
|
|
32
|
+
result = []
|
|
33
|
+
for arg in args:
|
|
34
|
+
if hasattr(arg, 'get'): # CuPy array
|
|
35
|
+
result.append(arg.get())
|
|
36
|
+
else:
|
|
37
|
+
result.append(arg)
|
|
38
|
+
return result if len(result) > 1 else result[0]
|
|
39
|
+
|
|
40
|
+
|
|
28
41
|
#==============================================================================
|
|
29
42
|
class GlobalGeometricProjector(metaclass=ABCMeta):
|
|
30
43
|
"""
|
|
@@ -207,8 +220,9 @@ class GlobalGeometricProjector(metaclass=ABCMeta):
|
|
|
207
220
|
solvercells += [V._histopolator]
|
|
208
221
|
|
|
209
222
|
# make 1D collocation matrix in stencil format
|
|
223
|
+
# Always use NumPy for indices since they're used for indexing/comparison
|
|
210
224
|
if array_backend.backend == "cupy":
|
|
211
|
-
row_indices, col_indices =
|
|
225
|
+
row_indices, col_indices = np.nonzero(np.asarray(V.hmat))
|
|
212
226
|
else:
|
|
213
227
|
row_indices, col_indices = xp.nonzero(V.hmat)
|
|
214
228
|
|
|
@@ -800,7 +814,10 @@ def evaluate_dofs_1d_0form(
|
|
|
800
814
|
|
|
801
815
|
F_temp = xp.zeros_like(F, order='C')
|
|
802
816
|
|
|
803
|
-
|
|
817
|
+
F_temp_np, f_pts_np = _to_numpy_for_kernel(F_temp, f_pts)
|
|
818
|
+
dof_kernels.evaluate_dofs_1d_0form(F_temp_np, f_pts_np)
|
|
819
|
+
if hasattr(F_temp, 'get'):
|
|
820
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
804
821
|
|
|
805
822
|
F[:] = F_temp
|
|
806
823
|
|
|
@@ -819,7 +836,10 @@ def evaluate_dofs_1d_1form(
|
|
|
819
836
|
# call kernel
|
|
820
837
|
F_temp = xp.zeros_like(F, order='C')
|
|
821
838
|
|
|
822
|
-
|
|
839
|
+
quad_w1_np, F_temp_np, f_pts_np = _to_numpy_for_kernel(quad_w1, F_temp, f_pts)
|
|
840
|
+
dof_kernels.evaluate_dofs_1d_1form(quad_w1_np, F_temp_np, f_pts_np)
|
|
841
|
+
if hasattr(F_temp, 'get'):
|
|
842
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
823
843
|
|
|
824
844
|
F[:] = F_temp
|
|
825
845
|
|
|
@@ -842,7 +862,10 @@ def evaluate_dofs_2d_0form(
|
|
|
842
862
|
|
|
843
863
|
F_temp = xp.zeros_like(F, order='C')
|
|
844
864
|
|
|
845
|
-
|
|
865
|
+
F_temp_np, f_pts_np = _to_numpy_for_kernel(F_temp, f_pts)
|
|
866
|
+
dof_kernels.evaluate_dofs_2d_0form(F_temp_np, f_pts_np)
|
|
867
|
+
if hasattr(F_temp, 'get'):
|
|
868
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
846
869
|
|
|
847
870
|
F[:, :] = F_temp
|
|
848
871
|
|
|
@@ -869,7 +892,12 @@ def evaluate_dofs_2d_1form_hcurl(
|
|
|
869
892
|
F1_temp = xp.zeros_like(F1, order='C')
|
|
870
893
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
871
894
|
|
|
872
|
-
|
|
895
|
+
quad_w1_np, quad_w2_np, F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, F1_temp, F2_temp, f1_pts, f2_pts)
|
|
896
|
+
dof_kernels.evaluate_dofs_2d_1form_hcurl(quad_w1_np, quad_w2_np, F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np)
|
|
897
|
+
if hasattr(F1_temp, 'get'):
|
|
898
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
899
|
+
if hasattr(F2_temp, 'get'):
|
|
900
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
873
901
|
|
|
874
902
|
F1[:, :] = F1_temp
|
|
875
903
|
F2[:, :] = F2_temp
|
|
@@ -897,7 +925,12 @@ def evaluate_dofs_2d_1form_hdiv(
|
|
|
897
925
|
F1_temp = xp.zeros_like(F1, order='C')
|
|
898
926
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
899
927
|
|
|
900
|
-
|
|
928
|
+
quad_w1_np, quad_w2_np, F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, F1_temp, F2_temp, f1_pts, f2_pts)
|
|
929
|
+
dof_kernels.evaluate_dofs_2d_1form_hdiv(quad_w1_np, quad_w2_np, F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np)
|
|
930
|
+
if hasattr(F1_temp, 'get'):
|
|
931
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
932
|
+
if hasattr(F2_temp, 'get'):
|
|
933
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
901
934
|
|
|
902
935
|
F1[:, :] = F1_temp
|
|
903
936
|
F2[:, :] = F2_temp
|
|
@@ -917,7 +950,10 @@ def evaluate_dofs_2d_2form(
|
|
|
917
950
|
# call kernel
|
|
918
951
|
F_temp = xp.zeros_like(F, order='C')
|
|
919
952
|
|
|
920
|
-
|
|
953
|
+
quad_w1_np, quad_w2_np, F_temp_np, f_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, F_temp, f_pts)
|
|
954
|
+
dof_kernels.evaluate_dofs_2d_2form(quad_w1_np, quad_w2_np, F_temp_np, f_pts_np)
|
|
955
|
+
if hasattr(F_temp, 'get'):
|
|
956
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
921
957
|
|
|
922
958
|
F[:, :] = F_temp
|
|
923
959
|
|
|
@@ -940,7 +976,12 @@ def evaluate_dofs_2d_vec(
|
|
|
940
976
|
F1_temp = xp.zeros_like(F1, order='C')
|
|
941
977
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
942
978
|
|
|
943
|
-
|
|
979
|
+
F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np = _to_numpy_for_kernel(F1_temp, F2_temp, f1_pts, f2_pts)
|
|
980
|
+
dof_kernels.evaluate_dofs_2d_vec(F1_temp_np, F2_temp_np, f1_pts_np, f2_pts_np)
|
|
981
|
+
if hasattr(F1_temp, 'get'):
|
|
982
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
983
|
+
if hasattr(F2_temp, 'get'):
|
|
984
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
944
985
|
|
|
945
986
|
F1[:, :] = F1_temp
|
|
946
987
|
F2[:, :] = F2_temp
|
|
@@ -965,7 +1006,10 @@ def evaluate_dofs_3d_0form(
|
|
|
965
1006
|
|
|
966
1007
|
F_temp = xp.zeros_like(F, order='C')
|
|
967
1008
|
|
|
968
|
-
|
|
1009
|
+
F_temp_np, f_pts_np = _to_numpy_for_kernel(F_temp, f_pts)
|
|
1010
|
+
dof_kernels.evaluate_dofs_3d_0form(F_temp_np, f_pts_np)
|
|
1011
|
+
if hasattr(F_temp, 'get'):
|
|
1012
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
969
1013
|
|
|
970
1014
|
F[:, :, :] = F_temp
|
|
971
1015
|
|
|
@@ -997,7 +1041,14 @@ def evaluate_dofs_3d_1form(
|
|
|
997
1041
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
998
1042
|
F3_temp = xp.zeros_like(F3, order='C')
|
|
999
1043
|
|
|
1000
|
-
|
|
1044
|
+
quad_w1_np, quad_w2_np, quad_w3_np, F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, quad_w3, F1_temp, F2_temp, F3_temp, f1_pts, f2_pts, f3_pts)
|
|
1045
|
+
dof_kernels.evaluate_dofs_3d_1form(quad_w1_np, quad_w2_np, quad_w3_np, F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np)
|
|
1046
|
+
if hasattr(F1_temp, 'get'):
|
|
1047
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
1048
|
+
if hasattr(F2_temp, 'get'):
|
|
1049
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
1050
|
+
if hasattr(F3_temp, 'get'):
|
|
1051
|
+
F3_temp[:] = xp.asarray(F3_temp_np)
|
|
1001
1052
|
|
|
1002
1053
|
F1[:, :, :] = F1_temp
|
|
1003
1054
|
F2[:, :, :] = F2_temp
|
|
@@ -1031,7 +1082,14 @@ def evaluate_dofs_3d_2form(
|
|
|
1031
1082
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
1032
1083
|
F3_temp = xp.zeros_like(F3, order='C')
|
|
1033
1084
|
|
|
1034
|
-
|
|
1085
|
+
quad_w1_np, quad_w2_np, quad_w3_np, F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, quad_w3, F1_temp, F2_temp, F3_temp, f1_pts, f2_pts, f3_pts)
|
|
1086
|
+
dof_kernels.evaluate_dofs_3d_2form(quad_w1_np, quad_w2_np, quad_w3_np, F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np)
|
|
1087
|
+
if hasattr(F1_temp, 'get'):
|
|
1088
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
1089
|
+
if hasattr(F2_temp, 'get'):
|
|
1090
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
1091
|
+
if hasattr(F3_temp, 'get'):
|
|
1092
|
+
F3_temp[:] = xp.asarray(F3_temp_np)
|
|
1035
1093
|
|
|
1036
1094
|
F1[:, :, :] = F1_temp
|
|
1037
1095
|
F2[:, :, :] = F2_temp
|
|
@@ -1052,7 +1110,10 @@ def evaluate_dofs_3d_3form(
|
|
|
1052
1110
|
# call kernel
|
|
1053
1111
|
F_temp = xp.zeros_like(F, order='C')
|
|
1054
1112
|
|
|
1055
|
-
|
|
1113
|
+
quad_w1_np, quad_w2_np, quad_w3_np, F_temp_np, f_pts_np = _to_numpy_for_kernel(quad_w1, quad_w2, quad_w3, F_temp, f_pts)
|
|
1114
|
+
dof_kernels.evaluate_dofs_3d_3form(quad_w1_np, quad_w2_np, quad_w3_np, F_temp_np, f_pts_np)
|
|
1115
|
+
if hasattr(F_temp, 'get'):
|
|
1116
|
+
F_temp[:] = xp.asarray(F_temp_np)
|
|
1056
1117
|
|
|
1057
1118
|
F[:, :, :] = F_temp
|
|
1058
1119
|
|
|
@@ -1078,7 +1139,14 @@ def evaluate_dofs_3d_vec(
|
|
|
1078
1139
|
F2_temp = xp.zeros_like(F2, order='C')
|
|
1079
1140
|
F3_temp = xp.zeros_like(F3, order='C')
|
|
1080
1141
|
|
|
1081
|
-
|
|
1142
|
+
F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np = _to_numpy_for_kernel(F1_temp, F2_temp, F3_temp, f1_pts, f2_pts, f3_pts)
|
|
1143
|
+
dof_kernels.evaluate_dofs_3d_vec(F1_temp_np, F2_temp_np, F3_temp_np, f1_pts_np, f2_pts_np, f3_pts_np)
|
|
1144
|
+
if hasattr(F1_temp, 'get'):
|
|
1145
|
+
F1_temp[:] = xp.asarray(F1_temp_np)
|
|
1146
|
+
if hasattr(F2_temp, 'get'):
|
|
1147
|
+
F2_temp[:] = xp.asarray(F2_temp_np)
|
|
1148
|
+
if hasattr(F3_temp, 'get'):
|
|
1149
|
+
F3_temp[:] = xp.asarray(F3_temp_np)
|
|
1082
1150
|
|
|
1083
1151
|
F1[:, :, :] = F1_temp
|
|
1084
1152
|
F2[:, :, :] = F2_temp
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
|
|
5
|
-
#---------------------------------------------------------------------------#
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# Copyright 2018 Yaman Güçlü
|
|
4
|
+
|
|
6
5
|
import cunumpy as xp
|
|
7
6
|
|
|
8
7
|
from feectools.core.bsplines import elements_spans
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# -*- coding: UTF-8 -*-
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
|
+
import numpy as np
|
|
4
5
|
import cunumpy as xp
|
|
5
6
|
|
|
6
7
|
from feectools.ddm.cart import CartDecomposition, InterfaceCartDecomposition, create_interfaces_cart
|
|
@@ -56,6 +57,10 @@ def partition_coefficients(domain_decomposition, spaces, min_blocks=None):
|
|
|
56
57
|
ee = domain_decomposition.global_element_ends [axis]
|
|
57
58
|
m = multiplicity[axis]
|
|
58
59
|
|
|
60
|
+
# Convert to numpy if CuPy (needed for MPI operations later)
|
|
61
|
+
if hasattr(ee, 'get'):
|
|
62
|
+
ee = ee.get()
|
|
63
|
+
|
|
59
64
|
global_ends [axis] = m*(ee+1)-1
|
|
60
65
|
global_ends [axis][-1] = npts[axis]-1
|
|
61
66
|
global_starts[axis] = xp.array([0] + (global_ends[axis][:-1]+1).tolist())
|
|
@@ -64,14 +69,18 @@ def partition_coefficients(domain_decomposition, spaces, min_blocks=None):
|
|
|
64
69
|
min_blocks = [None] * ndims
|
|
65
70
|
|
|
66
71
|
for s, e, V, mb in zip(global_starts, global_ends, spaces, min_blocks):
|
|
72
|
+
s_host = s.get() if hasattr(s, 'get') else np.asarray(s)
|
|
73
|
+
e_host = e.get() if hasattr(e, 'get') else np.asarray(e)
|
|
74
|
+
local_sizes = e_host - s_host + 1
|
|
75
|
+
|
|
67
76
|
if V.periodic or mb is None:
|
|
68
|
-
assert all(
|
|
77
|
+
assert all(local_sizes >= V.degree), f"Local number of elements (after domain decomposition) is to small for spline degree p={V.degree}: {local_sizes} is not >= {V.degree} everywhere.\n \
|
|
69
78
|
You can:\n \
|
|
70
79
|
1. increase Nel\n \
|
|
71
80
|
2. lower p\n \
|
|
72
81
|
3. decrease the MPI size."
|
|
73
82
|
else:
|
|
74
|
-
assert all(
|
|
83
|
+
assert all(local_sizes >= mb)
|
|
75
84
|
|
|
76
85
|
return global_starts, global_ends
|
|
77
86
|
|