From 996d1dea7b3f8731032f3fb60c4955bdd76a71a7 Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Thu, 6 Nov 2025 12:37:43 -0800 Subject: [PATCH 01/13] Start EB This is still work in progress. You can build EB and create EBFArrayBoxFactory objects from python. --- docs/source/usage/api.rst | 16 ++++++++++++++++ src/CMakeLists.txt | 4 +++- src/EB/CMakeLists.txt | 11 +++++++++++ src/EB/EB.cpp | 28 ++++++++++++++++++++++++++++ src/EB/EBFabFactory.cpp | 32 ++++++++++++++++++++++++++++++++ src/pyAMReX.cpp | 7 +++++++ 6 files changed, 97 insertions(+), 1 deletion(-) create mode 100644 src/EB/CMakeLists.txt create mode 100644 src/EB/EB.cpp create mode 100644 src/EB/EBFabFactory.cpp diff --git a/docs/source/usage/api.rst b/docs/source/usage/api.rst index ce537ea0..27e5b58a 100644 --- a/docs/source/usage/api.rst +++ b/docs/source/usage/api.rst @@ -280,3 +280,19 @@ This is for the legacy, AoS + SoA particle containers only: .. autoclass:: amrex.space3d.Particle_2_1 :members: :undoc-members: + +.. _usage-api-eb: + +Embedded Boundaries +------------------- + +Embedded boundary (EB) support is still experimental. To build pyAMReX with +EB support, you need to add ``-DAMReX_EB=ON`` to CMake build options. + +.. autofunction:: amrex.space3d.EB2_Build + +.. autoclass:: amrex.space3d.EBFArrayBoxFactory + :members: + :undoc-members: + +.. autofunction:: amrex.space3d.makeEBFabFactory diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97a3e483..5048bf49 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,7 +2,9 @@ add_subdirectory(AmrCore) add_subdirectory(Base) #add_subdirectory(Boundary) -#add_subdirectory(EB) +if (AMReX_EB) + add_subdirectory(EB) +endif() #add_subdirectory(Extern) #add_subdirectory(LinearSolvers) add_subdirectory(Particle) diff --git a/src/EB/CMakeLists.txt b/src/EB/CMakeLists.txt new file mode 100644 index 00000000..03f82d4e --- /dev/null +++ b/src/EB/CMakeLists.txt @@ -0,0 +1,11 @@ +foreach(D IN LISTS AMReX_SPACEDIM) + if (D EQUAL 1) + return() + endif() + + target_sources(pyAMReX_${D}d + PRIVATE + EB.cpp + EBFabFactory.cpp + ) +endforeach() diff --git a/src/EB/EB.cpp b/src/EB/EB.cpp new file mode 100644 index 00000000..f8264a26 --- /dev/null +++ b/src/EB/EB.cpp @@ -0,0 +1,28 @@ +#include "pyAMReX.H" + +#include + +void init_EBFabFactory (py::module& m); + +void init_EB (py::module& m) +{ + using namespace amrex; + + m.def( + "EB2_Build", + [] (Geometry const& geom, int required_coarsening_level, int max_coarsening_level, + int ngrow, bool build_coarse_level_by_coarsening, bool extend_domain_face, + int num_coarsen_opt) + { + EB2::Build(geom, required_coarsening_level, max_coarsening_level, ngrow, + build_coarse_level_by_coarsening, extend_domain_face, num_coarsen_opt); + }, + py::arg("geom"), py::arg("required_coarsening_level"), py::arg("max_coarsening_level"), + py::arg("ngrow") = 4, py::arg("build_coarse_level_by_coarsening") = true, + py::arg("extend_domain_face") = EB2::ExtendDomainFace(), + py::arg("num_coarsen_opt") = EB2::NumCoarsenOpt(), + "EB generation" + ); + + init_EBFabFactory(m); +} diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp new file mode 100644 index 00000000..38d9ef36 --- /dev/null +++ b/src/EB/EBFabFactory.cpp @@ -0,0 +1,32 @@ + +#include "pyAMReX.H" + +#include +#include + +void init_EBFabFactory (py::module& m) +{ + using namespace amrex; + + py::class_>(m, "EBFArrayBoxFactory") + .def("getVolFrac", &EBFArrayBoxFactory::getVolFrac, + py::return_value_policy::reference_internal, + "Return volume faction MultiFab"); + + py::enum_(m, "EBSupport") + .value("basic", EBSupport::basic) + .value("volume", EBSupport::volume) + .value("full", EBSupport::full); + + m.def( + "makeEBFabFactory", + [] (Geometry const& geom, BoxArray const& ba, DistributionMapping const& dm, + Vector const& ngrow, EBSupport support) + { + return makeEBFabFactory(geom, ba, dm, ngrow, support); + }, + py::arg("geom"), py::arg("ba"), py::arg("dm"), py::arg("ngrow"), + py::arg("support"). + "Make EBFArrayBoxFactory for given Geometry, BoxArray and DistributionMapping" + ); +} diff --git a/src/pyAMReX.cpp b/src/pyAMReX.cpp index 36ce03d0..aaf39d2e 100644 --- a/src/pyAMReX.cpp +++ b/src/pyAMReX.cpp @@ -48,6 +48,9 @@ void init_Utility(py::module &); void init_Vector(py::module &); void init_Version(py::module &); void init_VisMF(py::module &); +#ifdef AMREX_USE_EB +void init_EB(py::module &); +#endif #if AMREX_SPACEDIM == 1 PYBIND11_MODULE(amrex_1d_pybind, m) { @@ -139,6 +142,10 @@ PYBIND11_MODULE(amrex_3d_pybind, m) { init_Version(m); init_VisMF(m); +#ifdef AMREX_USE_EB + init_EB(m); +#endif + // authors m.attr("__author__") = "Axel Huebl, Ryan T. Sandberg, Shreyas Ananthan, David P. Grote, " From 51fc0ad86b5d85f220b2e395fed80733db3ae37d Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:36:10 -0800 Subject: [PATCH 02/13] Fix --- src/EB/EBFabFactory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp index 38d9ef36..e2624588 100644 --- a/src/EB/EBFabFactory.cpp +++ b/src/EB/EBFabFactory.cpp @@ -26,7 +26,7 @@ void init_EBFabFactory (py::module& m) return makeEBFabFactory(geom, ba, dm, ngrow, support); }, py::arg("geom"), py::arg("ba"), py::arg("dm"), py::arg("ngrow"), - py::arg("support"). + py::arg("support"), "Make EBFArrayBoxFactory for given Geometry, BoxArray and DistributionMapping" ); } From b3fb822649b9c6d7e6ea085d091d55d5a89eda13 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:36:21 -0800 Subject: [PATCH 03/13] CMake: Move EB Control in Just simplifies the call site. --- src/CMakeLists.txt | 4 +--- src/EB/CMakeLists.txt | 3 +++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5048bf49..e375e5f8 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -2,9 +2,7 @@ add_subdirectory(AmrCore) add_subdirectory(Base) #add_subdirectory(Boundary) -if (AMReX_EB) - add_subdirectory(EB) -endif() +add_subdirectory(EB) #add_subdirectory(Extern) #add_subdirectory(LinearSolvers) add_subdirectory(Particle) diff --git a/src/EB/CMakeLists.txt b/src/EB/CMakeLists.txt index 03f82d4e..f7beb8f0 100644 --- a/src/EB/CMakeLists.txt +++ b/src/EB/CMakeLists.txt @@ -1,4 +1,7 @@ foreach(D IN LISTS AMReX_SPACEDIM) + if (NOT AMReX_EB) + return() + endif() if (D EQUAL 1) return() endif() From 2a8ff88979f199bbf41665621c4b2717ef928c85 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:37:04 -0800 Subject: [PATCH 04/13] Docs Update Signed-off-by: Axel Huebl --- docs/source/usage/api.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/usage/api.rst b/docs/source/usage/api.rst index 27e5b58a..2b4f1ef2 100644 --- a/docs/source/usage/api.rst +++ b/docs/source/usage/api.rst @@ -286,7 +286,7 @@ This is for the legacy, AoS + SoA particle containers only: Embedded Boundaries ------------------- -Embedded boundary (EB) support is still experimental. To build pyAMReX with +Embedded boundary (EB) support in pyAMReX is still minimal. To build pyAMReX with EB support, you need to add ``-DAMReX_EB=ON`` to CMake build options. .. autofunction:: amrex.space3d.EB2_Build From 7856ff81c96bd0e10ececd8a55e9ce8c8f487769 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:38:53 -0800 Subject: [PATCH 05/13] Copyright File Headers --- src/EB/EB.cpp | 5 +++++ src/EB/EBFabFactory.cpp | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/EB/EB.cpp b/src/EB/EB.cpp index f8264a26..ba4b83fa 100644 --- a/src/EB/EB.cpp +++ b/src/EB/EB.cpp @@ -1,3 +1,8 @@ +/* Copyright 2022 The AMReX Community + * + * Authors: Weiqun Zhang, Axel Huebl + * License: BSD-3-Clause-LBNL + */ #include "pyAMReX.H" #include diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp index e2624588..6089c108 100644 --- a/src/EB/EBFabFactory.cpp +++ b/src/EB/EBFabFactory.cpp @@ -1,4 +1,8 @@ - +/* Copyright 2022 The AMReX Community + * + * Authors: Weiqun Zhang, Axel Huebl + * License: BSD-3-Clause-LBNL + */ #include "pyAMReX.H" #include From 8c8a6b7f6b9b190ebc1f2d8f7de832da853b904e Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:40:05 -0800 Subject: [PATCH 06/13] Modern Enum --- src/EB/EBFabFactory.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp index 6089c108..66616497 100644 --- a/src/EB/EBFabFactory.cpp +++ b/src/EB/EBFabFactory.cpp @@ -17,10 +17,13 @@ void init_EBFabFactory (py::module& m) py::return_value_policy::reference_internal, "Return volume faction MultiFab"); - py::enum_(m, "EBSupport") + py::native_enum(m, "EBSupport", "enum.Enum") .value("basic", EBSupport::basic) .value("volume", EBSupport::volume) - .value("full", EBSupport::full); + .value("full", EBSupport::full) + .export_values() + .finalize() + ; m.def( "makeEBFabFactory", From c4c8879ea322d3468ede8150856190dbada57f7f Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 14:44:54 -0800 Subject: [PATCH 07/13] Start EB Test Template --- tests/test_eb.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/test_eb.py diff --git a/tests/test_eb.py b/tests/test_eb.py new file mode 100644 index 00000000..e29bbf17 --- /dev/null +++ b/tests/test_eb.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- + +import pytest + +import amrex.space3d as amr + + +@pytest.mark.skipif(not amr.Config.have_eb, reason="Requires -DAMReX_EB=ON") +def test_makeEBFab(): + pass + + # TODO: + # EB2_Build(...) + # makeEBFabFactory(...) From 20c53ef49c02ff5839bd2c6131130cf1fe61e5b4 Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Fri, 7 Nov 2025 15:13:57 -0800 Subject: [PATCH 08/13] add ifdef AMREX_UEE_EB --- src/EB/EB.cpp | 4 ++++ src/EB/EBFabFactory.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/EB/EB.cpp b/src/EB/EB.cpp index ba4b83fa..1fe69e31 100644 --- a/src/EB/EB.cpp +++ b/src/EB/EB.cpp @@ -5,6 +5,8 @@ */ #include "pyAMReX.H" +#ifdef AMREX_USE_EB + #include void init_EBFabFactory (py::module& m); @@ -31,3 +33,5 @@ void init_EB (py::module& m) init_EBFabFactory(m); } + +#endif diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp index 66616497..93261f2b 100644 --- a/src/EB/EBFabFactory.cpp +++ b/src/EB/EBFabFactory.cpp @@ -5,6 +5,8 @@ */ #include "pyAMReX.H" +#ifdef AMREX_USE_EB + #include #include @@ -37,3 +39,5 @@ void init_EBFabFactory (py::module& m) "Make EBFArrayBoxFactory for given Geometry, BoxArray and DistributionMapping" ); } + +#endif From 2245540221272b0823aba115868639c43c342a05 Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Fri, 7 Nov 2025 15:44:28 -0800 Subject: [PATCH 09/13] Add test --- tests/test_eb.py | 47 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/tests/test_eb.py b/tests/test_eb.py index e29bbf17..d3392388 100644 --- a/tests/test_eb.py +++ b/tests/test_eb.py @@ -1,14 +1,51 @@ # -*- coding: utf-8 -*- +import numpy import pytest import amrex.space3d as amr @pytest.mark.skipif(not amr.Config.have_eb, reason="Requires -DAMReX_EB=ON") -def test_makeEBFab(): - pass +def test_makeEBFabFactory(): + n_cell = 64 + max_grid_size = 16 - # TODO: - # EB2_Build(...) - # makeEBFabFactory(...) + # Build Geometry + domain = amr.Box(amr.IntVect(0,0,0), amr.IntVect(n_cell-1, n_cell-1, n_cell-1)) + real_box = amr.RealBox([0., 0., 0.], [1. , 1., 1.]) + coord = 0 # Cartesian + is_per = [1, 1, 1] # is periodic? + geom = amr.Geometry(domain, real_box, coord, is_per) + + # EB parameters + pp = amr.ParmParse("eb2") + pp.add("geom_type", "sphere") + pp.addarr("sphere_center", [0.5, 0.5, 0.5]) + rsphere = 0.25 + pp.add("sphere_radius", rsphere) + pp.add("sphere_has_fluid_inside", 1) + + # EB generation + eb_requried_level = 0 + eb_max_level = 2 + amr.EB2_Build(geom, eb_requried_level, eb_max_level) + + # Build BoxArray + ba = amr.BoxArray(domain) + ba.max_size(max_grid_size) + + # Build DistributionMapping + dm = amr.DistributionMapping(ba) + + # Make EB Factory + ng = amr.Vector_int([1,1,1]) + factory = amr.makeEBFabFactory(geom, ba, dm, ng, amr.EBSupport.full) + + # Get EB data + vfrac = factory.getVolFrac() + + dx = geom.data().CellSize() + total_vol = vfrac.sum()*dx[0]*dx[1]*dx[2] + sphere_vol = 4./3.*numpy.pi*rsphere**3 + assert abs(sphere_vol-total_vol)/sphere_vol < 2.e-3 From b4f7d0d9eee581bfb7cb5ea8cc01065d650ad724 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Fri, 7 Nov 2025 23:44:39 +0000 Subject: [PATCH 10/13] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/test_eb.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/tests/test_eb.py b/tests/test_eb.py index d3392388..9378a302 100644 --- a/tests/test_eb.py +++ b/tests/test_eb.py @@ -12,10 +12,12 @@ def test_makeEBFabFactory(): max_grid_size = 16 # Build Geometry - domain = amr.Box(amr.IntVect(0,0,0), amr.IntVect(n_cell-1, n_cell-1, n_cell-1)) - real_box = amr.RealBox([0., 0., 0.], [1. , 1., 1.]) + domain = amr.Box( + amr.IntVect(0, 0, 0), amr.IntVect(n_cell - 1, n_cell - 1, n_cell - 1) + ) + real_box = amr.RealBox([0.0, 0.0, 0.0], [1.0, 1.0, 1.0]) coord = 0 # Cartesian - is_per = [1, 1, 1] # is periodic? + is_per = [1, 1, 1] # is periodic? geom = amr.Geometry(domain, real_box, coord, is_per) # EB parameters @@ -39,13 +41,13 @@ def test_makeEBFabFactory(): dm = amr.DistributionMapping(ba) # Make EB Factory - ng = amr.Vector_int([1,1,1]) + ng = amr.Vector_int([1, 1, 1]) factory = amr.makeEBFabFactory(geom, ba, dm, ng, amr.EBSupport.full) # Get EB data vfrac = factory.getVolFrac() dx = geom.data().CellSize() - total_vol = vfrac.sum()*dx[0]*dx[1]*dx[2] - sphere_vol = 4./3.*numpy.pi*rsphere**3 - assert abs(sphere_vol-total_vol)/sphere_vol < 2.e-3 + total_vol = vfrac.sum() * dx[0] * dx[1] * dx[2] + sphere_vol = 4.0 / 3.0 * numpy.pi * rsphere**3 + assert abs(sphere_vol - total_vol) / sphere_vol < 2.0e-3 From 076bee773d248594036ec391a721ec1a16c2604d Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Fri, 7 Nov 2025 16:06:55 -0800 Subject: [PATCH 11/13] add cmake build option to setup.py --- pyAMReXConfig.cmake.in | 1 + setup.py | 2 ++ 2 files changed, 3 insertions(+) diff --git a/pyAMReXConfig.cmake.in b/pyAMReXConfig.cmake.in index f929ff1c..2031894c 100644 --- a/pyAMReXConfig.cmake.in +++ b/pyAMReXConfig.cmake.in @@ -26,6 +26,7 @@ set(pyAMReX_CUDA @AMReX_CUDA@) set(pyAMReX_SYCL @AMReX_SYCL@) set(pyAMReX_HIP @AMReX_HIP@) set(pyAMReX_GPU_BACKEND @AMReX_GPU_BACKEND@) +set(pyAMReX_EB @AMReX_EB@) # define central pyAMReX::pyAMReX_${D}d targets include("${CMAKE_CURRENT_LIST_DIR}/pyAMReXTargets.cmake") diff --git a/setup.py b/setup.py index 70b38816..8c45a466 100644 --- a/setup.py +++ b/setup.py @@ -97,6 +97,7 @@ def build_extension(self, ext): "-DAMReX_MPI:BOOL=" + AMReX_MPI, "-DAMReX_PRECISION=" + AMReX_PRECISION, "-DAMReX_PARTICLES_PRECISION=" + AMReX_PARTICLES_PRECISION, + "-DAMReX_EB:BOOL=" + AMReX_EB, "-DpyAMReX_CCACHE=" + PYAMREX_CCACHE, "-DpyAMReX_IPO=" + PYAMREX_IPO, ## dependency control (developers & package managers) @@ -176,6 +177,7 @@ def build_extension(self, ext): AMReX_MPI = os.environ.get("AMREX_MPI", "OFF") AMReX_PRECISION = os.environ.get("AMREX_PRECISION", "DOUBLE") AMReX_PARTICLES_PRECISION = os.environ.get("AMREX_PARTICLES_PRECISION", "DOUBLE") +AMReX_EB = os.environ.get("AMREX_EB", "OFF") # single value or as a list 1;2;3 AMReX_SPACEDIM = os.environ.get("AMREX_SPACEDIM", "1;2;3") BUILD_SHARED_LIBS = os.environ.get("AMREX_BUILD_SHARED_LIBS", "OFF") From aa385c2c4af59a1580e7f81aff4ed81d6d24d4b9 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 21:36:32 -0800 Subject: [PATCH 12/13] Fix: CMake Logic `foreach` is not a function, so once 1D was built all EB `.cpp` files were skipped. --- src/EB/CMakeLists.txt | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/EB/CMakeLists.txt b/src/EB/CMakeLists.txt index f7beb8f0..2d99796b 100644 --- a/src/EB/CMakeLists.txt +++ b/src/EB/CMakeLists.txt @@ -1,14 +1,13 @@ +if (NOT AMReX_EB) + return() +endif() + foreach(D IN LISTS AMReX_SPACEDIM) - if (NOT AMReX_EB) - return() - endif() - if (D EQUAL 1) - return() + if (D GREATER 1) + target_sources(pyAMReX_${D}d + PRIVATE + EB.cpp + EBFabFactory.cpp + ) endif() - - target_sources(pyAMReX_${D}d - PRIVATE - EB.cpp - EBFabFactory.cpp - ) endforeach() From 724b5b84ad10308ad5b36c4768367259978746a6 Mon Sep 17 00:00:00 2001 From: Axel Huebl Date: Fri, 7 Nov 2025 21:37:56 -0800 Subject: [PATCH 13/13] Simplify Guards not needed. --- src/EB/EB.cpp | 5 +---- src/EB/EBFabFactory.cpp | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/EB/EB.cpp b/src/EB/EB.cpp index 1fe69e31..823ff143 100644 --- a/src/EB/EB.cpp +++ b/src/EB/EB.cpp @@ -5,10 +5,9 @@ */ #include "pyAMReX.H" -#ifdef AMREX_USE_EB - #include + void init_EBFabFactory (py::module& m); void init_EB (py::module& m) @@ -33,5 +32,3 @@ void init_EB (py::module& m) init_EBFabFactory(m); } - -#endif diff --git a/src/EB/EBFabFactory.cpp b/src/EB/EBFabFactory.cpp index 93261f2b..13044e8a 100644 --- a/src/EB/EBFabFactory.cpp +++ b/src/EB/EBFabFactory.cpp @@ -5,11 +5,10 @@ */ #include "pyAMReX.H" -#ifdef AMREX_USE_EB - #include #include + void init_EBFabFactory (py::module& m) { using namespace amrex; @@ -39,5 +38,3 @@ void init_EBFabFactory (py::module& m) "Make EBFArrayBoxFactory for given Geometry, BoxArray and DistributionMapping" ); } - -#endif