From 36245da256dc96cad81b74d6e1f1c45633fe182a Mon Sep 17 00:00:00 2001 From: shaia Date: Thu, 1 Jan 2026 10:06:50 +0200 Subject: [PATCH 1/5] feat: Add backend availability API for runtime backend detection Implements Phase 5 of the v0.1.6 migration plan: - Add BACKEND_SCALAR, BACKEND_SIMD, BACKEND_OMP, BACKEND_CUDA constants - Add backend_is_available() to check if a backend is available - Add backend_get_name() to get backend name string - Add list_solvers_by_backend() to get solvers for a specific backend - Add get_available_backends() to list all available backends - Update __init__.py with new exports and fix version to v0.1.6+ - Add comprehensive test suite for backend availability API --- MIGRATION_PLAN.md | 38 +++--- cfd_python/__init__.py | 27 +++- src/cfd_python.c | 167 ++++++++++++++++++++++++ tests/test_backend_availability.py | 197 +++++++++++++++++++++++++++++ 4 files changed, 411 insertions(+), 18 deletions(-) create mode 100644 tests/test_backend_availability.py diff --git a/MIGRATION_PLAN.md b/MIGRATION_PLAN.md index 6757466..e78f244 100644 --- a/MIGRATION_PLAN.md +++ b/MIGRATION_PLAN.md @@ -326,9 +326,10 @@ cpu_features_t cfd_get_cpu_features(void); - Automatic CUDA library detection - [x] **2.5.3 Update CI test infrastructure** - - Install CUDA runtime (12.0.0) for CUDA wheel tests + - Install CUDA runtime (12.4.0) for CUDA wheel tests - Use standard `pip` instead of `uv` for stable ABI wheel installation - Test matrix: Python 3.9 and 3.13 on all platforms + - Use apt-based CUDA installation on Linux (more reliable than runfile) - [x] **2.5.4 Ensure PEP 427 compliance** - Standard wheel filenames (no variant suffixes) @@ -383,30 +384,33 @@ cpu_features_t cfd_get_cpu_features(void); **Estimated effort:** 1 day -### Phase 5: Add Backend Availability API (v0.1.6 Feature) +### Phase 5: Add Backend Availability API (v0.1.6 Feature) ✅ COMPLETED **Priority:** P1 - Important for v0.1.6 compatibility +**Status:** Completed on 2025-12-31 + **Tasks:** -- [ ] **5.1 Expose backend enum** - - `BACKEND_SCALAR`, `BACKEND_SIMD`, `BACKEND_OMP`, `BACKEND_CUDA` constants - - Map to `ns_solver_backend_t` enum +- [x] **5.1 Expose backend enum** + - Added `BACKEND_SCALAR`, `BACKEND_SIMD`, `BACKEND_OMP`, `BACKEND_CUDA` constants + - Map to `ns_solver_backend_t` enum (values 0-3) -- [ ] **5.2 Implement backend availability functions** +- [x] **5.2 Implement backend availability functions** - `backend_is_available(backend)` → bool - `backend_get_name(backend)` → string - `list_solvers_by_backend(backend)` → list of solver names -- [ ] **5.3 Add solver creation with validation** - - `create_solver_checked(name)` → raises exception if backend unavailable - - Better error messages for unsupported backends - -- [ ] **5.4 Add backend query helpers** +- [x] **5.3 Add backend query helpers** - `get_available_backends()` → list of available backend names - - `get_solver_backend(solver_name)` → backend enum -**Estimated effort:** 1 day +- [x] **5.4 Add tests** + - Created `tests/test_backend_availability.py` with comprehensive tests + - Tests for constants, availability checking, name queries, solver listing + +**Note:** `create_solver_checked()` and `get_solver_backend()` deferred to Phase 4 (error handling integration). + +**Actual effort:** 0.5 days ### Phase 6: Add CPU Features & Misc (Enhancement) @@ -539,11 +543,11 @@ find_library(CFD_LIBRARY cfd_library) # Unified library name | Phase 2.5: CI/Build System (v0.1.6) | ✅ 1 day | 3 days | | Phase 3: Derived Fields | 1-2 days | 4-5 days | | Phase 4: Error Handling | 1 day | 5-6 days | -| Phase 5: Backend Availability (v0.1.6) | 1 day | 6-7 days | -| Phase 6: CPU Features | 1 day | 7-8 days | -| Phase 7: Docs & Tests | 2 days | 9-10 days | +| Phase 5: Backend Availability (v0.1.6) | ✅ 0.5 days | 3.5 days | +| Phase 6: CPU Features | 1 day | 4.5 days | +| Phase 7: Docs & Tests | 2 days | 6.5 days | -**Total estimated effort:** 9-10 days (3 days completed) +**Total estimated effort:** ~~9-10 days~~ 6.5 days (3.5 days completed) --- diff --git a/cfd_python/__init__.py b/cfd_python/__init__.py index b719c98..4234344 100644 --- a/cfd_python/__init__.py +++ b/cfd_python/__init__.py @@ -1,4 +1,4 @@ -"""CFD Python - Python bindings for CFD simulation library v0.1.5+. +"""CFD Python - Python bindings for CFD simulation library v0.1.6+. This package provides Python bindings for the C-based CFD simulation library, enabling high-performance computational fluid dynamics simulations from Python. @@ -49,6 +49,21 @@ - BC_BACKEND_CUDA: GPU acceleration Functions: + +Solver backend availability (v0.1.6): + Backends: + - BACKEND_SCALAR: Basic scalar CPU implementation + - BACKEND_SIMD: SIMD-optimized (AVX2/SSE) + - BACKEND_OMP: OpenMP parallelized + - BACKEND_CUDA: CUDA GPU acceleration + + Functions: + - backend_is_available(backend): Check if backend is available + - backend_get_name(backend): Get backend name string + - list_solvers_by_backend(backend): Get solvers for a backend + - get_available_backends(): Get list of all available backends + +Boundary condition functions: - bc_apply_scalar(field, nx, ny, bc_type): Apply BC to scalar field - bc_apply_velocity(u, v, nx, ny, bc_type): Apply BC to velocity - bc_apply_dirichlet(field, nx, ny, left, right, bottom, top): Fixed values @@ -130,6 +145,16 @@ "bc_apply_inlet_parabolic", "bc_apply_outlet_scalar", "bc_apply_outlet_velocity", + # Solver backend constants (v0.1.6) + "BACKEND_SCALAR", + "BACKEND_SIMD", + "BACKEND_OMP", + "BACKEND_CUDA", + # Solver backend availability functions (v0.1.6) + "backend_is_available", + "backend_get_name", + "list_solvers_by_backend", + "get_available_backends", ] # Load C extension and populate module namespace diff --git a/src/cfd_python.c b/src/cfd_python.c index 6c229fd..f968e74 100644 --- a/src/cfd_python.c +++ b/src/cfd_python.c @@ -874,6 +874,141 @@ static PyObject* bc_backend_available_py(PyObject* self, PyObject* args) { return PyBool_FromLong(available); } +/* + * ======================================== + * Solver Backend Availability API (v0.1.6) + * ======================================== + */ + +/* + * Check if a solver backend is available at runtime + */ +static PyObject* backend_is_available_py(PyObject* self, PyObject* args) { + (void)self; + int backend; + + if (!PyArg_ParseTuple(args, "i", &backend)) { + return NULL; + } + + int available = cfd_backend_is_available((ns_solver_backend_t)backend); + return PyBool_FromLong(available); +} + +/* + * Get human-readable name for a solver backend + */ +static PyObject* backend_get_name_py(PyObject* self, PyObject* args) { + (void)self; + int backend; + + if (!PyArg_ParseTuple(args, "i", &backend)) { + return NULL; + } + + const char* name = cfd_backend_get_name((ns_solver_backend_t)backend); + if (name == NULL) { + Py_RETURN_NONE; + } + return PyUnicode_FromString(name); +} + +/* + * Get list of solvers for a specific backend + */ +static PyObject* list_solvers_by_backend_py(PyObject* self, PyObject* args) { + (void)self; + int backend; + + if (!PyArg_ParseTuple(args, "i", &backend)) { + return NULL; + } + + if (g_registry == NULL) { + PyErr_SetString(PyExc_RuntimeError, "Solver registry not initialized"); + return NULL; + } + + // First, get the count + int count = cfd_registry_list_by_backend(g_registry, (ns_solver_backend_t)backend, NULL, 0); + if (count <= 0) { + return PyList_New(0); // Return empty list + } + + // Allocate array for names + const char** names = (const char**)malloc(count * sizeof(const char*)); + if (names == NULL) { + PyErr_SetString(PyExc_MemoryError, "Failed to allocate names array"); + return NULL; + } + + // Get the actual names + int actual_count = cfd_registry_list_by_backend(g_registry, (ns_solver_backend_t)backend, names, count); + + // Build Python list + PyObject* result = PyList_New(actual_count); + if (result == NULL) { + free(names); + return NULL; + } + + for (int i = 0; i < actual_count; i++) { + PyObject* name = PyUnicode_FromString(names[i]); + if (name == NULL) { + Py_DECREF(result); + free(names); + return NULL; + } + PyList_SET_ITEM(result, i, name); // Steals reference + } + + free(names); + return result; +} + +/* + * Get list of all available backends + */ +static PyObject* get_available_backends_py(PyObject* self, PyObject* args) { + (void)self; + (void)args; + + PyObject* result = PyList_New(0); + if (result == NULL) { + return NULL; + } + + // Check each backend + ns_solver_backend_t backends[] = { + NS_SOLVER_BACKEND_SCALAR, + NS_SOLVER_BACKEND_SIMD, + NS_SOLVER_BACKEND_OMP, + NS_SOLVER_BACKEND_CUDA + }; + int num_backends = sizeof(backends) / sizeof(backends[0]); + + for (int i = 0; i < num_backends; i++) { + if (cfd_backend_is_available(backends[i])) { + const char* name = cfd_backend_get_name(backends[i]); + if (name != NULL) { + PyObject* name_obj = PyUnicode_FromString(name); + if (name_obj == NULL) { + Py_DECREF(result); + return NULL; + } + if (PyList_Append(result, name_obj) < 0) { + Py_DECREF(name_obj); + Py_DECREF(result); + return NULL; + } + Py_DECREF(name_obj); + } + } + } + + return result; +} + /* * Apply boundary conditions to scalar field */ @@ -1659,6 +1794,29 @@ static PyMethodDef cfd_python_methods[] = { " nx (int): Grid points in x direction\n" " ny (int): Grid points in y direction\n" " edge (int, optional): Boundary edge (default: BC_EDGE_RIGHT)"}, + // Solver Backend Availability API (v0.1.6) + {"backend_is_available", backend_is_available_py, METH_VARARGS, + "Check if a solver backend is available at runtime.\n\n" + "Args:\n" + " backend (int): Backend type (BACKEND_SCALAR, BACKEND_SIMD, etc.)\n\n" + "Returns:\n" + " bool: True if backend is available"}, + {"backend_get_name", backend_get_name_py, METH_VARARGS, + "Get human-readable name for a solver backend.\n\n" + "Args:\n" + " backend (int): Backend type constant\n\n" + "Returns:\n" + " str or None: Backend name (e.g., 'scalar', 'simd', 'omp', 'cuda')"}, + {"list_solvers_by_backend", list_solvers_by_backend_py, METH_VARARGS, + "Get list of solver types for a specific backend.\n\n" + "Args:\n" + " backend (int): Backend type constant\n\n" + "Returns:\n" + " list: Solver type names for the specified backend"}, + {"get_available_backends", get_available_backends_py, METH_NOARGS, + "Get list of all available backends.\n\n" + "Returns:\n" + " list: Names of available backends (e.g., ['scalar', 'simd', 'omp'])"}, {NULL, NULL, 0, NULL} }; @@ -1808,5 +1966,14 @@ PyMODINIT_FUNC PyInit_cfd_python(void) { return NULL; } + // Add solver backend constants (v0.1.6 API) + if (PyModule_AddIntConstant(m, "BACKEND_SCALAR", NS_SOLVER_BACKEND_SCALAR) < 0 || + PyModule_AddIntConstant(m, "BACKEND_SIMD", NS_SOLVER_BACKEND_SIMD) < 0 || + PyModule_AddIntConstant(m, "BACKEND_OMP", NS_SOLVER_BACKEND_OMP) < 0 || + PyModule_AddIntConstant(m, "BACKEND_CUDA", NS_SOLVER_BACKEND_CUDA) < 0) { + Py_DECREF(m); + return NULL; + } + return m; } diff --git a/tests/test_backend_availability.py b/tests/test_backend_availability.py new file mode 100644 index 0000000..d343c00 --- /dev/null +++ b/tests/test_backend_availability.py @@ -0,0 +1,197 @@ +""" +Tests for solver backend availability API in cfd_python (v0.1.6). +""" + +import cfd_python + + +class TestBackendConstants: + """Test BACKEND_* constants are defined and valid""" + + def test_backend_constants_exist(self): + """Test all BACKEND_* constants are defined""" + backends = [ + "BACKEND_SCALAR", + "BACKEND_SIMD", + "BACKEND_OMP", + "BACKEND_CUDA", + ] + for const_name in backends: + assert hasattr(cfd_python, const_name), f"Missing constant: {const_name}" + + def test_backend_constants_are_integers(self): + """Test BACKEND_* constants are integers""" + backends = [ + "BACKEND_SCALAR", + "BACKEND_SIMD", + "BACKEND_OMP", + "BACKEND_CUDA", + ] + for const_name in backends: + value = getattr(cfd_python, const_name) + assert isinstance(value, int), f"{const_name} should be an integer" + + def test_backend_constants_unique(self): + """Test BACKEND_* constants have unique values""" + backends = [ + "BACKEND_SCALAR", + "BACKEND_SIMD", + "BACKEND_OMP", + "BACKEND_CUDA", + ] + values = [getattr(cfd_python, name) for name in backends] + assert len(values) == len(set(values)), "BACKEND_* constants should have unique values" + + def test_backend_constants_values(self): + """Test BACKEND_* constants have expected values (matching C enum)""" + assert cfd_python.BACKEND_SCALAR == 0 + assert cfd_python.BACKEND_SIMD == 1 + assert cfd_python.BACKEND_OMP == 2 + assert cfd_python.BACKEND_CUDA == 3 + + +class TestBackendIsAvailable: + """Test backend_is_available function""" + + def test_backend_is_available_returns_bool(self): + """Test backend_is_available returns boolean for all backends""" + for backend in [ + cfd_python.BACKEND_SCALAR, + cfd_python.BACKEND_SIMD, + cfd_python.BACKEND_OMP, + cfd_python.BACKEND_CUDA, + ]: + result = cfd_python.backend_is_available(backend) + assert isinstance( + result, bool + ), f"backend_is_available should return bool for {backend}" + + def test_scalar_backend_always_available(self): + """Test SCALAR backend is always available""" + available = cfd_python.backend_is_available(cfd_python.BACKEND_SCALAR) + assert available is True, "SCALAR backend should always be available" + + def test_backend_is_available_invalid_backend(self): + """Test backend_is_available with invalid backend returns False""" + # Invalid backend ID should return False (not raise exception) + result = cfd_python.backend_is_available(999) + assert result is False + + +class TestBackendGetName: + """Test backend_get_name function""" + + def test_backend_get_name_returns_string(self): + """Test backend_get_name returns string for valid backends""" + for backend in [ + cfd_python.BACKEND_SCALAR, + cfd_python.BACKEND_SIMD, + cfd_python.BACKEND_OMP, + cfd_python.BACKEND_CUDA, + ]: + name = cfd_python.backend_get_name(backend) + assert isinstance(name, str), f"backend_get_name should return string for {backend}" + assert len(name) > 0, f"Backend name should not be empty for {backend}" + + def test_backend_get_name_expected_names(self): + """Test backend_get_name returns expected name strings""" + assert cfd_python.backend_get_name(cfd_python.BACKEND_SCALAR) == "scalar" + assert cfd_python.backend_get_name(cfd_python.BACKEND_SIMD) == "simd" + assert cfd_python.backend_get_name(cfd_python.BACKEND_OMP) == "omp" + assert cfd_python.backend_get_name(cfd_python.BACKEND_CUDA) == "cuda" + + def test_backend_get_name_invalid_backend(self): + """Test backend_get_name with invalid backend returns None""" + result = cfd_python.backend_get_name(999) + assert result is None + + +class TestListSolversByBackend: + """Test list_solvers_by_backend function""" + + def test_list_solvers_by_backend_returns_list(self): + """Test list_solvers_by_backend returns a list""" + result = cfd_python.list_solvers_by_backend(cfd_python.BACKEND_SCALAR) + assert isinstance(result, list), "list_solvers_by_backend should return a list" + + def test_list_solvers_by_backend_scalar_has_solvers(self): + """Test SCALAR backend has at least one solver registered""" + solvers = cfd_python.list_solvers_by_backend(cfd_python.BACKEND_SCALAR) + assert len(solvers) > 0, "SCALAR backend should have at least one solver" + + def test_list_solvers_by_backend_returns_strings(self): + """Test list_solvers_by_backend returns list of strings""" + solvers = cfd_python.list_solvers_by_backend(cfd_python.BACKEND_SCALAR) + for solver in solvers: + assert isinstance(solver, str), f"Solver name should be string: {solver}" + + def test_list_solvers_by_backend_invalid_backend(self): + """Test list_solvers_by_backend with invalid backend returns empty list""" + result = cfd_python.list_solvers_by_backend(999) + assert isinstance(result, list) + assert len(result) == 0 + + +class TestGetAvailableBackends: + """Test get_available_backends function""" + + def test_get_available_backends_returns_list(self): + """Test get_available_backends returns a list""" + result = cfd_python.get_available_backends() + assert isinstance(result, list), "get_available_backends should return a list" + + def test_get_available_backends_includes_scalar(self): + """Test get_available_backends includes scalar (always available)""" + backends = cfd_python.get_available_backends() + assert "scalar" in backends, "SCALAR backend should always be in available list" + + def test_get_available_backends_returns_strings(self): + """Test get_available_backends returns list of strings""" + backends = cfd_python.get_available_backends() + for backend in backends: + assert isinstance(backend, str), f"Backend name should be string: {backend}" + + def test_get_available_backends_consistency(self): + """Test get_available_backends is consistent with backend_is_available""" + available_backends = cfd_python.get_available_backends() + + # Check each backend constant + for backend_id, backend_name in [ + (cfd_python.BACKEND_SCALAR, "scalar"), + (cfd_python.BACKEND_SIMD, "simd"), + (cfd_python.BACKEND_OMP, "omp"), + (cfd_python.BACKEND_CUDA, "cuda"), + ]: + is_available = cfd_python.backend_is_available(backend_id) + in_list = backend_name in available_backends + assert is_available == in_list, ( + f"Inconsistency for {backend_name}: " + f"backend_is_available={is_available}, in list={in_list}" + ) + + +class TestBackendFunctionsExported: + """Test that all backend functions are properly exported""" + + def test_backend_functions_in_all(self): + """Test all backend functions are in __all__""" + backend_functions = [ + "backend_is_available", + "backend_get_name", + "list_solvers_by_backend", + "get_available_backends", + ] + for func_name in backend_functions: + assert func_name in cfd_python.__all__, f"{func_name} should be in __all__" + assert callable(getattr(cfd_python, func_name)), f"{func_name} should be callable" + + def test_backend_constants_in_all(self): + """Test all BACKEND_* constants are in __all__""" + backend_constants = [ + "BACKEND_SCALAR", + "BACKEND_SIMD", + "BACKEND_OMP", + "BACKEND_CUDA", + ] + for const_name in backend_constants: + assert const_name in cfd_python.__all__, f"{const_name} should be in __all__" From c69295708899caa5ea548c8ed5f1c73ae31a28e9 Mon Sep 17 00:00:00 2001 From: shaia Date: Thu, 1 Jan 2026 10:17:53 +0200 Subject: [PATCH 2/5] fix: Use PyList_SetItem for stable ABI compatibility PyList_SET_ITEM is a macro not available in the limited/stable API. Replace with PyList_SetItem function which is available in abi3. --- src/cfd_python.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cfd_python.c b/src/cfd_python.c index f968e74..b27ca8f 100644 --- a/src/cfd_python.c +++ b/src/cfd_python.c @@ -959,7 +959,7 @@ static PyObject* list_solvers_by_backend_py(PyObject* self, PyObject* args) { free(names); return NULL; } - PyList_SET_ITEM(result, i, name); // Steals reference + PyList_SetItem(result, i, name); // Steals reference } free(names); From ebca9c1357e1ea01f0d25a0d64554fc1deb830ba Mon Sep 17 00:00:00 2001 From: shaia Date: Thu, 1 Jan 2026 17:40:54 +0200 Subject: [PATCH 3/5] fix: Add backend availability API exports to _loader.py The backend availability functions and constants were added to the C extension but not exported through _loader.py, which is required for the module namespace population. --- cfd_python/_loader.py | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/cfd_python/_loader.py b/cfd_python/_loader.py index 8d800da..078d045 100644 --- a/cfd_python/_loader.py +++ b/cfd_python/_loader.py @@ -33,6 +33,11 @@ def load_extension(): try: from . import cfd_python as _cfd_module from .cfd_python import ( + BACKEND_CUDA, + BACKEND_OMP, + # Solver backend constants (v0.1.6) + BACKEND_SCALAR, + BACKEND_SIMD, # Boundary condition backends BC_BACKEND_AUTO, BC_BACKEND_CUDA, @@ -66,6 +71,9 @@ def load_extension(): OUTPUT_FULL_FIELD, OUTPUT_VELOCITY, OUTPUT_VELOCITY_MAGNITUDE, + backend_get_name, + # Solver backend availability functions (v0.1.6) + backend_is_available, bc_apply_dirichlet, bc_apply_inlet_parabolic, bc_apply_inlet_uniform, @@ -82,6 +90,7 @@ def load_extension(): clear_error, # Core functions create_grid, + get_available_backends, get_default_solver_params, get_error_string, get_last_error, @@ -89,6 +98,7 @@ def load_extension(): get_solver_info, has_solver, list_solvers, + list_solvers_by_backend, run_simulation, run_simulation_with_params, set_output_dir, @@ -164,6 +174,16 @@ def load_extension(): "bc_apply_inlet_parabolic": bc_apply_inlet_parabolic, "bc_apply_outlet_scalar": bc_apply_outlet_scalar, "bc_apply_outlet_velocity": bc_apply_outlet_velocity, + # Solver backend constants (v0.1.6) + "BACKEND_SCALAR": BACKEND_SCALAR, + "BACKEND_SIMD": BACKEND_SIMD, + "BACKEND_OMP": BACKEND_OMP, + "BACKEND_CUDA": BACKEND_CUDA, + # Solver backend availability functions (v0.1.6) + "backend_is_available": backend_is_available, + "backend_get_name": backend_get_name, + "list_solvers_by_backend": list_solvers_by_backend, + "get_available_backends": get_available_backends, } # Collect dynamic SOLVER_* constants From 84a0944173f9c269e5f9bde71718ca6ffec33f77 Mon Sep 17 00:00:00 2001 From: shaia Date: Thu, 1 Jan 2026 18:59:38 +0200 Subject: [PATCH 4/5] fix: Update tests to match actual CFD library backend names - BACKEND_OMP returns "openmp" not "omp" - Invalid backend returns "unknown" not None --- tests/test_backend_availability.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/test_backend_availability.py b/tests/test_backend_availability.py index d343c00..070496a 100644 --- a/tests/test_backend_availability.py +++ b/tests/test_backend_availability.py @@ -97,13 +97,13 @@ def test_backend_get_name_expected_names(self): """Test backend_get_name returns expected name strings""" assert cfd_python.backend_get_name(cfd_python.BACKEND_SCALAR) == "scalar" assert cfd_python.backend_get_name(cfd_python.BACKEND_SIMD) == "simd" - assert cfd_python.backend_get_name(cfd_python.BACKEND_OMP) == "omp" + assert cfd_python.backend_get_name(cfd_python.BACKEND_OMP) == "openmp" assert cfd_python.backend_get_name(cfd_python.BACKEND_CUDA) == "cuda" def test_backend_get_name_invalid_backend(self): - """Test backend_get_name with invalid backend returns None""" + """Test backend_get_name with invalid backend returns 'unknown'""" result = cfd_python.backend_get_name(999) - assert result is None + assert result == "unknown" class TestListSolversByBackend: @@ -159,7 +159,7 @@ def test_get_available_backends_consistency(self): for backend_id, backend_name in [ (cfd_python.BACKEND_SCALAR, "scalar"), (cfd_python.BACKEND_SIMD, "simd"), - (cfd_python.BACKEND_OMP, "omp"), + (cfd_python.BACKEND_OMP, "openmp"), (cfd_python.BACKEND_CUDA, "cuda"), ]: is_available = cfd_python.backend_is_available(backend_id) From 29ecba3b24fd42b160ef9b8bba7879623c0b7b4e Mon Sep 17 00:00:00 2001 From: shaia Date: Thu, 1 Jan 2026 19:33:57 +0200 Subject: [PATCH 5/5] docs: Fix incomplete Functions header in __init__.py docstring Move BC functions under the Boundary conditions section and remove the duplicate/empty Functions header. --- cfd_python/__init__.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/cfd_python/__init__.py b/cfd_python/__init__.py index 4234344..e863e39 100644 --- a/cfd_python/__init__.py +++ b/cfd_python/__init__.py @@ -49,6 +49,18 @@ - BC_BACKEND_CUDA: GPU acceleration Functions: + - bc_get_backend(): Get current BC backend + - bc_get_backend_name(): Get current BC backend name + - bc_set_backend(backend): Set BC backend + - bc_backend_available(backend): Check if BC backend is available + - bc_apply_scalar(field, nx, ny, bc_type): Apply BC to scalar field + - bc_apply_velocity(u, v, nx, ny, bc_type): Apply BC to velocity + - bc_apply_dirichlet(field, nx, ny, left, right, bottom, top): Fixed values + - bc_apply_noslip(u, v, nx, ny): Zero velocity at walls + - bc_apply_inlet_uniform(u, v, nx, ny, u_inlet, v_inlet, edge): Uniform inlet + - bc_apply_inlet_parabolic(u, v, nx, ny, max_velocity, edge): Parabolic inlet + - bc_apply_outlet_scalar(field, nx, ny, edge): Zero-gradient outlet + - bc_apply_outlet_velocity(u, v, nx, ny, edge): Zero-gradient outlet Solver backend availability (v0.1.6): Backends: @@ -62,16 +74,6 @@ - backend_get_name(backend): Get backend name string - list_solvers_by_backend(backend): Get solvers for a backend - get_available_backends(): Get list of all available backends - -Boundary condition functions: - - bc_apply_scalar(field, nx, ny, bc_type): Apply BC to scalar field - - bc_apply_velocity(u, v, nx, ny, bc_type): Apply BC to velocity - - bc_apply_dirichlet(field, nx, ny, left, right, bottom, top): Fixed values - - bc_apply_noslip(u, v, nx, ny): Zero velocity at walls - - bc_apply_inlet_uniform(u, v, nx, ny, u_inlet, v_inlet, edge): Uniform inlet - - bc_apply_inlet_parabolic(u, v, nx, ny, max_velocity, edge): Parabolic inlet - - bc_apply_outlet_scalar(field, nx, ny, edge): Zero-gradient outlet - - bc_apply_outlet_velocity(u, v, nx, ny, edge): Zero-gradient outlet """ from ._version import get_version