From 1f858ef35b07a9b9ab28482f4e2fb76cd5831971 Mon Sep 17 00:00:00 2001 From: filipovic Date: Tue, 9 Dec 2025 12:57:49 +0100 Subject: [PATCH 01/38] Added removeMaterial info when removing top LS layer --- include/viennaps/psDomain.hpp | 6 +----- include/viennaps/psMaterials.hpp | 6 ++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index e1509113..2a6b7e9e 100644 --- a/include/viennaps/psDomain.hpp +++ b/include/viennaps/psDomain.hpp @@ -234,11 +234,7 @@ template class Domain { levelSets_.pop_back(); if (materialMap_) { - auto newMatMap = MaterialMapType::New(); - for (std::size_t i = 0; i < levelSets_.size(); i++) { - newMatMap->insertNextMaterial(materialMap_->getMaterialAtIdx(i)); - } - materialMap_ = newMatMap; + materialMap_->removeMaterial(); } } diff --git a/include/viennaps/psMaterials.hpp b/include/viennaps/psMaterials.hpp index 4a2f3ccc..3b3af1ef 100644 --- a/include/viennaps/psMaterials.hpp +++ b/include/viennaps/psMaterials.hpp @@ -182,6 +182,12 @@ class MaterialMap { map_->insertNextMaterial(static_cast(material)); } + void removeMaterial() { + if (map_) { + map_->removeLastMaterial(); + } + } + // Returns the material at the given index. If the index is out of bounds, it // returns Material::GAS. [[nodiscard]] Material getMaterialAtIdx(std::size_t idx) const { From bd89def6ee7af3a8a72a04f2959ad2af0a2c6ab4 Mon Sep 17 00:00:00 2001 From: filipovic Date: Wed, 10 Dec 2025 03:02:47 +0100 Subject: [PATCH 02/38] Added WENO 5th order advection scheme --- .../viennaps/process/psAdvectionHandler.hpp | 3 +- include/viennaps/psUtil.hpp | 7 +- python/scripts/install_ViennaPS_linux.py | 182 ++++++++---------- tests/util/testUtil.cpp | 6 + 4 files changed, 92 insertions(+), 106 deletions(-) diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index eeafc703..cb69d42f 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -29,7 +29,8 @@ template class AdvectionHandler { (intSchem != IntegrationScheme::ENGQUIST_OSHER_1ST_ORDER && intSchem != IntegrationScheme::ENGQUIST_OSHER_2ND_ORDER && intSchem != IntegrationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER && - intSchem != IntegrationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER)) { + intSchem != IntegrationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER && + intSchem != IntegrationScheme::WENO_5TH_ORDER)) { VIENNACORE_LOG_WARNING( "Translation field method not supported in combination " "with integration scheme."); diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index 5e9bd1e0..e50e55e1 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -36,6 +36,8 @@ convertIntegrationScheme(const std::string &s) { if (s == "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER" || s == "SLLF_1") return viennals::IntegrationSchemeEnum:: STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + if (s == "WENO_5TH_ORDER" || s == "WENO_5") + return viennals::IntegrationSchemeEnum::WENO_5TH_ORDER; throw std::invalid_argument( "The value must be one of the following: " "ENGQUIST_OSHER_1ST_ORDER, ENGQUIST_OSHER_2ND_ORDER, " @@ -45,7 +47,8 @@ convertIntegrationScheme(const std::string &s) { "LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER, " "LOCAL_LAX_FRIEDRICHS_1ST_ORDER, " "LOCAL_LAX_FRIEDRICHS_2ND_ORDER, " - "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER"); + "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER, " + "WENO_5TH_ORDER"); } [[nodiscard]] inline std::string @@ -72,6 +75,8 @@ convertIntegrationSchemeToString(viennals::IntegrationSchemeEnum scheme) { return "LOCAL_LAX_FRIEDRICHS_2ND_ORDER"; case viennals::IntegrationSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: return "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER"; + case viennals::IntegrationSchemeEnum::WENO_5TH_ORDER: + return "WENO_5TH_ORDER"; default: throw std::invalid_argument("Unknown integration scheme."); } diff --git a/python/scripts/install_ViennaPS_linux.py b/python/scripts/install_ViennaPS_linux.py index bf588325..69020f6c 100644 --- a/python/scripts/install_ViennaPS_linux.py +++ b/python/scripts/install_ViennaPS_linux.py @@ -9,8 +9,8 @@ REQUIRED_GCC = "12" REQUIRED_NVCC_MAJOR = 12 -DEFAULT_VIENNALS_VERSION = "5.2.0" - +# UPDATED: Pointing to local directory instead of git URL +VIENNALS_LOCAL_PATH = "/home/filipov/Software/GPU/ViennaLS" def run(cmd, **kwargs): print("+", " ".join(cmd)) @@ -46,10 +46,6 @@ def parse_nvcc_version(): sys.exit("Could not parse nvcc version. Need CUDA >= 12.0.") -def ensure_git(): - which_or_fail("git") - - def ensure_compilers(): which_or_fail(f"gcc-{REQUIRED_GCC}") which_or_fail(f"g++-{REQUIRED_GCC}") @@ -78,65 +74,49 @@ def venv_paths(venv_dir: Path): return python, pip -def pip_show_version(pip_path: Path, pkg: str): - try: - out = run_capture([str(pip_path), "show", pkg]) - except subprocess.CalledProcessError: - return None - for line in out.splitlines(): - if line.startswith("Version:"): - return line.split(":", 1)[1].strip() - return None - - -def install_viennals( - pip_path: Path, viennals_dir: Path | None, required_version: str, verbose: bool -): +def install_build_deps(pip_path: Path): + """ + Installs build dependencies required for --no-build-isolation. + """ + print("Installing build dependencies (scikit-build-core, pybind11, cmake, ninja)...") + run([ + str(pip_path), + "install", + "scikit-build-core", + "pybind11", + "cmake", + "ninja", + "pathspec", + "packaging" + ]) + + +def install_viennals(pip_path: Path, verbose: bool): + """ + Installs ViennaLS directly from the local directory using pip. + """ env = os.environ.copy() env["CC"] = f"gcc-{REQUIRED_GCC}" env["CXX"] = f"g++-{REQUIRED_GCC}" - current = pip_show_version(pip_path, "ViennaLS") - if current is None: - print("ViennaLS not installed. A local build is required.") - if viennals_dir is None: - ensure_git() - print(f"Cloning ViennaLS v{required_version}โ€ฆ") - with tempfile.TemporaryDirectory(prefix="ViennaLS_tmp_install_") as tmp: - tmp_path = Path(tmp) - run( - [ - "git", - "clone", - "https://github.com/ViennaTools/ViennaLS.git", - str(tmp_path), - ], - env=env, - ) - run(["git", "checkout", f"v{required_version}"], cwd=tmp_path, env=env) - cmd = [str(pip_path), "install", "."] - if verbose: - cmd.append("-v") - run(cmd, cwd=tmp_path, env=env) - else: - if not ( - viennals_dir.exists() and (viennals_dir / "CMakeLists.txt").exists() - ): - sys.exit(f"ViennaLS directory not valid: {viennals_dir}") - cmd = [str(pip_path), "install", "."] - if verbose: - cmd.append("-v") - run(cmd, cwd=viennals_dir, env=env) - else: - print( - f"ViennaLS already installed ({current}). Local build is required and version should be {required_version}." - ) - if current != required_version: - sys.exit( - f"Version mismatch. Please change to the required version {required_version}.\n" - "Then re-run this script." - ) - print("Proceeding with the currently installed ViennaLS.") + print(f"Installing ViennaLS from: {VIENNALS_LOCAL_PATH}") + + # Use pip to handle the install logic internally. + # --no-build-isolation ensures it uses the build deps we just installed. + # --force-reinstall ensuring we overwrite any old versions. + cmd = [ + str(pip_path), + "install", + VIENNALS_LOCAL_PATH, + "--force-reinstall", + "--no-cache-dir", + "--no-build-isolation", + ] + + if verbose: + cmd.append("-v") + + run(cmd, env=env) def get_viennaps_dir(viennaps_dir_arg: str | None) -> Path: @@ -147,7 +127,6 @@ def get_viennaps_dir(viennaps_dir_arg: str | None) -> Path: if cwd.name == "ViennaPS": viennaps_dir = cwd else: - # try location of this script script_path = Path(__file__).resolve() cwd = script_path.parent.parent if cwd.name == "ViennaPS": @@ -179,14 +158,22 @@ def install_viennaps( sys.exit( f"{viennaps_dir} does not look like a ViennaPS source directory (missing CMakeLists.txt)." ) + + # # --- CRITICAL FIX: Clean Build Directory --- + # # This prevents the "poisoned cache" issue where CMake remembers the old ViennaLS path. + # build_dir = viennaps_dir / "build" + # if build_dir.exists(): + # print(f"Removing dirty build directory: {build_dir}") + # shutil.rmtree(build_dir) + # ------------------------------------------- + env = os.environ.copy() env["CC"] = f"gcc-{REQUIRED_GCC}" env["CXX"] = f"g++-{REQUIRED_GCC}" - # GPU on cmake_args = [] if gpu_build: - cmake_args = ["-DVIENNAPS_USE_GPU=ON"] + cmake_args.append("-DVIENNAPS_USE_GPU=ON") if debug_build: print("Enabling debug build.") @@ -196,10 +183,20 @@ def install_viennaps( if optix_dir is not None: env["OptiX_INSTALL_DIR"] = str(optix_dir) - env["CMAKE_ARGS"] = " ".join(cmake_args) - cmd = [str(pip_path), "install", "."] + if cmake_args: + env["CMAKE_ARGS"] = " ".join(cmake_args) + + cmd = [ + str(pip_path), + "install", + ".", + "--force-reinstall", + "--no-cache-dir", + "--no-build-isolation" + ] if verbose: cmd.append("-v") + run(cmd, cwd=viennaps_dir, env=env) @@ -213,16 +210,10 @@ def main(): parser.add_argument( "--venv", default=".venv", help="Path to the virtual environment directory." ) - parser.add_argument( - "--viennals-dir", - default=None, - help="Path to a local ViennaLS checkout (optional).", - ) - parser.add_argument( - "--viennals-version", - default=DEFAULT_VIENNALS_VERSION, - help="ViennaLS version tag to use if cloning.", - ) + # These args are ignored now as we force the local path, but kept for compatibility + parser.add_argument("--viennals-dir", default=None, help="Ignored: Using local path.") + parser.add_argument("--viennals-version", default=None, help="Ignored: Using local path.") + parser.add_argument( "--viennaps-dir", default=None, @@ -231,7 +222,7 @@ def main(): parser.add_argument( "--optix", default=None, - help="Path to OptiX installation directory (optional - will auto-download OptiX headers if not provided).", + help="Path to OptiX installation directory (optional).", ) parser.add_argument( "--debug-build", @@ -241,7 +232,7 @@ def main(): parser.add_argument( "--skip-toolchain-check", action="store_true", - help="Skip checking for required compilers and CUDA (use with caution).", + help="Skip checking for required compilers and CUDA.", ) parser.add_argument( "--no-gpu", @@ -255,20 +246,10 @@ def main(): ensure_compilers() ensure_cuda() - # OptiX dir if not args.no_gpu: optix_dir = args.optix or os.environ.get("OptiX_INSTALL_DIR") if not optix_dir: print("No OptiX directory provided. Will auto-download OptiX headers.") - print("\nWARNING: OptiX uses a different license than ViennaPS.") - print( - "By proceeding with auto-download, you agree to the NVIDIA OptiX license terms." - ) - print( - "Please review the OptiX license at: https://developer.nvidia.com/designworks/sdk-samples-tools-software-license-agreement" - ) - print("If you do not agree, abort now (Ctrl+C).") - input("Press Enter to continue...") optix_dir = None else: optix_dir = Path(optix_dir).expanduser().resolve() @@ -283,11 +264,11 @@ def main(): create_or_reuse_venv(venv_dir) venv_python, venv_pip = venv_paths(venv_dir) - # ViennaLS - viennals_dir = ( - Path(args.viennals_dir).expanduser().resolve() if args.viennals_dir else None - ) - install_viennals(venv_pip, viennals_dir, args.viennals_version, args.verbose) + # 1. Install Build Dependencies + install_build_deps(venv_pip) + + # 2. Install ViennaLS from Local Path + install_viennals(venv_pip, args.verbose) # ViennaPS dir viennaps_dir = get_viennaps_dir(args.viennaps_dir) @@ -302,18 +283,11 @@ def main(): args.verbose, ) - # Final info - bindir = "Scripts" if os.name == "nt" else "bin" - activate_hint = ( - venv_dir / bindir / ("activate" if os.name != "nt" else "activate.bat") - ) print("\nInstallation complete.") - if os.name == "nt": - print(f"Activate the virtual environment:\n {activate_hint}") - else: - print(f"Activate the virtual environment:\n source {activate_hint}") - print("To deactivate:\n deactivate") + bindir = "Scripts" if os.name == "nt" else "bin" + activate_hint = venv_dir / bindir / ("activate" if os.name != "nt" else "activate.bat") + print(f"Activate: source {activate_hint}") if __name__ == "__main__": - main() + main() \ No newline at end of file diff --git a/tests/util/testUtil.cpp b/tests/util/testUtil.cpp index d5692c4f..61f1476c 100644 --- a/tests/util/testUtil.cpp +++ b/tests/util/testUtil.cpp @@ -11,6 +11,12 @@ void TestIntegrationSchemeConversion() { VC_TEST_ASSERT(convertIntegrationScheme("EO_1") == viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER); + // Test string to enum + VC_TEST_ASSERT(convertIntegrationScheme("WENO_5TH_ORDER") == + viennals::IntegrationSchemeEnum::WENO_5TH_ORDER); + VC_TEST_ASSERT(convertIntegrationScheme("WENO_5") == + viennals::IntegrationSchemeEnum::WENO_5TH_ORDER); + // Test enum to string VC_TEST_ASSERT( convertIntegrationSchemeToString( From 1b914232194cf951733ede7f24f46fa49c152bd4 Mon Sep 17 00:00:00 2001 From: filipovic Date: Wed, 10 Dec 2025 15:38:36 +0100 Subject: [PATCH 03/38] Reverted back to install script, with ViennaLS default version 5.2.1 --- python/scripts/install_ViennaPS_linux.py | 182 +++++++++++++---------- 1 file changed, 104 insertions(+), 78 deletions(-) diff --git a/python/scripts/install_ViennaPS_linux.py b/python/scripts/install_ViennaPS_linux.py index 69020f6c..87cc7611 100644 --- a/python/scripts/install_ViennaPS_linux.py +++ b/python/scripts/install_ViennaPS_linux.py @@ -9,8 +9,8 @@ REQUIRED_GCC = "12" REQUIRED_NVCC_MAJOR = 12 -# UPDATED: Pointing to local directory instead of git URL -VIENNALS_LOCAL_PATH = "/home/filipov/Software/GPU/ViennaLS" +DEFAULT_VIENNALS_VERSION = "5.2.1" + def run(cmd, **kwargs): print("+", " ".join(cmd)) @@ -46,6 +46,10 @@ def parse_nvcc_version(): sys.exit("Could not parse nvcc version. Need CUDA >= 12.0.") +def ensure_git(): + which_or_fail("git") + + def ensure_compilers(): which_or_fail(f"gcc-{REQUIRED_GCC}") which_or_fail(f"g++-{REQUIRED_GCC}") @@ -74,49 +78,65 @@ def venv_paths(venv_dir: Path): return python, pip -def install_build_deps(pip_path: Path): - """ - Installs build dependencies required for --no-build-isolation. - """ - print("Installing build dependencies (scikit-build-core, pybind11, cmake, ninja)...") - run([ - str(pip_path), - "install", - "scikit-build-core", - "pybind11", - "cmake", - "ninja", - "pathspec", - "packaging" - ]) - - -def install_viennals(pip_path: Path, verbose: bool): - """ - Installs ViennaLS directly from the local directory using pip. - """ +def pip_show_version(pip_path: Path, pkg: str): + try: + out = run_capture([str(pip_path), "show", pkg]) + except subprocess.CalledProcessError: + return None + for line in out.splitlines(): + if line.startswith("Version:"): + return line.split(":", 1)[1].strip() + return None + + +def install_viennals( + pip_path: Path, viennals_dir: Path | None, required_version: str, verbose: bool +): env = os.environ.copy() env["CC"] = f"gcc-{REQUIRED_GCC}" env["CXX"] = f"g++-{REQUIRED_GCC}" - print(f"Installing ViennaLS from: {VIENNALS_LOCAL_PATH}") - - # Use pip to handle the install logic internally. - # --no-build-isolation ensures it uses the build deps we just installed. - # --force-reinstall ensuring we overwrite any old versions. - cmd = [ - str(pip_path), - "install", - VIENNALS_LOCAL_PATH, - "--force-reinstall", - "--no-cache-dir", - "--no-build-isolation", - ] - - if verbose: - cmd.append("-v") - - run(cmd, env=env) + current = pip_show_version(pip_path, "ViennaLS") + if current is None: + print("ViennaLS not installed. A local build is required.") + if viennals_dir is None: + ensure_git() + print(f"Cloning ViennaLS v{required_version}โ€ฆ") + with tempfile.TemporaryDirectory(prefix="ViennaLS_tmp_install_") as tmp: + tmp_path = Path(tmp) + run( + [ + "git", + "clone", + "https://github.com/ViennaTools/ViennaLS.git", + str(tmp_path), + ], + env=env, + ) + run(["git", "checkout", f"v{required_version}"], cwd=tmp_path, env=env) + cmd = [str(pip_path), "install", "."] + if verbose: + cmd.append("-v") + run(cmd, cwd=tmp_path, env=env) + else: + if not ( + viennals_dir.exists() and (viennals_dir / "CMakeLists.txt").exists() + ): + sys.exit(f"ViennaLS directory not valid: {viennals_dir}") + cmd = [str(pip_path), "install", "."] + if verbose: + cmd.append("-v") + run(cmd, cwd=viennals_dir, env=env) + else: + print( + f"ViennaLS already installed ({current}). Local build is required and version should be {required_version}." + ) + if current != required_version: + sys.exit( + f"Version mismatch. Please change to the required version {required_version}.\n" + "Then re-run this script." + ) + print("Proceeding with the currently installed ViennaLS.") def get_viennaps_dir(viennaps_dir_arg: str | None) -> Path: @@ -127,6 +147,7 @@ def get_viennaps_dir(viennaps_dir_arg: str | None) -> Path: if cwd.name == "ViennaPS": viennaps_dir = cwd else: + # try location of this script script_path = Path(__file__).resolve() cwd = script_path.parent.parent if cwd.name == "ViennaPS": @@ -158,22 +179,14 @@ def install_viennaps( sys.exit( f"{viennaps_dir} does not look like a ViennaPS source directory (missing CMakeLists.txt)." ) - - # # --- CRITICAL FIX: Clean Build Directory --- - # # This prevents the "poisoned cache" issue where CMake remembers the old ViennaLS path. - # build_dir = viennaps_dir / "build" - # if build_dir.exists(): - # print(f"Removing dirty build directory: {build_dir}") - # shutil.rmtree(build_dir) - # ------------------------------------------- - env = os.environ.copy() env["CC"] = f"gcc-{REQUIRED_GCC}" env["CXX"] = f"g++-{REQUIRED_GCC}" + # GPU on cmake_args = [] if gpu_build: - cmake_args.append("-DVIENNAPS_USE_GPU=ON") + cmake_args = ["-DVIENNAPS_USE_GPU=ON"] if debug_build: print("Enabling debug build.") @@ -183,20 +196,10 @@ def install_viennaps( if optix_dir is not None: env["OptiX_INSTALL_DIR"] = str(optix_dir) - if cmake_args: - env["CMAKE_ARGS"] = " ".join(cmake_args) - - cmd = [ - str(pip_path), - "install", - ".", - "--force-reinstall", - "--no-cache-dir", - "--no-build-isolation" - ] + env["CMAKE_ARGS"] = " ".join(cmake_args) + cmd = [str(pip_path), "install", "."] if verbose: cmd.append("-v") - run(cmd, cwd=viennaps_dir, env=env) @@ -210,10 +213,16 @@ def main(): parser.add_argument( "--venv", default=".venv", help="Path to the virtual environment directory." ) - # These args are ignored now as we force the local path, but kept for compatibility - parser.add_argument("--viennals-dir", default=None, help="Ignored: Using local path.") - parser.add_argument("--viennals-version", default=None, help="Ignored: Using local path.") - + parser.add_argument( + "--viennals-dir", + default=None, + help="Path to a local ViennaLS checkout (optional).", + ) + parser.add_argument( + "--viennals-version", + default=DEFAULT_VIENNALS_VERSION, + help="ViennaLS version tag to use if cloning.", + ) parser.add_argument( "--viennaps-dir", default=None, @@ -222,7 +231,7 @@ def main(): parser.add_argument( "--optix", default=None, - help="Path to OptiX installation directory (optional).", + help="Path to OptiX installation directory (optional - will auto-download OptiX headers if not provided).", ) parser.add_argument( "--debug-build", @@ -232,7 +241,7 @@ def main(): parser.add_argument( "--skip-toolchain-check", action="store_true", - help="Skip checking for required compilers and CUDA.", + help="Skip checking for required compilers and CUDA (use with caution).", ) parser.add_argument( "--no-gpu", @@ -246,10 +255,20 @@ def main(): ensure_compilers() ensure_cuda() + # OptiX dir if not args.no_gpu: optix_dir = args.optix or os.environ.get("OptiX_INSTALL_DIR") if not optix_dir: print("No OptiX directory provided. Will auto-download OptiX headers.") + print("\nWARNING: OptiX uses a different license than ViennaPS.") + print( + "By proceeding with auto-download, you agree to the NVIDIA OptiX license terms." + ) + print( + "Please review the OptiX license at: https://developer.nvidia.com/designworks/sdk-samples-tools-software-license-agreement" + ) + print("If you do not agree, abort now (Ctrl+C).") + input("Press Enter to continue...") optix_dir = None else: optix_dir = Path(optix_dir).expanduser().resolve() @@ -264,11 +283,11 @@ def main(): create_or_reuse_venv(venv_dir) venv_python, venv_pip = venv_paths(venv_dir) - # 1. Install Build Dependencies - install_build_deps(venv_pip) - - # 2. Install ViennaLS from Local Path - install_viennals(venv_pip, args.verbose) + # ViennaLS + viennals_dir = ( + Path(args.viennals_dir).expanduser().resolve() if args.viennals_dir else None + ) + install_viennals(venv_pip, viennals_dir, args.viennals_version, args.verbose) # ViennaPS dir viennaps_dir = get_viennaps_dir(args.viennaps_dir) @@ -283,11 +302,18 @@ def main(): args.verbose, ) - print("\nInstallation complete.") + # Final info bindir = "Scripts" if os.name == "nt" else "bin" - activate_hint = venv_dir / bindir / ("activate" if os.name != "nt" else "activate.bat") - print(f"Activate: source {activate_hint}") + activate_hint = ( + venv_dir / bindir / ("activate" if os.name != "nt" else "activate.bat") + ) + print("\nInstallation complete.") + if os.name == "nt": + print(f"Activate the virtual environment:\n {activate_hint}") + else: + print(f"Activate the virtual environment:\n source {activate_hint}") + print("To deactivate:\n deactivate") if __name__ == "__main__": - main() \ No newline at end of file + main() From 5c6ca3ae50452e75f58c8f5e9bf8dba69bc11ce5 Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 10 Dec 2025 16:29:28 +0100 Subject: [PATCH 04/38] Add option to enable adaptive time stepping during advection --- CMakeLists.txt | 1 + .../boschProcess/boschProcessSimulate.cpp | 32 +++++++++---------- examples/boschProcess/boschProcessSimulate.py | 17 +++++----- .../viennaps/process/psAdvectionHandler.hpp | 2 ++ include/viennaps/process/psProcessParams.hpp | 1 + python/pyWrap.cpp | 2 ++ python/viennaps/_core/__init__.pyi | 2 +- 7 files changed, 31 insertions(+), 26 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e08213ea..77f139ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS VERSION 5.2.1 + GIT_TAG fix_material_interface GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/examples/boschProcess/boschProcessSimulate.cpp b/examples/boschProcess/boschProcessSimulate.cpp index 489172a9..b4e21ba2 100644 --- a/examples/boschProcess/boschProcessSimulate.cpp +++ b/examples/boschProcess/boschProcessSimulate.cpp @@ -8,9 +8,10 @@ using namespace viennaps; constexpr int D = 2; using NumericType = double; +const std::string name = "boschProcessSimulate_"; -void etch(SmartPointer> domain, - util::Parameters ¶ms) { +void etch(SmartPointer> domain, util::Parameters ¶ms, + int &n) { std::cout << " - Etching - " << std::endl; auto etchModel = SmartPointer>::New(); etchModel->addNeutralParticle(params.get("neutralStickingProbability")); @@ -29,10 +30,11 @@ void etch(SmartPointer> domain, return rate; }); Process(domain, etchModel, params.get("etchTime")).apply(); + domain->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); } void punchThrough(SmartPointer> domain, - util::Parameters ¶ms) { + util::Parameters ¶ms, int &n) { std::cout << " - Punching through - " << std::endl; NumericType depositionThickness = params.get("depositionThickness"); @@ -41,10 +43,11 @@ void punchThrough(SmartPointer> domain, -depositionThickness, 1. /* sticking */, params.get("ionSourceExponent"), Material::Mask); Process(domain, depoRemoval, 1.).apply(); + domain->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); } void deposit(SmartPointer> domain, - util::Parameters ¶ms) { + util::Parameters ¶ms, int &n) { std::cout << " - Deposition - " << std::endl; NumericType depositionThickness = params.get("depositionThickness"); NumericType depositionSticking = params.get("depositionStickingProbability"); @@ -52,11 +55,13 @@ void deposit(SmartPointer> domain, auto model = SmartPointer>::New( depositionThickness, depositionSticking); Process(domain, model, 1.).apply(); + domain->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); } -void ash(SmartPointer> domain) { +void ash(SmartPointer> domain, int &n) { domain->removeTopLevelSet(); domain->removeStrayPoints(); + domain->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); } int main(int argc, char **argv) { @@ -87,25 +92,18 @@ int main(int argc, char **argv) { params.get("maskHeight")) .apply(); - const NumericType depositionThickness = params.get("depositionThickness"); const int numCycles = params.get("numCycles"); - const std::string name = "boschProcessSimulate_"; int n = 0; geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); - etch(geometry, params); - geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); + etch(geometry, params, n); for (int i = 0; i < numCycles; ++i) { std::cout << "Cycle " << i + 1 << std::endl; - deposit(geometry, params); - geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); - punchThrough(geometry, params); - geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); - etch(geometry, params); - geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); - ash(geometry); - geometry->saveSurfaceMesh(name + std::to_string(n++) + ".vtp"); + deposit(geometry, params, n); + punchThrough(geometry, params, n); + etch(geometry, params, n); + ash(geometry, n); } geometry->saveVolumeMesh(name + "final"); diff --git a/examples/boschProcess/boschProcessSimulate.py b/examples/boschProcess/boschProcessSimulate.py index d2090676..80a1e1df 100644 --- a/examples/boschProcess/boschProcessSimulate.py +++ b/examples/boschProcess/boschProcessSimulate.py @@ -65,23 +65,25 @@ def rateFunction(fluxes, material): etchModel.setRateFunction(rateFunction) etchTime = params["etchTime"] - n = 0 -def runProcess(model, name, time=1.0): +def saveGeometry(geometry): global n + geometry.saveSurfaceMesh("boschProcessSimulate_{}".format(n), addInterfaces=True) + n += 1 + + +def runProcess(model, name, time=1.0): print(" - {} - ".format(name)) ps.Process(geometry, model, time).apply() - geometry.saveSurfaceMesh("boschProcessSimulate_{}".format(n)) - n += 1 + saveGeometry(geometry) numCycles = int(params["numCycles"]) # Initial geometry -geometry.saveSurfaceMesh("boschProcessSimulate_{}".format(n)) -n += 1 +saveGeometry(geometry) runProcess(etchModel, "Etching", etchTime) @@ -101,8 +103,7 @@ def runProcess(model, name, time=1.0): # Ash (remove) the polymer geometry.removeTopLevelSet() geometry.removeStrayPoints() - geometry.saveSurfaceMesh("boschProcessSimulate_{}".format(n)) - n += 1 + saveGeometry(geometry) # save the final geometry geometry.saveVolumeMesh("boschProcessSimulate_final") diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index cb69d42f..896d32fc 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -51,6 +51,8 @@ template class AdvectionHandler { advectionKernel_.setIgnoreVoids(context.advectionParams.ignoreVoids); advectionKernel_.setCheckDissipation( context.advectionParams.checkDissipation); + advectionKernel_.setAdaptiveTimeStepping( + context.advectionParams.adaptiveTimeStepping); // normals vectors are only necessary for analytical velocity fields if (translationMethod > 0) advectionKernel_.setCalculateNormalVectors(false); diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 055fe312..0c15ed7d 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -58,6 +58,7 @@ struct AdvectionParameters { bool checkDissipation = true; bool velocityOutput = false; bool ignoreVoids = false; + bool adaptiveTimeStepping = false; auto toMetaData() const { std::unordered_map> metaData; diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 31cb4d65..49fc1ed5 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -462,6 +462,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .def_readwrite("checkDissipation", &AdvectionParameters::checkDissipation) .def_readwrite("velocityOutput", &AdvectionParameters::velocityOutput) .def_readwrite("ignoreVoids", &AdvectionParameters::ignoreVoids) + .def_readwrite("adaptiveTimeStepping", + &AdvectionParameters::adaptiveTimeStepping) .def("toMetaData", &AdvectionParameters::toMetaData, "Convert the advection parameters to a metadata dict.") .def("toMetaDataString", &AdvectionParameters::toMetaDataString, diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index 898a2bf5..96ecf029 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -64,7 +64,7 @@ __all__: list[str] = [ ] class AdvectionParameters: - checkDissipation: bool + adaptiveTimeStepping: bool ignoreVoids: bool integrationScheme: viennals._core.IntegrationSchemeEnum velocityOutput: bool From b7fef2e6f3119a917604813b982e10df15996119 Mon Sep 17 00:00:00 2001 From: reiter Date: Mon, 15 Dec 2025 11:02:23 +0100 Subject: [PATCH 05/38] Add adptive time step threshold --- .../viennaps/process/psAdvectionHandler.hpp | 3 +++ include/viennaps/process/psProcess.hpp | 4 +++- include/viennaps/process/psProcessParams.hpp | 1 + python/pyWrap.cpp | 2 ++ python/pyWrapDimension.hpp | 22 +++++++++++++++++++ python/viennaps/_core/__init__.pyi | 9 ++++++-- python/viennaps/d2/__init__.pyi | 8 +++++++ python/viennaps/d3/__init__.pyi | 8 +++++++ 8 files changed, 54 insertions(+), 3 deletions(-) diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 896d32fc..af554225 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -53,6 +53,9 @@ template class AdvectionHandler { context.advectionParams.checkDissipation); advectionKernel_.setAdaptiveTimeStepping( context.advectionParams.adaptiveTimeStepping); + advectionKernel_.setAdaptiveTimeStepThreshold( + context.advectionParams.adaptiveTimeStepThreshold); + // normals vectors are only necessary for analytical velocity fields if (translationMethod > 0) advectionKernel_.setCalculateNormalVectors(false); diff --git a/include/viennaps/process/psProcess.hpp b/include/viennaps/process/psProcess.hpp index 0a4f7196..b2039d4d 100644 --- a/include/viennaps/process/psProcess.hpp +++ b/include/viennaps/process/psProcess.hpp @@ -41,10 +41,12 @@ template class Process { Process(SmartPointer> domain) : context_{domain} { initializeStrategies(); } + template Process(SmartPointer> domain, SmartPointer> model, - NumericType processDuration = 0.) + NumericType processDuration = 0., ParamArgs... params) : context_{domain, model, processDuration} { + (setParameters(params), ...); initializeStrategies(); } diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 0c15ed7d..511206c1 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -55,6 +55,7 @@ struct AdvectionParameters { IntegrationScheme::ENGQUIST_OSHER_1ST_ORDER; double timeStepRatio = 0.4999; double dissipationAlpha = 1.0; + double adaptiveTimeStepThreshold = 0.05; bool checkDissipation = true; bool velocityOutput = false; bool ignoreVoids = false; diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 49fc1ed5..9c1b602e 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -464,6 +464,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .def_readwrite("ignoreVoids", &AdvectionParameters::ignoreVoids) .def_readwrite("adaptiveTimeStepping", &AdvectionParameters::adaptiveTimeStepping) + .def_readwrite("adaptiveTimeStepThreshold", + &AdvectionParameters::adaptiveTimeStepThreshold) .def("toMetaData", &AdvectionParameters::toMetaData, "Convert the advection parameters to a metadata dict.") .def("toMetaDataString", &AdvectionParameters::toMetaDataString, diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index 1a06eb68..6c51d13f 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -1244,6 +1244,28 @@ template void bindApi(py::module &module) { .def(py::init(), py::arg("domain")) .def(py::init>, T>(), py::arg("domain"), py::arg("model"), py::arg("duration") = 0.) + .def(py::init([](DomainType domain, + SmartPointer> model, T duration, + py::args args) { + ProcessTD process(domain, model, duration); + for (auto arg : args) { + if (py::isinstance(arg)) { + process.setParameters(arg.cast()); + } else if (py::isinstance(arg)) { + process.setParameters(arg.cast()); + } else if (py::isinstance(arg)) { + process.setParameters(arg.cast()); + } else if (py::isinstance(arg)) { + process.setParameters( + arg.cast()); + } else { + throw py::type_error( + "Unsupported parameter type for Process constructor"); + } + } + return process; + }), + py::arg("domain"), py::arg("model"), py::arg("duration") = 0.) // methods .def("apply", &ProcessTD::apply, // py::call_guard(), diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index 96ecf029..f2b7ee07 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -7,10 +7,10 @@ import collections.abc import enum import typing import viennals._core -from viennaps import d2 import viennaps.d2 -import viennaps.d3 +from viennaps import d2 from viennaps import d3 +import viennaps.d3 from . import constants from . import gpu from . import util @@ -65,6 +65,7 @@ __all__: list[str] = [ class AdvectionParameters: adaptiveTimeStepping: bool + checkDissipation: bool ignoreVoids: bool integrationScheme: viennals._core.IntegrationSchemeEnum velocityOutput: bool @@ -79,6 +80,10 @@ class AdvectionParameters: Convert the advection parameters to a metadata string. """ + @property + def adaptiveTimeStepThreshold(self) -> float: ... + @adaptiveTimeStepThreshold.setter + def adaptiveTimeStepThreshold(self, arg0: typing.SupportsFloat) -> None: ... @property def dissipationAlpha(self) -> float: ... @dissipationAlpha.setter diff --git a/python/viennaps/d2/__init__.pyi b/python/viennaps/d2/__init__.pyi index 4b798719..c37bc02e 100644 --- a/python/viennaps/d2/__init__.pyi +++ b/python/viennaps/d2/__init__.pyi @@ -1200,6 +1200,14 @@ class Process: model: ProcessModelBase, duration: typing.SupportsFloat = 0.0, ) -> None: ... + @typing.overload + def __init__( + self, + domain: Domain, + model: ProcessModelBase, + duration: typing.SupportsFloat = 0.0, + *args, + ) -> None: ... def apply(self) -> None: """ Run the process. diff --git a/python/viennaps/d3/__init__.pyi b/python/viennaps/d3/__init__.pyi index 08ec6ae6..81d2993f 100644 --- a/python/viennaps/d3/__init__.pyi +++ b/python/viennaps/d3/__init__.pyi @@ -1205,6 +1205,14 @@ class Process: model: ProcessModelBase, duration: typing.SupportsFloat = 0.0, ) -> None: ... + @typing.overload + def __init__( + self, + domain: Domain, + model: ProcessModelBase, + duration: typing.SupportsFloat = 0.0, + *args, + ) -> None: ... def apply(self) -> None: """ Run the process. From 5fddbe955e6066fb96f7df6be209d6e864a9db36 Mon Sep 17 00:00:00 2001 From: reiter Date: Mon, 15 Dec 2025 12:55:11 +0100 Subject: [PATCH 06/38] Update ViennaLS version --- CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77f139ec..66980fdc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -120,8 +120,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS - VERSION 5.2.1 - GIT_TAG fix_material_interface + VERSION 5.3.0 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) From 04f8fe4047669423818f3f8203e3365c195ecf3c Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 17 Dec 2025 10:58:38 +0100 Subject: [PATCH 07/38] Implement VTK rendering --- CMakeLists.txt | 1 + include/viennaps/process/psALPStrategy.hpp | 4 +- include/viennaps/psDomain.hpp | 11 + include/viennaps/psVTKRenderWindow.hpp | 417 +++++++++++++++++++++ 4 files changed, 432 insertions(+), 1 deletion(-) create mode 100644 include/viennaps/psVTKRenderWindow.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 69a28e58..bdf5ec07 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,6 +121,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS VERSION 5.3.0 + GIT_TAG vtk-render GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/include/viennaps/process/psALPStrategy.hpp b/include/viennaps/process/psALPStrategy.hpp index d0ca07c7..364c1b35 100644 --- a/include/viennaps/process/psALPStrategy.hpp +++ b/include/viennaps/process/psALPStrategy.hpp @@ -93,7 +93,9 @@ class ALPStrategy final : public ProcessStrategy { // Initialize translation field. Converts points ids from level set points // to surface points - const int translationMethod = context.needsExtendedVelocities() ? 2 : 1; + /// TODO: find out why translationMethod 1 does not work properly + const int translationMethod = + 2; // context.needsExtendedVelocities() ? 2 : 1; context.translationField = SmartPointer>::New( context.model->getVelocityField(), context.domain->getMaterialMap(), diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index 2a6b7e9e..6974058d 100644 --- a/include/viennaps/psDomain.hpp +++ b/include/viennaps/psDomain.hpp @@ -4,6 +4,7 @@ #include "psMaterials.hpp" #include "psPreCompileMacros.hpp" #include "psSurfacePointValuesToLevelSet.hpp" +#include "psVTKRenderWindow.hpp" #include "psVersion.hpp" #include @@ -601,6 +602,16 @@ template class Domain { } } + void show() const { +#ifdef VIENNALS_VTK_RENDERING + auto thisDomain = SmartPointer>::New(*this); + VTKRenderWindow(thisDomain).render(); +#else + VIENNACORE_LOG_ERROR("VTK rendering is disabled. Please enable " + "VIENNALS_VTK_RENDERING to use this feature."); +#endif + } + void clear() { levelSets_.clear(); if (cellSet_) diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp new file mode 100644 index 00000000..bbb1eb58 --- /dev/null +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -0,0 +1,417 @@ +#pragma once + +#ifdef VIENNALS_VTK_RENDERING + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef VIENNALS_VTK_MODULE_INIT +VTK_MODULE_INIT(vtkRenderingOpenGL2); +VTK_MODULE_INIT(vtkInteractionStyle); +VTK_MODULE_INIT(vtkRenderingFreeType); +VTK_MODULE_INIT(vtkRenderingUI); +#endif + +namespace viennaps { +template class VTKRenderWindow; + +enum class RenderMode { SURFACE, INTERFACE, VOLUME }; +} // namespace viennaps + +// Forward declaration - full definition after VTKRenderWindow +class Custom3DInteractorStyle; +class Custom2DInteractorStyle; + +namespace viennaps { + +// forward declaration of Domain +template class Domain; + +template class VTKRenderWindow { +public: + VTKRenderWindow() { initialize(); } + VTKRenderWindow(SmartPointer> passedDomain) + : domain(passedDomain) { + initialize(); + } + + ~VTKRenderWindow(); + + void setBackgroundColor(const std::array &color) { + backgroundColor = color; + if (renderer) { + renderer->SetBackground(backgroundColor.data()); + } + } + + void setRenderMode(RenderMode mode) { renderMode = mode; } + + void render() { + updateDisplay(); + interactor->Initialize(); + interactor->Start(); + } + + // Update the display without starting a new event loop (for use during + // interaction) + void updateDisplay() { + updateRenderer(); + renderWindow->Render(); + } + +private: + void initialize(); + + void updateRenderer() { + if (!domain) { + VIENNACORE_LOG_WARNING("No domain set for rendering."); + return; + } + + // Clear previous actors + renderer->RemoveAllViewProps(); + + switch (renderMode) { + case RenderMode::SURFACE: { + auto surfaceMesh = domain->getSurfaceMesh(); + updatePolyData(surfaceMesh); + break; + } + case RenderMode::INTERFACE: { + auto interfaceMesh = domain->getSurfaceMesh(true); + updatePolyData(interfaceMesh); + break; + } + case RenderMode::VOLUME: { + viennals::WriteVisualizationMesh writer; + auto matMap = domain->getMaterialMap(); + auto levelSets = domain->getLevelSets(); + int minMatId = std::numeric_limits::max(); + int maxMatId = std::numeric_limits::min(); + for (auto i{0u}; i < domain->getNumberOfLevelSets(); ++i) { + writer.insertNextLevelSet(levelSets[i]); + if (matMap) { + int lsMinId = static_cast(matMap->getMaterialAtIdx(i)); + int lsMaxId = static_cast(matMap->getMaterialAtIdx(i)); + minMatId = std::min(minMatId, lsMinId); + maxMatId = std::max(maxMatId, lsMaxId); + } + } + writer.setMaterialMap(domain->getMaterialMap()->getMaterialMap()); + writer.setWriteToFile(false); + writer.apply(); + + auto volumeMesh = writer.getVolumeMesh(); + updateVolumeMesh(volumeMesh, minMatId, maxMatId); + break; + } + default: + assert(false && "Unknown render mode."); + } + } + +private: + void updatePolyData(SmartPointer> mesh) { + if (mesh == nullptr) { + return; + } + + auto polyData = vtkSmartPointer::New(); + + // Points + vtkSmartPointer points = vtkSmartPointer::New(); + for (const auto &node : mesh->getNodes()) { + points->InsertNextPoint(node[0], node[1], node[2]); + } + polyData->SetPoints(points); + + // Vertices + if (!mesh->vertices.empty()) { + vtkSmartPointer verts = + vtkSmartPointer::New(); + for (const auto &vertex : mesh->vertices) { + verts->InsertNextCell(1); + verts->InsertCellPoint(vertex[0]); + } + polyData->SetVerts(verts); + } + + // Lines + if (!mesh->lines.empty()) { + vtkSmartPointer lines = + vtkSmartPointer::New(); + for (const auto &line : mesh->lines) { + lines->InsertNextCell(2); + lines->InsertCellPoint(line[0]); + lines->InsertCellPoint(line[1]); + } + polyData->SetLines(lines); + } + + // Triangles + if (!mesh->triangles.empty()) { + if constexpr (D < 3) { + VIENNACORE_LOG_WARNING("Adding triangles to a 2D mesh."); + } + + vtkSmartPointer polys = + vtkSmartPointer::New(); + for (const auto &triangle : mesh->triangles) { + polys->InsertNextCell(3); + polys->InsertCellPoint(triangle[0]); + polys->InsertCellPoint(triangle[1]); + polys->InsertCellPoint(triangle[2]); + } + polyData->SetPolys(polys); + } + + // Material IDs as cell data + auto materialIds = mesh->getCellData().getScalarData("MaterialIds", true); + bool useMaterialIds = + materialIds && + (materialIds->size() == mesh->lines.size() + mesh->triangles.size()); + int minId = std::numeric_limits::max(); + int maxId = std::numeric_limits::min(); + if (useMaterialIds) { + vtkSmartPointer matIdArray = + vtkSmartPointer::New(); + matIdArray->SetName("MaterialIds"); + for (const auto &id : *materialIds) { + int mId = static_cast(id); + matIdArray->InsertNextValue(mId); + minId = std::min(minId, mId); + maxId = std::max(maxId, mId); + } + polyData->GetCellData()->AddArray(matIdArray); + polyData->GetCellData()->SetActiveScalars("MaterialIds"); + VIENNACORE_LOG_DEBUG("Added MaterialIds array to cell data."); + } + + auto mapper = vtkSmartPointer::New(); + mapper->SetInputData(polyData); + + if (useMaterialIds) { + mapper->SetScalarModeToUseCellData(); + mapper->ScalarVisibilityOn(); + mapper->SelectColorArray("MaterialIds"); + + vtkSmartPointer lut = + vtkSmartPointer::New(); + + lut->SetNumberOfTableValues(256); + lut->SetHueRange(0.667, 0.0); // blue โ†’ red + lut->SetSaturationRange(1.0, 1.0); + lut->SetValueRange(1.0, 1.0); + lut->Build(); + + mapper->SetLookupTable(lut); + mapper->SetScalarRange(minId, maxId); + } + + auto actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetLineWidth(3.0); // Thicker lines + + renderer->AddActor(actor); + renderer->ResetCamera(); + } + + void updateVolumeMesh(vtkSmartPointer volumeMesh, + int minMatId = 0, int maxMatId = 100) { + auto mapper = vtkSmartPointer::New(); + mapper->SetInputData(volumeMesh); + mapper->SetScalarModeToUseCellData(); + mapper->ScalarVisibilityOn(); + mapper->SelectColorArray("Material"); + + vtkSmartPointer lut = + vtkSmartPointer::New(); + + lut->SetNumberOfTableValues(256); + lut->SetHueRange(0.667, 0.0); // blue โ†’ red + lut->SetSaturationRange(1.0, 1.0); + lut->SetValueRange(1.0, 1.0); + lut->Build(); + + mapper->SetLookupTable(lut); + mapper->SetScalarRange(minMatId, maxMatId); + + auto actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + renderer->AddActor(actor); + renderer->ResetCamera(); + } + +private: + SmartPointer> domain; + + vtkSmartPointer renderer; + vtkSmartPointer renderWindow; + vtkSmartPointer interactor; + + std::array backgroundColor = {84.0 / 255, 89.0 / 255, 109.0 / 255}; + std::array windowSize = {800, 600}; + + RenderMode renderMode = RenderMode::INTERFACE; +}; + +} // namespace viennaps + +// Full definition of Custom3DInteractorStyle after VTKRenderWindow is complete +class Custom3DInteractorStyle : public vtkInteractorStyleTrackballCamera { +public: + static Custom3DInteractorStyle *New(); + vtkTypeMacro(Custom3DInteractorStyle, vtkInteractorStyleTrackballCamera); + + virtual void OnChar() { + if (Window == nullptr) + return; + + vtkRenderWindowInteractor *rwi = this->Interactor; + if (!rwi || rwi->GetDone()) + return; + + switch (rwi->GetKeyCode()) { + case '1': + Window->setRenderMode(viennaps::RenderMode::SURFACE); + Window->updateDisplay(); + return; + case '2': + Window->setRenderMode(viennaps::RenderMode::INTERFACE); + Window->updateDisplay(); + return; + case '3': + Window->setRenderMode(viennaps::RenderMode::VOLUME); + Window->updateDisplay(); + return; + } + } + + void setRenderWindow(viennaps::VTKRenderWindow *window) { + this->Window = window; + } + +private: + viennaps::VTKRenderWindow *Window = nullptr; +}; + +vtkStandardNewMacro(Custom3DInteractorStyle); + +class Custom2DInteractorStyle : public vtkInteractorStyleImage { +public: + static Custom2DInteractorStyle *New(); + vtkTypeMacro(Custom2DInteractorStyle, vtkInteractorStyleImage); + + void OnLeftButtonDown() override { this->StartPan(); } + + void OnLeftButtonUp() override { this->EndPan(); } + + virtual void OnChar() { + if (Window == nullptr) + return; + + vtkRenderWindowInteractor *rwi = this->Interactor; + if (!rwi || rwi->GetDone()) + return; + + switch (rwi->GetKeyCode()) { + case '1': + Window->setRenderMode(viennaps::RenderMode::SURFACE); + Window->updateDisplay(); + return; + case '2': + Window->setRenderMode(viennaps::RenderMode::INTERFACE); + Window->updateDisplay(); + return; + case '3': + Window->setRenderMode(viennaps::RenderMode::VOLUME); + Window->updateDisplay(); + return; + } + } + + void setRenderWindow(viennaps::VTKRenderWindow *window) { + this->Window = window; + } + +private: + viennaps::VTKRenderWindow *Window = nullptr; +}; + +vtkStandardNewMacro(Custom2DInteractorStyle); + +// VTKRenderWindow::initialize() implementation - defined after +// Custom3DInteractorStyle +namespace viennaps { + +template VTKRenderWindow::~VTKRenderWindow() { + if (interactor) { + if (auto *customStyle = Custom3DInteractorStyle::SafeDownCast( + interactor->GetInteractorStyle())) { + customStyle->setRenderWindow(nullptr); + } + interactor->SetInteractorStyle(nullptr); + interactor->SetRenderWindow(nullptr); + } + if (renderWindow) { + renderWindow->SetInteractor(nullptr); + renderWindow->RemoveRenderer(renderer); + } +} + +template void VTKRenderWindow::initialize() { + renderer = vtkSmartPointer::New(); + renderer->SetBackground(backgroundColor.data()); + + renderWindow = vtkSmartPointer::New(); + renderWindow->SetWindowName("ViennaPS Render Window"); + renderWindow->SetSize(windowSize.data()); + renderWindow->AddRenderer(renderer); + + // Initialize interactor + interactor = vtkSmartPointer::New(); + + if constexpr (D == 2) { + vtkCamera *cam = renderer->GetActiveCamera(); + cam->ParallelProjectionOn(); + auto style = vtkSmartPointer::New(); + style->setRenderWindow(this); + interactor->SetInteractorStyle(style); + } else { + auto style = vtkSmartPointer::New(); + style->setRenderWindow(this); + interactor->SetInteractorStyle(style); + } + + interactor->SetRenderWindow(renderWindow); + renderWindow->SetInteractor(interactor); + + if (auto style = interactor->GetInteractorStyle()) { + style->SetDefaultRenderer(renderer); + style->SetCurrentRenderer(renderer); + } +} +} // namespace viennaps + +#endif // VIENNALS_VTK_RENDERING \ No newline at end of file From a36e05beed641fad43f95544a30f72f794cc8468 Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 17 Dec 2025 11:47:31 +0100 Subject: [PATCH 08/38] Add python bindings --- python/pyWrapDimension.hpp | 1 + python/viennaps/_core/__init__.pyi | 2 +- python/viennaps/d2/__init__.pyi | 5 +++++ python/viennaps/d3/__init__.pyi | 5 +++++ 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index 6c51d13f..a27784ec 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -531,6 +531,7 @@ template void bindApi(py::module &module) { "print", [](Domain &self, bool hrle) { self.print(std::cout, hrle); }, "Print the domain information.", py::arg("hrleInfo") = false) + .def("show", &Domain::show, "Render the domain using VTK.") .def("getLevelSetMesh", &Domain::getLevelSetMesh, py::arg("width") = 1, "Get the level set grids of layers in the domain.") diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index f2b7ee07..d23c0378 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -7,8 +7,8 @@ import collections.abc import enum import typing import viennals._core -import viennaps.d2 from viennaps import d2 +import viennaps.d2 from viennaps import d3 import viennaps.d3 from . import constants diff --git a/python/viennaps/d2/__init__.pyi b/python/viennaps/d2/__init__.pyi index c37bc02e..7ebcb65d 100644 --- a/python/viennaps/d2/__init__.pyi +++ b/python/viennaps/d2/__init__.pyi @@ -650,6 +650,11 @@ class Domain: Setup the domain. """ + def show(self) -> None: + """ + Render the domain using VTK. + """ + class DomainSetup: @typing.overload def __init__(self) -> None: ... diff --git a/python/viennaps/d3/__init__.pyi b/python/viennaps/d3/__init__.pyi index 81d2993f..87f09f54 100644 --- a/python/viennaps/d3/__init__.pyi +++ b/python/viennaps/d3/__init__.pyi @@ -650,6 +650,11 @@ class Domain: Setup the domain. """ + def show(self) -> None: + """ + Render the domain using VTK. + """ + class DomainSetup: @typing.overload def __init__(self) -> None: ... From f70be9b1148f63ea51058802a5fba03d43a06be1 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Wed, 17 Dec 2025 15:15:21 +0100 Subject: [PATCH 09/38] Use caching for switch rendering modes --- include/viennaps/psVTKRenderWindow.hpp | 156 ++++++++++++++----------- 1 file changed, 89 insertions(+), 67 deletions(-) diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index bbb1eb58..4bc6448a 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -24,6 +24,8 @@ #include #include #include +#include +#include #ifndef VIENNALS_VTK_MODULE_INIT VTK_MODULE_INIT(vtkRenderingOpenGL2); @@ -55,7 +57,16 @@ template class VTKRenderWindow { initialize(); } - ~VTKRenderWindow(); + ~VTKRenderWindow() { + if (interactor) { + interactor->SetInteractorStyle(nullptr); + interactor->SetRenderWindow(nullptr); + } + if (renderWindow) { + renderWindow->SetInteractor(nullptr); + renderWindow->RemoveRenderer(renderer); + } + } void setBackgroundColor(const std::array &color) { backgroundColor = color; @@ -74,15 +85,15 @@ template class VTKRenderWindow { // Update the display without starting a new event loop (for use during // interaction) - void updateDisplay() { - updateRenderer(); + void updateDisplay(bool useCache = false) { + updateRenderer(useCache); renderWindow->Render(); } private: void initialize(); - void updateRenderer() { + void updateRenderer(bool useCache = false) { if (!domain) { VIENNACORE_LOG_WARNING("No domain set for rendering."); return; @@ -93,16 +104,32 @@ template class VTKRenderWindow { switch (renderMode) { case RenderMode::SURFACE: { - auto surfaceMesh = domain->getSurfaceMesh(); + SmartPointer> surfaceMesh; + if (useCache && cachedSurfaceMesh) { + surfaceMesh = cachedSurfaceMesh; + } else { + surfaceMesh = domain->getSurfaceMesh(); + cachedSurfaceMesh = surfaceMesh; + } updatePolyData(surfaceMesh); break; } case RenderMode::INTERFACE: { - auto interfaceMesh = domain->getSurfaceMesh(true); + SmartPointer> interfaceMesh; + if (useCache && cachedInterfaceMesh) { + interfaceMesh = cachedInterfaceMesh; + } else { + interfaceMesh = domain->getSurfaceMesh(true); + cachedInterfaceMesh = interfaceMesh; + } updatePolyData(interfaceMesh); break; } case RenderMode::VOLUME: { + if (useCache && cachedVolumeMesh) { + updateVolumeMesh(cachedVolumeMesh, cachedMinMatId, cachedMaxMatId); + break; + } viennals::WriteVisualizationMesh writer; auto matMap = domain->getMaterialMap(); auto levelSets = domain->getLevelSets(); @@ -122,6 +149,9 @@ template class VTKRenderWindow { writer.apply(); auto volumeMesh = writer.getVolumeMesh(); + cachedVolumeMesh = volumeMesh; + cachedMinMatId = minMatId; + cachedMaxMatId = maxMatId; updateVolumeMesh(volumeMesh, minMatId, maxMatId); break; } @@ -274,8 +304,44 @@ template class VTKRenderWindow { std::array windowSize = {800, 600}; RenderMode renderMode = RenderMode::INTERFACE; + + // cached meshes + SmartPointer> cachedSurfaceMesh; + SmartPointer> cachedInterfaceMesh; + vtkSmartPointer cachedVolumeMesh; + int cachedMinMatId = -1; + int cachedMaxMatId = -1; }; +namespace impl { +template +void InteractorOnChar(vtkRenderWindowInteractor *rwi, + VTKRenderWindow *window) { + + if (!window || !rwi || rwi->GetDone()) + return; + + switch (rwi->GetKeyCode()) { + case '1': + window->setRenderMode(RenderMode::SURFACE); + window->updateDisplay(true); + return; + case '2': + window->setRenderMode(RenderMode::INTERFACE); + window->updateDisplay(true); + return; + case '3': + window->setRenderMode(RenderMode::VOLUME); + window->updateDisplay(true); + return; + case 'e': + [[fallthrough]]; + case 'q': + rwi->TerminateApp(); + return; + } +} +} // namespace impl } // namespace viennaps // Full definition of Custom3DInteractorStyle after VTKRenderWindow is complete @@ -284,37 +350,18 @@ class Custom3DInteractorStyle : public vtkInteractorStyleTrackballCamera { static Custom3DInteractorStyle *New(); vtkTypeMacro(Custom3DInteractorStyle, vtkInteractorStyleTrackballCamera); - virtual void OnChar() { - if (Window == nullptr) - return; - + void OnChar() { vtkRenderWindowInteractor *rwi = this->Interactor; - if (!rwi || rwi->GetDone()) - return; - - switch (rwi->GetKeyCode()) { - case '1': - Window->setRenderMode(viennaps::RenderMode::SURFACE); - Window->updateDisplay(); - return; - case '2': - Window->setRenderMode(viennaps::RenderMode::INTERFACE); - Window->updateDisplay(); - return; - case '3': - Window->setRenderMode(viennaps::RenderMode::VOLUME); - Window->updateDisplay(); - return; - } + viennaps::impl::InteractorOnChar(rwi, Window); } void setRenderWindow(viennaps::VTKRenderWindow *window) { - this->Window = window; + Window = window; } private: viennaps::VTKRenderWindow *Window = nullptr; -}; +}; // namespace viennaps vtkStandardNewMacro(Custom3DInteractorStyle); @@ -327,37 +374,18 @@ class Custom2DInteractorStyle : public vtkInteractorStyleImage { void OnLeftButtonUp() override { this->EndPan(); } - virtual void OnChar() { - if (Window == nullptr) - return; - + void OnChar() { vtkRenderWindowInteractor *rwi = this->Interactor; - if (!rwi || rwi->GetDone()) - return; - - switch (rwi->GetKeyCode()) { - case '1': - Window->setRenderMode(viennaps::RenderMode::SURFACE); - Window->updateDisplay(); - return; - case '2': - Window->setRenderMode(viennaps::RenderMode::INTERFACE); - Window->updateDisplay(); - return; - case '3': - Window->setRenderMode(viennaps::RenderMode::VOLUME); - Window->updateDisplay(); - return; - } + viennaps::impl::InteractorOnChar(rwi, Window); } void setRenderWindow(viennaps::VTKRenderWindow *window) { - this->Window = window; + Window = window; } private: viennaps::VTKRenderWindow *Window = nullptr; -}; +}; // namespace viennaps vtkStandardNewMacro(Custom2DInteractorStyle); @@ -365,25 +393,19 @@ vtkStandardNewMacro(Custom2DInteractorStyle); // Custom3DInteractorStyle namespace viennaps { -template VTKRenderWindow::~VTKRenderWindow() { - if (interactor) { - if (auto *customStyle = Custom3DInteractorStyle::SafeDownCast( - interactor->GetInteractorStyle())) { - customStyle->setRenderWindow(nullptr); - } - interactor->SetInteractorStyle(nullptr); - interactor->SetRenderWindow(nullptr); - } - if (renderWindow) { - renderWindow->SetInteractor(nullptr); - renderWindow->RemoveRenderer(renderer); - } -} - template void VTKRenderWindow::initialize() { renderer = vtkSmartPointer::New(); renderer->SetBackground(backgroundColor.data()); + // add text actor for instructions + auto instructions = vtkSmartPointer::New(); + instructions->SetInput( + "Press 1: Surface | 2: Interface | 3: Volume | q/e: Quit"); + instructions->GetTextProperty()->SetFontSize(14); + instructions->GetTextProperty()->SetColor(1.0, 1.0, 1.0); + instructions->SetPosition(10, 10); + renderer->AddActor(instructions); + renderWindow = vtkSmartPointer::New(); renderWindow->SetWindowName("ViennaPS Render Window"); renderWindow->SetSize(windowSize.data()); From f64c5e36437e5297a2169ad3e68111d7f03b7d8a Mon Sep 17 00:00:00 2001 From: reiter Date: Thu, 18 Dec 2025 16:13:42 +0100 Subject: [PATCH 10/38] Screenshot feature --- include/viennaps/psVTKRenderWindow.hpp | 98 +++++++++++++++++++++----- python/CMakeLists.txt | 19 +++++ python/pyWrapDimension.hpp | 19 +++++ python/viennaps/__init__.pyi | 2 + python/viennaps/d2/__init__.pyi | 46 ++++++++++++ python/viennaps/d3/__init__.pyi | 46 ++++++++++++ 6 files changed, 214 insertions(+), 16 deletions(-) diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index 4bc6448a..d5cd1da9 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -7,7 +7,7 @@ #include #include -#include +#include #include #include #include @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -24,10 +25,14 @@ #include #include #include +#include #include #include +#include +#include #ifndef VIENNALS_VTK_MODULE_INIT +#include VTK_MODULE_INIT(vtkRenderingOpenGL2); VTK_MODULE_INIT(vtkInteractionStyle); VTK_MODULE_INIT(vtkRenderingFreeType); @@ -68,6 +73,10 @@ template class VTKRenderWindow { } } + void setDomain(SmartPointer> passedDomain) { + domain = passedDomain; + } + void setBackgroundColor(const std::array &color) { backgroundColor = color; if (renderer) { @@ -75,8 +84,19 @@ template class VTKRenderWindow { } } + void setWindowSize(const std::array &size) { + windowSize = size; + if (renderWindow) { + renderWindow->SetSize(windowSize[0], windowSize[1]); + } + } + void setRenderMode(RenderMode mode) { renderMode = mode; } + void setScreenshotScale(int scale) { screenshotScale = scale; } + + int getScreenshotScale() const { return screenshotScale; } + void render() { updateDisplay(); interactor->Initialize(); @@ -91,6 +111,7 @@ template class VTKRenderWindow { } private: + // forward declaration, requires full definition of Interactor styles void initialize(); void updateRenderer(bool useCache = false) { @@ -101,6 +122,7 @@ template class VTKRenderWindow { // Clear previous actors renderer->RemoveAllViewProps(); + renderer->AddActor(instructionsActor); switch (renderMode) { case RenderMode::SURFACE: { @@ -300,8 +322,12 @@ template class VTKRenderWindow { vtkSmartPointer renderWindow; vtkSmartPointer interactor; + // text + vtkSmartPointer instructionsActor; + std::array backgroundColor = {84.0 / 255, 89.0 / 255, 109.0 / 255}; std::array windowSize = {800, 600}; + int screenshotScale = 1; RenderMode renderMode = RenderMode::INTERFACE; @@ -321,6 +347,9 @@ void InteractorOnChar(vtkRenderWindowInteractor *rwi, if (!window || !rwi || rwi->GetDone()) return; + auto renderer = rwi->GetRenderWindow()->GetRenderers()->GetFirstRenderer(); + auto camera = renderer->GetActiveCamera(); + switch (rwi->GetKeyCode()) { case '1': window->setRenderMode(RenderMode::SURFACE); @@ -339,6 +368,50 @@ void InteractorOnChar(vtkRenderWindowInteractor *rwi, case 'q': rwi->TerminateApp(); return; + case 'x': + camera->SetPosition(500.0, 0, 0); // Positive X + camera->SetFocalPoint(0.0, 0.0, 0.0); + camera->SetViewUp(0.0, 1.0, 0.0); + renderer->ResetCamera(); + rwi->GetRenderWindow()->Render(); + return; + case 'y': + camera->SetPosition(0, 500.0, 0); // Positive Y + camera->SetFocalPoint(0.0, 0.0, 0.0); + camera->SetViewUp(0.0, 0.0, 1.0); + renderer->ResetCamera(); + rwi->GetRenderWindow()->Render(); + return; + case 'z': + camera->SetPosition(0, 0, 500.0); // Positive Z + camera->SetFocalPoint(0.0, 0.0, 0.0); + camera->SetViewUp(0.0, 1.0, 0.0); + renderer->ResetCamera(); + rwi->GetRenderWindow()->Render(); + return; + case 's': { + vtkSmartPointer windowToImageFilter = + vtkSmartPointer::New(); + windowToImageFilter->SetInput(rwi->GetRenderWindow()); + windowToImageFilter->SetScale( + window->getScreenshotScale()); // image quality + windowToImageFilter->Update(); + + auto time_t = + std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + char timeStamp[20]; + std::strftime(timeStamp, sizeof(timeStamp), "%Y-%m-%d_%H-%M-%S", + std::localtime(&time_t)); + const std::string fileName = + "screenshot_" + std::string(timeStamp) + ".png"; + VIENNACORE_LOG_INFO("Saving screenshot '" + fileName + "'"); + + vtkSmartPointer writer = vtkSmartPointer::New(); + writer->SetFileName(fileName.c_str()); + writer->SetInputData(windowToImageFilter->GetOutput()); + writer->Write(); + return; + } } } } // namespace impl @@ -350,10 +423,7 @@ class Custom3DInteractorStyle : public vtkInteractorStyleTrackballCamera { static Custom3DInteractorStyle *New(); vtkTypeMacro(Custom3DInteractorStyle, vtkInteractorStyleTrackballCamera); - void OnChar() { - vtkRenderWindowInteractor *rwi = this->Interactor; - viennaps::impl::InteractorOnChar(rwi, Window); - } + void OnChar() { viennaps::impl::InteractorOnChar(this->Interactor, Window); } void setRenderWindow(viennaps::VTKRenderWindow *window) { Window = window; @@ -374,10 +444,7 @@ class Custom2DInteractorStyle : public vtkInteractorStyleImage { void OnLeftButtonUp() override { this->EndPan(); } - void OnChar() { - vtkRenderWindowInteractor *rwi = this->Interactor; - viennaps::impl::InteractorOnChar(rwi, Window); - } + void OnChar() { viennaps::impl::InteractorOnChar(this->Interactor, Window); } void setRenderWindow(viennaps::VTKRenderWindow *window) { Window = window; @@ -398,13 +465,12 @@ template void VTKRenderWindow::initialize() { renderer->SetBackground(backgroundColor.data()); // add text actor for instructions - auto instructions = vtkSmartPointer::New(); - instructions->SetInput( - "Press 1: Surface | 2: Interface | 3: Volume | q/e: Quit"); - instructions->GetTextProperty()->SetFontSize(14); - instructions->GetTextProperty()->SetColor(1.0, 1.0, 1.0); - instructions->SetPosition(10, 10); - renderer->AddActor(instructions); + instructionsActor = vtkSmartPointer::New(); + instructionsActor->SetInput("Press 1: Surface | 2: Interface | 3: Volume | " + "x/y/z: View | s: Screenshot | q/e: Quit"); + instructionsActor->GetTextProperty()->SetFontSize(14); + instructionsActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0); + instructionsActor->SetPosition(10, 10); renderWindow = vtkSmartPointer::New(); renderWindow->SetWindowName("ViennaPS Render Window"); diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 1f8d7dc7..ccb1f2cf 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -59,6 +59,25 @@ target_link_libraries(${VIENNAPS_PYTHON_MODULE_NAME} PRIVATE ViennaPS) target_compile_definitions(${VIENNAPS_PYTHON_MODULE_NAME} PRIVATE VIENNAPS_MODULE_NAME=${VIENNAPS_PYTHON_MODULE_NAME}) +# To prevent symbol clashes when multiple python which use VTK modules are loaded, the modules are initialized here +if(VIENNALS_VTK_RENDERING) + # We need to find VTK again here to get the proper module targets + # TODO: Refactor to avoid multiple finds + CPMFindPackage( + NAME VTK + GIT_TAG v9.3.1 + VERSION 9.0.0 + GIT_REPOSITORY "https://gitlab.kitware.com/vtk/vtk") + + # These modules need to be initialized for VTK rendering to work properly + vtk_module_autoinit( + TARGETS + ${VIENNAPS_PYTHON_MODULE_NAME} + MODULES + ${VTK_LIBRARIES}) + target_compile_definitions(${VIENNAPS_PYTHON_MODULE_NAME} PRIVATE VIENNALS_VTK_MODULE_INIT) +endif() + # Put the built .so in build/ for convenience set_target_properties( ${VIENNAPS_PYTHON_MODULE_NAME} diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index a27784ec..097deb03 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -72,6 +72,7 @@ // visualization #include +#include // other #include @@ -1327,6 +1328,24 @@ template void bindApi(py::module &module) { // .def("getTranslator", &ToDiskMesh::getTranslator, // "Retrieve the translator from the mesh converter."); +#ifdef VIENNALS_VTK_RENDERING + py::class_>(module, "VTKRenderWindow") + .def(py::init<>()) + .def(py::init(), py::arg("domain")) + .def("setDomain", &VTKRenderWindow::setDomain, + "Set the domain to be visualized.") + .def("render", &VTKRenderWindow::render, + "Render the current domain state.") + .def("setBackgroundColor", &VTKRenderWindow::setBackgroundColor, + "Set the background color of the render window.") + .def("setWindowSize", &VTKRenderWindow::setWindowSize, + "Set the size of the render window.") + .def("setRenderMode", &VTKRenderWindow::setRenderMode, + "Set the render mode (surface, interfaces, volume).") + .def("setScreenshotScale", &VTKRenderWindow::setScreenshotScale, + "Set the scale factor for screenshots taken."); +#endif + // *************************************************************************** // IO OPERATIONS // *************************************************************************** diff --git a/python/viennaps/__init__.pyi b/python/viennaps/__init__.pyi index bd9e7167..42f0992e 100644 --- a/python/viennaps/__init__.pyi +++ b/python/viennaps/__init__.pyi @@ -98,6 +98,7 @@ from viennaps.d2 import StencilLocalLaxFriedrichsScalar from viennaps.d2 import TEOSDeposition from viennaps.d2 import TEOSPECVD from viennaps.d2 import ToDiskMesh +from viennaps.d2 import VTKRenderWindow from viennaps.d2 import WetEtching from viennaps.d2 import Writer from . import _core @@ -187,6 +188,7 @@ __all__: list[str] = [ "Time", "TimeUnit", "ToDiskMesh", + "VTKRenderWindow", "WetEtching", "Writer", "constants", diff --git a/python/viennaps/d2/__init__.pyi b/python/viennaps/d2/__init__.pyi index 7ebcb65d..46ea0d54 100644 --- a/python/viennaps/d2/__init__.pyi +++ b/python/viennaps/d2/__init__.pyi @@ -53,6 +53,7 @@ __all__: list[str] = [ "TEOSDeposition", "TEOSPECVD", "ToDiskMesh", + "VTKRenderWindow", "WetEtching", "Writer", "gpu", @@ -1491,6 +1492,51 @@ class ToDiskMesh: Set the mesh in the mesh converter """ +class VTKRenderWindow: + @typing.overload + def __init__(self) -> None: ... + @typing.overload + def __init__(self, domain: Domain) -> None: ... + def render(self) -> None: + """ + Render the current domain state. + """ + + def setBackgroundColor( + self, + arg0: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ], + ) -> None: + """ + Set the background color of the render window. + """ + + def setDomain(self, arg0: Domain) -> None: + """ + Set the domain to be visualized. + """ + + def setRenderMode(self, arg0: ...) -> None: + """ + Set the render mode (surface, interfaces, volume). + """ + + def setScreenshotScale(self, arg0: typing.SupportsInt) -> None: + """ + Set the scale factor for screenshots taken. + """ + + def setWindowSize( + self, + arg0: typing.Annotated[ + collections.abc.Sequence[typing.SupportsInt], "FixedSize(2)" + ], + ) -> None: + """ + Set the size of the render window. + """ + class WetEtching(ProcessModel): @typing.overload def __init__( diff --git a/python/viennaps/d3/__init__.pyi b/python/viennaps/d3/__init__.pyi index 87f09f54..165499c3 100644 --- a/python/viennaps/d3/__init__.pyi +++ b/python/viennaps/d3/__init__.pyi @@ -53,6 +53,7 @@ __all__: list[str] = [ "TEOSDeposition", "TEOSPECVD", "ToDiskMesh", + "VTKRenderWindow", "WetEtching", "Writer", "gpu", @@ -1496,6 +1497,51 @@ class ToDiskMesh: Set the mesh in the mesh converter """ +class VTKRenderWindow: + @typing.overload + def __init__(self) -> None: ... + @typing.overload + def __init__(self, domain: Domain) -> None: ... + def render(self) -> None: + """ + Render the current domain state. + """ + + def setBackgroundColor( + self, + arg0: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ], + ) -> None: + """ + Set the background color of the render window. + """ + + def setDomain(self, arg0: Domain) -> None: + """ + Set the domain to be visualized. + """ + + def setRenderMode(self, arg0: ...) -> None: + """ + Set the render mode (surface, interfaces, volume). + """ + + def setScreenshotScale(self, arg0: typing.SupportsInt) -> None: + """ + Set the scale factor for screenshots taken. + """ + + def setWindowSize( + self, + arg0: typing.Annotated[ + collections.abc.Sequence[typing.SupportsInt], "FixedSize(2)" + ], + ) -> None: + """ + Set the size of the render window. + """ + class WetEtching(ProcessModel): @typing.overload def __init__( From 69665e5c657fc1771e756046bb93193cff731de4 Mon Sep 17 00:00:00 2001 From: Roman Kostal Date: Thu, 18 Dec 2025 17:24:20 +0100 Subject: [PATCH 11/38] renaming integration -> discretization --- examples/DRAMWiggling/DRAMWiggling.cpp | 4 +- examples/DRAMWiggling/DRAMWiggling.py | 4 +- examples/DRAMWiggling/config.txt | 2 +- .../blazedGratingsEtching.cpp | 6 +-- .../blazedGratingsEtching.py | 2 +- .../cantileverWetEtching.cpp | 4 +- .../cantileverWetEtching.py | 6 +-- examples/emulation/FinFET.cpp | 8 +-- examples/emulation/FinFET.py | 6 +-- .../faradayCageEtching/faradayCageEtching.cpp | 4 +- examples/holeEtching/config.txt | 2 +- examples/holeEtching/holeEtching.cpp | 4 +- examples/holeEtching/holeEtching.py | 4 +- examples/holeEtching/testFluxes.py | 2 +- examples/ionBeamEtching/ionBeamEtching.cpp | 4 +- examples/ionBeamEtching/ionBeamEtching.py | 2 +- .../selectiveEpitaxy/selectiveEpitaxy.cpp | 4 +- examples/selectiveEpitaxy/selectiveEpitaxy.py | 4 +- examples/stackEtching/stackEtching.cpp | 4 +- examples/stackEtching/stackEtching.py | 2 +- include/viennaps/process/psALPStrategy.hpp | 4 +- .../viennaps/process/psAdvectionHandler.hpp | 22 ++++---- .../process/psAnalyticProcessStrategy.hpp | 4 +- .../viennaps/process/psAtomicLayerProcess.hpp | 15 +++--- .../process/psFluxProcessStrategy.hpp | 4 +- include/viennaps/process/psProcessContext.hpp | 27 +++++----- include/viennaps/process/psProcessParams.hpp | 13 ++--- include/viennaps/psUtil.hpp | 53 ++++++++++--------- python/__init__.py | 2 +- python/pyWrap.cpp | 8 +-- python/viennaps/__init__.pyi | 4 +- python/viennaps/_core/__init__.pyi | 2 +- python/viennaps/_core/util.pyi | 6 +-- .../analyticProcessStrategy.cpp | 4 +- tests/util/testUtil.cpp | 30 +++++------ 35 files changed, 141 insertions(+), 135 deletions(-) diff --git a/examples/DRAMWiggling/DRAMWiggling.cpp b/examples/DRAMWiggling/DRAMWiggling.cpp index 5e6f7ab2..d0af9609 100644 --- a/examples/DRAMWiggling/DRAMWiggling.cpp +++ b/examples/DRAMWiggling/DRAMWiggling.cpp @@ -60,8 +60,8 @@ int main(int argc, char **argv) { // Advection parameters AdvectionParameters advectionParams; - advectionParams.integrationScheme = util::convertIntegrationScheme( - params.get("integrationScheme")); + advectionParams.discretizationScheme = util::convertDiscretizationScheme( + params.get("discretizationScheme")); RayTracingParameters rayParams; rayParams.raysPerPoint = params.get("raysPerPoint"); diff --git a/examples/DRAMWiggling/DRAMWiggling.py b/examples/DRAMWiggling/DRAMWiggling.py index 3364a6e8..f064504b 100644 --- a/examples/DRAMWiggling/DRAMWiggling.py +++ b/examples/DRAMWiggling/DRAMWiggling.py @@ -57,8 +57,8 @@ rayTracingParams.raysPerPoint = int(params["raysPerPoint"]) advectionParams = ps.AdvectionParameters() -advectionParams.integrationScheme = ps.util.convertIntegrationScheme( - params["integrationScheme"] +advectionParams.discretizationScheme = ps.util.convertDiscretizationScheme( + params["discretizationScheme"] ) # process setup diff --git a/examples/DRAMWiggling/config.txt b/examples/DRAMWiggling/config.txt index ef26c49f..974c4b41 100644 --- a/examples/DRAMWiggling/config.txt +++ b/examples/DRAMWiggling/config.txt @@ -17,7 +17,7 @@ ionExponent=1000 meanEnergy=200 # eV sigmaEnergy=10 # eV -integrationScheme=LF_2 +discretizationScheme=LF_2 numSteps=100 raysPerPoint=1000 diff --git a/examples/blazedGratingsEtching/blazedGratingsEtching.cpp b/examples/blazedGratingsEtching/blazedGratingsEtching.cpp index e9287ff3..6f483760 100644 --- a/examples/blazedGratingsEtching/blazedGratingsEtching.cpp +++ b/examples/blazedGratingsEtching/blazedGratingsEtching.cpp @@ -32,8 +32,8 @@ int main(int argc, char **argv) { geometry->saveSurfaceMesh("initial"); AdvectionParameters advParams; - advParams.integrationScheme = - viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; + advParams.discretizationScheme = + viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; advParams.timeStepRatio = 0.25; RayTracingParameters rayTracingParams; @@ -83,4 +83,4 @@ int main(int argc, char **argv) { process.apply(); geometry->saveSurfaceMesh("BlazedGratingsEtch_P" + std::to_string(i)); } -} \ No newline at end of file +} diff --git a/examples/blazedGratingsEtching/blazedGratingsEtching.py b/examples/blazedGratingsEtching/blazedGratingsEtching.py index ec738646..d2f18b35 100644 --- a/examples/blazedGratingsEtching/blazedGratingsEtching.py +++ b/examples/blazedGratingsEtching/blazedGratingsEtching.py @@ -54,7 +54,7 @@ # ----- Model Setup ----- # advectionParams = ps.AdvectionParameters() -advectionParams.integrationScheme = ps.IntegrationScheme.LAX_FRIEDRICHS_2ND_ORDER +advectionParams.discretizationScheme = ps.DiscretizationScheme.LAX_FRIEDRICHS_2ND_ORDER advectionParams.timeStepRatio = 0.25 rayTracingParams = ps.RayTracingParameters() diff --git a/examples/cantileverWetEtching/cantileverWetEtching.cpp b/examples/cantileverWetEtching/cantileverWetEtching.cpp index 37ecd17c..9162cb28 100644 --- a/examples/cantileverWetEtching/cantileverWetEtching.cpp +++ b/examples/cantileverWetEtching/cantileverWetEtching.cpp @@ -71,8 +71,8 @@ int main(int argc, char **argv) { {ps::Material::Si, -1.}}); ps::AdvectionParameters advectionParams; - advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + advectionParams.discretizationScheme = viennals::DiscretizationSchemeEnum:: + STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; ps::Process process; process.setDomain(geometry); diff --git a/examples/cantileverWetEtching/cantileverWetEtching.py b/examples/cantileverWetEtching/cantileverWetEtching.py index 831a5644..b807aebf 100644 --- a/examples/cantileverWetEtching/cantileverWetEtching.py +++ b/examples/cantileverWetEtching/cantileverWetEtching.py @@ -1,6 +1,6 @@ # This example only works in 3D mode import viennaps.d3 as psd -from viennaps import BoundaryType, Material, AdvectionParameters, IntegrationScheme +from viennaps import BoundaryType, Material, AdvectionParameters, DiscretizationScheme maskFileName = "cantilever_mask.gds" @@ -56,8 +56,8 @@ ) advectionParams = AdvectionParameters() -advectionParams.integrationScheme = ( - IntegrationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER +advectionParams.discretizationScheme = ( + DiscretizationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER ) process = psd.Process() diff --git a/examples/emulation/FinFET.cpp b/examples/emulation/FinFET.cpp index d03205ee..3d214032 100644 --- a/examples/emulation/FinFET.cpp +++ b/examples/emulation/FinFET.cpp @@ -220,8 +220,8 @@ int main() { auto model = SmartPointer>::New(-1., masks); AdvectionParameters advectionParams; - advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; + advectionParams.discretizationScheme = + viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; Process process(domain, model, 5.); process.setParameters(advectionParams); process.apply(); @@ -236,8 +236,8 @@ int main() { domain->duplicateTopLevelSet(Material::SiGe); Logger::setLogLevel(LogLevel::INFO); AdvectionParameters advectionParams; - advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + advectionParams.discretizationScheme = viennals::DiscretizationSchemeEnum:: + STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; lsInternal::StencilLocalLaxFriedrichsScalar::setMaxDissipation(100); diff --git a/examples/emulation/FinFET.py b/examples/emulation/FinFET.py index 733358e2..74275141 100644 --- a/examples/emulation/FinFET.py +++ b/examples/emulation/FinFET.py @@ -183,7 +183,7 @@ def writeSurface(domain): masks = [ps.Material.PolySi, ps.Material.SiO2, ps.Material.Si3N4] model = ps.IsotropicProcess(rate=-1.0, maskMaterial=masks) advParams = ps.AdvectionParameters() -advParams.integrationScheme = ps.IntegrationScheme.LAX_FRIEDRICHS_2ND_ORDER +advParams.discretizationScheme = ps.DiscretizationScheme.LAX_FRIEDRICHS_2ND_ORDER process = ps.Process(domain, model, 5.0) process.setParameters(advParams) process.apply() @@ -195,8 +195,8 @@ def writeSurface(domain): print("S/D Epitaxy ...", end="", flush=True) domain.duplicateTopLevelSet(ps.Material.SiGe) advectionParams = ps.AdvectionParameters() -advectionParams.integrationScheme = ( - ps.IntegrationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER +advectionParams.discretizationScheme = ( + ps.DiscretizationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER ) ps.StencilLocalLaxFriedrichsScalar.setMaxDissipation(1000) material = [ diff --git a/examples/faradayCageEtching/faradayCageEtching.cpp b/examples/faradayCageEtching/faradayCageEtching.cpp index 1a428800..7eef4661 100644 --- a/examples/faradayCageEtching/faradayCageEtching.cpp +++ b/examples/faradayCageEtching/faradayCageEtching.cpp @@ -46,8 +46,8 @@ int main(int argc, char *argv[]) { cageParams, maskMaterials); ps::AdvectionParameters advectionParams; - advectionParams.integrationScheme = - ps::IntegrationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + advectionParams.discretizationScheme = + ps::DiscretizationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; ps::RayTracingParameters rayParams; rayParams.raysPerPoint = params.get("raysPerPoint"); diff --git a/examples/holeEtching/config.txt b/examples/holeEtching/config.txt index 80aa6f2c..b8bc9b69 100644 --- a/examples/holeEtching/config.txt +++ b/examples/holeEtching/config.txt @@ -28,7 +28,7 @@ A_O=2 # passivation layer yield constant A_Si=7 # Si yield constant etchStopDepth=-10 # maximum etching depth -integrationScheme=EO_1 +discretizationScheme=EO_1 raysPerPoint=1000 diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index f5e57a1e..93ad328f 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -60,8 +60,8 @@ int main(int argc, char *argv[]) { rayTracingParams.raysPerPoint = params.get("raysPerPoint"); AdvectionParameters advectionParams; - advectionParams.integrationScheme = util::convertIntegrationScheme( - params.get("integrationScheme")); + advectionParams.discretizationScheme = util::convertDiscretizationScheme( + params.get("discretizationScheme")); // process setup Process process(geometry, model); diff --git a/examples/holeEtching/holeEtching.py b/examples/holeEtching/holeEtching.py index e328b653..cb2362e9 100644 --- a/examples/holeEtching/holeEtching.py +++ b/examples/holeEtching/holeEtching.py @@ -55,8 +55,8 @@ rayParams.smoothingNeighbors = 2 advParams = ps.AdvectionParameters() -advParams.integrationScheme = ps.util.convertIntegrationScheme( - params["integrationScheme"] +advParams.discretizationScheme = ps.util.convertDiscretizationScheme( + params["discretizationScheme"] ) # process setup diff --git a/examples/holeEtching/testFluxes.py b/examples/holeEtching/testFluxes.py index 3d2b2b8f..a7a7aaa6 100644 --- a/examples/holeEtching/testFluxes.py +++ b/examples/holeEtching/testFluxes.py @@ -57,7 +57,7 @@ processDuration = 3 # min advParams = ps.AdvectionParameters() -advParams.integrationScheme = ps.IntegrationScheme.ENGQUIST_OSHER_2ND_ORDER +advParams.discretizationScheme = ps.DiscretizationScheme.ENGQUIST_OSHER_2ND_ORDER rayParams = ps.RayTracingParameters() rayParams.raysPerPoint = int(1000) diff --git a/examples/ionBeamEtching/ionBeamEtching.cpp b/examples/ionBeamEtching/ionBeamEtching.cpp index 2ec6b9e4..a4f7cdca 100644 --- a/examples/ionBeamEtching/ionBeamEtching.cpp +++ b/examples/ionBeamEtching/ionBeamEtching.cpp @@ -57,8 +57,8 @@ int main(int argc, char *argv[]) { model->setPrimaryDirection(direction); AdvectionParameters advectionParams; - advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; + advectionParams.discretizationScheme = + viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; Process process(geometry, model); process.setProcessDuration(params.get("processTime")); diff --git a/examples/ionBeamEtching/ionBeamEtching.py b/examples/ionBeamEtching/ionBeamEtching.py index d2a27212..9b689943 100644 --- a/examples/ionBeamEtching/ionBeamEtching.py +++ b/examples/ionBeamEtching/ionBeamEtching.py @@ -59,7 +59,7 @@ model.setPrimaryDirection(direction) advParams = ps.AdvectionParameters() -advParams.integrationScheme = ps.IntegrationScheme.LAX_FRIEDRICHS_2ND_ORDER +advParams.discretizationScheme = ps.DiscretizationScheme.LAX_FRIEDRICHS_2ND_ORDER process = ps.Process(geometry, model) process.setProcessDuration(params["processTime"]) diff --git a/examples/selectiveEpitaxy/selectiveEpitaxy.cpp b/examples/selectiveEpitaxy/selectiveEpitaxy.cpp index 51f687c7..6a26e0fd 100644 --- a/examples/selectiveEpitaxy/selectiveEpitaxy.cpp +++ b/examples/selectiveEpitaxy/selectiveEpitaxy.cpp @@ -48,8 +48,8 @@ int main(int argc, char *argv[]) { params.get("R111"), params.get("R100")); ps::AdvectionParameters advectionParams; - advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + advectionParams.discretizationScheme = viennals::DiscretizationSchemeEnum:: + STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; // advectionParams.velocityOutput = true; lsInternal::StencilLocalLaxFriedrichsScalar::setMaxDissipation(1000); diff --git a/examples/selectiveEpitaxy/selectiveEpitaxy.py b/examples/selectiveEpitaxy/selectiveEpitaxy.py index ea17045e..64784b50 100644 --- a/examples/selectiveEpitaxy/selectiveEpitaxy.py +++ b/examples/selectiveEpitaxy/selectiveEpitaxy.py @@ -48,8 +48,8 @@ ) advectionParams = ps.AdvectionParameters() -advectionParams.integrationScheme = ( - ps.IntegrationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER +advectionParams.discretizationScheme = ( + ps.DiscretizationScheme.STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER ) process = ps.Process(geometry, model, params["processTime"]) diff --git a/examples/stackEtching/stackEtching.cpp b/examples/stackEtching/stackEtching.cpp index 44358af8..5193dddc 100644 --- a/examples/stackEtching/stackEtching.cpp +++ b/examples/stackEtching/stackEtching.cpp @@ -70,8 +70,8 @@ int main(int argc, char *argv[]) { SmartPointer>::New(parameters); AdvectionParameters advectionParams; - advectionParams.integrationScheme = - IntegrationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + advectionParams.discretizationScheme = + DiscretizationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; advectionParams.timeStepRatio = 0.25; CoverageParameters coverageParams; diff --git a/examples/stackEtching/stackEtching.py b/examples/stackEtching/stackEtching.py index 98d98300..f06028dd 100644 --- a/examples/stackEtching/stackEtching.py +++ b/examples/stackEtching/stackEtching.py @@ -83,7 +83,7 @@ covParams.tolerance = 1e-4 advParams = vps.AdvectionParameters() -advParams.integrationScheme = vps.IntegrationScheme.LOCAL_LAX_FRIEDRICHS_1ST_ORDER +advParams.discretizationScheme = vps.DiscretizationScheme.LOCAL_LAX_FRIEDRICHS_1ST_ORDER process = vps.d2.Process() process.setDomain(geometry) diff --git a/include/viennaps/process/psALPStrategy.hpp b/include/viennaps/process/psALPStrategy.hpp index d0ca07c7..9c6f098e 100644 --- a/include/viennaps/process/psALPStrategy.hpp +++ b/include/viennaps/process/psALPStrategy.hpp @@ -148,7 +148,7 @@ class ALPStrategy final : public ProcessStrategy { VIENNACORE_LOG_INFO("Cycle: " + std::to_string(cycle + 1) + "/" + std::to_string(numCycles)); - // Prepare advection (expand level set based on integration scheme) + // Prepare advection (expand level set based on discretization scheme) advectionHandler_.prepareAdvection(context); updateState(context); @@ -322,4 +322,4 @@ class ALPStrategy final : public ProcessStrategy { } }; -} // namespace viennaps \ No newline at end of file +} // namespace viennaps diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index af554225..1480d203 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -24,16 +24,18 @@ template class AdvectionHandler { return ProcessResult::INVALID_INPUT; } - auto &intSchem = context.advectionParams.integrationScheme; + auto &discSchem = context.advectionParams.discretizationScheme; if (translationMethod == 1 && - (intSchem != IntegrationScheme::ENGQUIST_OSHER_1ST_ORDER && - intSchem != IntegrationScheme::ENGQUIST_OSHER_2ND_ORDER && - intSchem != IntegrationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER && - intSchem != IntegrationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER && - intSchem != IntegrationScheme::WENO_5TH_ORDER)) { + (discSchem != DiscretizationScheme::ENGQUIST_OSHER_1ST_ORDER && + discSchem != DiscretizationScheme::ENGQUIST_OSHER_2ND_ORDER && + discSchem != + DiscretizationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER && + discSchem != + DiscretizationScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER && + discSchem != DiscretizationScheme::WENO_5TH_ORDER)) { VIENNACORE_LOG_WARNING( "Translation field method not supported in combination " - "with integration scheme."); + "with discretization scheme."); return ProcessResult::INVALID_INPUT; } @@ -41,8 +43,8 @@ template class AdvectionHandler { advectionKernel_.setSingleStep(true); advectionKernel_.setVelocityField(context.translationField); - advectionKernel_.setIntegrationScheme( - context.advectionParams.integrationScheme); + advectionKernel_.setDiscretizationScheme( + context.advectionParams.discretizationScheme); advectionKernel_.setTimeStepRatio(context.advectionParams.timeStepRatio); advectionKernel_.setSaveAdvectionVelocities( context.advectionParams.velocityOutput); @@ -167,4 +169,4 @@ template class AdvectionHandler { void resetTimer() { timer_.reset(); } }; -} // namespace viennaps \ No newline at end of file +} // namespace viennaps diff --git a/include/viennaps/process/psAnalyticProcessStrategy.hpp b/include/viennaps/process/psAnalyticProcessStrategy.hpp index a131a8cb..88034956 100644 --- a/include/viennaps/process/psAnalyticProcessStrategy.hpp +++ b/include/viennaps/process/psAnalyticProcessStrategy.hpp @@ -107,7 +107,7 @@ class AnalyticProcessStrategy final : public ProcessStrategy { } ProcessResult processTimeStep(ProcessContext &context) { - // Prepare advection based on integration scheme + // Prepare advection based on discretization scheme // Initialize model advectionHandler_.prepareAdvection(context); @@ -195,4 +195,4 @@ class AnalyticProcessStrategy final : public ProcessStrategy { } }; -} // namespace viennaps \ No newline at end of file +} // namespace viennaps diff --git a/include/viennaps/process/psAtomicLayerProcess.hpp b/include/viennaps/process/psAtomicLayerProcess.hpp index 1d7d9f58..b0669d5d 100644 --- a/include/viennaps/process/psAtomicLayerProcess.hpp +++ b/include/viennaps/process/psAtomicLayerProcess.hpp @@ -104,12 +104,12 @@ template class AtomicLayerProcess { rayTracingParams_.raysPerPoint = numRays; } - // Set the integration scheme for solving the level-set equation. - // Possible integration schemes are specified in - // viennals::IntegrationSchemeEnum. - void setIntegrationScheme( - viennals::IntegrationSchemeEnum passedIntegrationScheme) { - advectionParams_.integrationScheme = passedIntegrationScheme; + // Set the discretization scheme for solving the level-set equation. + // Possible discretization schemes are specified in + // viennals::DiscretizationSchemeEnum. + void setDiscretizationScheme( + viennals::DiscretizationSchemeEnum passedDiscretizationScheme) { + advectionParams_.discretizationScheme = passedDiscretizationScheme; } // Enable the use of random seeds for ray tracing. This is useful to @@ -156,7 +156,8 @@ template class AtomicLayerProcess { viennals::Advect advectionKernel; advectionKernel.setVelocityField(transField); - advectionKernel.setIntegrationScheme(advectionParams_.integrationScheme); + advectionKernel.setDiscretizationScheme( + advectionParams_.discretizationScheme); advectionKernel.setTimeStepRatio(advectionParams_.timeStepRatio); advectionKernel.setSaveAdvectionVelocities(advectionParams_.velocityOutput); advectionKernel.setDissipationAlpha(advectionParams_.dissipationAlpha); diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index a1a4db2c..1c6b3a0d 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -223,7 +223,7 @@ class FluxProcessStrategy final : public ProcessStrategy { } ProcessResult processTimeStep(ProcessContext &context) { - // Prepare advection (expand level set based on integration scheme) + // Prepare advection (expand level set based on discretization scheme) advectionHandler_.prepareAdvection(context); // Update surface for flux calculation @@ -459,4 +459,4 @@ class FluxProcessStrategy final : public ProcessStrategy { } }; -} // namespace viennaps \ No newline at end of file +} // namespace viennaps diff --git a/include/viennaps/process/psProcessContext.hpp b/include/viennaps/process/psProcessContext.hpp index 8551cb3c..d2588002 100644 --- a/include/viennaps/process/psProcessContext.hpp +++ b/include/viennaps/process/psProcessContext.hpp @@ -96,19 +96,20 @@ template struct ProcessContext { } bool needsExtendedVelocities() const { - return advectionParams.integrationScheme == - IntegrationScheme::LAX_FRIEDRICHS_1ST_ORDER || - advectionParams.integrationScheme == - IntegrationScheme::LAX_FRIEDRICHS_2ND_ORDER || - advectionParams.integrationScheme == - IntegrationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER || - advectionParams.integrationScheme == - IntegrationScheme::LOCAL_LAX_FRIEDRICHS_2ND_ORDER || - advectionParams.integrationScheme == - IntegrationScheme::LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER || - advectionParams.integrationScheme == - IntegrationScheme::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + return advectionParams.discretizationScheme == + DiscretizationScheme::LAX_FRIEDRICHS_1ST_ORDER || + advectionParams.discretizationScheme == + DiscretizationScheme::LAX_FRIEDRICHS_2ND_ORDER || + advectionParams.discretizationScheme == + DiscretizationScheme::LOCAL_LAX_FRIEDRICHS_1ST_ORDER || + advectionParams.discretizationScheme == + DiscretizationScheme::LOCAL_LAX_FRIEDRICHS_2ND_ORDER || + advectionParams.discretizationScheme == + DiscretizationScheme:: + LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER || + advectionParams.discretizationScheme == + DiscretizationScheme::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; } }; -} // namespace viennaps \ No newline at end of file +} // namespace viennaps diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 511206c1..45603f14 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -12,7 +12,7 @@ namespace viennaps { using namespace viennacore; -using IntegrationScheme = viennals::IntegrationSchemeEnum; +using DiscretizationScheme = viennals::DiscretizationSchemeEnum; struct RayTracingParameters { viennaray::NormalizationType normalizationType = @@ -51,8 +51,8 @@ struct RayTracingParameters { }; struct AdvectionParameters { - IntegrationScheme integrationScheme = - IntegrationScheme::ENGQUIST_OSHER_1ST_ORDER; + DiscretizationScheme discretizationScheme = + DiscretizationScheme::ENGQUIST_OSHER_1ST_ORDER; double timeStepRatio = 0.4999; double dissipationAlpha = 1.0; double adaptiveTimeStepThreshold = 0.05; @@ -63,15 +63,16 @@ struct AdvectionParameters { auto toMetaData() const { std::unordered_map> metaData; - metaData["IntegrationScheme"] = {static_cast(integrationScheme)}; + metaData["DiscretizationScheme"] = { + static_cast(discretizationScheme)}; metaData["TimeStepRatio"] = {timeStepRatio}; metaData["DissipationAlpha"] = {dissipationAlpha}; return metaData; } auto toMetaDataString() const { - return "\nIntegrationScheme: " + - util::convertIntegrationSchemeToString(integrationScheme) + + return "\nDiscretizationScheme: " + + util::convertDiscretizationSchemeToString(discretizationScheme) + "\nTimeStepRatio: " + std::to_string(timeStepRatio) + "\nDissipationAlpha: " + std::to_string(dissipationAlpha) + "\nCheckDissipation: " + util::boolString(checkDissipation) + diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index e50e55e1..fa9e8059 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -10,34 +10,34 @@ // Use viennacore here to avoid conflicts with other namespaces namespace viennacore::util { -[[nodiscard]] inline viennals::IntegrationSchemeEnum -convertIntegrationScheme(const std::string &s) { +[[nodiscard]] inline viennals::DiscretizationSchemeEnum +convertDiscretizationScheme(const std::string &s) { if (s == "ENGQUIST_OSHER_1ST_ORDER" || s == "EO_1") - return viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER; + return viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER; if (s == "ENGQUIST_OSHER_2ND_ORDER" || s == "EO_2") - return viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_2ND_ORDER; + return viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_2ND_ORDER; if (s == "LAX_FRIEDRICHS_1ST_ORDER" || s == "LF_1") - return viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_1ST_ORDER; + return viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_1ST_ORDER; if (s == "LAX_FRIEDRICHS_2ND_ORDER" || s == "LF_2") - return viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; + return viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; if (s == "LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER" || s == "LLFA_1") - return viennals::IntegrationSchemeEnum:: + return viennals::DiscretizationSchemeEnum:: LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER; if (s == "LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER" || s == "LLLF_1") - return viennals::IntegrationSchemeEnum:: + return viennals::DiscretizationSchemeEnum:: LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; if (s == "LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER" || s == "LLLF_2") - return viennals::IntegrationSchemeEnum:: + return viennals::DiscretizationSchemeEnum:: LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER; if (s == "LOCAL_LAX_FRIEDRICHS_1ST_ORDER" || s == "LLF_1") - return viennals::IntegrationSchemeEnum::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + return viennals::DiscretizationSchemeEnum::LOCAL_LAX_FRIEDRICHS_1ST_ORDER; if (s == "LOCAL_LAX_FRIEDRICHS_2ND_ORDER" || s == "LLF_2") - return viennals::IntegrationSchemeEnum::LOCAL_LAX_FRIEDRICHS_2ND_ORDER; + return viennals::DiscretizationSchemeEnum::LOCAL_LAX_FRIEDRICHS_2ND_ORDER; if (s == "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER" || s == "SLLF_1") - return viennals::IntegrationSchemeEnum:: + return viennals::DiscretizationSchemeEnum:: STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; if (s == "WENO_5TH_ORDER" || s == "WENO_5") - return viennals::IntegrationSchemeEnum::WENO_5TH_ORDER; + return viennals::DiscretizationSchemeEnum::WENO_5TH_ORDER; throw std::invalid_argument( "The value must be one of the following: " "ENGQUIST_OSHER_1ST_ORDER, ENGQUIST_OSHER_2ND_ORDER, " @@ -52,33 +52,34 @@ convertIntegrationScheme(const std::string &s) { } [[nodiscard]] inline std::string -convertIntegrationSchemeToString(viennals::IntegrationSchemeEnum scheme) { +convertDiscretizationSchemeToString(viennals::DiscretizationSchemeEnum scheme) { switch (scheme) { - case viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER: + case viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER: return "ENGQUIST_OSHER_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_2ND_ORDER: + case viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_2ND_ORDER: return "ENGQUIST_OSHER_2ND_ORDER"; - case viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_1ST_ORDER: + case viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_1ST_ORDER: return "LAX_FRIEDRICHS_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER: + case viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER: return "LAX_FRIEDRICHS_2ND_ORDER"; - case viennals::IntegrationSchemeEnum:: + case viennals::DiscretizationSchemeEnum:: LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER: return "LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: + case viennals::DiscretizationSchemeEnum::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: return "LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER: + case viennals::DiscretizationSchemeEnum::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER: return "LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER"; - case viennals::IntegrationSchemeEnum::LOCAL_LAX_FRIEDRICHS_1ST_ORDER: + case viennals::DiscretizationSchemeEnum::LOCAL_LAX_FRIEDRICHS_1ST_ORDER: return "LOCAL_LAX_FRIEDRICHS_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::LOCAL_LAX_FRIEDRICHS_2ND_ORDER: + case viennals::DiscretizationSchemeEnum::LOCAL_LAX_FRIEDRICHS_2ND_ORDER: return "LOCAL_LAX_FRIEDRICHS_2ND_ORDER"; - case viennals::IntegrationSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: + case viennals::DiscretizationSchemeEnum:: + STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: return "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER"; - case viennals::IntegrationSchemeEnum::WENO_5TH_ORDER: + case viennals::DiscretizationSchemeEnum::WENO_5TH_ORDER: return "WENO_5TH_ORDER"; default: - throw std::invalid_argument("Unknown integration scheme."); + throw std::invalid_argument("Unknown discretization scheme."); } } diff --git a/python/__init__.py b/python/__init__.py index 11ede66a..2c8bf2b6 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -40,7 +40,7 @@ def _module_ptx_path(): import viennals as ls -from viennals import IntegrationSchemeEnum as IntegrationScheme +from viennals import DiscretizationSchemeEnum as DiscretizationScheme from viennals import BoundaryConditionEnum as BoundaryType from viennals import LogLevel as LogLevel from . import _core as _C # the binary inside the package diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 9c1b602e..7cd18471 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -455,8 +455,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { // AdvectionParameters py::class_(module, "AdvectionParameters") .def(py::init<>()) - .def_readwrite("integrationScheme", - &AdvectionParameters::integrationScheme) + .def_readwrite("discretizationScheme", + &AdvectionParameters::discretizationScheme) .def_readwrite("timeStepRatio", &AdvectionParameters::timeStepRatio) .def_readwrite("dissipationAlpha", &AdvectionParameters::dissipationAlpha) .def_readwrite("checkDissipation", &AdvectionParameters::checkDissipation) @@ -518,8 +518,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { // Utility functions auto m_util = module.def_submodule("util", "Utility functions."); - m_util.def("convertIntegrationScheme", &util::convertIntegrationScheme, - "Convert a string to an integration scheme."); + m_util.def("convertDiscretizationScheme", &util::convertDiscretizationScheme, + "Convert a string to an discretization scheme."); // *************************************************************************** // MAIN API diff --git a/python/viennaps/__init__.pyi b/python/viennaps/__init__.pyi index bd9e7167..ff4105ce 100644 --- a/python/viennaps/__init__.pyi +++ b/python/viennaps/__init__.pyi @@ -13,7 +13,7 @@ from __future__ import annotations import sys as _sys import viennals as ls from viennals._core import BoundaryConditionEnum as BoundaryType -from viennals._core import IntegrationSchemeEnum as IntegrationScheme +from viennals._core import DiscretizationSchemeEnum as DiscretizationScheme from viennals._core import LogLevel from viennaps._core import AdvectionParameters from viennaps._core import AtomicLayerProcessParameters @@ -139,7 +139,7 @@ __all__: list[str] = [ "HoleShape", "IBEParameters", "IBEParametersCos4Yield", - "IntegrationScheme", + "DiscretizationScheme", "Interpolation", "IonBeamEtching", "IsotropicProcess", diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index f2b7ee07..2ff31b25 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -67,7 +67,7 @@ class AdvectionParameters: adaptiveTimeStepping: bool checkDissipation: bool ignoreVoids: bool - integrationScheme: viennals._core.IntegrationSchemeEnum + discretizationScheme: viennals._core.DiscretizationSchemeEnum velocityOutput: bool def __init__(self) -> None: ... def toMetaData(self) -> dict[str, list[float]]: diff --git a/python/viennaps/_core/util.pyi b/python/viennaps/_core/util.pyi index fececa7e..4aa5e2c5 100644 --- a/python/viennaps/_core/util.pyi +++ b/python/viennaps/_core/util.pyi @@ -5,9 +5,9 @@ Utility functions. from __future__ import annotations import viennals._core -__all__: list[str] = ["convertIntegrationScheme"] +__all__: list[str] = ["convertDiscretizationScheme"] -def convertIntegrationScheme(arg0: str) -> viennals._core.IntegrationSchemeEnum: +def convertDiscretizationScheme(arg0: str) -> viennals._core.DiscretizationSchemeEnum: """ - Convert a string to an integration scheme. + Convert a string to an discretization scheme. """ diff --git a/tests/analyticProcessStrategy/analyticProcessStrategy.cpp b/tests/analyticProcessStrategy/analyticProcessStrategy.cpp index 9fe7eb95..09f026a7 100644 --- a/tests/analyticProcessStrategy/analyticProcessStrategy.cpp +++ b/tests/analyticProcessStrategy/analyticProcessStrategy.cpp @@ -115,8 +115,8 @@ createBasicContext(SmartPointer> domain, (model->getAdvectionCallback() != nullptr); // Set default advection parameters - context.advectionParams.integrationScheme = - viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER; + context.advectionParams.discretizationScheme = + viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER; context.advectionParams.timeStepRatio = 0.4999; context.advectionParams.velocityOutput = false; context.advectionParams.dissipationAlpha = 0.0; diff --git a/tests/util/testUtil.cpp b/tests/util/testUtil.cpp index 61f1476c..40ad57b7 100644 --- a/tests/util/testUtil.cpp +++ b/tests/util/testUtil.cpp @@ -4,29 +4,29 @@ using namespace viennacore::util; -void TestIntegrationSchemeConversion() { +void TestDiscretizationSchemeConversion() { // Test string to enum - VC_TEST_ASSERT(convertIntegrationScheme("ENGQUIST_OSHER_1ST_ORDER") == - viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER); - VC_TEST_ASSERT(convertIntegrationScheme("EO_1") == - viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER); + VC_TEST_ASSERT(convertDiscretizationScheme("ENGQUIST_OSHER_1ST_ORDER") == + viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER); + VC_TEST_ASSERT(convertDiscretizationScheme("EO_1") == + viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER); // Test string to enum - VC_TEST_ASSERT(convertIntegrationScheme("WENO_5TH_ORDER") == - viennals::IntegrationSchemeEnum::WENO_5TH_ORDER); - VC_TEST_ASSERT(convertIntegrationScheme("WENO_5") == - viennals::IntegrationSchemeEnum::WENO_5TH_ORDER); + VC_TEST_ASSERT(convertDiscretizationScheme("WENO_5TH_ORDER") == + viennals::DiscretizationSchemeEnum::WENO_5TH_ORDER); + VC_TEST_ASSERT(convertDiscretizationScheme("WENO_5") == + viennals::DiscretizationSchemeEnum::WENO_5TH_ORDER); // Test enum to string VC_TEST_ASSERT( - convertIntegrationSchemeToString( - viennals::IntegrationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER) == + convertDiscretizationSchemeToString( + viennals::DiscretizationSchemeEnum::ENGQUIST_OSHER_1ST_ORDER) == "ENGQUIST_OSHER_1ST_ORDER"); // Test round trip - auto scheme = viennals::IntegrationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; - VC_TEST_ASSERT(convertIntegrationScheme( - convertIntegrationSchemeToString(scheme)) == scheme); + auto scheme = viennals::DiscretizationSchemeEnum::LAX_FRIEDRICHS_2ND_ORDER; + VC_TEST_ASSERT(convertDiscretizationScheme( + convertDiscretizationSchemeToString(scheme)) == scheme); } void TestBoundaryConditionConversion() { @@ -47,7 +47,7 @@ void TestMetaDataToString() { } int main() { - TestIntegrationSchemeConversion(); + TestDiscretizationSchemeConversion(); TestBoundaryConditionConversion(); TestMetaDataToString(); std::cout << "Util tests passed!" << std::endl; From 684bd7b534f736d3300f849cd683957fcd7987d6 Mon Sep 17 00:00:00 2001 From: reiter Date: Thu, 18 Dec 2025 17:45:28 +0100 Subject: [PATCH 12/38] Domain offsets --- include/viennaps/psDomain.hpp | 10 ++ include/viennaps/psVTKRenderWindow.hpp | 233 +++++++++++++++---------- python/pyWrapDimension.hpp | 11 +- python/viennaps/_core/__init__.pyi | 2 +- python/viennaps/d2/__init__.pyi | 26 ++- python/viennaps/d3/__init__.pyi | 26 ++- 6 files changed, 205 insertions(+), 103 deletions(-) diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index 6974058d..d509d204 100644 --- a/include/viennaps/psDomain.hpp +++ b/include/viennaps/psDomain.hpp @@ -446,6 +446,16 @@ template class Domain { return levelSets_.back()->getGrid().getBoundaryConditions(); } + auto getMaterialsInDomain() const { + std::set materials; + if (materialMap_) { + for (std::size_t i = 0; i < materialMap_->size(); i++) { + materials.insert(materialMap_->getMaterialAtIdx(i)); + } + } + return materials; + } + void print(std::ostream &out = std::cout, bool hrle = false) const { constexpr std::string_view separator = "*****************************************\n"; diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index d5cd1da9..c17c8e42 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -28,6 +28,9 @@ #include #include #include +#include +#include +#include #include #include @@ -56,10 +59,9 @@ template class Domain; template class VTKRenderWindow { public: - VTKRenderWindow() { initialize(); } - VTKRenderWindow(SmartPointer> passedDomain) - : domain(passedDomain) { - initialize(); + VTKRenderWindow() = default; + VTKRenderWindow(SmartPointer> passedDomain) { + insertNextDomain(passedDomain); } ~VTKRenderWindow() { @@ -73,8 +75,19 @@ template class VTKRenderWindow { } } - void setDomain(SmartPointer> passedDomain) { - domain = passedDomain; + void insertNextDomain(SmartPointer> passedDomain, + const std::array &offset = {0.0, 0.0, 0.0}) { + domains.push_back(passedDomain); + domainOffsets.push_back(offset); + } + + void setDomainOffset(std::size_t domainIndex, + const std::array &offset) { + if (domainIndex >= domainOffsets.size()) { + VIENNACORE_LOG_ERROR("Domain index out of range."); + return; + } + domainOffsets[domainIndex] = offset; } void setBackgroundColor(const std::array &color) { @@ -98,8 +111,8 @@ template class VTKRenderWindow { int getScreenshotScale() const { return screenshotScale; } void render() { + initialize(); updateDisplay(); - interactor->Initialize(); interactor->Start(); } @@ -115,8 +128,8 @@ template class VTKRenderWindow { void initialize(); void updateRenderer(bool useCache = false) { - if (!domain) { - VIENNACORE_LOG_WARNING("No domain set for rendering."); + if (domains.empty()) { + VIENNACORE_LOG_WARNING("No domains set for rendering."); return; } @@ -124,67 +137,87 @@ template class VTKRenderWindow { renderer->RemoveAllViewProps(); renderer->AddActor(instructionsActor); - switch (renderMode) { - case RenderMode::SURFACE: { - SmartPointer> surfaceMesh; - if (useCache && cachedSurfaceMesh) { - surfaceMesh = cachedSurfaceMesh; - } else { - surfaceMesh = domain->getSurfaceMesh(); - cachedSurfaceMesh = surfaceMesh; + // Get min and max material IDs present in the domains + materialMinId = std::numeric_limits::max(); + materialMaxId = 0; + for (const auto &domain : domains) { + if (domain->getLevelSets().empty()) { + VIENNACORE_LOG_WARNING("Domain has no level sets for rendering."); + continue; } - updatePolyData(surfaceMesh); - break; - } - case RenderMode::INTERFACE: { - SmartPointer> interfaceMesh; - if (useCache && cachedInterfaceMesh) { - interfaceMesh = cachedInterfaceMesh; + auto materialsInDomain = domain->getMaterialsInDomain(); + if (!materialsInDomain.empty()) { + materialMinId = std::min(materialMinId, + static_cast(*materialsInDomain.begin())); + materialMaxId = std::max(materialMaxId, + static_cast(*materialsInDomain.rbegin())); } else { - interfaceMesh = domain->getSurfaceMesh(true); - cachedInterfaceMesh = interfaceMesh; + materialMinId = 0; + materialMaxId = std::max( + materialMaxId, static_cast(domain->getLevelSets().size() - 1)); } - updatePolyData(interfaceMesh); - break; } - case RenderMode::VOLUME: { - if (useCache && cachedVolumeMesh) { - updateVolumeMesh(cachedVolumeMesh, cachedMinMatId, cachedMaxMatId); + + cachedSurfaceMesh.resize(domains.size()); + cachedInterfaceMesh.resize(domains.size()); + cachedVolumeMesh.resize(domains.size()); + + for (std::size_t i{0}; i < domains.size(); ++i) { + switch (renderMode) { + case RenderMode::SURFACE: { + SmartPointer> surfaceMesh; + if (useCache && cachedSurfaceMesh[i]) { + surfaceMesh = cachedSurfaceMesh[i]; + } else { + surfaceMesh = domains[i]->getSurfaceMesh(); + cachedSurfaceMesh[i] = surfaceMesh; + } + updatePolyData(surfaceMesh, domainOffsets[i]); break; } - viennals::WriteVisualizationMesh writer; - auto matMap = domain->getMaterialMap(); - auto levelSets = domain->getLevelSets(); - int minMatId = std::numeric_limits::max(); - int maxMatId = std::numeric_limits::min(); - for (auto i{0u}; i < domain->getNumberOfLevelSets(); ++i) { - writer.insertNextLevelSet(levelSets[i]); - if (matMap) { - int lsMinId = static_cast(matMap->getMaterialAtIdx(i)); - int lsMaxId = static_cast(matMap->getMaterialAtIdx(i)); - minMatId = std::min(minMatId, lsMinId); - maxMatId = std::max(maxMatId, lsMaxId); + case RenderMode::INTERFACE: { + SmartPointer> interfaceMesh; + if (useCache && cachedInterfaceMesh[i]) { + interfaceMesh = cachedInterfaceMesh[i]; + } else { + interfaceMesh = domains[i]->getSurfaceMesh(true); + cachedInterfaceMesh[i] = interfaceMesh; } + updatePolyData(interfaceMesh, domainOffsets[i]); + break; + } + case RenderMode::VOLUME: { + if (useCache && cachedVolumeMesh[i]) { + updateVolumeMesh(cachedVolumeMesh[i], domainOffsets[i]); + break; + } + viennals::WriteVisualizationMesh writer; + auto const &levelSets = domains[i]->getLevelSets(); + for (auto ls : levelSets) { + writer.insertNextLevelSet(ls); + } + writer.setMaterialMap(domains[i]->getMaterialMap()->getMaterialMap()); + writer.setWriteToFile(false); + writer.apply(); + + auto volumeMesh = writer.getVolumeMesh(); + cachedVolumeMesh[i] = volumeMesh; + updateVolumeMesh(volumeMesh, domainOffsets[i]); + break; + } + default: + assert(false && "Unknown render mode."); } - writer.setMaterialMap(domain->getMaterialMap()->getMaterialMap()); - writer.setWriteToFile(false); - writer.apply(); - - auto volumeMesh = writer.getVolumeMesh(); - cachedVolumeMesh = volumeMesh; - cachedMinMatId = minMatId; - cachedMaxMatId = maxMatId; - updateVolumeMesh(volumeMesh, minMatId, maxMatId); - break; - } - default: - assert(false && "Unknown render mode."); } + + renderer->ResetCamera(); } private: - void updatePolyData(SmartPointer> mesh) { + void updatePolyData(SmartPointer> mesh, + const std::array &offset) { if (mesh == nullptr) { + assert(false && "Mesh is null."); return; } @@ -242,42 +275,37 @@ template class VTKRenderWindow { bool useMaterialIds = materialIds && (materialIds->size() == mesh->lines.size() + mesh->triangles.size()); - int minId = std::numeric_limits::max(); - int maxId = std::numeric_limits::min(); if (useMaterialIds) { vtkSmartPointer matIdArray = vtkSmartPointer::New(); matIdArray->SetName("MaterialIds"); for (const auto &id : *materialIds) { - int mId = static_cast(id); - matIdArray->InsertNextValue(mId); - minId = std::min(minId, mId); - maxId = std::max(maxId, mId); + matIdArray->InsertNextValue(static_cast(id)); } polyData->GetCellData()->AddArray(matIdArray); polyData->GetCellData()->SetActiveScalars("MaterialIds"); VIENNACORE_LOG_DEBUG("Added MaterialIds array to cell data."); } + vtkSmartPointer transform = + vtkSmartPointer::New(); + transform->Translate(offset.data()); + vtkSmartPointer transformFilter = + vtkSmartPointer::New(); + transformFilter->SetTransform(transform); + transformFilter->SetInputData(polyData); + transformFilter->Update(); + auto mapper = vtkSmartPointer::New(); - mapper->SetInputData(polyData); + mapper->SetInputData(transformFilter->GetOutput()); if (useMaterialIds) { mapper->SetScalarModeToUseCellData(); mapper->ScalarVisibilityOn(); mapper->SelectColorArray("MaterialIds"); - - vtkSmartPointer lut = - vtkSmartPointer::New(); - - lut->SetNumberOfTableValues(256); - lut->SetHueRange(0.667, 0.0); // blue โ†’ red - lut->SetSaturationRange(1.0, 1.0); - lut->SetValueRange(1.0, 1.0); - lut->Build(); - mapper->SetLookupTable(lut); - mapper->SetScalarRange(minId, maxId); + assert(materialMinId != -1 && materialMaxId != -1); + mapper->SetScalarRange(materialMinId, materialMaxId); } auto actor = vtkSmartPointer::New(); @@ -285,42 +313,47 @@ template class VTKRenderWindow { actor->GetProperty()->SetLineWidth(3.0); // Thicker lines renderer->AddActor(actor); - renderer->ResetCamera(); } void updateVolumeMesh(vtkSmartPointer volumeMesh, - int minMatId = 0, int maxMatId = 100) { + const std::array &offset) { + if (volumeMesh == nullptr) { + assert(false && "Volume mesh is null."); + return; + } + + vtkSmartPointer transform = + vtkSmartPointer::New(); + transform->Translate(offset.data()); + vtkSmartPointer transformFilter = + vtkSmartPointer::New(); + transformFilter->SetTransform(transform); + transformFilter->SetInputData(volumeMesh); + transformFilter->Update(); + auto mapper = vtkSmartPointer::New(); - mapper->SetInputData(volumeMesh); + mapper->SetInputData(transformFilter->GetOutput()); mapper->SetScalarModeToUseCellData(); mapper->ScalarVisibilityOn(); mapper->SelectColorArray("Material"); - vtkSmartPointer lut = - vtkSmartPointer::New(); - - lut->SetNumberOfTableValues(256); - lut->SetHueRange(0.667, 0.0); // blue โ†’ red - lut->SetSaturationRange(1.0, 1.0); - lut->SetValueRange(1.0, 1.0); - lut->Build(); - mapper->SetLookupTable(lut); - mapper->SetScalarRange(minMatId, maxMatId); + mapper->SetScalarRange(materialMinId, materialMaxId); auto actor = vtkSmartPointer::New(); actor->SetMapper(mapper); renderer->AddActor(actor); - renderer->ResetCamera(); } private: - SmartPointer> domain; + std::vector>> domains; + std::vector> domainOffsets; vtkSmartPointer renderer; vtkSmartPointer renderWindow; vtkSmartPointer interactor; + vtkSmartPointer lut; // text vtkSmartPointer instructionsActor; @@ -332,11 +365,11 @@ template class VTKRenderWindow { RenderMode renderMode = RenderMode::INTERFACE; // cached meshes - SmartPointer> cachedSurfaceMesh; - SmartPointer> cachedInterfaceMesh; - vtkSmartPointer cachedVolumeMesh; - int cachedMinMatId = -1; - int cachedMaxMatId = -1; + std::vector>> cachedSurfaceMesh; + std::vector>> cachedInterfaceMesh; + std::vector> cachedVolumeMesh; + int materialMinId = -1; + int materialMaxId = -1; }; namespace impl { @@ -499,6 +532,16 @@ template void VTKRenderWindow::initialize() { style->SetDefaultRenderer(renderer); style->SetCurrentRenderer(renderer); } + + interactor->Initialize(); + + lut = vtkSmartPointer::New(); + + lut->SetNumberOfTableValues(256); + lut->SetHueRange(0.667, 0.0); // blue โ†’ red + lut->SetSaturationRange(1.0, 1.0); + lut->SetValueRange(.5, 1.0); + lut->Build(); } } // namespace viennaps diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index 097deb03..d86c1388 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -517,6 +517,8 @@ template void bindApi(py::module &module) { .def("generateCellSet", &Domain::generateCellSet, "Generate the cell set.") .def("getLevelSets", &Domain::getLevelSets) + .def("getMaterialsInDomain", &Domain::getMaterialsInDomain, + "Get the material IDs present in the domain.") .def("getSurface", &Domain::getSurface, "Get the surface level set.") .def("getCellSet", &Domain::getCellSet, "Get the cell set.") @@ -1332,8 +1334,9 @@ template void bindApi(py::module &module) { py::class_>(module, "VTKRenderWindow") .def(py::init<>()) .def(py::init(), py::arg("domain")) - .def("setDomain", &VTKRenderWindow::setDomain, - "Set the domain to be visualized.") + .def("insertNextDomain", &VTKRenderWindow::insertNextDomain, + "Insert domain to be visualized.", py::arg("domain"), + py::arg("offset") = std::array{0., 0., 0.}) .def("render", &VTKRenderWindow::render, "Render the current domain state.") .def("setBackgroundColor", &VTKRenderWindow::setBackgroundColor, @@ -1343,7 +1346,9 @@ template void bindApi(py::module &module) { .def("setRenderMode", &VTKRenderWindow::setRenderMode, "Set the render mode (surface, interfaces, volume).") .def("setScreenshotScale", &VTKRenderWindow::setScreenshotScale, - "Set the scale factor for screenshots taken."); + "Set the scale factor for screenshots taken.") + .def("setDomainOffset", &VTKRenderWindow::setDomainOffset, + "Set an offset to be applied to the domain during rendering."); #endif // *************************************************************************** diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index d23c0378..24a5eefc 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -9,8 +9,8 @@ import typing import viennals._core from viennaps import d2 import viennaps.d2 -from viennaps import d3 import viennaps.d3 +from viennaps import d3 from . import constants from . import gpu from . import util diff --git a/python/viennaps/d2/__init__.pyi b/python/viennaps/d2/__init__.pyi index 46ea0d54..bfa5390a 100644 --- a/python/viennaps/d2/__init__.pyi +++ b/python/viennaps/d2/__init__.pyi @@ -535,6 +535,11 @@ class Domain: def getLevelSets(self) -> list[viennals.d2.Domain]: ... def getMaterialMap(self) -> viennaps._core.MaterialMap: ... + def getMaterialsInDomain(self) -> set[viennaps._core.Material]: + """ + Get the material IDs present in the domain. + """ + def getMetaData(self) -> dict[str, list[float]]: """ Get meta data (e.g. process data) stored in the domain @@ -1497,6 +1502,17 @@ class VTKRenderWindow: def __init__(self) -> None: ... @typing.overload def __init__(self, domain: Domain) -> None: ... + def insertNextDomain( + self, + domain: Domain, + offset: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ] = [0.0, 0.0, 0.0], + ) -> None: + """ + Insert domain to be visualized. + """ + def render(self) -> None: """ Render the current domain state. @@ -1512,9 +1528,15 @@ class VTKRenderWindow: Set the background color of the render window. """ - def setDomain(self, arg0: Domain) -> None: + def setDomainOffset( + self, + arg0: typing.SupportsInt, + arg1: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ], + ) -> None: """ - Set the domain to be visualized. + Set an offset to be applied to the domain during rendering. """ def setRenderMode(self, arg0: ...) -> None: diff --git a/python/viennaps/d3/__init__.pyi b/python/viennaps/d3/__init__.pyi index 165499c3..e419aac3 100644 --- a/python/viennaps/d3/__init__.pyi +++ b/python/viennaps/d3/__init__.pyi @@ -535,6 +535,11 @@ class Domain: def getLevelSets(self) -> list[viennals.d3.Domain]: ... def getMaterialMap(self) -> viennaps._core.MaterialMap: ... + def getMaterialsInDomain(self) -> set[viennaps._core.Material]: + """ + Get the material IDs present in the domain. + """ + def getMetaData(self) -> dict[str, list[float]]: """ Get meta data (e.g. process data) stored in the domain @@ -1502,6 +1507,17 @@ class VTKRenderWindow: def __init__(self) -> None: ... @typing.overload def __init__(self, domain: Domain) -> None: ... + def insertNextDomain( + self, + domain: Domain, + offset: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ] = [0.0, 0.0, 0.0], + ) -> None: + """ + Insert domain to be visualized. + """ + def render(self) -> None: """ Render the current domain state. @@ -1517,9 +1533,15 @@ class VTKRenderWindow: Set the background color of the render window. """ - def setDomain(self, arg0: Domain) -> None: + def setDomainOffset( + self, + arg0: typing.SupportsInt, + arg1: typing.Annotated[ + collections.abc.Sequence[typing.SupportsFloat], "FixedSize(3)" + ], + ) -> None: """ - Set the domain to be visualized. + Set an offset to be applied to the domain during rendering. """ def setRenderMode(self, arg0: ...) -> None: From 9adde097a9fb05fc2c6d0f605af7641b7f7cccb1 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Sun, 21 Dec 2025 20:42:55 +0100 Subject: [PATCH 13/38] Add more features to render window --- include/viennaps/psVTKRenderWindow.hpp | 162 ++++++++++++++++++------- python/pyWrap.cpp | 7 ++ python/pyWrapDimension.hpp | 46 +++++-- 3 files changed, 160 insertions(+), 55 deletions(-) diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index c17c8e42..fec5064e 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -6,13 +6,9 @@ #include #include -#include -#include -#include #include #include #include -#include #include #include #include @@ -42,25 +38,21 @@ VTK_MODULE_INIT(vtkRenderingFreeType); VTK_MODULE_INIT(vtkRenderingUI); #endif -namespace viennaps { -template class VTKRenderWindow; - -enum class RenderMode { SURFACE, INTERFACE, VOLUME }; -} // namespace viennaps - // Forward declaration - full definition after VTKRenderWindow class Custom3DInteractorStyle; class Custom2DInteractorStyle; namespace viennaps { +enum class RenderMode { SURFACE, INTERFACE, VOLUME }; // forward declaration of Domain template class Domain; template class VTKRenderWindow { public: - VTKRenderWindow() = default; + VTKRenderWindow() { initialize(); } VTKRenderWindow(SmartPointer> passedDomain) { + initialize(); insertNextDomain(passedDomain); } @@ -106,28 +98,117 @@ template class VTKRenderWindow { void setRenderMode(RenderMode mode) { renderMode = mode; } + void setCameraPosition(const std::array &position) { + if (renderer) { + renderer->GetActiveCamera()->SetPosition(position.data()); + } + } + + void setCameraViewUp(const std::array &viewUp) { + if (renderer) { + renderer->GetActiveCamera()->SetViewUp(viewUp.data()); + } + } + + void setCameraFocalPoint(const std::array &focalPoint) { + if (renderer) { + renderer->GetActiveCamera()->SetFocalPoint(focalPoint.data()); + } + } + + void setCameraView(int axis) { + if (renderer) { + vtkCamera *camera = renderer->GetActiveCamera(); + switch (axis) { + case 0: // X + camera->SetPosition(1, 0, 0); + camera->SetFocalPoint(0, 0, 0); + camera->SetViewUp(0, 0, 1); + break; + case 1: // Y + camera->SetPosition(0, 1, 0); + camera->SetFocalPoint(0, 0, 0); + camera->SetViewUp(0, 0, 1); + break; + case 2: // Z + camera->SetPosition(0, 0, 1); + camera->SetFocalPoint(0, 0, 0); + camera->SetViewUp(0, 1, 0); + break; + default: + VIENNACORE_LOG_WARNING("Invalid axis for camera view."); + } + } + } + + void printCameraInfo() { + if (renderer) { + vtkCamera *camera = renderer->GetActiveCamera(); + double position[3]; + camera->GetPosition(position); + double focalPoint[3]; + camera->GetFocalPoint(focalPoint); + double viewUp[3]; + camera->GetViewUp(viewUp); + + VIENNACORE_LOG_INFO("Camera Position: (" + std::to_string(position[0]) + + ", " + std::to_string(position[1]) + ", " + + std::to_string(position[2]) + ")"); + VIENNACORE_LOG_INFO("Camera Focal Point: (" + + std::to_string(focalPoint[0]) + ", " + + std::to_string(focalPoint[1]) + ", " + + std::to_string(focalPoint[2]) + ")"); + VIENNACORE_LOG_INFO("Camera View Up: (" + std::to_string(viewUp[0]) + + ", " + std::to_string(viewUp[1]) + ", " + + std::to_string(viewUp[2]) + ")"); + } + } + void setScreenshotScale(int scale) { screenshotScale = scale; } - int getScreenshotScale() const { return screenshotScale; } + void saveScreenshot(const std::string &fileName) { + vtkSmartPointer windowToImageFilter = + vtkSmartPointer::New(); + windowToImageFilter->SetInput(renderWindow); + windowToImageFilter->SetScale(screenshotScale); // image quality + windowToImageFilter->Update(); + + VIENNACORE_LOG_INFO("Saving screenshot '" + fileName + "'"); + + vtkSmartPointer writer = vtkSmartPointer::New(); + writer->SetFileName(fileName.c_str()); + writer->SetInputData(windowToImageFilter->GetOutput()); + writer->Write(); + } void render() { - initialize(); updateDisplay(); interactor->Start(); } // Update the display without starting a new event loop (for use during // interaction) - void updateDisplay(bool useCache = false) { + void updateDisplay(bool useCache = true) { updateRenderer(useCache); renderWindow->Render(); } + void toggleInstructionText() { + if (instructionsAdded) { + instructionsActor->SetInput(""); + instructionsAdded = false; + } else { + instructionsActor->SetInput(instructionsText.c_str()); + instructionsAdded = true; + } + renderWindow->Render(); + } + private: // forward declaration, requires full definition of Interactor styles void initialize(); - void updateRenderer(bool useCache = false) { + void updateRenderer(bool useCache = true) { if (domains.empty()) { VIENNACORE_LOG_WARNING("No domains set for rendering."); return; @@ -356,7 +437,11 @@ template class VTKRenderWindow { vtkSmartPointer lut; // text + const std::string instructionsText = + "Press 1: Surface | 2: Interface | 3: Volume | " + "x/y/z: View | s: Screenshot | h: Show/Hide Instructions | q/e: Quit"; vtkSmartPointer instructionsActor; + bool instructionsAdded = false; std::array backgroundColor = {84.0 / 255, 89.0 / 255, 109.0 / 255}; std::array windowSize = {800, 600}; @@ -402,34 +487,21 @@ void InteractorOnChar(vtkRenderWindowInteractor *rwi, rwi->TerminateApp(); return; case 'x': - camera->SetPosition(500.0, 0, 0); // Positive X - camera->SetFocalPoint(0.0, 0.0, 0.0); - camera->SetViewUp(0.0, 1.0, 0.0); + window->setCameraView(0); renderer->ResetCamera(); rwi->GetRenderWindow()->Render(); return; case 'y': - camera->SetPosition(0, 500.0, 0); // Positive Y - camera->SetFocalPoint(0.0, 0.0, 0.0); - camera->SetViewUp(0.0, 0.0, 1.0); + window->setCameraView(1); renderer->ResetCamera(); rwi->GetRenderWindow()->Render(); return; case 'z': - camera->SetPosition(0, 0, 500.0); // Positive Z - camera->SetFocalPoint(0.0, 0.0, 0.0); - camera->SetViewUp(0.0, 1.0, 0.0); + window->setCameraView(2); renderer->ResetCamera(); rwi->GetRenderWindow()->Render(); return; case 's': { - vtkSmartPointer windowToImageFilter = - vtkSmartPointer::New(); - windowToImageFilter->SetInput(rwi->GetRenderWindow()); - windowToImageFilter->SetScale( - window->getScreenshotScale()); // image quality - windowToImageFilter->Update(); - auto time_t = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); char timeStamp[20]; @@ -437,14 +509,15 @@ void InteractorOnChar(vtkRenderWindowInteractor *rwi, std::localtime(&time_t)); const std::string fileName = "screenshot_" + std::string(timeStamp) + ".png"; - VIENNACORE_LOG_INFO("Saving screenshot '" + fileName + "'"); - - vtkSmartPointer writer = vtkSmartPointer::New(); - writer->SetFileName(fileName.c_str()); - writer->SetInputData(windowToImageFilter->GetOutput()); - writer->Write(); + window->saveScreenshot(fileName); return; } + case 'h': + window->toggleInstructionText(); + return; + case 'p': + window->printCameraInfo(); + return; } } } // namespace impl @@ -456,7 +529,9 @@ class Custom3DInteractorStyle : public vtkInteractorStyleTrackballCamera { static Custom3DInteractorStyle *New(); vtkTypeMacro(Custom3DInteractorStyle, vtkInteractorStyleTrackballCamera); - void OnChar() { viennaps::impl::InteractorOnChar(this->Interactor, Window); } + void OnChar() override { + viennaps::impl::InteractorOnChar(this->Interactor, Window); + } void setRenderWindow(viennaps::VTKRenderWindow *window) { Window = window; @@ -477,7 +552,9 @@ class Custom2DInteractorStyle : public vtkInteractorStyleImage { void OnLeftButtonUp() override { this->EndPan(); } - void OnChar() { viennaps::impl::InteractorOnChar(this->Interactor, Window); } + void OnChar() override { + viennaps::impl::InteractorOnChar(this->Interactor, Window); + } void setRenderWindow(viennaps::VTKRenderWindow *window) { Window = window; @@ -499,14 +576,14 @@ template void VTKRenderWindow::initialize() { // add text actor for instructions instructionsActor = vtkSmartPointer::New(); - instructionsActor->SetInput("Press 1: Surface | 2: Interface | 3: Volume | " - "x/y/z: View | s: Screenshot | q/e: Quit"); instructionsActor->GetTextProperty()->SetFontSize(14); instructionsActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0); instructionsActor->SetPosition(10, 10); + instructionsActor->SetInput(instructionsText.c_str()); + instructionsAdded = true; renderWindow = vtkSmartPointer::New(); - renderWindow->SetWindowName("ViennaPS Render Window"); + renderWindow->SetWindowName("ViennaPS"); renderWindow->SetSize(windowSize.data()); renderWindow->AddRenderer(renderer); @@ -520,6 +597,7 @@ template void VTKRenderWindow::initialize() { style->setRenderWindow(this); interactor->SetInteractorStyle(style); } else { + setCameraView(1); // Default view along Y axis auto style = vtkSmartPointer::New(); style->setRenderWindow(this); interactor->SetInteractorStyle(style); diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 9c1b602e..3a4c67e9 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -71,6 +71,13 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .value("FULL", MetaDataLevel::FULL) .finalize(); + // Render Mode Enum + py::native_enum(module, "RenderMode", "enum.IntEnum") + .value("SURFACE", RenderMode::SURFACE) + .value("INTERFACE", RenderMode::INTERFACE) + .value("VOLUME", RenderMode::VOLUME) + .finalize(); + // HoleShape Enum py::native_enum(module, "HoleShape", "enum.IntEnum") .value("FULL", HoleShape::FULL) diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index d86c1388..d8c476b4 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -1289,23 +1289,27 @@ template void bindApi(py::module &module) { py::arg("path"), "Set the path for intermediate output files during the process.") .def("setParameters", - (void(ProcessTD::*)(const AdvectionParameters &)) & - ProcessTD::template setParameters, + (void (ProcessTD::*)( + const AdvectionParameters + &))&ProcessTD::template setParameters, py::arg("parameters"), "Set the advection parameters for the process.") .def("setParameters", - (void(ProcessTD::*)(const RayTracingParameters &)) & - ProcessTD::template setParameters, + (void (ProcessTD::*)( + const RayTracingParameters + &))&ProcessTD::template setParameters, py::arg("parameters"), "Set the ray tracing parameters for the process.") .def("setParameters", - (void(ProcessTD::*)(const CoverageParameters &)) & - ProcessTD::template setParameters, + (void (ProcessTD::*)( + const CoverageParameters + &))&ProcessTD::template setParameters, py::arg("parameters"), "Set the coverage parameters for the process.") .def("setParameters", - (void(ProcessTD::*)(const AtomicLayerProcessParameters &)) & - ProcessTD::template setParameters, + (void (ProcessTD::*)( + const AtomicLayerProcessParameters &))&ProcessTD:: + template setParameters, py::arg("parameters"), "Set the atomic layer parameters for the process."); @@ -1337,18 +1341,34 @@ template void bindApi(py::module &module) { .def("insertNextDomain", &VTKRenderWindow::insertNextDomain, "Insert domain to be visualized.", py::arg("domain"), py::arg("offset") = std::array{0., 0., 0.}) - .def("render", &VTKRenderWindow::render, - "Render the current domain state.") + .def("setDomainOffset", &VTKRenderWindow::setDomainOffset, + "Set an offset to be applied to the domain during rendering.") .def("setBackgroundColor", &VTKRenderWindow::setBackgroundColor, "Set the background color of the render window.") .def("setWindowSize", &VTKRenderWindow::setWindowSize, "Set the size of the render window.") .def("setRenderMode", &VTKRenderWindow::setRenderMode, "Set the render mode (surface, interfaces, volume).") + .def("setCameraPosition", &VTKRenderWindow::setCameraPosition, + "Set the camera position in world coordinates.") + .def("setCameraFocalPoint", &VTKRenderWindow::setCameraFocalPoint, + "Set the camera focal point in world coordinates.") + .def("setCameraViewUp", &VTKRenderWindow::setCameraViewUp, + "Set the camera view up vector.") + .def("setCameraView", &VTKRenderWindow::setCameraView, + "Set the camera view along an axix (x,y,z)", py::arg("axis")) + .def("printCameraInfo", &VTKRenderWindow::printCameraInfo, + "Print the current camera settings to the console.") + .def("saveScreenshot", &VTKRenderWindow::saveScreenshot, + "Save a screenshot of the current render window.", + py::arg("fileName")) + .def("toggleInstructionText", + &VTKRenderWindow::toggleInstructionText, + "Toggle the instruction text overlay on/off.") + .def("render", &VTKRenderWindow::render, + "Render the current domain state.") .def("setScreenshotScale", &VTKRenderWindow::setScreenshotScale, - "Set the scale factor for screenshots taken.") - .def("setDomainOffset", &VTKRenderWindow::setDomainOffset, - "Set an offset to be applied to the domain during rendering."); + "Set the scale factor for screenshots taken."); #endif // *************************************************************************** From 58d36c087615323e4becf4a6c041dbc729de8198 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Sun, 21 Dec 2025 22:39:50 +0100 Subject: [PATCH 14/38] Add material colors and scalar bar --- include/viennaps/psMaterials.hpp | 194 +++++++++++++------------ include/viennaps/psVTKRenderWindow.hpp | 103 ++++++++++--- python/pyWrap.cpp | 3 +- python/pyWrapDimension.hpp | 6 +- 4 files changed, 181 insertions(+), 125 deletions(-) diff --git a/include/viennaps/psMaterials.hpp b/include/viennaps/psMaterials.hpp index 3b3af1ef..ac7f7f88 100644 --- a/include/viennaps/psMaterials.hpp +++ b/include/viennaps/psMaterials.hpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -29,108 +30,107 @@ enum class MaterialCategory : uint8_t { }; #define MATERIAL_LIST(X) \ - /* id, sym, cat, density_gcm3, conductive */ \ - X(0, Mask, Hardmask, 500.0, false) \ - X(1, Polymer, Generic, 1.2, false) \ - X(2, Air, Generic, 0.0012, false) \ - X(3, GAS, Generic, 0.001, false) \ - X(4, Dielectric, Generic, 2.2, false) \ - X(5, Metal, Metal, 7.5, true) \ - X(6, Undefined, Generic, 0.0, false) \ + /* id, sym, cat, density_gcm3, conductive, color (hex) */ \ + X(0, Mask, Hardmask, 500.0, false, 0x555555) \ + X(1, Polymer, Generic, 1.2, false, 0xffd54f) \ + X(2, Air, Generic, 0.0012, false, 0x87ceeb) \ + X(3, GAS, Generic, 0.001, false, 0xb0e0e6) \ + X(4, Dielectric, Generic, 2.2, false, 0xaed6f1) \ + X(5, Metal, Metal, 7.5, true, 0xc0c0c0) \ + X(6, Undefined, Generic, 0.0, false, 0xcccccc) \ /* Silicon and derivatives */ \ - X(10, Si, Silicon, 2.33, false) \ - X(11, PolySi, Silicon, 2.33, false) \ - X(12, aSi, Silicon, 2.2, false) \ - X(13, SiGe, Silicon, 4.0, false) \ - X(14, SiC, Silicon, 3.21, false) \ - X(15, SiN, OxideNitride, 3.1, false) \ - X(16, Si3N4, OxideNitride, 3.1, false) \ - X(17, SiON, OxideNitride, 2.4, false) \ - X(18, SiCN, OxideNitride, 2.6, false) \ - X(19, SiBCN, OxideNitride, 2.3, false) \ - X(20, SiCOH, OxideNitride, 1.9, false) \ - X(21, SiOCN, OxideNitride, 2.1, false) \ + X(10, Si, Silicon, 2.33, false, 0xc79a08) \ + X(11, PolySi, Silicon, 2.33, false, 0x888888) \ + X(12, aSi, Silicon, 2.2, false, 0x666666) \ + X(13, SiGe, Silicon, 4.0, false, 0x9e9e9e) \ + X(14, SiC, Silicon, 3.21, false, 0x4f4f4f) \ + X(15, SiN, OxideNitride, 3.1, false, 0x00bfa5) \ + X(16, Si3N4, OxideNitride, 3.1, false, 0x00a8a8) \ + X(17, SiON, OxideNitride, 2.4, false, 0x33cccc) \ + X(18, SiCN, OxideNitride, 2.6, false, 0x2aa198) \ + X(19, SiBCN, OxideNitride, 2.3, false, 0x00897b) \ + X(20, SiCOH, OxideNitride, 1.9, false, 0x26c6da) \ + X(21, SiOCN, OxideNitride, 2.1, false, 0x00acc1) \ /* Oxides and nitrides */ \ - X(30, SiO2, OxideNitride, 2.2, false) \ - X(31, Al2O3, OxideNitride, 3.95, false) \ - X(32, HfO2, OxideNitride, 9.7, false) \ - X(33, ZrO2, OxideNitride, 5.7, false) \ - X(34, TiO2, OxideNitride, 4.2, false) \ - X(35, Y2O3, OxideNitride, 5.0, false) \ - X(36, La2O3, OxideNitride, 6.5, false) \ - X(37, AlN, OxideNitride, 3.26, false) \ - X(38, Ta2O5, OxideNitride, 8.2, false) \ - X(39, BN, OxideNitride, 2.1, false) \ - X(40, hBN, OxideNitride, 2.1, false) \ + X(30, SiO2, OxideNitride, 2.2, false, 0x66ccff) \ + X(31, Al2O3, OxideNitride, 3.95, false, 0x90caf9) \ + X(32, HfO2, OxideNitride, 9.7, false, 0x3f51b5) \ + X(33, ZrO2, OxideNitride, 5.7, false, 0x5c6bc0) \ + X(34, TiO2, OxideNitride, 4.2, false, 0x64b5f6) \ + X(35, Y2O3, OxideNitride, 5.0, false, 0x42a5f5) \ + X(36, La2O3, OxideNitride, 6.5, false, 0x2196f3) \ + X(37, AlN, OxideNitride, 3.26, false, 0x00bcd4) \ + X(38, Ta2O5, OxideNitride, 8.2, false, 0x1976d2) \ + X(39, BN, OxideNitride, 2.1, false, 0x4db6ac) \ + X(40, hBN, OxideNitride, 2.1, false, 0x80cbc4) \ /* Carbon / hardmasks and organics */ \ - X(50, C, Hardmask, 2.2, false) \ - X(51, aC, Hardmask, 1.8, false) \ - X(52, SOC, Hardmask, 1.4, false) \ - X(53, SOG, OxideNitride, 1.4, false) \ - X(54, BPSG, OxideNitride, 2.2, false) \ - X(55, PSG, OxideNitride, 2.2, false) \ - X(56, SiLK, Hardmask, 1.0, false) \ - X(57, ARC, Hardmask, 1.1, false) \ - X(58, PMMA, Hardmask, 1.18, false) \ - X(59, PHS, Hardmask, 1.2, false) \ - X(60, HSQ, OxideNitride, 1.3, false) \ + X(50, C, Hardmask, 2.2, false, 0x212121) \ + X(51, aC, Hardmask, 1.8, false, 0x303030) \ + X(52, SOC, Hardmask, 1.4, false, 0x795548) \ + X(53, SOG, OxideNitride, 1.4, false, 0xa1887f) \ + X(54, BPSG, OxideNitride, 2.2, false, 0x8d6e63) \ + X(55, PSG, OxideNitride, 2.2, false, 0x6d4c41) \ + X(56, SiLK, Hardmask, 1.0, false, 0xffb74d) \ + X(57, ARC, Hardmask, 1.1, false, 0xffa000) \ + X(58, PMMA, Hardmask, 1.18, false, 0xec407a) \ + X(59, PHS, Hardmask, 1.2, false, 0xffe082) \ + X(60, HSQ, OxideNitride, 1.3, false, 0x81d4fa) \ /* Metals */ \ - X(70, W, Metal, 19.3, true) \ - X(71, Cu, Metal, 8.96, true) \ - X(72, Co, Metal, 8.9, true) \ - X(73, Ru, Metal, 12.4, true) \ - X(74, Ni, Metal, 8.9, true) \ - X(75, Pt, Metal, 21.4, true) \ - X(76, Ta, Metal, 16.7, true) \ - X(77, TaN, Metal, 14.3, true) \ - X(78, Ti, Metal, 4.5, true) \ - X(79, TiN, Metal, 5.4, true) \ - X(80, Mo, Metal, 10.3, true) \ - X(81, Ir, Metal, 22.6, true) \ - X(82, Rh, Metal, 12.4, true) \ - X(83, Pd, Metal, 12.0, true) \ - X(84, RuTa, Metal, 13.5, true) \ - X(85, CoW, Metal, 9.5, true) \ - X(86, NiW, Metal, 9.6, true) \ - X(87, TiAlN, Metal, 4.8, true) \ - X(88, Mn, Metal, 7.2, true) \ - X(89, MnO, Metal, 5.4, false) \ - X(90, MnN, Metal, 6.1, false) \ - X(91, Au, Metal, 19.3, true) \ - X(92, Cr, Metal, 7.19, true) \ + X(70, W, Metal, 19.3, true, 0x6e6e6e) \ + X(71, Cu, Metal, 8.96, true, 0xb87333) \ + X(72, Co, Metal, 8.9, true, 0x3d5a99) \ + X(73, Ru, Metal, 12.4, true, 0x7a7a7a) \ + X(74, Ni, Metal, 8.9, true, 0x9c9c9c) \ + X(75, Pt, Metal, 21.4, true, 0xe5e4e2) \ + X(76, Ta, Metal, 16.7, true, 0x8d909b) \ + X(77, TaN, Metal, 14.3, true, 0x6b6f7b) \ + X(78, Ti, Metal, 4.5, true, 0xc0c0c0) \ + X(79, TiN, Metal, 5.4, true, 0xc5a200) \ + X(80, Mo, Metal, 10.3, true, 0x8f8f8f) \ + X(81, Ir, Metal, 22.6, true, 0xdfe0e2) \ + X(82, Rh, Metal, 12.4, true, 0xd1d1d1) \ + X(83, Pd, Metal, 12.0, true, 0xc9c9c9) \ + X(84, RuTa, Metal, 13.5, true, 0x7b7f8a) \ + X(85, CoW, Metal, 9.5, true, 0x708090) \ + X(86, NiW, Metal, 9.6, true, 0x7f8c8d) \ + X(87, TiAlN, Metal, 4.8, true, 0x9b8a3e) \ + X(88, Mn, Metal, 7.2, true, 0x7b7b7b) \ + X(89, MnO, Metal, 5.4, false, 0x556b2f) \ + X(90, MnN, Metal, 6.1, false, 0x2f4f4f) \ + X(91, Au, Metal, 19.3, true, 0xd4af37) \ + X(92, Cr, Metal, 7.19, true, 0xa3a3a3) \ /* Silicides */ \ - X(100, WSi2, Silicide, 9.3, true) \ - X(101, TiSi2, Silicide, 4.0, true) \ - X(102, MoSi2, Silicide, 6.3, true) \ + X(100, WSi2, Silicide, 9.3, true, 0x607d8b) \ + X(101, TiSi2, Silicide, 4.0, true, 0x546e7a) \ + X(102, MoSi2, Silicide, 6.3, true, 0x78909c) \ /* Compound semiconductors */ \ - X(110, Ge, Compound, 5.32, false) \ - X(111, GaN, Compound, 6.15, false) \ - X(112, GaAs, Compound, 5.32, false) \ - X(113, InP, Compound, 4.81, false) \ - X(114, InGaAs, Compound, 5.6, false) \ - X(115, SiGaN, Compound, 5.0, false) \ - X(116, SiOCH, OxideNitride, 1.8, false) \ + X(110, Ge, Compound, 5.32, false, 0x808080) \ + X(111, GaN, Compound, 6.15, false, 0x00ced1) \ + X(112, GaAs, Compound, 5.32, false, 0x8a2be2) \ + X(113, InP, Compound, 4.81, false, 0xff6347) \ + X(114, InGaAs, Compound, 5.6, false, 0x7b1fa2) \ + X(115, SiGaN, Compound, 5.0, false, 0x26a69a) \ + X(116, SiOCH, OxideNitride, 1.8, false, 0x4fc3f7) \ /* 2D + emerging */ \ - X(130, Graphene, TwoD, 2.2, true) \ - X(131, MoS2, TwoD, 5.0, false) \ - X(132, WS2, TwoD, 7.5, false) \ - X(133, WSe2, TwoD, 9.3, false) \ - X(134, VO2, TwoD, 4.6, false) \ - X(135, GST, TwoD, 6.1, false) \ + X(130, Graphene, TwoD, 2.2, true, 0x000000) \ + X(131, MoS2, TwoD, 5.0, false, 0x66bb6a) \ + X(132, WS2, TwoD, 7.5, false, 0xffee58) \ + X(133, WSe2, TwoD, 9.3, false, 0xec407a) \ + X(134, VO2, TwoD, 4.6, false, 0x8d6e63) \ + X(135, GST, TwoD, 6.1, false, 0x800020) \ /* Transparent conductors */ \ - X(150, ITO, TCO, 7.1, true) \ - X(151, ZnO, TCO, 5.6, true) \ - X(152, AZO, TCO, 5.5, true) \ + X(150, ITO, TCO, 7.1, true, 0x00ffff) \ + X(151, ZnO, TCO, 5.6, true, 0x98fb98) \ + X(152, AZO, TCO, 5.5, true, 0x20b2aa) \ /* Misc hardmask aliases */ \ - X(170, SiON_HM, Hardmask, 2.4, false) \ - X(171, SiN_HM, Hardmask, 3.1, false) \ - X(172, SiC_HM, Hardmask, 3.2, false) \ - X(173, TiO, Misc, 4.9, false) \ - X(174, ZrO, Misc, 5.2, false) \ - X(175, SiO2_HM, Hardmask, 2.2, false) - + X(170, SiON_HM, Hardmask, 2.4, false, 0x33cccc) \ + X(171, SiN_HM, Hardmask, 3.1, false, 0x00a8a8) \ + X(172, SiC_HM, Hardmask, 3.2, false, 0x4f4f4f) \ + X(173, TiO, Misc, 4.9, false, 0x64b5f6) \ + X(174, ZrO, Misc, 5.2, false, 0x5c6bc0) \ + X(175, SiO2_HM, Hardmask, 2.2, false, 0x66ccff) enum class Material : uint16_t { -#define ENUM_ELEM(id, sym, cat, dens, cond) sym = id, +#define ENUM_ELEM(id, sym, cat, dens, cond, color) sym = id, MATERIAL_LIST(ENUM_ELEM) #undef ENUM_ELEM }; @@ -140,6 +140,7 @@ struct MaterialInfo { MaterialCategory category; double density_gcm3; // nominal; tune per PDK bool conductive; + uint32_t colorHex; // 0xRRGGBB }; constexpr uint16_t kMaterialMaxId = 175; @@ -148,10 +149,10 @@ constexpr std::array kMaterialTable = [] { std::array t{}; // default fill for (auto &e : t) - e = {"Undefined", MaterialCategory::Generic, 0.0, false}; - // populate -#define FILL_ROW(id, sym, cat, dens, cond) \ - t[id] = {#sym, MaterialCategory::cat, dens, cond}; + e = {"Undefined", MaterialCategory::Generic, 0.0, false, 0xcccccc}; + // populate +#define FILL_ROW(id, sym, cat, dens, cond, color) \ + t[id] = {#sym, MaterialCategory::cat, dens, cond, color}; MATERIAL_LIST(FILL_ROW) #undef FILL_ROW return t; @@ -167,6 +168,7 @@ constexpr std::string_view to_string_view(Material m) { return info(m).name; } constexpr MaterialCategory categoryOf(Material m) { return info(m).category; } constexpr double density(Material m) { return info(m).density_gcm3; } constexpr bool isConductive(Material m) { return info(m).conductive; } +constexpr uint32_t color(Material m) { return info(m).colorHex; } #ifndef __CUDACC__ /// A class that wraps the viennals MaterialMap class and provides a more user diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index fec5064e..7ee9e50a 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -164,13 +165,11 @@ template class VTKRenderWindow { } } - void setScreenshotScale(int scale) { screenshotScale = scale; } - - void saveScreenshot(const std::string &fileName) { + void saveScreenshot(const std::string &fileName, int scale = 1) { vtkSmartPointer windowToImageFilter = vtkSmartPointer::New(); windowToImageFilter->SetInput(renderWindow); - windowToImageFilter->SetScale(screenshotScale); // image quality + windowToImageFilter->SetScale(scale); // image quality windowToImageFilter->Update(); VIENNACORE_LOG_INFO("Saving screenshot '" + fileName + "'"); @@ -204,6 +203,17 @@ template class VTKRenderWindow { renderWindow->Render(); } + void toggleScalarBar() { + if (showScalarBar) { + renderer->RemoveActor(scalarBar); + showScalarBar = false; + } else { + renderer->AddActor(scalarBar); + showScalarBar = true; + } + renderWindow->Render(); + } + private: // forward declaration, requires full definition of Interactor styles void initialize(); @@ -219,25 +229,44 @@ template class VTKRenderWindow { renderer->AddActor(instructionsActor); // Get min and max material IDs present in the domains - materialMinId = std::numeric_limits::max(); - materialMaxId = 0; + std::set uniqueMaterialIds; for (const auto &domain : domains) { if (domain->getLevelSets().empty()) { VIENNACORE_LOG_WARNING("Domain has no level sets for rendering."); continue; } auto materialsInDomain = domain->getMaterialsInDomain(); - if (!materialsInDomain.empty()) { - materialMinId = std::min(materialMinId, - static_cast(*materialsInDomain.begin())); - materialMaxId = std::max(materialMaxId, - static_cast(*materialsInDomain.rbegin())); - } else { - materialMinId = 0; - materialMaxId = std::max( - materialMaxId, static_cast(domain->getLevelSets().size() - 1)); - } + uniqueMaterialIds.insert(materialsInDomain.begin(), + materialsInDomain.end()); + } + + // Build annotated LUT for material IDs (categorical) + lut->SetNumberOfTableValues(uniqueMaterialIds.size()); + lut->IndexedLookupOn(); + lut->ResetAnnotations(); + materialMinId = std::numeric_limits::max(); + materialMaxId = std::numeric_limits::min(); + int index = 0; + for (const auto &materialId : uniqueMaterialIds) { + auto colorHex = color(materialId); + double r = ((colorHex >> 16) & 0xFF) / 255.0; + double g = ((colorHex >> 8) & 0xFF) / 255.0; + double b = (colorHex & 0xFF) / 255.0; + lut->SetTableValue(index, r, g, b, 1.0); + auto label = to_string_view(materialId); + int id = static_cast(materialId); + lut->SetAnnotation(id, label.data()); + ++index; + + materialMinId = std::min(materialMinId, id); + materialMaxId = std::max(materialMaxId, id); } + lut->Build(); + scalarBar->SetLookupTable(lut); + scalarBar->SetMaximumNumberOfColors(uniqueMaterialIds.size()); + // When using annotations (categorical), don't draw numeric labels + scalarBar->SetNumberOfLabels(0); + scalarBar->SetTitle("Materials"); cachedSurfaceMesh.resize(domains.size()); cachedInterfaceMesh.resize(domains.size()); @@ -385,8 +414,10 @@ template class VTKRenderWindow { mapper->ScalarVisibilityOn(); mapper->SelectColorArray("MaterialIds"); mapper->SetLookupTable(lut); - assert(materialMinId != -1 && materialMaxId != -1); mapper->SetScalarRange(materialMinId, materialMaxId); + + if (showScalarBar) + renderer->AddActor(scalarBar); } auto actor = vtkSmartPointer::New(); @@ -425,6 +456,10 @@ template class VTKRenderWindow { actor->SetMapper(mapper); renderer->AddActor(actor); + + // Add scalar bar + if (showScalarBar) + renderer->AddActor(scalarBar); } private: @@ -435,17 +470,18 @@ template class VTKRenderWindow { vtkSmartPointer renderWindow; vtkSmartPointer interactor; vtkSmartPointer lut; + vtkSmartPointer scalarBar; // text const std::string instructionsText = "Press 1: Surface | 2: Interface | 3: Volume | " - "x/y/z: View | s: Screenshot | h: Show/Hide Instructions | q/e: Quit"; + "x/y/z: View | s: Screenshot | h: Show/Hide Instructions | b: Show/Hide " + "Scalar Bar | q/e: Quit"; vtkSmartPointer instructionsActor; bool instructionsAdded = false; std::array backgroundColor = {84.0 / 255, 89.0 / 255, 109.0 / 255}; std::array windowSize = {800, 600}; - int screenshotScale = 1; RenderMode renderMode = RenderMode::INTERFACE; @@ -455,6 +491,7 @@ template class VTKRenderWindow { std::vector> cachedVolumeMesh; int materialMinId = -1; int materialMaxId = -1; + bool showScalarBar = true; }; namespace impl { @@ -515,6 +552,9 @@ void InteractorOnChar(vtkRenderWindowInteractor *rwi, case 'h': window->toggleInstructionText(); return; + case 'b': + window->toggleScalarBar(); + return; case 'p': window->printCameraInfo(); return; @@ -615,11 +655,26 @@ template void VTKRenderWindow::initialize() { lut = vtkSmartPointer::New(); - lut->SetNumberOfTableValues(256); - lut->SetHueRange(0.667, 0.0); // blue โ†’ red - lut->SetSaturationRange(1.0, 1.0); - lut->SetValueRange(.5, 1.0); - lut->Build(); + // lut->SetNumberOfTableValues(256); + // lut->SetHueRange(0.667, 0.0); // blue โ†’ red + // lut->SetSaturationRange(1.0, 1.0); + // lut->SetValueRange(.5, 1.0); + // lut->Build(); + + scalarBar = vtkSmartPointer::New(); + // Make scalar bar smaller and labels larger by default + scalarBar->SetOrientationToVertical(); + // Position in normalized viewport coordinates (x,y) + scalarBar->SetPosition(0.88, 0.15); + // Size in normalized viewport coordinates (width,height) + scalarBar->SetPosition2(0.08, 0.70); + // Make the color swatch thinner relative to the actor box + scalarBar->SetBarRatio(0.20); + // Increase annotation (label) and title font sizes + scalarBar->GetLabelTextProperty()->SetFontSize(18); + scalarBar->GetTitleTextProperty()->SetFontSize(20); + scalarBar->GetLabelTextProperty()->BoldOn(); + scalarBar->GetTitleTextProperty()->BoldOn(); } } // namespace viennaps diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 3a4c67e9..2c76e78f 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -43,7 +43,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { auto matEnum = py::native_enum(module, "Material", "enum.IntEnum", "Material types for domain and level sets"); -#define ENUM_BIND(id, sym, cat, dens, cond) matEnum.value(#sym, Material::sym); +#define ENUM_BIND(id, sym, cat, dens, cond, color) \ + matEnum.value(#sym, Material::sym); MATERIAL_LIST(ENUM_BIND) #undef ENUM_BIND matEnum.finalize(); diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index d8c476b4..b6a3b545 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -1361,14 +1361,12 @@ template void bindApi(py::module &module) { "Print the current camera settings to the console.") .def("saveScreenshot", &VTKRenderWindow::saveScreenshot, "Save a screenshot of the current render window.", - py::arg("fileName")) + py::arg("fileName"), py::arg("scale") = 1) .def("toggleInstructionText", &VTKRenderWindow::toggleInstructionText, "Toggle the instruction text overlay on/off.") .def("render", &VTKRenderWindow::render, - "Render the current domain state.") - .def("setScreenshotScale", &VTKRenderWindow::setScreenshotScale, - "Set the scale factor for screenshots taken."); + "Render the current domain state."); #endif // *************************************************************************** From ab6352a00718272d6f6a7c39328b78263bc2f2f6 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Sun, 21 Dec 2025 23:10:46 +0100 Subject: [PATCH 15/38] Hex to RGB util --- include/viennaps/psUtil.hpp | 9 +++++++++ include/viennaps/psVTKRenderWindow.hpp | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index 428f1f51..e4ad44af 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -130,4 +130,13 @@ template [[nodiscard]] std::string toString(const T &value) { } return str.str(); } + +[[nodiscard]] inline std::array +hexToRGBArray(const uint32_t hexColor) { + std::array rgb; + rgb[0] = static_cast((hexColor >> 16) & 0xFF) / 255.0; + rgb[1] = static_cast((hexColor >> 8) & 0xFF) / 255.0; + rgb[2] = static_cast(hexColor & 0xFF) / 255.0; + return rgb; +} }; // namespace viennacore::util diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index 7ee9e50a..425301d7 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -6,6 +6,8 @@ #include #include +#include "psUtil.hpp" + #include #include #include @@ -249,9 +251,7 @@ template class VTKRenderWindow { int index = 0; for (const auto &materialId : uniqueMaterialIds) { auto colorHex = color(materialId); - double r = ((colorHex >> 16) & 0xFF) / 255.0; - double g = ((colorHex >> 8) & 0xFF) / 255.0; - double b = (colorHex & 0xFF) / 255.0; + auto [r, g, b] = util::hexToRGBArray(colorHex); lut->SetTableValue(index, r, g, b, 1.0); auto label = to_string_view(materialId); int id = static_cast(materialId); From f4354a9854fd8e5d22bae89aa99923890dfe2500 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Mon, 22 Dec 2025 09:44:57 +0100 Subject: [PATCH 16/38] Fix sphere dist examples --- examples/boschProcess/boschProcessEmulate.py | 4 +--- .../trenchDepositionGeometric/trenchDepositionGeometric.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/examples/boschProcess/boschProcessEmulate.py b/examples/boschProcess/boschProcessEmulate.py index e83f1b0a..701d5a19 100644 --- a/examples/boschProcess/boschProcessEmulate.py +++ b/examples/boschProcess/boschProcessEmulate.py @@ -38,9 +38,7 @@ direction[args.dim - 1] = -1.0 # Geometric advection model for deposition -depoModel = ps.SphereDistribution( - radius=params["depositionThickness"], gridDelta=params["gridDelta"] -) +depoModel = ps.SphereDistribution(radius=params["depositionThickness"]) # Define purely directional rate for depo removal etchDir = ps.RateSet( diff --git a/examples/trenchDepositionGeometric/trenchDepositionGeometric.py b/examples/trenchDepositionGeometric/trenchDepositionGeometric.py index d3c68605..eed29a0e 100644 --- a/examples/trenchDepositionGeometric/trenchDepositionGeometric.py +++ b/examples/trenchDepositionGeometric/trenchDepositionGeometric.py @@ -35,9 +35,7 @@ # copy top layer to capture deposition geometry.duplicateTopLevelSet(ps.Material.SiO2) -model = ps.SphereDistribution( - radius=params["layerThickness"], gridDelta=params["gridDelta"] -) +model = ps.SphereDistribution(radius=params["layerThickness"]) geometry.saveHullMesh("initial") From 224d88ca2be8403ff62c35bc5692b99fc3f8b609 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Mon, 22 Dec 2025 19:01:45 +0100 Subject: [PATCH 17/38] Add comments --- CMakeLists.txt | 2 +- include/viennaps/psVTKRenderWindow.hpp | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bdf5ec07..bf477a2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS VERSION 5.3.0 - GIT_TAG vtk-render + GIT_TAG master GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index 425301d7..4006c7d9 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -51,6 +51,12 @@ enum class RenderMode { SURFACE, INTERFACE, VOLUME }; // forward declaration of Domain template class Domain; +/// Lightweight VTK-based viewer for one or more ViennaPS domains. +/// +/// Wraps a renderer, window, and interactor to visualize level-set derived +/// meshes either as surfaces, interfaces, or volume cells. Provides helpers to +/// manage camera presets, toggle overlays, and capture screenshots without the +/// caller dealing with raw VTK plumbing. template class VTKRenderWindow { public: VTKRenderWindow() { initialize(); } @@ -70,12 +76,14 @@ template class VTKRenderWindow { } } + /// Queue a domain for rendering with an optional translation offset. void insertNextDomain(SmartPointer> passedDomain, const std::array &offset = {0.0, 0.0, 0.0}) { domains.push_back(passedDomain); domainOffsets.push_back(offset); } + /// Adjust the translation offset of an already enqueued domain. void setDomainOffset(std::size_t domainIndex, const std::array &offset) { if (domainIndex >= domainOffsets.size()) { @@ -85,6 +93,7 @@ template class VTKRenderWindow { domainOffsets[domainIndex] = offset; } + /// Set the renderer background color (RGB in [0,1]). void setBackgroundColor(const std::array &color) { backgroundColor = color; if (renderer) { @@ -92,6 +101,7 @@ template class VTKRenderWindow { } } + /// Set the render window size in pixels. void setWindowSize(const std::array &size) { windowSize = size; if (renderWindow) { @@ -99,26 +109,31 @@ template class VTKRenderWindow { } } + /// Choose whether to render surfaces, interfaces, or volume cells. void setRenderMode(RenderMode mode) { renderMode = mode; } + /// Convenience setter for the active camera position. void setCameraPosition(const std::array &position) { if (renderer) { renderer->GetActiveCamera()->SetPosition(position.data()); } } + /// Convenience setter for the active camera view-up vector. void setCameraViewUp(const std::array &viewUp) { if (renderer) { renderer->GetActiveCamera()->SetViewUp(viewUp.data()); } } + /// Convenience setter for the active camera focal point. void setCameraFocalPoint(const std::array &focalPoint) { if (renderer) { renderer->GetActiveCamera()->SetFocalPoint(focalPoint.data()); } } + /// Snap camera to axis-aligned views (0=x, 1=y, 2=z). void setCameraView(int axis) { if (renderer) { vtkCamera *camera = renderer->GetActiveCamera(); @@ -144,6 +159,7 @@ template class VTKRenderWindow { } } + /// Log current camera position, focal point, and view-up vector. void printCameraInfo() { if (renderer) { vtkCamera *camera = renderer->GetActiveCamera(); @@ -167,6 +183,7 @@ template class VTKRenderWindow { } } + /// Capture the current framebuffer to a PNG file. void saveScreenshot(const std::string &fileName, int scale = 1) { vtkSmartPointer windowToImageFilter = vtkSmartPointer::New(); @@ -182,6 +199,7 @@ template class VTKRenderWindow { writer->Write(); } + /// Render and enter the VTK event loop. void render() { updateDisplay(); interactor->Start(); @@ -189,11 +207,13 @@ template class VTKRenderWindow { // Update the display without starting a new event loop (for use during // interaction) + /// Refresh the scene; optionally reuse cached meshes. void updateDisplay(bool useCache = true) { updateRenderer(useCache); renderWindow->Render(); } + /// Toggle the on-screen keyboard instruction overlay. void toggleInstructionText() { if (instructionsAdded) { instructionsActor->SetInput(""); @@ -205,6 +225,7 @@ template class VTKRenderWindow { renderWindow->Render(); } + /// Toggle the material lookup-table legend. void toggleScalarBar() { if (showScalarBar) { renderer->RemoveActor(scalarBar); From 904395bda6d1f536d42aecb216d73d4781b7b067 Mon Sep 17 00:00:00 2001 From: reiter Date: Tue, 23 Dec 2025 19:02:44 +0100 Subject: [PATCH 18/38] Format --- include/viennaps/psMaterials.hpp | 2 +- python/CMakeLists.txt | 6 +----- python/pyWrapDimension.hpp | 20 ++++++++------------ 3 files changed, 10 insertions(+), 18 deletions(-) diff --git a/include/viennaps/psMaterials.hpp b/include/viennaps/psMaterials.hpp index ac7f7f88..49b86bc3 100644 --- a/include/viennaps/psMaterials.hpp +++ b/include/viennaps/psMaterials.hpp @@ -150,7 +150,7 @@ constexpr std::array kMaterialTable = [] { // default fill for (auto &e : t) e = {"Undefined", MaterialCategory::Generic, 0.0, false, 0xcccccc}; - // populate + // populate #define FILL_ROW(id, sym, cat, dens, cond, color) \ t[id] = {#sym, MaterialCategory::cat, dens, cond, color}; MATERIAL_LIST(FILL_ROW) diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index ccb1f2cf..d35983ae 100644 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -70,11 +70,7 @@ if(VIENNALS_VTK_RENDERING) GIT_REPOSITORY "https://gitlab.kitware.com/vtk/vtk") # These modules need to be initialized for VTK rendering to work properly - vtk_module_autoinit( - TARGETS - ${VIENNAPS_PYTHON_MODULE_NAME} - MODULES - ${VTK_LIBRARIES}) + vtk_module_autoinit(TARGETS ${VIENNAPS_PYTHON_MODULE_NAME} MODULES ${VTK_LIBRARIES}) target_compile_definitions(${VIENNAPS_PYTHON_MODULE_NAME} PRIVATE VIENNALS_VTK_MODULE_INIT) endif() diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index b6a3b545..187a7fe8 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -1289,27 +1289,23 @@ template void bindApi(py::module &module) { py::arg("path"), "Set the path for intermediate output files during the process.") .def("setParameters", - (void (ProcessTD::*)( - const AdvectionParameters - &))&ProcessTD::template setParameters, + (void(ProcessTD::*)(const AdvectionParameters &)) & + ProcessTD::template setParameters, py::arg("parameters"), "Set the advection parameters for the process.") .def("setParameters", - (void (ProcessTD::*)( - const RayTracingParameters - &))&ProcessTD::template setParameters, + (void(ProcessTD::*)(const RayTracingParameters &)) & + ProcessTD::template setParameters, py::arg("parameters"), "Set the ray tracing parameters for the process.") .def("setParameters", - (void (ProcessTD::*)( - const CoverageParameters - &))&ProcessTD::template setParameters, + (void(ProcessTD::*)(const CoverageParameters &)) & + ProcessTD::template setParameters, py::arg("parameters"), "Set the coverage parameters for the process.") .def("setParameters", - (void (ProcessTD::*)( - const AtomicLayerProcessParameters &))&ProcessTD:: - template setParameters, + (void(ProcessTD::*)(const AtomicLayerProcessParameters &)) & + ProcessTD::template setParameters, py::arg("parameters"), "Set the atomic layer parameters for the process."); From d830d029f3a779f6b6f57327ef00bf26a97ed9ce Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Tue, 23 Dec 2025 19:52:17 +0100 Subject: [PATCH 19/38] Update README --- README.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index f76a27a1..724bca28 100644 --- a/README.md +++ b/README.md @@ -53,23 +53,32 @@ ViennaPS is also available on the [Python Package Index (PyPI)](https://pypi.org * C++17 Compiler with OpenMP support -### Dependencies (installed automatically) +### ViennaTools Dependencies (installed automatically) -* [ViennaCore](https://github.com/ViennaTools/viennacore) +ViennaPS is part of the ViennaTools ecosystem and depends on several lightweight, header-only ViennaTools libraries. During configuration, CMake will look for them and fetch them automatically as part of the ViennaPS build. No separate installation step is required: +* [ViennaCore](https://github.com/ViennaTools/viennacore) * [ViennaLS](https://github.com/ViennaTools/viennals) - * [ViennaHRLE](https://github.com/ViennaTools/viennahrle) - * [VTK](https://vtk.org/) (9.0.0+) - +* [ViennaHRLE](https://github.com/ViennaTools/viennahrle) * [ViennaRay](https://github.com/ViennaTools/viennaray) - * [Embree](https://www.embree.org/) (4.0.0+) - * [ViennaCS](https://github.com/ViennaTools/viennacs) -* [pybind11](https://github.com/pybind/pybind11) (3.0.0+, only for building Python libs) +### External Dependencies + +The following external dependencies are required to build ViennaPS. On most systems, installing them via a package manager (e.g. `apt`, `brew`, or `vcpkg`) is the fastest option: + +* [VTK](https://vtk.org/) (9.0.0+) +* [Embree](https://www.embree.org/) (4.0.0+) + +CMake automatically checks for these dependencies during configuration. If they are not found, they can be built from source as part of the build. + +To prefer a specific local installation, point CMake to it via `VIENNAPS_LOOKUP_DIRS` (a semicolon-separated list of prefixes): + +```bash +cmake -B build -DVIENNAPS_LOOKUP_DIRS="/path/to/vtk;/path/to/embree" +``` -The CMake configuration automatically checks if the dependencies are installed. -If the dependencies are not found on the system, they will be built from source. To use local installations of the dependencies, the `VIENNAPS_LOOKUP_DIRS` variable can be set to the installation path of the dependencies. +Alternatively (or additionally), you can use `CMAKE_PREFIX_PATH` if that better matches your local setup. ## Installing From 7cc9bdef41e85e16cc2f4647df77e3a3c68688e7 Mon Sep 17 00:00:00 2001 From: filipovic Date: Sat, 27 Dec 2025 23:18:12 +0100 Subject: [PATCH 20/38] Update advection handler to use RK3 time integration from ViennaLS. Tested with the multiParticleProcess test, holeEtching example shows how to select a temporal scheme. --- CMakeLists.txt | 9 ++-- examples/holeEtching/config.txt | 1 + examples/holeEtching/holeEtching.cpp | 2 + .../viennaps/process/psAdvectionHandler.hpp | 49 +++++++++++-------- include/viennaps/process/psProcessContext.hpp | 4 +- include/viennaps/process/psProcessParams.hpp | 6 +++ include/viennaps/psUtil.hpp | 23 +++++++++ python/pyWrap.cpp | 4 ++ .../multiParticleProcess.cpp | 11 ++++- 9 files changed, 81 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66980fdc..ff37ed87 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ include("cmake/cpm.cmake") CPMAddPackage( NAME ViennaCore - VERSION 1.7.4 + VERSION 1.8.0 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaCore" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON} OPTIONS "VIENNACORE_USE_GPU ${VIENNAPS_USE_GPU}") @@ -113,7 +113,7 @@ CPMAddPackage( CPMFindPackage( NAME ViennaRay - VERSION 3.9.0 + VERSION 3.9.1 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaRay" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON} OPTIONS "VIENNARAY_USE_GPU ${VIENNAPS_USE_GPU}") @@ -121,6 +121,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS VERSION 5.3.0 + GIT_TAG fix_material_interface GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) @@ -177,8 +178,6 @@ endif() if(VIENNAPS_USE_GPU AND VIENNACORE_PTX_DIR) message(STATUS "[ViennaPS] Enabled GPU Support") add_subdirectory(gpu) - target_include_directories(${PROJECT_NAME} - INTERFACE $) else() message(STATUS "[ViennaPS] Disabled GPU Support") set(VIENNAPS_USE_GPU OFF) @@ -227,4 +226,4 @@ packageProject( INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include/viennaps INCLUDE_DESTINATION include/viennaps-${PROJECT_VERSION} COMPATIBILITY SameMajorVersion - DEPENDENCIES "ViennaCore;ViennaLS;ViennaRay;ViennaCS;OpenMP") + DEPENDENCIES "ViennaCore;ViennaLS;ViennaRay;ViennaCS;OpenMP") \ No newline at end of file diff --git a/examples/holeEtching/config.txt b/examples/holeEtching/config.txt index 80aa6f2c..899fa734 100644 --- a/examples/holeEtching/config.txt +++ b/examples/holeEtching/config.txt @@ -29,6 +29,7 @@ A_Si=7 # Si yield constant etchStopDepth=-10 # maximum etching depth integrationScheme=EO_1 +temporalScheme=RK3 raysPerPoint=1000 diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index f5e57a1e..e27294ed 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -62,6 +62,8 @@ int main(int argc, char *argv[]) { AdvectionParameters advectionParams; advectionParams.integrationScheme = util::convertIntegrationScheme( params.get("integrationScheme")); + advectionParams.temporalScheme = util::convertTemporalScheme( + params.get("temporalScheme")); // process setup Process process(geometry, model); diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index af554225..727b4d27 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -4,13 +4,14 @@ #include "psTranslationField.hpp" #include +#include #include namespace viennaps { template class AdvectionHandler { - viennals::Advect advectionKernel_; + SmartPointer> advectionKernel_; viennacore::Timer<> timer_; unsigned lsVelOutputCounter = 0; @@ -39,44 +40,52 @@ template class AdvectionHandler { context.resetTime(); - advectionKernel_.setSingleStep(true); - advectionKernel_.setVelocityField(context.translationField); - advectionKernel_.setIntegrationScheme( + if (context.advectionParams.temporalScheme == + TemporalScheme::RUNGE_KUTTA_3RD_ORDER) { + advectionKernel_ = + SmartPointer>::New(); + } else { + advectionKernel_ = SmartPointer>::New(); + } + + advectionKernel_->setSingleStep(true); + advectionKernel_->setVelocityField(context.translationField); + advectionKernel_->setIntegrationScheme( context.advectionParams.integrationScheme); - advectionKernel_.setTimeStepRatio(context.advectionParams.timeStepRatio); - advectionKernel_.setSaveAdvectionVelocities( + advectionKernel_->setTimeStepRatio(context.advectionParams.timeStepRatio); + advectionKernel_->setSaveAdvectionVelocities( context.advectionParams.velocityOutput); - advectionKernel_.setDissipationAlpha( + advectionKernel_->setDissipationAlpha( context.advectionParams.dissipationAlpha); - advectionKernel_.setIgnoreVoids(context.advectionParams.ignoreVoids); - advectionKernel_.setCheckDissipation( + advectionKernel_->setIgnoreVoids(context.advectionParams.ignoreVoids); + advectionKernel_->setCheckDissipation( context.advectionParams.checkDissipation); - advectionKernel_.setAdaptiveTimeStepping( + advectionKernel_->setAdaptiveTimeStepping( context.advectionParams.adaptiveTimeStepping); advectionKernel_.setAdaptiveTimeStepThreshold( context.advectionParams.adaptiveTimeStepThreshold); // normals vectors are only necessary for analytical velocity fields if (translationMethod > 0) - advectionKernel_.setCalculateNormalVectors(false); + advectionKernel_->setCalculateNormalVectors(false); - advectionKernel_.clearLevelSets(); + advectionKernel_->clearLevelSets(); for (auto &dom : context.domain->getLevelSets()) { - advectionKernel_.insertNextLevelSet(dom); + advectionKernel_->insertNextLevelSet(dom); } return ProcessResult::SUCCESS; } void setAdvectionTime(double time) { - advectionKernel_.setAdvectionTime(time); + advectionKernel_->setAdvectionTime(time); } - void disableSingleStep() { advectionKernel_.setSingleStep(false); } + void disableSingleStep() { advectionKernel_->setSingleStep(false); } void prepareAdvection(const ProcessContext &context) { // Prepare for advection step - advectionKernel_.prepareLS(); + advectionKernel_->prepareLS(); context.model->initialize(context.domain, context.processTime); } @@ -85,12 +94,12 @@ template class AdvectionHandler { // Set the maximum advection time. if (!context.flags.isALP) { - advectionKernel_.setAdvectionTime(context.processDuration - - context.processTime); + advectionKernel_->setAdvectionTime(context.processDuration - + context.processTime); } timer_.start(); - advectionKernel_.apply(); + advectionKernel_->apply(); timer_.finish(); if (context.advectionParams.velocityOutput) { @@ -104,7 +113,7 @@ template class AdvectionHandler { .apply(); } - context.timeStep = advectionKernel_.getAdvectedTime(); + context.timeStep = advectionKernel_->getAdvectedTime(); if (context.timeStep == std::numeric_limits::max()) { VIENNACORE_LOG_WARNING( "Process terminated early: Velocities are zero everywhere."); diff --git a/include/viennaps/process/psProcessContext.hpp b/include/viennaps/process/psProcessContext.hpp index 8551cb3c..ff4f9fcd 100644 --- a/include/viennaps/process/psProcessContext.hpp +++ b/include/viennaps/process/psProcessContext.hpp @@ -107,7 +107,9 @@ template struct ProcessContext { advectionParams.integrationScheme == IntegrationScheme::LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER || advectionParams.integrationScheme == - IntegrationScheme::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + IntegrationScheme::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER || + advectionParams.temporalScheme == + TemporalScheme::RUNGE_KUTTA_3RD_ORDER; } }; diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 511206c1..bea197aa 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -13,6 +13,7 @@ namespace viennaps { using namespace viennacore; using IntegrationScheme = viennals::IntegrationSchemeEnum; +using TemporalScheme = viennals::TemporalSchemeEnum; struct RayTracingParameters { viennaray::NormalizationType normalizationType = @@ -53,6 +54,8 @@ struct RayTracingParameters { struct AdvectionParameters { IntegrationScheme integrationScheme = IntegrationScheme::ENGQUIST_OSHER_1ST_ORDER; + TemporalScheme temporalScheme = + TemporalScheme::FORWARD_EULER; double timeStepRatio = 0.4999; double dissipationAlpha = 1.0; double adaptiveTimeStepThreshold = 0.05; @@ -64,6 +67,7 @@ struct AdvectionParameters { auto toMetaData() const { std::unordered_map> metaData; metaData["IntegrationScheme"] = {static_cast(integrationScheme)}; + metaData["TemporalScheme"] = {static_cast(temporalScheme)}; metaData["TimeStepRatio"] = {timeStepRatio}; metaData["DissipationAlpha"] = {dissipationAlpha}; return metaData; @@ -72,6 +76,8 @@ struct AdvectionParameters { auto toMetaDataString() const { return "\nIntegrationScheme: " + util::convertIntegrationSchemeToString(integrationScheme) + + "\nTemporalScheme: " + + util::convertTemporalSchemeToString(temporalScheme) + "\nTimeStepRatio: " + std::to_string(timeStepRatio) + "\nDissipationAlpha: " + std::to_string(dissipationAlpha) + "\nCheckDissipation: " + util::boolString(checkDissipation) + diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index e50e55e1..830beee5 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -51,6 +51,17 @@ convertIntegrationScheme(const std::string &s) { "WENO_5TH_ORDER"); } +[[nodiscard]] inline viennals::TemporalSchemeEnum +convertTemporalScheme(const std::string &s) { + if (s == "FORWARD_EULER" || s == "FE") + return viennals::TemporalSchemeEnum::FORWARD_EULER; + if (s == "RUNGE_KUTTA_3RD_ORDER" || s == "RK3") + return viennals::TemporalSchemeEnum::RUNGE_KUTTA_3RD_ORDER; + throw std::invalid_argument( + "The value must be one of the following: " + "FORWARD_EULER, RUNGE_KUTTA_3RD_ORDER"); +} + [[nodiscard]] inline std::string convertIntegrationSchemeToString(viennals::IntegrationSchemeEnum scheme) { switch (scheme) { @@ -82,6 +93,18 @@ convertIntegrationSchemeToString(viennals::IntegrationSchemeEnum scheme) { } } +[[nodiscard]] inline std::string +convertTemporalSchemeToString(viennals::TemporalSchemeEnum scheme) { + switch (scheme) { + case viennals::TemporalSchemeEnum::FORWARD_EULER: + return "FORWARD_EULER"; + case viennals::TemporalSchemeEnum::RUNGE_KUTTA_3RD_ORDER: + return "RUNGE_KUTTA_3RD_ORDER"; + default: + throw std::invalid_argument("Unknown temporal integration scheme."); + } +} + [[nodiscard]] inline viennaray::BoundaryCondition convertBoundaryCondition( viennals::BoundaryConditionEnum originalBoundaryCondition) { switch (originalBoundaryCondition) { diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 9c1b602e..e35240a5 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -457,6 +457,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .def(py::init<>()) .def_readwrite("integrationScheme", &AdvectionParameters::integrationScheme) + .def_readwrite("temporalScheme", + &AdvectionParameters::temporalScheme) .def_readwrite("timeStepRatio", &AdvectionParameters::timeStepRatio) .def_readwrite("dissipationAlpha", &AdvectionParameters::dissipationAlpha) .def_readwrite("checkDissipation", &AdvectionParameters::checkDissipation) @@ -520,6 +522,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { auto m_util = module.def_submodule("util", "Utility functions."); m_util.def("convertIntegrationScheme", &util::convertIntegrationScheme, "Convert a string to an integration scheme."); + m_util.def("convertTemporalScheme", &util::convertTemporalScheme, + "Convert a string to a time integration scheme."); // *************************************************************************** // MAIN API diff --git a/tests/multiParticleProcess/multiParticleProcess.cpp b/tests/multiParticleProcess/multiParticleProcess.cpp index 7fb4a0bc..2dba23bd 100644 --- a/tests/multiParticleProcess/multiParticleProcess.cpp +++ b/tests/multiParticleProcess/multiParticleProcess.cpp @@ -13,7 +13,10 @@ using namespace viennaps; template void RunTest() { Logger::setLogLevel(LogLevel::WARNING); - { + const std::vector schemes = { + TemporalScheme::FORWARD_EULER, TemporalScheme::RUNGE_KUTTA_3RD_ORDER}; + + for (const auto scheme : schemes) { auto domain = Domain::New(); MakeTrench(domain, 1., 10., 10., 2.5, 5., 10., 1., false, true, Material::Si) @@ -36,10 +39,14 @@ template void RunTest() { }); RayTracingParameters rayParams; - rayParams.raysPerPoint = 10; + rayParams.raysPerPoint = 100; + + AdvectionParameters advectionParams; + advectionParams.temporalScheme = scheme; Process process(domain, model, 1.); process.setParameters(rayParams); + process.setParameters(advectionParams); process.setFluxEngineType(FluxEngineType::CPU_DISK); process.apply(); From 43bbac0cd324c74234591d4d27291e3d481ea91d Mon Sep 17 00:00:00 2001 From: filipovic Date: Sun, 28 Dec 2025 23:54:35 +0100 Subject: [PATCH 21/38] format (newline at the end of CMakeLists.txt) --- CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ff37ed87..e9956add 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -226,4 +226,5 @@ packageProject( INCLUDE_DIR ${PROJECT_SOURCE_DIR}/include/viennaps INCLUDE_DESTINATION include/viennaps-${PROJECT_VERSION} COMPATIBILITY SameMajorVersion - DEPENDENCIES "ViennaCore;ViennaLS;ViennaRay;ViennaCS;OpenMP") \ No newline at end of file + DEPENDENCIES "ViennaCore;ViennaLS;ViennaRay;ViennaCS;OpenMP") + \ No newline at end of file From 9b0d4b0c4c61aa6a5362425c8baee6409c56ce52 Mon Sep 17 00:00:00 2001 From: filipovic Date: Mon, 29 Dec 2025 00:20:35 +0100 Subject: [PATCH 22/38] Fixed format. Binding errors persist due to ViennaLS version missmatch.. This PR must follow the ViennaLS PR. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e9956add..54fe1fba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -227,4 +227,3 @@ packageProject( INCLUDE_DESTINATION include/viennaps-${PROJECT_VERSION} COMPATIBILITY SameMajorVersion DEPENDENCIES "ViennaCore;ViennaLS;ViennaRay;ViennaCS;OpenMP") - \ No newline at end of file From ad83400c836f51c2512ef3f68a45f0fa41c07f25 Mon Sep 17 00:00:00 2001 From: filipovic Date: Tue, 30 Dec 2025 00:49:42 +0100 Subject: [PATCH 23/38] Adapt ViennaPS to match temporal scheme from the latest ViennaLS commit. --- .../viennaps/process/psAdvectionHandler.hpp | 49 ++++++++----------- include/viennaps/process/psProcessContext.hpp | 2 + include/viennaps/psUtil.hpp | 7 ++- .../multiParticleProcess.cpp | 3 +- 4 files changed, 31 insertions(+), 30 deletions(-) diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 748ab573..5162292a 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -4,14 +4,13 @@ #include "psTranslationField.hpp" #include -#include #include namespace viennaps { template class AdvectionHandler { - SmartPointer> advectionKernel_; + viennals::Advect advectionKernel_; viennacore::Timer<> timer_; unsigned lsVelOutputCounter = 0; @@ -40,50 +39,44 @@ template class AdvectionHandler { context.resetTime(); - if (context.advectionParams.temporalScheme == - TemporalScheme::RUNGE_KUTTA_3RD_ORDER) { - advectionKernel_ = - SmartPointer>::New(); - } else { - advectionKernel_ = SmartPointer>::New(); - } + advectionKernel_.setTemporalScheme(context.advectionParams.temporalScheme); - advectionKernel_->setSingleStep(true); - advectionKernel_->setVelocityField(context.translationField); - advectionKernel_->setSpatialScheme(context.advectionParams.spatialScheme); - advectionKernel_->setTimeStepRatio(context.advectionParams.timeStepRatio); - advectionKernel_->setSaveAdvectionVelocities( + advectionKernel_.setSingleStep(true); + advectionKernel_.setVelocityField(context.translationField); + advectionKernel_.setSpatialScheme(context.advectionParams.spatialScheme); + advectionKernel_.setTimeStepRatio(context.advectionParams.timeStepRatio); + advectionKernel_.setSaveAdvectionVelocities( context.advectionParams.velocityOutput); - advectionKernel_->setDissipationAlpha( + advectionKernel_.setDissipationAlpha( context.advectionParams.dissipationAlpha); - advectionKernel_->setIgnoreVoids(context.advectionParams.ignoreVoids); - advectionKernel_->setCheckDissipation( + advectionKernel_.setIgnoreVoids(context.advectionParams.ignoreVoids); + advectionKernel_.setCheckDissipation( context.advectionParams.checkDissipation); - advectionKernel_->setAdaptiveTimeStepping( + advectionKernel_.setAdaptiveTimeStepping( context.advectionParams.adaptiveTimeStepping, context.advectionParams.adaptiveTimeStepSubdivisions); // normals vectors are only necessary for analytical velocity fields if (translationMethod > 0) - advectionKernel_->setCalculateNormalVectors(false); + advectionKernel_.setCalculateNormalVectors(false); - advectionKernel_->clearLevelSets(); + advectionKernel_.clearLevelSets(); for (auto &dom : context.domain->getLevelSets()) { - advectionKernel_->insertNextLevelSet(dom); + advectionKernel_.insertNextLevelSet(dom); } return ProcessResult::SUCCESS; } void setAdvectionTime(double time) { - advectionKernel_->setAdvectionTime(time); + advectionKernel_.setAdvectionTime(time); } - void disableSingleStep() { advectionKernel_->setSingleStep(false); } + void disableSingleStep() { advectionKernel_.setSingleStep(false); } void prepareAdvection(const ProcessContext &context) { // Prepare for advection step - advectionKernel_->prepareLS(); + advectionKernel_.prepareLS(); context.model->initialize(context.domain, context.processTime); } @@ -92,12 +85,12 @@ template class AdvectionHandler { // Set the maximum advection time. if (!context.flags.isALP) { - advectionKernel_->setAdvectionTime(context.processDuration - - context.processTime); + advectionKernel_.setAdvectionTime(context.processDuration - + context.processTime); } timer_.start(); - advectionKernel_->apply(); + advectionKernel_.apply(); timer_.finish(); if (context.advectionParams.velocityOutput) { @@ -111,7 +104,7 @@ template class AdvectionHandler { .apply(); } - context.timeStep = advectionKernel_->getAdvectedTime(); + context.timeStep = advectionKernel_.getAdvectedTime(); if (context.timeStep == std::numeric_limits::max()) { VIENNACORE_LOG_WARNING( "Process terminated early: Velocities are zero everywhere."); diff --git a/include/viennaps/process/psProcessContext.hpp b/include/viennaps/process/psProcessContext.hpp index 7feaeb9f..3de17c7f 100644 --- a/include/viennaps/process/psProcessContext.hpp +++ b/include/viennaps/process/psProcessContext.hpp @@ -108,6 +108,8 @@ template struct ProcessContext { SpatialScheme::LOCAL_LAX_FRIEDRICHS_ANALYTICAL_1ST_ORDER || advectionParams.spatialScheme == SpatialScheme::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER || + advectionParams.temporalScheme == + TemporalScheme::RUNGE_KUTTA_2ND_ORDER || advectionParams.temporalScheme == TemporalScheme::RUNGE_KUTTA_3RD_ORDER; } diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index 06071487..c224d60a 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -67,10 +67,13 @@ convertIntegrationScheme(const std::string &s) { convertTemporalScheme(const std::string &s) { if (s == "FORWARD_EULER" || s == "FE") return viennals::TemporalSchemeEnum::FORWARD_EULER; + if (s == "RUNGE_KUTTA_2ND_ORDER" || s == "RK2") + return viennals::TemporalSchemeEnum::RUNGE_KUTTA_2ND_ORDER; if (s == "RUNGE_KUTTA_3RD_ORDER" || s == "RK3") return viennals::TemporalSchemeEnum::RUNGE_KUTTA_3RD_ORDER; throw std::invalid_argument("The value must be one of the following: " - "FORWARD_EULER, RUNGE_KUTTA_3RD_ORDER"); + "FORWARD_EULER, RUNGE_KUTTA_2ND_ORDER, " + "RUNGE_KUTTA_3RD_ORDER"); } [[nodiscard]] inline std::string @@ -108,6 +111,8 @@ convertTemporalSchemeToString(viennals::TemporalSchemeEnum scheme) { switch (scheme) { case viennals::TemporalSchemeEnum::FORWARD_EULER: return "FORWARD_EULER"; + case viennals::TemporalSchemeEnum::RUNGE_KUTTA_2ND_ORDER: + return "RUNGE_KUTTA_2ND_ORDER"; case viennals::TemporalSchemeEnum::RUNGE_KUTTA_3RD_ORDER: return "RUNGE_KUTTA_3RD_ORDER"; default: diff --git a/tests/multiParticleProcess/multiParticleProcess.cpp b/tests/multiParticleProcess/multiParticleProcess.cpp index 2dba23bd..5aca8f1c 100644 --- a/tests/multiParticleProcess/multiParticleProcess.cpp +++ b/tests/multiParticleProcess/multiParticleProcess.cpp @@ -14,7 +14,8 @@ template void RunTest() { Logger::setLogLevel(LogLevel::WARNING); const std::vector schemes = { - TemporalScheme::FORWARD_EULER, TemporalScheme::RUNGE_KUTTA_3RD_ORDER}; + TemporalScheme::FORWARD_EULER, TemporalScheme::RUNGE_KUTTA_2ND_ORDER, + TemporalScheme::RUNGE_KUTTA_3RD_ORDER}; for (const auto scheme : schemes) { auto domain = Domain::New(); From 20d03577127ec1be6dc1eb7558df66bd8567039c Mon Sep 17 00:00:00 2001 From: filipovic Date: Tue, 30 Dec 2025 08:38:50 +0100 Subject: [PATCH 24/38] Allow for calculating intermediate velocities during higher order time integration --- examples/holeEtching/holeEtching.cpp | 120 ++++++++++-------- .../viennaps/process/psAdvectionHandler.hpp | 5 + .../process/psFluxProcessStrategy.hpp | 35 +++++ include/viennaps/process/psProcessParams.hpp | 4 +- 4 files changed, 112 insertions(+), 52 deletions(-) diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index b964ca61..32c047fd 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -30,55 +30,73 @@ int main(int argc, char *argv[]) { units::Length::setUnit(params.get("lengthUnit")); units::Time::setUnit(params.get("timeUnit")); - // geometry setup - auto geometry = Domain::New( - params.get("gridDelta"), params.get("xExtent"), params.get("yExtent")); - MakeHole(geometry, params.get("holeRadius"), - 0.0, // holeDepth - 0.0, // holeTaperAngle - params.get("maskHeight"), params.get("taperAngle"), - HoleShape::QUARTER) - .apply(); - - // use pre-defined model SF6O2 etching model - auto modelParams = SF6O2Etching::defaultParameters(); - modelParams.ionFlux = params.get("ionFlux"); - modelParams.etchantFlux = params.get("etchantFlux"); - modelParams.passivationFlux = params.get("oxygenFlux"); - modelParams.Ions.meanEnergy = params.get("meanEnergy"); - modelParams.Ions.sigmaEnergy = params.get("sigmaEnergy"); - modelParams.Ions.exponent = params.get("ionExponent"); - modelParams.Passivation.A_ie = params.get("A_O"); - modelParams.Substrate.A_ie = params.get("A_Si"); - modelParams.etchStopDepth = params.get("etchStopDepth"); - auto model = SmartPointer>::New(modelParams); - - CoverageParameters coverageParams; - coverageParams.tolerance = 1e-4; - - RayTracingParameters rayTracingParams; - rayTracingParams.raysPerPoint = params.get("raysPerPoint"); - - AdvectionParameters advectionParams; - advectionParams.spatialScheme = - util::convertSpatialScheme(params.get("spatialScheme")); - advectionParams.temporalScheme = - util::convertTemporalScheme(params.get("temporalScheme")); - - // process setup - Process process(geometry, model); - process.setProcessDuration(params.get("processTime")); - process.setParameters(coverageParams); - process.setParameters(rayTracingParams); - process.setParameters(advectionParams); - - // print initial surface - geometry->saveSurfaceMesh("initial.vtp"); - - // run the process - process.apply(); - - // print final surface - geometry->saveSurfaceMesh(params.get("outputFile"), true, 0.01, - true); + auto runSimulation = [&](bool intermediateVelocities, std::string suffix) { + // geometry setup + auto geometry = Domain::New( + params.get("gridDelta"), params.get("xExtent"), params.get("yExtent")); + MakeHole(geometry, params.get("holeRadius"), + 0.0, // holeDepth + 0.0, // holeTaperAngle + params.get("maskHeight"), params.get("taperAngle"), + HoleShape::QUARTER) + .apply(); + + // use pre-defined model SF6O2 etching model + auto modelParams = SF6O2Etching::defaultParameters(); + modelParams.ionFlux = params.get("ionFlux"); + modelParams.etchantFlux = params.get("etchantFlux"); + modelParams.passivationFlux = params.get("oxygenFlux"); + modelParams.Ions.meanEnergy = params.get("meanEnergy"); + modelParams.Ions.sigmaEnergy = params.get("sigmaEnergy"); + modelParams.Ions.exponent = params.get("ionExponent"); + modelParams.Passivation.A_ie = params.get("A_O"); + modelParams.Substrate.A_ie = params.get("A_Si"); + modelParams.etchStopDepth = params.get("etchStopDepth"); + auto model = SmartPointer>::New(modelParams); + + CoverageParameters coverageParams; + coverageParams.tolerance = 1e-4; + + RayTracingParameters rayTracingParams; + rayTracingParams.raysPerPoint = params.get("raysPerPoint"); + + AdvectionParameters advectionParams; + advectionParams.spatialScheme = + util::convertSpatialScheme(params.get("spatialScheme")); + advectionParams.temporalScheme = + util::convertTemporalScheme(params.get("temporalScheme")); + advectionParams.calculateIntermediateVelocities = intermediateVelocities; + + // process setup + Process process(geometry, model); + process.setProcessDuration(params.get("processTime")); + process.setParameters(coverageParams); + process.setParameters(rayTracingParams); + process.setParameters(advectionParams); + + // print initial surface + if (suffix == "_noIntermediate") + geometry->saveSurfaceMesh("initial.vtp"); + + // run the process + process.apply(); + + // print final surface + std::string outputFile = params.get("outputFile"); + auto pos = outputFile.find_last_of('.'); + if (pos != std::string::npos) { + outputFile.insert(pos, suffix); + } else { + outputFile += suffix; + } + geometry->saveSurfaceMesh(outputFile, true, 0.01, true); + }; + + std::cout << "Running simulation without intermediate velocity calculation..." + << std::endl; + runSimulation(false, "_noIntermediate"); + + std::cout << "Running simulation with intermediate velocity calculation..." + << std::endl; + runSimulation(true, "_intermediate"); } diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 5162292a..2cf0f4fb 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -72,6 +72,11 @@ template class AdvectionHandler { advectionKernel_.setAdvectionTime(time); } + void setVelocityUpdateCallback( + std::function>)> callback) { + advectionKernel_.setVelocityUpdateCallback(callback); + } + void disableSingleStep() { advectionKernel_.setSingleStep(false); } void prepareAdvection(const ProcessContext &context) { diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index 1c6b3a0d..7cab6813 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -165,6 +165,41 @@ class FluxProcessStrategy final : public ProcessStrategy { // Initialize advection handler PROCESS_CHECK(advectionHandler_.initialize(context)); + // Register velocity update callback for high-order time integration + if (context.advectionParams.calculateIntermediateVelocities) { + advectionHandler_.setVelocityUpdateCallback( + [this, &context]( + SmartPointer> domain) { + // Update the mesh and translator based on the intermediate level set + this->updateState(context); + + // If coverages are used, map them from the grid (which holds t^n data) + // to the new intermediate surface + if (context.flags.useCoverages) { + this->advectionHandler_.updateCoveragesFromAdvectedSurface( + context, this->translator_); + } + + // Update the surface in the flux engine + if (this->fluxEngine_->updateSurface(context) != + ProcessResult::SUCCESS) + return false; + + // Calculate fluxes on the intermediate surface + auto fluxes = SmartPointer>::New(); + if (this->fluxEngine_->calculateFluxes(context, fluxes) != + ProcessResult::SUCCESS) + return false; + + // Calculate velocities + auto velocities = this->calculateVelocities(context, fluxes); + context.model->getVelocityField()->prepare(context.domain, velocities, + context.processTime); + + return true; + }); + } + if (context.flags.useAdvectionCallback) { context.model->getAdvectionCallback()->setDomain(context.domain); } diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 75708e2e..af838ef7 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -69,6 +69,7 @@ struct AdvectionParameters { bool velocityOutput = false; bool ignoreVoids = false; bool adaptiveTimeStepping = false; + bool calculateIntermediateVelocities = false; auto toMetaData() const { std::unordered_map> metaData; @@ -88,7 +89,8 @@ struct AdvectionParameters { "\nCheckDissipation: " + util::toString(checkDissipation) + "\nVelocityOutput: " + util::toString(velocityOutput) + "\nIgnoreVoids: " + util::toString(ignoreVoids) + - "\nAdaptiveTimeStepping: " + util::toString(adaptiveTimeStepping); + "\nAdaptiveTimeStepping: " + util::toString(adaptiveTimeStepping) + + "\nCalculateIntermediateVelocities: " + util::toString(calculateIntermediateVelocities); } }; From 45992a49668fd9cf7fb51f56cbb67f46e0b7f640 Mon Sep 17 00:00:00 2001 From: filipovic Date: Tue, 30 Dec 2025 22:12:45 +0100 Subject: [PATCH 25/38] Introduce velocity recalculation during intermediate time integration stpes when using higher order schemes (e.g., RK2, RK3). Added python bindings and a simpleEthing example which uses these schemes in C++ and Python. --- CMakeLists.txt | 2 +- examples/simpleEtching/CMakeLists.txt | 4 + examples/simpleEtching/simpleEtching.cpp | 75 +++++++++++++++++++ examples/simpleEtching/simpleEtching.py | 62 +++++++++++++++ .../viennaps/process/psAdvectionHandler.hpp | 3 +- .../process/psFluxProcessStrategy.hpp | 15 ++-- include/viennaps/process/psProcessParams.hpp | 3 +- python/pyWrap.cpp | 2 + 8 files changed, 156 insertions(+), 10 deletions(-) create mode 100644 examples/simpleEtching/CMakeLists.txt create mode 100644 examples/simpleEtching/simpleEtching.cpp create mode 100644 examples/simpleEtching/simpleEtching.py diff --git a/CMakeLists.txt b/CMakeLists.txt index 54fe1fba..ae9c1e2e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -121,7 +121,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS VERSION 5.3.0 - GIT_TAG fix_material_interface + GIT_TAG int-velocities GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/examples/simpleEtching/CMakeLists.txt b/examples/simpleEtching/CMakeLists.txt new file mode 100644 index 00000000..1bd6da45 --- /dev/null +++ b/examples/simpleEtching/CMakeLists.txt @@ -0,0 +1,4 @@ +project(simpleEtching LANGUAGES CXX) + +viennaps_add_example(${PROJECT_NAME} "${PROJECT_NAME}.cpp") + diff --git a/examples/simpleEtching/simpleEtching.cpp b/examples/simpleEtching/simpleEtching.cpp new file mode 100644 index 00000000..4fd85347 --- /dev/null +++ b/examples/simpleEtching/simpleEtching.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include + +namespace ps = viennaps; + +int main() { + // Dimension of the domain: 2 for Trench, 3 for Hole + constexpr int D = 2; + omp_set_num_threads(16); + using NumericType = double; + + ps::Logger::setLogLevel(ps::LogLevel::INFO); + + // Geometry parameters + NumericType gridDelta = 0.05; + NumericType xExtent = 3.0; + NumericType yExtent = 3.0; + NumericType featureWidth = 1.0; // Diameter for hole, Width for trench + NumericType maskHeight = 1.0; + NumericType taperAngle = 0.0; + + // Single Particle Process Model + // Parameters: rate, stickingProbability, yield, maskMaterial + NumericType rate = -2.0; + NumericType stickingProbability = 0.2; + NumericType sourcePower = 1.0; + NumericType processTime = 1.0; + + auto runSimulation = [&](ps::TemporalScheme temporalScheme, + bool calcIntermediate, std::string suffix) { + auto domain = ps::SmartPointer>::New( + gridDelta, xExtent, yExtent); + + if constexpr (D == 3) { + // Create a Hole in 3D + ps::MakeHole(domain, featureWidth / 2.0, 0.0, 0.0, + maskHeight, taperAngle, + ps::HoleShape::QUARTER) + .apply(); + } else { + // Create a Trench in 2D + ps::MakeTrench(domain, featureWidth, 0.0, 0.0, maskHeight, + taperAngle, false) + .apply(); + } + + auto model = + ps::SmartPointer>::New( + rate, stickingProbability, sourcePower, ps::Material::Mask); + + ps::Process process(domain, model, processTime); + + ps::AdvectionParameters advectionParams; + advectionParams.spatialScheme = ps::SpatialScheme::WENO_5TH_ORDER; + advectionParams.temporalScheme = temporalScheme; + advectionParams.calculateIntermediateVelocities = calcIntermediate; + process.setParameters(advectionParams); + + ps::Logger::getInstance().addInfo("Running simulation: " + suffix).print(); + + process.apply(); + + domain->saveSurfaceMesh("simpleEtching_" + suffix + ".vtp"); + }; + + runSimulation(ps::TemporalScheme::FORWARD_EULER, false, "FE"); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_2ND_ORDER, false, "RK2"); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, false, "RK3"); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, true, "RK3_recalc"); + + return 0; +} diff --git a/examples/simpleEtching/simpleEtching.py b/examples/simpleEtching/simpleEtching.py new file mode 100644 index 00000000..bad52e3c --- /dev/null +++ b/examples/simpleEtching/simpleEtching.py @@ -0,0 +1,62 @@ +import viennaps +import viennaps.d2 as vps2 +import viennaps.d3 as vps3 + +def main(): + # Dimension of the domain: 2 for Trench, 3 for Hole + D = 2 + + viennaps.Logger.setLogLevel(viennaps.LogLevel.INFO) + + # Geometry parameters + grid_delta = 0.05 + x_extent = 3.0 + y_extent = 3.0 + feature_width = 1.0 # Diameter for hole, Width for trench + mask_height = 1.0 + taper_angle = 0.0 + + # Single Particle Process Model + # Parameters: rate, stickingProbability, yield, maskMaterial + rate = -2.0 + sticking_probability = 0.2 + source_power = 1.0 + process_time = 1.0 + + def run_simulation(temporal_scheme, calc_intermediate, suffix): + if D == 3: + # Create a Hole in 3D + domain = vps3.Domain(grid_delta, x_extent, y_extent) + vps3.MakeHole(domain, feature_width / 2.0, 0.0, 0.0, + mask_height, taper_angle, + viennaps.HoleShape.QUARTER).apply() + + model = vps3.SingleParticleProcess(rate, sticking_probability, source_power, viennaps.Material.Mask) + process = vps3.Process(domain, model, process_time) + else: + # Create a Trench in 2D + domain = vps2.Domain(grid_delta, x_extent, y_extent) + vps2.MakeTrench(domain, feature_width, 0.0, 0.0, mask_height, + taper_angle, False).apply() + + model = vps2.SingleParticleProcess(rate, sticking_probability, source_power, viennaps.Material.Mask) + process = vps2.Process(domain, model, process_time) + + advection_params = viennaps.AdvectionParameters() + advection_params.spatialScheme = viennaps.util.convertSpatialScheme("WENO_5TH_ORDER") + advection_params.temporalScheme = temporal_scheme + advection_params.calculateIntermediateVelocities = calc_intermediate + process.setParameters(advection_params) + + viennaps.Logger.getInstance().addInfo(f"Running simulation: {suffix}").print() + process.apply() + + domain.saveSurfaceMesh(f"simpleEtching_{suffix}.vtp") + + run_simulation(viennaps.util.convertTemporalScheme("FORWARD_EULER"), False, "FE") + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), False, "RK2") + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), False, "RK3") + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), True, "RK3_recalc") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 2cf0f4fb..3e48bcfa 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -73,7 +73,8 @@ template class AdvectionHandler { } void setVelocityUpdateCallback( - std::function>)> callback) { + std::function>)> + callback) { advectionKernel_.setVelocityUpdateCallback(callback); } diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index 7cab6813..d145f708 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -168,13 +168,14 @@ class FluxProcessStrategy final : public ProcessStrategy { // Register velocity update callback for high-order time integration if (context.advectionParams.calculateIntermediateVelocities) { advectionHandler_.setVelocityUpdateCallback( - [this, &context]( - SmartPointer> domain) { - // Update the mesh and translator based on the intermediate level set + [this, + &context](SmartPointer> domain) { + // Update the mesh and translator based on the intermediate level + // set this->updateState(context); - // If coverages are used, map them from the grid (which holds t^n data) - // to the new intermediate surface + // If coverages are used, map them from the grid (which holds t^n + // data) to the new intermediate surface if (context.flags.useCoverages) { this->advectionHandler_.updateCoveragesFromAdvectedSurface( context, this->translator_); @@ -193,8 +194,8 @@ class FluxProcessStrategy final : public ProcessStrategy { // Calculate velocities auto velocities = this->calculateVelocities(context, fluxes); - context.model->getVelocityField()->prepare(context.domain, velocities, - context.processTime); + context.model->getVelocityField()->prepare( + context.domain, velocities, context.processTime); return true; }); diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index af838ef7..60e70556 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -90,7 +90,8 @@ struct AdvectionParameters { "\nVelocityOutput: " + util::toString(velocityOutput) + "\nIgnoreVoids: " + util::toString(ignoreVoids) + "\nAdaptiveTimeStepping: " + util::toString(adaptiveTimeStepping) + - "\nCalculateIntermediateVelocities: " + util::toString(calculateIntermediateVelocities); + "\nCalculateIntermediateVelocities: " + + util::toString(calculateIntermediateVelocities); } }; diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index b9ab4087..36a7b65b 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -491,6 +491,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { &AdvectionParameters::adaptiveTimeStepping) .def_readwrite("adaptiveTimeStepSubdivisions", &AdvectionParameters::adaptiveTimeStepSubdivisions) + .def_readwrite("calculateIntermediateVelocities", + &AdvectionParameters::calculateIntermediateVelocities) .def("toMetaData", &AdvectionParameters::toMetaData, "Convert the advection parameters to a metadata dict.") .def("toMetaDataString", &AdvectionParameters::toMetaDataString, From 5d5db4b3137501ae2339155be93c2a742e50f64f Mon Sep 17 00:00:00 2001 From: filipovic Date: Thu, 8 Jan 2026 16:38:19 +0100 Subject: [PATCH 26/38] adapted examples, tested against latest ViennaLS build for int-velocities --- CMakeLists.txt | 4 +- examples/holeEtching/holeEtching.py | 132 +++++++++++++---------- examples/simpleEtching/simpleEtching.cpp | 16 ++- examples/simpleEtching/simpleEtching.py | 14 ++- 4 files changed, 99 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ae9c1e2e..e2d3184b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -101,7 +101,7 @@ include("cmake/cpm.cmake") CPMAddPackage( NAME ViennaCore - VERSION 1.8.0 + VERSION 1.9.0 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaCore" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON} OPTIONS "VIENNACORE_USE_GPU ${VIENNAPS_USE_GPU}") @@ -120,7 +120,7 @@ CPMFindPackage( CPMFindPackage( NAME ViennaLS - VERSION 5.3.0 + VERSION 5.4.0 GIT_TAG int-velocities GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/examples/holeEtching/holeEtching.py b/examples/holeEtching/holeEtching.py index e3fba33d..866bb98a 100644 --- a/examples/holeEtching/holeEtching.py +++ b/examples/holeEtching/holeEtching.py @@ -13,64 +13,86 @@ else: print("Running 3D simulation.") ps.setDimension(args.dim) +ps.setNumThreads(16) params = ps.readConfigFile(args.filename) ps.Length.setUnit(params["lengthUnit"]) ps.Time.setUnit(params["timeUnit"]) -# geometry setup, all units in um -geometry = ps.Domain( - gridDelta=params["gridDelta"], - xExtent=params["xExtent"], - yExtent=params["yExtent"], -) -ps.MakeHole( - domain=geometry, - holeRadius=params["holeRadius"], - holeDepth=0.0, - maskHeight=params["maskHeight"], - maskTaperAngle=params["taperAngle"], - holeShape=ps.HoleShape.HALF, -).apply() - -# use pre-defined model SF6O2 etching model -modelParams = ps.SF6O2Etching.defaultParameters() -modelParams.ionFlux = params["ionFlux"] -modelParams.etchantFlux = params["etchantFlux"] -modelParams.passivationFlux = params["oxygenFlux"] -modelParams.Ions.meanEnergy = params["meanEnergy"] -modelParams.Ions.sigmaEnergy = params["sigmaEnergy"] -modelParams.Ions.exponent = params["ionExponent"] -modelParams.Passivation.A_ie = params["A_O"] -modelParams.Substrate.A_ie = params["A_Si"] -modelParams.etchStopDepth = params["etchStopDepth"] -model = ps.SF6O2Etching(modelParams) - -covParams = ps.CoverageParameters() -covParams.tolerance = 1e-4 - -rayParams = ps.RayTracingParameters() -rayParams.raysPerPoint = int(params["raysPerPoint"]) -rayParams.smoothingNeighbors = 2 - -advParams = ps.AdvectionParameters() -advParams.spatialScheme = ps.util.convertSpatialScheme( - params["spatialScheme"] -) - -# process setup -process = ps.Process(geometry, model) -process.setProcessDuration(params["processTime"]) # seconds -process.setParameters(covParams) -process.setParameters(rayParams) -process.setParameters(advParams) - -# print initial surface -geometry.saveSurfaceMesh(filename="initial.vtp") - -# run the process -process.apply() - -# print final surface -geometry.saveSurfaceMesh(filename="final.vtp", addInterfaces=True) +def run_simulation(intermediate_velocities, suffix): + # geometry setup, all units in um + geometry = ps.Domain( + gridDelta=params["gridDelta"], + xExtent=params["xExtent"], + yExtent=params["yExtent"], + ) + + hole_shape = ps.HoleShape.QUARTER if args.dim == 3 else ps.HoleShape.HALF + + ps.MakeHole( + domain=geometry, + holeRadius=params["holeRadius"], + holeDepth=0.0, + maskHeight=params["maskHeight"], + maskTaperAngle=params["taperAngle"], + holeShape=hole_shape, + ).apply() + + # use pre-defined model SF6O2 etching model + modelParams = ps.SF6O2Etching.defaultParameters() + modelParams.ionFlux = params["ionFlux"] + modelParams.etchantFlux = params["etchantFlux"] + modelParams.passivationFlux = params["oxygenFlux"] + modelParams.Ions.meanEnergy = params["meanEnergy"] + modelParams.Ions.sigmaEnergy = params["sigmaEnergy"] + modelParams.Ions.exponent = params["ionExponent"] + modelParams.Passivation.A_ie = params["A_O"] + modelParams.Substrate.A_ie = params["A_Si"] + modelParams.etchStopDepth = params["etchStopDepth"] + model = ps.SF6O2Etching(modelParams) + + covParams = ps.CoverageParameters() + covParams.tolerance = 1e-4 + + rayParams = ps.RayTracingParameters() + rayParams.raysPerPoint = int(params["raysPerPoint"]) + + advParams = ps.AdvectionParameters() + advParams.spatialScheme = ps.util.convertSpatialScheme( + params["spatialScheme"] + ) + advParams.temporalScheme = ps.util.convertTemporalScheme( + params["temporalScheme"] + ) + advParams.calculateIntermediateVelocities = intermediate_velocities + + # process setup + process = ps.Process(geometry, model) + process.setProcessDuration(params["processTime"]) # seconds + process.setParameters(covParams) + process.setParameters(rayParams) + process.setParameters(advParams) + + # print initial surface + if suffix == "_noIntermediate": + geometry.saveSurfaceMesh(filename="initial.vtp") + + # run the process + process.apply() + + # print final surface + output_file = params["outputFile"] + if "." in output_file: + parts = output_file.rsplit(".", 1) + output_file = f"{parts[0]}{suffix}.{parts[1]}" + else: + output_file += suffix + + geometry.saveSurfaceMesh(filename=output_file, addInterfaces=True, boolMaterials=True) + +print("Running simulation without intermediate velocity calculation...") +run_simulation(False, "_noIntermediate") + +print("Running simulation with intermediate velocity calculation...") +run_simulation(True, "_intermediate") diff --git a/examples/simpleEtching/simpleEtching.cpp b/examples/simpleEtching/simpleEtching.cpp index 4fd85347..77a23ccb 100644 --- a/examples/simpleEtching/simpleEtching.cpp +++ b/examples/simpleEtching/simpleEtching.cpp @@ -3,6 +3,7 @@ #include #include #include +#include namespace ps = viennaps; @@ -30,7 +31,11 @@ int main() { NumericType processTime = 1.0; auto runSimulation = [&](ps::TemporalScheme temporalScheme, - bool calcIntermediate, std::string suffix) { + bool calcIntermediate) { + std::string suffix = viennacore::util::toString(temporalScheme); + if (calcIntermediate) { + suffix += "_recalc"; + } auto domain = ps::SmartPointer>::New( gridDelta, xExtent, yExtent); @@ -66,10 +71,11 @@ int main() { domain->saveSurfaceMesh("simpleEtching_" + suffix + ".vtp"); }; - runSimulation(ps::TemporalScheme::FORWARD_EULER, false, "FE"); - runSimulation(ps::TemporalScheme::RUNGE_KUTTA_2ND_ORDER, false, "RK2"); - runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, false, "RK3"); - runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, true, "RK3_recalc"); + runSimulation(ps::TemporalScheme::FORWARD_EULER, false); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_2ND_ORDER, false); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_2ND_ORDER, true); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, false); + runSimulation(ps::TemporalScheme::RUNGE_KUTTA_3RD_ORDER, true); return 0; } diff --git a/examples/simpleEtching/simpleEtching.py b/examples/simpleEtching/simpleEtching.py index bad52e3c..866a6a15 100644 --- a/examples/simpleEtching/simpleEtching.py +++ b/examples/simpleEtching/simpleEtching.py @@ -23,7 +23,10 @@ def main(): source_power = 1.0 process_time = 1.0 - def run_simulation(temporal_scheme, calc_intermediate, suffix): + def run_simulation(temporal_scheme, calc_intermediate): + suffix = str(temporal_scheme).split(".")[-1] + if calc_intermediate: + suffix += "_recalc" if D == 3: # Create a Hole in 3D domain = vps3.Domain(grid_delta, x_extent, y_extent) @@ -53,10 +56,11 @@ def run_simulation(temporal_scheme, calc_intermediate, suffix): domain.saveSurfaceMesh(f"simpleEtching_{suffix}.vtp") - run_simulation(viennaps.util.convertTemporalScheme("FORWARD_EULER"), False, "FE") - run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), False, "RK2") - run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), False, "RK3") - run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), True, "RK3_recalc") + run_simulation(viennaps.util.convertTemporalScheme("FORWARD_EULER"), False) + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), False) + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), True) + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), False) + run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), True) if __name__ == "__main__": main() \ No newline at end of file From 1555d19471b55b6958db898bf574dc8cf11157bb Mon Sep 17 00:00:00 2001 From: filipovic Date: Fri, 9 Jan 2026 14:55:45 +0100 Subject: [PATCH 27/38] fix for removeStrayPoints --- python/pyWrap.cpp | 10 +- python/viennaps/__init__.pyi | 346 ++++++------------ python/viennaps/_core/__init__.pyi | 9 +- tests/removeStrayPoints/removeStrayPoints.cpp | 6 +- 4 files changed, 126 insertions(+), 245 deletions(-) diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index d1b04e65..d647b8df 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -60,8 +60,6 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { auto matEnum = py::native_enum(module, "Material", "enum.IntEnum", "Material types for domain and level sets"); -#define ENUM_BIND(id, sym, cat, dens, cond, color) \ - matEnum.value(#sym, Material::sym); #define ENUM_BIND(id, sym, cat, dens, cond, color) \ matEnum.value(#sym, Material::sym); MATERIAL_LIST(ENUM_BIND) @@ -128,13 +126,6 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .value("VOLUME", RenderMode::VOLUME) .finalize(); - // Render Mode Enum - py::native_enum(module, "RenderMode", "enum.IntEnum") - .value("SURFACE", RenderMode::SURFACE) - .value("INTERFACE", RenderMode::INTERFACE) - .value("VOLUME", RenderMode::VOLUME) - .finalize(); - // HoleShape Enum py::native_enum(module, "HoleShape", "enum.IntEnum") .value("FULL", HoleShape::FULL) @@ -559,6 +550,7 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { .def(py::init<>()) .def_readwrite("tolerance", &CoverageParameters::tolerance) .def_readwrite("maxIterations", &CoverageParameters::maxIterations) + .def_readwrite("initialized", &CoverageParameters::initialized) .def("toMetaData", &CoverageParameters::toMetaData, "Convert the coverage parameters to a metadata dict.") .def("toMetaDataString", &CoverageParameters::toMetaDataString, diff --git a/python/viennaps/__init__.pyi b/python/viennaps/__init__.pyi index b318f394..6c8699cf 100644 --- a/python/viennaps/__init__.pyi +++ b/python/viennaps/__init__.pyi @@ -1,5 +1,4 @@ """ - ViennaPS ======== @@ -8,239 +7,122 @@ which includes surface and volume representations, a ray tracer, and physical models for the simulation of microelectronic fabrication processes. """ -from __future__ import annotations + + +def _windows_dll_path(): + import os + + additional_paths = [ + os.path.join(os.path.dirname(os.path.dirname(__file__)), "viennaps.libs") + ] + + for path in additional_paths: + if not os.path.exists(path): + continue + + os.add_dll_directory(path) + os.environ["PATH"] = path + os.pathsep + os.environ["PATH"] + + +def _module_ptx_path(): + from importlib.util import find_spec + import os + + spec = find_spec("viennaps") + install_path = os.path.dirname(os.path.abspath(spec.origin)) + return os.path.join(install_path, "ptx") + + import sys as _sys + +if _sys.platform == "win32": + _windows_dll_path() + + import viennals as ls -from viennals._core import BoundaryConditionEnum as BoundaryType -from viennals._core import SpatialSchemeEnum as SpatialScheme -from viennals._core import LogLevel -from viennals._core import SpatialSchemeEnum as SpatialScheme -from viennals._core import TemporalSchemeEnum as TemporalScheme -from viennaps._core import AdvectionParameters -from viennaps._core import AtomicLayerProcessParameters -from viennaps._core import CF4O2Parameters -from viennaps._core import CF4O2ParametersIons -from viennaps._core import CF4O2ParametersMask -from viennaps._core import CF4O2ParametersPassivation -from viennaps._core import CF4O2ParametersSi -from viennaps._core import CF4O2ParametersSiGe -from viennaps._core import CoverageParameters -from viennaps._core import Extrude -from viennaps._core import FaradayCageParameters -from viennaps._core import FluorocarbonMaterialParameters -from viennaps._core import FluorocarbonParameters -from viennaps._core import FluorocarbonParametersIons -from viennaps._core import FluxEngineType -from viennaps._core import HoleShape -from viennaps._core import IBEParameters -from viennaps._core import IBEParametersCos4Yield -from viennaps._core import Length -from viennaps._core import LengthUnit -from viennaps._core import Logger -from viennaps._core import Material -from viennaps._core import MaterialCategory -from viennaps._core import MaterialInfo -from viennaps._core import MaterialMap -from viennaps._core import MetaDataLevel -from viennaps._core import NormalizationType -from viennaps._core import PlasmaEtchingParameters -from viennaps._core import PlasmaEtchingParametersIons -from viennaps._core import PlasmaEtchingParametersMask -from viennaps._core import PlasmaEtchingParametersPassivation -from viennaps._core import PlasmaEtchingParametersPolymer -from viennaps._core import PlasmaEtchingParametersSubstrate -from viennaps._core import ProcessParams -from viennaps._core import RateSet -from viennaps._core import RayTracingParameters -from viennaps._core import RenderMode -from viennaps._core import Slice -from viennaps._core import Time -from viennaps._core import TimeUnit -from viennaps._core import constants -from viennaps._core import gpu -from viennaps._core import gpuAvailable -from viennaps._core import setNumThreads -from viennaps._core import util -from viennaps.d2 import AdvectionCallback -from viennaps.d2 import BoxDistribution -from viennaps.d2 import CF4O2Etching -from viennaps.d2 import CSVFileProcess -from viennaps.d2 import DenseCellSet -from viennaps.d2 import DirectionalProcess -from viennaps.d2 import Domain -from viennaps.d2 import DomainSetup -from viennaps.d2 import FaradayCageEtching -from viennaps.d2 import FluorocarbonEtching -from viennaps.d2 import GDSGeometry -from viennaps.d2 import GDSReader -from viennaps.d2 import GeometricTrenchDeposition -from viennaps.d2 import GeometryFactory -from viennaps.d2 import HBrO2Etching -from viennaps.d2 import Interpolation -from viennaps.d2 import IonBeamEtching -from viennaps.d2 import IsotropicProcess -from viennaps.d2 import MakeFin -from viennaps.d2 import MakeHole -from viennaps.d2 import MakePlane -from viennaps.d2 import MakeStack -from viennaps.d2 import MakeTrench -from viennaps.d2 import MultiParticleProcess -from viennaps.d2 import OxideRegrowth -from viennaps.d2 import Planarize -from viennaps.d2 import Process -from viennaps.d2 import ProcessModel -from viennaps.d2 import ProcessModelBase -from viennaps.d2 import RateGrid -from viennaps.d2 import Reader -from viennaps.d2 import SF6C4F8Etching -from viennaps.d2 import SF6O2Etching -from viennaps.d2 import SelectiveEpitaxy -from viennaps.d2 import SingleParticleALD -from viennaps.d2 import SingleParticleProcess -from viennaps.d2 import SphereDistribution -from viennaps.d2 import StencilLocalLaxFriedrichsScalar -from viennaps.d2 import TEOSDeposition -from viennaps.d2 import TEOSPECVD -from viennaps.d2 import ToDiskMesh -from viennaps.d2 import VTKRenderWindow -from viennaps.d2 import WetEtching -from viennaps.d2 import Writer -from . import _core -from . import d2 -from . import d3 - -__all__: list[str] = [ - "AdvectionCallback", - "AdvectionParameters", - "AtomicLayerProcessParameters", - "BoundaryType", - "BoxDistribution", - "CF4O2Etching", - "CF4O2Parameters", - "CF4O2ParametersIons", - "CF4O2ParametersMask", - "CF4O2ParametersPassivation", - "CF4O2ParametersSi", - "CF4O2ParametersSiGe", - "CSVFileProcess", - "CoverageParameters", - "DenseCellSet", - "DirectionalProcess", - "Domain", - "DomainSetup", - "Extrude", - "FaradayCageEtching", - "FaradayCageParameters", - "FluorocarbonEtching", - "FluorocarbonMaterialParameters", - "FluorocarbonParameters", - "FluorocarbonParametersIons", - "FluxEngineType", - "GDSGeometry", - "GDSReader", - "GeometricTrenchDeposition", - "GeometryFactory", - "HBrO2Etching", - "HoleShape", - "IBEParameters", - "IBEParametersCos4Yield", - "IntegrationScheme", - "Interpolation", - "IonBeamEtching", - "IsotropicProcess", - "Length", - "LengthUnit", - "LogLevel", - "Logger", - "MakeFin", - "MakeHole", - "MakePlane", - "MakeStack", - "MakeTrench", - "Material", - "MaterialMap", - "MetaDataLevel", - "MultiParticleProcess", - "NormalizationType", - "OxideRegrowth", - "PROXY_DIM", - "Planarize", - "PlasmaEtchingParameters", - "PlasmaEtchingParametersIons", - "PlasmaEtchingParametersMask", - "PlasmaEtchingParametersPassivation", - "PlasmaEtchingParametersPolymer", - "PlasmaEtchingParametersSubstrate", - "Process", - "ProcessModel", - "ProcessModelBase", - "ProcessParams", - "RateGrid", - "RateSet", - "RayTracingParameters", - "Reader", - "RenderMode", - "SF6C4F8Etching", - "SF6O2Etching", - "SelectiveEpitaxy", - "SingleParticleALD", - "SingleParticleProcess", - "Slice", - "SphereDistribution", - "StencilLocalLaxFriedrichsScalar", - "TemporalScheme", - "TEOSDeposition", - "TEOSPECVD", - "Time", - "TimeUnit", - "ToDiskMesh", - "VTKRenderWindow", - "WetEtching", - "Writer", - "constants", - "d2", - "d3", - "gpu", - "gpuAvailable", - "ls", - "ptxPath", - "readConfigFile", - "setDimension", - "setNumThreads", - "util", - "version", -] - -def __dir__(): ... -def __getattr__(name): ... -def _module_ptx_path(): ... -def _windows_dll_path(): ... -def readConfigFile(fileName: str): - """ - Read a config file in the ViennaPS standard config file format. - - Parameters - ---------- - fileName: str - Name of the config file. - - Returns - ------- - dict - A dictionary containing the parameters from the config file. - - """ + +# Convenience imports +from viennals import SpatialSchemeEnum as SpatialScheme +from viennals import TemporalSchemeEnum as TemporalScheme +from viennals import BoundaryConditionEnum as BoundaryType +from viennals import LogLevel as LogLevel +from . import _core as _C # the binary inside the package + +# bring d2 and d3 into the top-level namespace +d2 = _C.d2 +d3 = _C.d3 +_sys.modules[__name__ + ".d2"] = d2 +_sys.modules[__name__ + ".d3"] = d3 +PROXY_DIM = 2 # default dimension is 2D + + def setDimension(d: int): + """Set the dimension of the simulation (2 or 3). + + Parameters + ---------- + d: int + Dimension of the simulation (2 or 3). """ - Set the dimension of the simulation (2 or 3). - - Parameters - ---------- - d: int - Dimension of the simulation (2 or 3). - + global PROXY_DIM + if d == 2 or d == 3: + PROXY_DIM = d + ls.setDimension(d) + else: + raise ValueError("Dimension must be 2 or 3.") + + +# Config file reader helper function +def readConfigFile(fileName: str): + """Read a config file in the ViennaPS standard config file format. + + Parameters + ---------- + fileName: str + Name of the config file. + + Returns + ------- + dict + A dictionary containing the parameters from the config file. """ -PROXY_DIM: int = 2 -__version__: str = '4.2.0' -version: str = '4.2.0' -_C = _core + par_dict = {} + + with open(fileName, "r") as file: + lines = file.readlines() + for line in lines: + + line = line[: line.find("#")] # remove comments + + if len(line) > 0: + par_name = line[: line.find("=")].strip(" ") + par_value = line[line.find("=") + 1 :] + + try: + val = float(par_value) + except: + val = par_value + + par_dict[par_name] = val + + return par_dict + + +def __getattr__(name): + # 1) common/top-level from _core + try: + return getattr(_C, name) + except AttributeError as e_core: + pass + # 2) fallback to current default dimension + m = d2 if PROXY_DIM == 2 else d3 + try: + return getattr(m, name) + except AttributeError: + raise AttributeError( + f"module {__name__!r} has no attribute {name!r}" + ) from e_core + + +def __dir__(): + return sorted(set(globals()) | set(dir(_C)) | set(dir(d2)) | set(dir(d3))) \ No newline at end of file diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index a15f60f8..2c01b829 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -8,14 +8,15 @@ import typing import viennals._core from viennaps import d2 import viennaps.d2 -import viennaps.d3 from viennaps import d3 +import viennaps.d3 from . import constants from . import gpu from . import util __all__: list[str] = ['AdvectionParameters', 'AtomicLayerProcessParameters', 'CF4O2Parameters', 'CF4O2ParametersIons', 'CF4O2ParametersMask', 'CF4O2ParametersPassivation', 'CF4O2ParametersSi', 'CF4O2ParametersSiGe', 'CoverageParameters', 'Extrude', 'FaradayCageParameters', 'FluorocarbonMaterialParameters', 'FluorocarbonParameters', 'FluorocarbonParametersIons', 'FluxEngineType', 'HoleShape', 'IBEParameters', 'IBEParametersCos4Yield', 'Length', 'LengthUnit', 'Logger', 'Material', 'MaterialCategory', 'MaterialInfo', 'MaterialMap', 'MetaDataLevel', 'NormalizationType', 'PlasmaEtchingParameters', 'PlasmaEtchingParametersIons', 'PlasmaEtchingParametersMask', 'PlasmaEtchingParametersPassivation', 'PlasmaEtchingParametersPolymer', 'PlasmaEtchingParametersSubstrate', 'ProcessParams', 'RateSet', 'RayTracingParameters', 'RenderMode', 'Slice', 'Time', 'TimeUnit', 'constants', 'd2', 'd3', 'gpu', 'gpuAvailable', 'setNumThreads', 'util', 'version'] class AdvectionParameters: adaptiveTimeStepping: bool + calculateIntermediateVelocities: bool checkDissipation: bool ignoreVoids: bool integrationScheme: viennals._core.SpatialSchemeEnum @@ -363,6 +364,12 @@ class CoverageParameters: def maxIterations(self, arg0: typing.SupportsInt) -> None: ... @property + def initialized(self) -> bool: + ... + @initialized.setter + def initialized(self, arg0: bool) -> None: + ... + @property def tolerance(self) -> float: ... @tolerance.setter diff --git a/tests/removeStrayPoints/removeStrayPoints.cpp b/tests/removeStrayPoints/removeStrayPoints.cpp index a0be8b5c..9a587e9c 100644 --- a/tests/removeStrayPoints/removeStrayPoints.cpp +++ b/tests/removeStrayPoints/removeStrayPoints.cpp @@ -41,7 +41,7 @@ int main() { std::cout << "Number of components before removing stray points: " << domain->getNumberOfComponents() << std::endl; - VC_TEST_ASSERT(domain->getNumberOfComponents() == 7); + VC_TEST_ASSERT(domain->getNumberOfComponents() == 8); domain->removeStrayPoints(); @@ -50,12 +50,12 @@ int main() { std::cout << "Number of components after removing stray points: " << domain->getNumberOfComponents() << std::endl; - VC_TEST_ASSERT(domain->getNumberOfComponents() == 1); + VC_TEST_ASSERT(domain->getNumberOfComponents() == 2); MakeTrench(domain, 5.0, 0.0, 0.0, 1.0).apply(); domain->removeMaterial(Material::Si); - VC_TEST_ASSERT(domain->getNumberOfComponents() == 2); + VC_TEST_ASSERT(domain->getNumberOfComponents() == 3); domain->saveLevelSetMesh("testInitial"); } \ No newline at end of file From 783d5afb5f57afe15f86d7f4b9c82aef6634ef23 Mon Sep 17 00:00:00 2001 From: filipovic Date: Fri, 9 Jan 2026 15:01:48 +0100 Subject: [PATCH 28/38] revert /python/viennaps/__init__.py --- python/viennaps/__init__.pyi | 247 +++++++++++++++++++---------------- 1 file changed, 133 insertions(+), 114 deletions(-) diff --git a/python/viennaps/__init__.pyi b/python/viennaps/__init__.pyi index 6c8699cf..c99acd91 100644 --- a/python/viennaps/__init__.pyi +++ b/python/viennaps/__init__.pyi @@ -1,4 +1,5 @@ """ + ViennaPS ======== @@ -7,122 +8,140 @@ which includes surface and volume representations, a ray tracer, and physical models for the simulation of microelectronic fabrication processes. """ - - -def _windows_dll_path(): - import os - - additional_paths = [ - os.path.join(os.path.dirname(os.path.dirname(__file__)), "viennaps.libs") - ] - - for path in additional_paths: - if not os.path.exists(path): - continue - - os.add_dll_directory(path) - os.environ["PATH"] = path + os.pathsep + os.environ["PATH"] - - -def _module_ptx_path(): - from importlib.util import find_spec - import os - - spec = find_spec("viennaps") - install_path = os.path.dirname(os.path.abspath(spec.origin)) - return os.path.join(install_path, "ptx") - - +from __future__ import annotations import sys as _sys - -if _sys.platform == "win32": - _windows_dll_path() - - import viennals as ls - -# Convenience imports -from viennals import SpatialSchemeEnum as SpatialScheme -from viennals import TemporalSchemeEnum as TemporalScheme -from viennals import BoundaryConditionEnum as BoundaryType -from viennals import LogLevel as LogLevel -from . import _core as _C # the binary inside the package - -# bring d2 and d3 into the top-level namespace -d2 = _C.d2 -d3 = _C.d3 -_sys.modules[__name__ + ".d2"] = d2 -_sys.modules[__name__ + ".d3"] = d3 -PROXY_DIM = 2 # default dimension is 2D - - +from viennals._core import BoundaryConditionEnum as BoundaryType +from viennals._core import LogLevel +from viennals._core import SpatialSchemeEnum as SpatialScheme +from viennals._core import TemporalSchemeEnum as TemporalScheme +from viennaps._core import AdvectionParameters +from viennaps._core import AtomicLayerProcessParameters +from viennaps._core import CF4O2Parameters +from viennaps._core import CF4O2ParametersIons +from viennaps._core import CF4O2ParametersMask +from viennaps._core import CF4O2ParametersPassivation +from viennaps._core import CF4O2ParametersSi +from viennaps._core import CF4O2ParametersSiGe +from viennaps._core import CoverageParameters +from viennaps._core import Extrude +from viennaps._core import FaradayCageParameters +from viennaps._core import FluorocarbonMaterialParameters +from viennaps._core import FluorocarbonParameters +from viennaps._core import FluorocarbonParametersIons +from viennaps._core import FluxEngineType +from viennaps._core import HoleShape +from viennaps._core import IBEParameters +from viennaps._core import IBEParametersCos4Yield +from viennaps._core import Length +from viennaps._core import LengthUnit +from viennaps._core import Logger +from viennaps._core import Material +from viennaps._core import MaterialCategory +from viennaps._core import MaterialInfo +from viennaps._core import MaterialMap +from viennaps._core import MetaDataLevel +from viennaps._core import NormalizationType +from viennaps._core import PlasmaEtchingParameters +from viennaps._core import PlasmaEtchingParametersIons +from viennaps._core import PlasmaEtchingParametersMask +from viennaps._core import PlasmaEtchingParametersPassivation +from viennaps._core import PlasmaEtchingParametersPolymer +from viennaps._core import PlasmaEtchingParametersSubstrate +from viennaps._core import ProcessParams +from viennaps._core import RateSet +from viennaps._core import RayTracingParameters +from viennaps._core import RenderMode +from viennaps._core import Slice +from viennaps._core import Time +from viennaps._core import TimeUnit +from viennaps._core import constants +from viennaps._core import gpu +from viennaps._core import gpuAvailable +from viennaps._core import setNumThreads +from viennaps._core import util +from viennaps.d2 import AdvectionCallback +from viennaps.d2 import BoxDistribution +from viennaps.d2 import CF4O2Etching +from viennaps.d2 import CSVFileProcess +from viennaps.d2 import DenseCellSet +from viennaps.d2 import DirectionalProcess +from viennaps.d2 import Domain +from viennaps.d2 import DomainSetup +from viennaps.d2 import FaradayCageEtching +from viennaps.d2 import FluorocarbonEtching +from viennaps.d2 import GDSGeometry +from viennaps.d2 import GDSReader +from viennaps.d2 import GeometricTrenchDeposition +from viennaps.d2 import GeometryFactory +from viennaps.d2 import HBrO2Etching +from viennaps.d2 import Interpolation +from viennaps.d2 import IonBeamEtching +from viennaps.d2 import IsotropicProcess +from viennaps.d2 import MakeFin +from viennaps.d2 import MakeHole +from viennaps.d2 import MakePlane +from viennaps.d2 import MakeStack +from viennaps.d2 import MakeTrench +from viennaps.d2 import MultiParticleProcess +from viennaps.d2 import OxideRegrowth +from viennaps.d2 import Planarize +from viennaps.d2 import Process +from viennaps.d2 import ProcessModel +from viennaps.d2 import ProcessModelBase +from viennaps.d2 import RateGrid +from viennaps.d2 import Reader +from viennaps.d2 import SF6C4F8Etching +from viennaps.d2 import SF6O2Etching +from viennaps.d2 import SelectiveEpitaxy +from viennaps.d2 import SingleParticleALD +from viennaps.d2 import SingleParticleProcess +from viennaps.d2 import SphereDistribution +from viennaps.d2 import StencilLocalLaxFriedrichsScalar +from viennaps.d2 import TEOSDeposition +from viennaps.d2 import TEOSPECVD +from viennaps.d2 import ToDiskMesh +from viennaps.d2 import VTKRenderWindow +from viennaps.d2 import WetEtching +from viennaps.d2 import Writer +from . import _core +from . import d2 +from . import d3 +__all__: list[str] = ['AdvectionCallback', 'AdvectionParameters', 'AtomicLayerProcessParameters', 'BoundaryType', 'BoxDistribution', 'CF4O2Etching', 'CF4O2Parameters', 'CF4O2ParametersIons', 'CF4O2ParametersMask', 'CF4O2ParametersPassivation', 'CF4O2ParametersSi', 'CF4O2ParametersSiGe', 'CSVFileProcess', 'CoverageParameters', 'DenseCellSet', 'DirectionalProcess', 'Domain', 'DomainSetup', 'Extrude', 'FaradayCageEtching', 'FaradayCageParameters', 'FluorocarbonEtching', 'FluorocarbonMaterialParameters', 'FluorocarbonParameters', 'FluorocarbonParametersIons', 'FluxEngineType', 'GDSGeometry', 'GDSReader', 'GeometricTrenchDeposition', 'GeometryFactory', 'HBrO2Etching', 'HoleShape', 'IBEParameters', 'IBEParametersCos4Yield', 'Interpolation', 'IonBeamEtching', 'IsotropicProcess', 'Length', 'LengthUnit', 'LogLevel', 'Logger', 'MakeFin', 'MakeHole', 'MakePlane', 'MakeStack', 'MakeTrench', 'Material', 'MaterialCategory', 'MaterialInfo', 'MaterialMap', 'MetaDataLevel', 'MultiParticleProcess', 'NormalizationType', 'OxideRegrowth', 'PROXY_DIM', 'Planarize', 'PlasmaEtchingParameters', 'PlasmaEtchingParametersIons', 'PlasmaEtchingParametersMask', 'PlasmaEtchingParametersPassivation', 'PlasmaEtchingParametersPolymer', 'PlasmaEtchingParametersSubstrate', 'Process', 'ProcessModel', 'ProcessModelBase', 'ProcessParams', 'RateGrid', 'RateSet', 'RayTracingParameters', 'Reader', 'RenderMode', 'SF6C4F8Etching', 'SF6O2Etching', 'SelectiveEpitaxy', 'SingleParticleALD', 'SingleParticleProcess', 'Slice', 'SpatialScheme', 'SphereDistribution', 'StencilLocalLaxFriedrichsScalar', 'TEOSDeposition', 'TEOSPECVD', 'TemporalScheme', 'Time', 'TimeUnit', 'ToDiskMesh', 'VTKRenderWindow', 'WetEtching', 'Writer', 'constants', 'd2', 'd3', 'gpu', 'gpuAvailable', 'ls', 'readConfigFile', 'setDimension', 'setNumThreads', 'util', 'version'] +def __dir__(): + ... +def __getattr__(name): + ... +def _module_ptx_path(): + ... +def _windows_dll_path(): + ... +def readConfigFile(fileName: str): + """ + Read a config file in the ViennaPS standard config file format. + + Parameters + ---------- + fileName: str + Name of the config file. + + Returns + ------- + dict + A dictionary containing the parameters from the config file. + + """ def setDimension(d: int): - """Set the dimension of the simulation (2 or 3). - - Parameters - ---------- - d: int - Dimension of the simulation (2 or 3). """ - global PROXY_DIM - if d == 2 or d == 3: - PROXY_DIM = d - ls.setDimension(d) - else: - raise ValueError("Dimension must be 2 or 3.") - - -# Config file reader helper function -def readConfigFile(fileName: str): - """Read a config file in the ViennaPS standard config file format. - - Parameters - ---------- - fileName: str - Name of the config file. - - Returns - ------- - dict - A dictionary containing the parameters from the config file. + Set the dimension of the simulation (2 or 3). + + Parameters + ---------- + d: int + Dimension of the simulation (2 or 3). + """ - par_dict = {} - - with open(fileName, "r") as file: - lines = file.readlines() - for line in lines: - - line = line[: line.find("#")] # remove comments - - if len(line) > 0: - par_name = line[: line.find("=")].strip(" ") - par_value = line[line.find("=") + 1 :] - - try: - val = float(par_value) - except: - val = par_value - - par_dict[par_name] = val - - return par_dict - - -def __getattr__(name): - # 1) common/top-level from _core - try: - return getattr(_C, name) - except AttributeError as e_core: - pass - # 2) fallback to current default dimension - m = d2 if PROXY_DIM == 2 else d3 - try: - return getattr(m, name) - except AttributeError: - raise AttributeError( - f"module {__name__!r} has no attribute {name!r}" - ) from e_core - - -def __dir__(): - return sorted(set(globals()) | set(dir(_C)) | set(dir(d2)) | set(dir(d3))) \ No newline at end of file +PROXY_DIM: int = 2 +__version__: str = '4.2.0' +version: str = '4.2.0' +_C = _core \ No newline at end of file From 8b133e3024424ca84cf6ab72c2032c773bbd3a13 Mon Sep 17 00:00:00 2001 From: filipovic Date: Sun, 11 Jan 2026 20:30:22 +0100 Subject: [PATCH 29/38] format --- python/viennaps/__init__.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/viennaps/__init__.pyi b/python/viennaps/__init__.pyi index c99acd91..0436b417 100644 --- a/python/viennaps/__init__.pyi +++ b/python/viennaps/__init__.pyi @@ -144,4 +144,4 @@ def setDimension(d: int): PROXY_DIM: int = 2 __version__: str = '4.2.0' version: str = '4.2.0' -_C = _core \ No newline at end of file +_C = _core From 4c37da531e47242a41167e20c8545655c57a7e00 Mon Sep 17 00:00:00 2001 From: filipovic Date: Thu, 15 Jan 2026 11:36:55 +0100 Subject: [PATCH 30/38] remove GIT_TAG --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0adabea6..75d1a9da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -125,7 +125,6 @@ CPMAddPackage( CPMAddPackage( NAME ViennaLS VERSION 5.4.0 - GIT_TAG int-velocities GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) From f13eee1da6b9e7bc609ecf307eb004ed7d24cb73 Mon Sep 17 00:00:00 2001 From: filipovic Date: Thu, 15 Jan 2026 19:15:45 +0100 Subject: [PATCH 31/38] minor fixes --- examples/holeEtching/holeEtching.cpp | 5 +++-- examples/simpleEtching/simpleEtching.py | 3 ++- tests/removeStrayPoints/removeStrayPoints.cpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index 32c047fd..bdcd74f9 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -8,9 +8,10 @@ using namespace viennaps; int main(int argc, char *argv[]) { using NumericType = double; - constexpr int D = 3; + constexpr int D = 2; - omp_set_num_threads(16); + Logger::setLogLevel(LogLevel::ERROR); + omp_set_num_threads(8); // Parse the parameters util::Parameters params; diff --git a/examples/simpleEtching/simpleEtching.py b/examples/simpleEtching/simpleEtching.py index 866a6a15..e9e38e88 100644 --- a/examples/simpleEtching/simpleEtching.py +++ b/examples/simpleEtching/simpleEtching.py @@ -63,4 +63,5 @@ def run_simulation(temporal_scheme, calc_intermediate): run_simulation(viennaps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), True) if __name__ == "__main__": - main() \ No newline at end of file + main() + \ No newline at end of file diff --git a/tests/removeStrayPoints/removeStrayPoints.cpp b/tests/removeStrayPoints/removeStrayPoints.cpp index 9a587e9c..d6aa44a4 100644 --- a/tests/removeStrayPoints/removeStrayPoints.cpp +++ b/tests/removeStrayPoints/removeStrayPoints.cpp @@ -58,4 +58,4 @@ int main() { VC_TEST_ASSERT(domain->getNumberOfComponents() == 3); domain->saveLevelSetMesh("testInitial"); -} \ No newline at end of file +} From e245eb2a1f4fb990726f56b2de3052fe126f8fb9 Mon Sep 17 00:00:00 2001 From: filipovic Date: Thu, 15 Jan 2026 22:19:04 +0100 Subject: [PATCH 32/38] Set CMake to use ViennaLS5.5.0 for intermediate velocity calculation for RK2/3 --- CMakeLists.txt | 4 ++-- examples/holeEtching/config.txt | 1 + examples/holeEtching/holeEtching.cpp | 4 ++++ examples/holeEtching/holeEtching.py | 4 ++++ examples/simpleEtching/simpleEtching.cpp | 5 ++++- examples/simpleEtching/simpleEtching.py | 3 +++ include/viennaps/process/psAdvectionHandler.hpp | 1 + include/viennaps/psUtil.hpp | 5 +++++ pyproject.toml | 2 +- python/scripts/install_ViennaPS_linux.py | 2 +- 10 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 75d1a9da..720c3f58 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -105,7 +105,7 @@ include("cmake/cpm.cmake") CPMAddPackage( NAME ViennaCore - VERSION 1.9.2 + VERSION 1.9.4 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaCore" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON} OPTIONS "VIENNACORE_USE_GPU ${VIENNAPS_USE_GPU}") @@ -124,7 +124,7 @@ CPMAddPackage( CPMAddPackage( NAME ViennaLS - VERSION 5.4.0 + VERSION 5.5.0 GIT_REPOSITORY "https://github.com/ViennaTools/ViennaLS" EXCLUDE_FROM_ALL ${VIENNAPS_BUILD_PYTHON}) diff --git a/examples/holeEtching/config.txt b/examples/holeEtching/config.txt index 4af1874e..a4c9f036 100644 --- a/examples/holeEtching/config.txt +++ b/examples/holeEtching/config.txt @@ -30,6 +30,7 @@ A_Si=7 # Si yield constant etchStopDepth=-10 # maximum etching depth spatialScheme=EO_1 temporalScheme=RK3 +fluxEngine=CD raysPerPoint=1000 diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index bdcd74f9..18b59df7 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -69,11 +69,15 @@ int main(int argc, char *argv[]) { advectionParams.calculateIntermediateVelocities = intermediateVelocities; // process setup + const std::string fluxEngineStr = params.get("fluxEngine"); + const auto fluxEngine = util::convertFluxEngineType(fluxEngineStr); + Process process(geometry, model); process.setProcessDuration(params.get("processTime")); process.setParameters(coverageParams); process.setParameters(rayTracingParams); process.setParameters(advectionParams); + process.setFluxEngineType(fluxEngine); // print initial surface if (suffix == "_noIntermediate") diff --git a/examples/holeEtching/holeEtching.py b/examples/holeEtching/holeEtching.py index 866bb98a..51437aee 100644 --- a/examples/holeEtching/holeEtching.py +++ b/examples/holeEtching/holeEtching.py @@ -74,6 +74,10 @@ def run_simulation(intermediate_velocities, suffix): process.setParameters(rayParams) process.setParameters(advParams) + fluxEngineStr = params["fluxEngine"] + fluxEngine = ps.util.convertFluxEngineType(fluxEngineStr) + process.setFluxEngineType(fluxEngine) + # print initial surface if suffix == "_noIntermediate": geometry.saveSurfaceMesh(filename="initial.vtp") diff --git a/examples/simpleEtching/simpleEtching.cpp b/examples/simpleEtching/simpleEtching.cpp index 77a23ccb..6021fa1a 100644 --- a/examples/simpleEtching/simpleEtching.cpp +++ b/examples/simpleEtching/simpleEtching.cpp @@ -58,11 +58,14 @@ int main() { ps::Process process(domain, model, processTime); + const auto fluxEngine = viennacore::util::convertFluxEngineType("CT"); + ps::AdvectionParameters advectionParams; - advectionParams.spatialScheme = ps::SpatialScheme::WENO_5TH_ORDER; + advectionParams.spatialScheme = ps::SpatialScheme::WENO_3RD_ORDER; advectionParams.temporalScheme = temporalScheme; advectionParams.calculateIntermediateVelocities = calcIntermediate; process.setParameters(advectionParams); + process.setFluxEngineType(fluxEngine); ps::Logger::getInstance().addInfo("Running simulation: " + suffix).print(); diff --git a/examples/simpleEtching/simpleEtching.py b/examples/simpleEtching/simpleEtching.py index e9e38e88..dfa8eaa1 100644 --- a/examples/simpleEtching/simpleEtching.py +++ b/examples/simpleEtching/simpleEtching.py @@ -51,6 +51,9 @@ def run_simulation(temporal_scheme, calc_intermediate): advection_params.calculateIntermediateVelocities = calc_intermediate process.setParameters(advection_params) + fluxEngine = viennaps.util.convertFluxEngineType("GT") + process.setFluxEngineType(fluxEngine) + viennaps.Logger.getInstance().addInfo(f"Running simulation: {suffix}").print() process.apply() diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index d81bc1fb..293ad308 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -29,6 +29,7 @@ template class AdvectionHandler { discSchem != SpatialScheme::ENGQUIST_OSHER_2ND_ORDER && discSchem != SpatialScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER && discSchem != SpatialScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER && + discSchem != SpatialScheme::WENO_3RD_ORDER && discSchem != SpatialScheme::WENO_5TH_ORDER)) { VIENNACORE_LOG_WARNING( "Translation field method not supported in combination " diff --git a/include/viennaps/psUtil.hpp b/include/viennaps/psUtil.hpp index 2049d42a..7ba8062d 100644 --- a/include/viennaps/psUtil.hpp +++ b/include/viennaps/psUtil.hpp @@ -48,6 +48,8 @@ convertSpatialScheme(const std::string &s) { return viennals::SpatialSchemeEnum::LOCAL_LAX_FRIEDRICHS_2ND_ORDER; if (s == "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER" || s == "SLLF_1") return viennals::SpatialSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER; + if (s == "WENO_3RD_ORDER" || s == "WENO_3") + return viennals::SpatialSchemeEnum::WENO_3RD_ORDER; if (s == "WENO_5TH_ORDER" || s == "WENO_5") return viennals::SpatialSchemeEnum::WENO_5TH_ORDER; throw std::invalid_argument( @@ -60,6 +62,7 @@ convertSpatialScheme(const std::string &s) { "LOCAL_LAX_FRIEDRICHS_1ST_ORDER, " "LOCAL_LAX_FRIEDRICHS_2ND_ORDER, " "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER, " + "WENO_3RD_ORDER, " "WENO_5TH_ORDER"); } @@ -127,6 +130,8 @@ convertSpatialSchemeToString(viennals::SpatialSchemeEnum scheme) { return "LOCAL_LAX_FRIEDRICHS_2ND_ORDER"; case viennals::SpatialSchemeEnum::STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER: return "STENCIL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER"; + case viennals::SpatialSchemeEnum::WENO_3RD_ORDER: + return "WENO_3RD_ORDER"; case viennals::SpatialSchemeEnum::WENO_5TH_ORDER: return "WENO_5TH_ORDER"; default: diff --git a/pyproject.toml b/pyproject.toml index c9904de7..4e486d10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -8,7 +8,7 @@ name = "ViennaPS" readme = "README.md" license = { file = "LICENSE" } description = "Topography simulation library for microelectronic fabrication processes" -dependencies = ["ViennaLS>=5.4.0"] +dependencies = ["ViennaLS>=5.5.0"] [project.urls] Homepage = "https://viennatools.github.io/ViennaPS/" diff --git a/python/scripts/install_ViennaPS_linux.py b/python/scripts/install_ViennaPS_linux.py index 36b2010e..122f464e 100644 --- a/python/scripts/install_ViennaPS_linux.py +++ b/python/scripts/install_ViennaPS_linux.py @@ -9,7 +9,7 @@ REQUIRED_GCC = "12" REQUIRED_NVCC_MAJOR = 12 -DEFAULT_VIENNALS_VERSION = "5.4.0" +DEFAULT_VIENNALS_VERSION = "5.5.0" def run(cmd, **kwargs): From 821625b38114e412c01022afa5a785df9ceaafa7 Mon Sep 17 00:00:00 2001 From: filipovic Date: Fri, 16 Jan 2026 03:42:29 +0100 Subject: [PATCH 33/38] fix holeEtching config --- examples/holeEtching/config.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/holeEtching/config.txt b/examples/holeEtching/config.txt index 7fb6a7f6..7c4a1d5d 100644 --- a/examples/holeEtching/config.txt +++ b/examples/holeEtching/config.txt @@ -33,3 +33,4 @@ temporalScheme=RK3 fluxEngine=CD raysPerPoint=1000 +outputFile=final.vtp From 2cb9df4221fb55476fcbd3085104f488da89ce69 Mon Sep 17 00:00:00 2001 From: filipovic Date: Fri, 16 Jan 2026 03:43:39 +0100 Subject: [PATCH 34/38] format --- include/viennaps/process/psAdvectionHandler.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 293ad308..06c2fe1a 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -29,7 +29,7 @@ template class AdvectionHandler { discSchem != SpatialScheme::ENGQUIST_OSHER_2ND_ORDER && discSchem != SpatialScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_1ST_ORDER && discSchem != SpatialScheme::LOCAL_LOCAL_LAX_FRIEDRICHS_2ND_ORDER && - discSchem != SpatialScheme::WENO_3RD_ORDER && + discSchem != SpatialScheme::WENO_3RD_ORDER && discSchem != SpatialScheme::WENO_5TH_ORDER)) { VIENNACORE_LOG_WARNING( "Translation field method not supported in combination " From ae1919f2bc3cd68db61c01c417d58ad83a6c6ce6 Mon Sep 17 00:00:00 2001 From: filipovic Date: Fri, 16 Jan 2026 03:54:43 +0100 Subject: [PATCH 35/38] format --- examples/simpleEtching/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/simpleEtching/CMakeLists.txt b/examples/simpleEtching/CMakeLists.txt index 1bd6da45..d8339baf 100644 --- a/examples/simpleEtching/CMakeLists.txt +++ b/examples/simpleEtching/CMakeLists.txt @@ -1,4 +1,3 @@ project(simpleEtching LANGUAGES CXX) viennaps_add_example(${PROJECT_NAME} "${PROJECT_NAME}.cpp") - From 75241e27e14940551900a40f108d0bb32b60f516 Mon Sep 17 00:00:00 2001 From: Lado Filipovic Date: Fri, 16 Jan 2026 08:29:51 +0100 Subject: [PATCH 36/38] avoid caching FetchContent deps on Windows --- .github/workflows/build.yml | 11 +++++++++-- .github/workflows/python.yml | 26 +++++++++++++++++++++----- 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66b2725c..6a74752c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,12 +51,19 @@ jobs: run: | brew install embree tbb vtk - - name: ๐Ÿฆฅ Cache Dependencies + - name: ๐Ÿฆฅ Cache Dependencies (non-Windows only) + if: ${{ matrix.os != 'windows-latest' }} uses: actions/cache@v4 with: - key: test-${{ matrix.os }}-${{ matrix.config }} + key: test-${{ matrix.os }}-${{ matrix.config }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} path: build + # - name: ๐Ÿฆฅ Cache Dependencies + # uses: actions/cache@v4 + # with: + # key: test-${{ matrix.os }}-${{ matrix.config }} + # path: build + - name: ๐Ÿ—๏ธ Compile run: cmake -DVIENNAPS_BUILD_TESTS=ON -B build && cmake --build build --config ${{ matrix.config }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 30973319..ae0b6d10 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -48,25 +48,41 @@ jobs: run: | brew install embree tbb vtk - - name: ๐Ÿฆฅ Cache Dependencies + - name: ๐Ÿฆฅ Cache Dependencies (non-Windows only) + if: ${{ matrix.os != 'windows-latest' }} uses: actions/cache@v4 with: - key: python-${{ matrix.os }} + key: python-${{ matrix.os }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} path: build + # - name: ๐Ÿฆฅ Cache Dependencies + # uses: actions/cache@v4 + # with: + # key: python-${{ matrix.os }} + # path: build + - name: ๐Ÿ› ๏ธ Disable IPO (Alpine) if: ${{ matrix.os == 'ubuntu-latest' }} run: | sed -i 's/\(DVIENNAPS_BUILD_PYTHON=ON"\)/\1,"-DUSE_IPO=off"/g' pyproject.toml cat pyproject.toml + # - name: ๐Ÿ Build and check Python Module (Windows) + # if: ${{ matrix.os == 'windows-latest' }} + # run: | + # python -m venv venv + # ./venv/Scripts/activate.bat + # pip install . + # python -c "import viennaps; print(viennaps.__doc__)" + - name: ๐Ÿ Build and check Python Module (Windows) if: ${{ matrix.os == 'windows-latest' }} + shell: pwsh run: | python -m venv venv - ./venv/Scripts/activate.bat - pip install . - python -c "import viennaps; print(viennaps.__doc__)" + .\venv\Scripts\python -m pip install -U pip + .\venv\Scripts\python -m pip install . + .\venv\Scripts\python -c "import viennaps; print(viennaps.__doc__)" - name: ๐Ÿ Build and check Python Module (Other) if: ${{ matrix.os != 'windows-latest' }} From 660310b2f1f27384b8a883e98ba80e056c656a26 Mon Sep 17 00:00:00 2001 From: Lado Filipovic Date: Fri, 16 Jan 2026 13:57:32 +0100 Subject: [PATCH 37/38] Revert to caching windows-latest --- .github/workflows/build.yml | 11 ++--------- .github/workflows/python.yml | 28 ++++++---------------------- 2 files changed, 8 insertions(+), 31 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6a74752c..66b2725c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -51,19 +51,12 @@ jobs: run: | brew install embree tbb vtk - - name: ๐Ÿฆฅ Cache Dependencies (non-Windows only) - if: ${{ matrix.os != 'windows-latest' }} + - name: ๐Ÿฆฅ Cache Dependencies uses: actions/cache@v4 with: - key: test-${{ matrix.os }}-${{ matrix.config }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} + key: test-${{ matrix.os }}-${{ matrix.config }} path: build - # - name: ๐Ÿฆฅ Cache Dependencies - # uses: actions/cache@v4 - # with: - # key: test-${{ matrix.os }}-${{ matrix.config }} - # path: build - - name: ๐Ÿ—๏ธ Compile run: cmake -DVIENNAPS_BUILD_TESTS=ON -B build && cmake --build build --config ${{ matrix.config }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index ae0b6d10..889a2e73 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -48,41 +48,25 @@ jobs: run: | brew install embree tbb vtk - - name: ๐Ÿฆฅ Cache Dependencies (non-Windows only) - if: ${{ matrix.os != 'windows-latest' }} + - name: ๐Ÿฆฅ Cache Dependencies uses: actions/cache@v4 with: - key: python-${{ matrix.os }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} + key: python-${{ matrix.os }} path: build - # - name: ๐Ÿฆฅ Cache Dependencies - # uses: actions/cache@v4 - # with: - # key: python-${{ matrix.os }} - # path: build - - name: ๐Ÿ› ๏ธ Disable IPO (Alpine) if: ${{ matrix.os == 'ubuntu-latest' }} run: | sed -i 's/\(DVIENNAPS_BUILD_PYTHON=ON"\)/\1,"-DUSE_IPO=off"/g' pyproject.toml cat pyproject.toml - # - name: ๐Ÿ Build and check Python Module (Windows) - # if: ${{ matrix.os == 'windows-latest' }} - # run: | - # python -m venv venv - # ./venv/Scripts/activate.bat - # pip install . - # python -c "import viennaps; print(viennaps.__doc__)" - - name: ๐Ÿ Build and check Python Module (Windows) if: ${{ matrix.os == 'windows-latest' }} - shell: pwsh run: | python -m venv venv - .\venv\Scripts\python -m pip install -U pip - .\venv\Scripts\python -m pip install . - .\venv\Scripts\python -c "import viennaps; print(viennaps.__doc__)" + ./venv/Scripts/activate.bat + pip install . + python -c "import viennaps; print(viennaps.__doc__)" - name: ๐Ÿ Build and check Python Module (Other) if: ${{ matrix.os != 'windows-latest' }} @@ -180,4 +164,4 @@ jobs: merge-multiple: true - name: ๐Ÿš€ Publish Wheels - uses: pypa/gh-action-pypi-publish@release/v1 + uses: pypa/gh-action-pypi-publish@release/v1 \ No newline at end of file From 76968fe9d47e3b17111703d6f712692053de0340 Mon Sep 17 00:00:00 2001 From: Lado Filipovic Date: Fri, 16 Jan 2026 14:03:30 +0100 Subject: [PATCH 38/38] Clean FetchContent deps (Windows) --- .github/workflows/build.yml | 8 +++++++- .github/workflows/python.yml | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 66b2725c..aca6a9bf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,9 +54,15 @@ jobs: - name: ๐Ÿฆฅ Cache Dependencies uses: actions/cache@v4 with: - key: test-${{ matrix.os }}-${{ matrix.config }} + key: test-${{ matrix.os }}-${{ matrix.config }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} path: build + - name: ๐Ÿงน Clean FetchContent deps (Windows) + if: ${{ matrix.os == 'windows-latest' }} + shell: pwsh + run: | + if (Test-Path build/_deps) { Remove-Item -Recurse -Force build/_deps } + - name: ๐Ÿ—๏ธ Compile run: cmake -DVIENNAPS_BUILD_TESTS=ON -B build && cmake --build build --config ${{ matrix.config }} diff --git a/.github/workflows/python.yml b/.github/workflows/python.yml index 889a2e73..aeb661b2 100644 --- a/.github/workflows/python.yml +++ b/.github/workflows/python.yml @@ -51,9 +51,15 @@ jobs: - name: ๐Ÿฆฅ Cache Dependencies uses: actions/cache@v4 with: - key: python-${{ matrix.os }} + key: python-${{ matrix.os }}-${{ hashFiles('CMakeLists.txt', 'cmake/**', 'pyproject.toml') }} path: build + - name: ๐Ÿงน Clean FetchContent deps (Windows) + if: ${{ matrix.os == 'windows-latest' }} + shell: pwsh + run: | + if (Test-Path build/_deps) { Remove-Item -Recurse -Force build/_deps } + - name: ๐Ÿ› ๏ธ Disable IPO (Alpine) if: ${{ matrix.os == 'ubuntu-latest' }} run: |