From fb0320caa336cd3c3a4a443b653c27cc1fbe4cc6 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Tue, 20 Jan 2026 21:05:57 +0100 Subject: [PATCH 01/11] NumericType and Dimension concept --- examples/holeEtching/config.txt | 2 +- examples/holeEtching/holeEtching.py | 18 +++-- examples/simpleEtching/simpleEtching.py | 71 +++++++++---------- include/viennaps/process/psALPStrategy.hpp | 2 +- .../viennaps/process/psAdvectionCallback.hpp | 2 +- .../viennaps/process/psAdvectionHandler.hpp | 2 +- .../process/psAnalyticProcessStrategy.hpp | 2 +- .../viennaps/process/psAtomicLayerProcess.hpp | 2 +- include/viennaps/process/psCPUDiskEngine.hpp | 2 +- .../viennaps/process/psCPUTriangleEngine.hpp | 2 +- .../process/psCallbackOnlyStrategy.hpp | 2 +- .../viennaps/process/psCoverageManager.hpp | 2 +- include/viennaps/process/psFluxEngine.hpp | 2 +- .../process/psFluxProcessStrategy.hpp | 11 +-- include/viennaps/process/psGPUDiskEngine.hpp | 2 +- include/viennaps/process/psGPULineEngine.hpp | 2 +- .../viennaps/process/psGPUTriangleEngine.hpp | 2 +- include/viennaps/process/psGeometricModel.hpp | 2 +- .../process/psGeometricProcessStrategy.hpp | 2 +- include/viennaps/process/psProcess.hpp | 16 ++--- include/viennaps/process/psProcessContext.hpp | 2 +- include/viennaps/process/psProcessModel.hpp | 6 +- include/viennaps/process/psProcessParams.hpp | 6 ++ .../viennaps/process/psProcessStrategy.hpp | 2 +- include/viennaps/process/psSurfaceModel.hpp | 2 +- .../viennaps/process/psTranslationField.hpp | 2 +- include/viennaps/process/psVelocityField.hpp | 4 +- include/viennaps/psCreateSurfaceMesh.hpp | 18 +++-- include/viennaps/psDomain.hpp | 3 +- include/viennaps/psDomainSetup.hpp | 5 +- include/viennaps/psElementToPointData.hpp | 34 +++++---- include/viennaps/psExtrude.hpp | 2 +- include/viennaps/psPlanarize.hpp | 2 +- include/viennaps/psPointToElementData.hpp | 12 ++-- include/viennaps/psPreCompileMacros.hpp | 12 ++++ include/viennaps/psRateGrid.hpp | 2 +- include/viennaps/psReader.hpp | 2 +- include/viennaps/psSlice.hpp | 2 +- .../psSurfacePointValuesToLevelSet.hpp | 4 +- include/viennaps/psToDiskMesh.hpp | 2 +- include/viennaps/psVTKRenderWindow.hpp | 2 +- include/viennaps/psWriter.hpp | 2 +- 42 files changed, 153 insertions(+), 123 deletions(-) diff --git a/examples/holeEtching/config.txt b/examples/holeEtching/config.txt index 7c4a1d5d..ceb92467 100644 --- a/examples/holeEtching/config.txt +++ b/examples/holeEtching/config.txt @@ -30,7 +30,7 @@ A_Si=7 # Si yield constant etchStopDepth=-10 # maximum etching depth spatialScheme=EO_1 temporalScheme=RK3 -fluxEngine=CD +fluxEngine=GT raysPerPoint=1000 outputFile=final.vtp diff --git a/examples/holeEtching/holeEtching.py b/examples/holeEtching/holeEtching.py index 51437aee..31ad612b 100644 --- a/examples/holeEtching/holeEtching.py +++ b/examples/holeEtching/holeEtching.py @@ -20,6 +20,7 @@ ps.Length.setUnit(params["lengthUnit"]) ps.Time.setUnit(params["timeUnit"]) + def run_simulation(intermediate_velocities, suffix): # geometry setup, all units in um geometry = ps.Domain( @@ -27,8 +28,6 @@ def run_simulation(intermediate_velocities, suffix): xExtent=params["xExtent"], yExtent=params["yExtent"], ) - - hole_shape = ps.HoleShape.QUARTER if args.dim == 3 else ps.HoleShape.HALF ps.MakeHole( domain=geometry, @@ -36,7 +35,7 @@ def run_simulation(intermediate_velocities, suffix): holeDepth=0.0, maskHeight=params["maskHeight"], maskTaperAngle=params["taperAngle"], - holeShape=hole_shape, + holeShape=ps.HoleShape.QUARTER, ).apply() # use pre-defined model SF6O2 etching model @@ -59,12 +58,8 @@ def run_simulation(intermediate_velocities, suffix): rayParams.raysPerPoint = int(params["raysPerPoint"]) advParams = ps.AdvectionParameters() - advParams.spatialScheme = ps.util.convertSpatialScheme( - params["spatialScheme"] - ) - advParams.temporalScheme = ps.util.convertTemporalScheme( - params["temporalScheme"] - ) + advParams.spatialScheme = ps.util.convertSpatialScheme(params["spatialScheme"]) + advParams.temporalScheme = ps.util.convertTemporalScheme(params["temporalScheme"]) advParams.calculateIntermediateVelocities = intermediate_velocities # process setup @@ -93,7 +88,10 @@ def run_simulation(intermediate_velocities, suffix): else: output_file += suffix - geometry.saveSurfaceMesh(filename=output_file, addInterfaces=True, boolMaterials=True) + geometry.saveSurfaceMesh( + filename=output_file, addInterfaces=True, boolMaterials=True + ) + print("Running simulation without intermediate velocity calculation...") run_simulation(False, "_noIntermediate") diff --git a/examples/simpleEtching/simpleEtching.py b/examples/simpleEtching/simpleEtching.py index dfa8eaa1..f071355d 100644 --- a/examples/simpleEtching/simpleEtching.py +++ b/examples/simpleEtching/simpleEtching.py @@ -1,18 +1,17 @@ -import viennaps -import viennaps.d2 as vps2 -import viennaps.d3 as vps3 +import viennaps as ps + + +ps.setDimension(3) # Set to 3 for hole etching in 3D +ps.Logger.setLogLevel(ps.LogLevel.INFO) + 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 + feature_width = 1.0 # Diameter for hole, Width for trench mask_height = 1.0 taper_angle = 0.0 @@ -24,47 +23,43 @@ def main(): process_time = 1.0 def run_simulation(temporal_scheme, calc_intermediate): - suffix = str(temporal_scheme).split(".")[-1] + suffix = temporal_scheme.name if calc_intermediate: suffix += "_recalc" - 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") + # Create a Hole in 3D (defaults to trench in 2D) + domain = ps.Domain(grid_delta, x_extent, y_extent) + ps.MakeHole( + domain, + feature_width / 2.0, + 0.0, + 0.0, + mask_height, + taper_angle, + ).apply() + + model = ps.SingleParticleProcess( + rate, sticking_probability, source_power, ps.Material.Mask + ) + process = ps.Process(domain, model, process_time) + + advection_params = ps.AdvectionParameters() + advection_params.spatialScheme = ps.SpatialScheme.WENO_5TH_ORDER advection_params.temporalScheme = temporal_scheme 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() + ps.Logger.getInstance().addInfo(f"Running simulation: {suffix}").print() process.apply() domain.saveSurfaceMesh(f"simpleEtching_{suffix}.vtp") - 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) + run_simulation(ps.util.convertTemporalScheme("FORWARD_EULER"), False) + run_simulation(ps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), False) + run_simulation(ps.util.convertTemporalScheme("RUNGE_KUTTA_2ND_ORDER"), True) + run_simulation(ps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), False) + run_simulation(ps.util.convertTemporalScheme("RUNGE_KUTTA_3RD_ORDER"), True) + if __name__ == "__main__": main() - \ No newline at end of file diff --git a/include/viennaps/process/psALPStrategy.hpp b/include/viennaps/process/psALPStrategy.hpp index fa1123af..22966774 100644 --- a/include/viennaps/process/psALPStrategy.hpp +++ b/include/viennaps/process/psALPStrategy.hpp @@ -8,7 +8,7 @@ namespace viennaps { -template +VIENNAPS_TEMPLATE_ND class ALPStrategy final : public ProcessStrategy { using TranslatorType = std::unordered_map; diff --git a/include/viennaps/process/psAdvectionCallback.hpp b/include/viennaps/process/psAdvectionCallback.hpp index e0ddc375..bff07bef 100644 --- a/include/viennaps/process/psAdvectionCallback.hpp +++ b/include/viennaps/process/psAdvectionCallback.hpp @@ -6,7 +6,7 @@ namespace viennaps { using namespace viennacore; -template class AdvectionCallback { +VIENNAPS_TEMPLATE_ND class AdvectionCallback { protected: SmartPointer> domain = nullptr; diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 06c2fe1a..a45ec712 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -8,7 +8,7 @@ namespace viennaps { -template class AdvectionHandler { +VIENNAPS_TEMPLATE_ND class AdvectionHandler { viennals::Advect advectionKernel_; viennacore::Timer<> timer_; unsigned lsVelOutputCounter = 0; diff --git a/include/viennaps/process/psAnalyticProcessStrategy.hpp b/include/viennaps/process/psAnalyticProcessStrategy.hpp index 88034956..3d7fb06e 100644 --- a/include/viennaps/process/psAnalyticProcessStrategy.hpp +++ b/include/viennaps/process/psAnalyticProcessStrategy.hpp @@ -6,7 +6,7 @@ namespace viennaps { -template +VIENNAPS_TEMPLATE_ND class AnalyticProcessStrategy final : public ProcessStrategy { viennals::ToDiskMesh meshConverter_; AdvectionHandler advectionHandler_; diff --git a/include/viennaps/process/psAtomicLayerProcess.hpp b/include/viennaps/process/psAtomicLayerProcess.hpp index 10e8a28b..13dd9788 100644 --- a/include/viennaps/process/psAtomicLayerProcess.hpp +++ b/include/viennaps/process/psAtomicLayerProcess.hpp @@ -21,7 +21,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class DesorptionSource : public viennaray::Source { public: DesorptionSource(const std::vector> &points, diff --git a/include/viennaps/process/psCPUDiskEngine.hpp b/include/viennaps/process/psCPUDiskEngine.hpp index f3cd7496..78462d27 100644 --- a/include/viennaps/process/psCPUDiskEngine.hpp +++ b/include/viennaps/process/psCPUDiskEngine.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class CPUDiskEngine final : public FluxEngine { public: ProcessResult checkInput(ProcessContext &context) override { diff --git a/include/viennaps/process/psCPUTriangleEngine.hpp b/include/viennaps/process/psCPUTriangleEngine.hpp index f51f220d..75f4daa1 100644 --- a/include/viennaps/process/psCPUTriangleEngine.hpp +++ b/include/viennaps/process/psCPUTriangleEngine.hpp @@ -13,7 +13,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class CPUTriangleEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psCallbackOnlyStrategy.hpp b/include/viennaps/process/psCallbackOnlyStrategy.hpp index 95f0deeb..21619785 100644 --- a/include/viennaps/process/psCallbackOnlyStrategy.hpp +++ b/include/viennaps/process/psCallbackOnlyStrategy.hpp @@ -4,7 +4,7 @@ namespace viennaps { -template +VIENNAPS_TEMPLATE_ND class CallbackOnlyStrategy : public ProcessStrategy { public: DEFINE_CLASS_NAME(CallbackOnlyStrategy) diff --git a/include/viennaps/process/psCoverageManager.hpp b/include/viennaps/process/psCoverageManager.hpp index ba477b26..53f64001 100644 --- a/include/viennaps/process/psCoverageManager.hpp +++ b/include/viennaps/process/psCoverageManager.hpp @@ -4,7 +4,7 @@ namespace viennaps { -template class CoverageManager { +VIENNAPS_TEMPLATE_ND class CoverageManager { std::ofstream covMetricFile_; SmartPointer> previousCoverages_; diff --git a/include/viennaps/process/psFluxEngine.hpp b/include/viennaps/process/psFluxEngine.hpp index f938fbcf..99f2adfd 100644 --- a/include/viennaps/process/psFluxEngine.hpp +++ b/include/viennaps/process/psFluxEngine.hpp @@ -6,7 +6,7 @@ namespace viennaps { -template class FluxEngine { +VIENNAPS_TEMPLATE_ND class FluxEngine { protected: viennacore::Timer<> timer_; diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index d145f708..6dd2c0e8 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -10,9 +10,10 @@ namespace viennaps { -template +VIENNAPS_TEMPLATE_ND class FluxProcessStrategy final : public ProcessStrategy { using TranslatorType = std::unordered_map; + static constexpr char *materialIdsLabel = "MaterialIds"; AdvectionHandler advectionHandler_; CoverageManager coverageManager_; @@ -262,7 +263,7 @@ class FluxProcessStrategy final : public ProcessStrategy { // Prepare advection (expand level set based on discretization scheme) advectionHandler_.prepareAdvection(context); - // Update surface for flux calculation + // Update surface mesh for flux calculation updateState(context); PROCESS_CHECK(fluxEngine_->updateSurface(context)); @@ -374,7 +375,7 @@ class FluxProcessStrategy final : public ProcessStrategy { auto const &points = context.diskMesh->getNodes(); assert(points.size() > 0); auto const &materialIds = - *context.diskMesh->getCellData().getScalarData("MaterialIds"); + *context.diskMesh->getCellData().getScalarData(materialIdsLabel); return context.model->getSurfaceModel()->calculateVelocities(fluxes, points, materialIds); } @@ -386,10 +387,10 @@ class FluxProcessStrategy final : public ProcessStrategy { assert(surfaceModel->getCoverages() != nullptr); assert(context.diskMesh != nullptr); - assert(context.diskMesh->getCellData().getScalarData("MaterialIds") != + assert(context.diskMesh->getCellData().getScalarData(materialIdsLabel) != nullptr); auto const &materialIds = - *context.diskMesh->getCellData().getScalarData("MaterialIds"); + *context.diskMesh->getCellData().getScalarData(materialIdsLabel); surfaceModel->updateCoverages(fluxes, materialIds); } diff --git a/include/viennaps/process/psGPUDiskEngine.hpp b/include/viennaps/process/psGPUDiskEngine.hpp index d56418cb..a3301b88 100644 --- a/include/viennaps/process/psGPUDiskEngine.hpp +++ b/include/viennaps/process/psGPUDiskEngine.hpp @@ -14,7 +14,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class GPUDiskEngine final : public FluxEngine { public: explicit GPUDiskEngine(std::shared_ptr deviceContext) diff --git a/include/viennaps/process/psGPULineEngine.hpp b/include/viennaps/process/psGPULineEngine.hpp index 4eed6957..eb823390 100644 --- a/include/viennaps/process/psGPULineEngine.hpp +++ b/include/viennaps/process/psGPULineEngine.hpp @@ -17,7 +17,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class GPULineEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psGPUTriangleEngine.hpp b/include/viennaps/process/psGPUTriangleEngine.hpp index 95bbc66f..1ab3ca4b 100644 --- a/include/viennaps/process/psGPUTriangleEngine.hpp +++ b/include/viennaps/process/psGPUTriangleEngine.hpp @@ -21,7 +21,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class GPUTriangleEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psGeometricModel.hpp b/include/viennaps/process/psGeometricModel.hpp index c7be65c2..0ac4d3da 100644 --- a/include/viennaps/process/psGeometricModel.hpp +++ b/include/viennaps/process/psGeometricModel.hpp @@ -8,7 +8,7 @@ namespace viennaps { using namespace viennacore; -template class GeometricModel { +VIENNAPS_TEMPLATE_ND class GeometricModel { SmartPointer> domain = nullptr; SmartPointer> dist = nullptr; diff --git a/include/viennaps/process/psGeometricProcessStrategy.hpp b/include/viennaps/process/psGeometricProcessStrategy.hpp index 7537cddf..36f24277 100644 --- a/include/viennaps/process/psGeometricProcessStrategy.hpp +++ b/include/viennaps/process/psGeometricProcessStrategy.hpp @@ -4,7 +4,7 @@ namespace viennaps { -template +VIENNAPS_TEMPLATE_ND class GeometricProcessStrategy : public ProcessStrategy { public: DEFINE_CLASS_NAME(GeometricProcessStrategy) diff --git a/include/viennaps/process/psProcess.hpp b/include/viennaps/process/psProcess.hpp index 360c42c3..cce519eb 100644 --- a/include/viennaps/process/psProcess.hpp +++ b/include/viennaps/process/psProcess.hpp @@ -22,15 +22,15 @@ namespace viennaps { using namespace viennacore; +inline consteval bool gpuAvailable() { #ifdef VIENNACORE_COMPILE_GPU -inline constexpr bool gpuAvailable() { return true; } + return true; #else -inline constexpr bool gpuAvailable() { return false; } + return false; #endif +} -template constexpr bool always_false = false; - -template class Process { +VIENNAPS_TEMPLATE_ND class Process { private: ProcessContext context_; std::vector>> strategies_; @@ -62,7 +62,8 @@ template class Process { context_.processDuration = duration; } - template void setParameters(const ParamType ¶ms) { + template + void setParameters(const ParamType ¶ms) { if constexpr (std::is_same_v) { context_.rayTracingParams = params; } else if constexpr (std::is_same_v) { @@ -72,9 +73,6 @@ template class Process { } else if constexpr (std::is_same_v) { context_.atomicLayerParams = params; - } else { - static_assert(always_false, - "Unsupported parameter type for Process."); } } diff --git a/include/viennaps/process/psProcessContext.hpp b/include/viennaps/process/psProcessContext.hpp index 87144cae..5c580919 100644 --- a/include/viennaps/process/psProcessContext.hpp +++ b/include/viennaps/process/psProcessContext.hpp @@ -17,7 +17,7 @@ enum class ProcessResult { NOT_IMPLEMENTED }; -template struct ProcessContext { +VIENNAPS_TEMPLATE_ND struct ProcessContext { // Core components SmartPointer> domain; SmartPointer> model; diff --git a/include/viennaps/process/psProcessModel.hpp b/include/viennaps/process/psProcessModel.hpp index 3550a82f..6b444d21 100644 --- a/include/viennaps/process/psProcessModel.hpp +++ b/include/viennaps/process/psProcessModel.hpp @@ -24,7 +24,7 @@ using namespace viennacore; /// The process model combines all models (particle types, surface model, /// geometric model, advection callback) -template class ProcessModelBase { +VIENNAPS_TEMPLATE_ND class ProcessModelBase { protected: SmartPointer> surfaceModel = nullptr; SmartPointer> advectionCallback = nullptr; @@ -82,7 +82,7 @@ template class ProcessModelBase { }; /// Process model for CPU-based particle tracing (or no particle tracing) -template +VIENNAPS_TEMPLATE_ND class ProcessModelCPU : public ProcessModelBase { protected: std::vector>> @@ -176,7 +176,7 @@ PS_PRECOMPILE_PRECISION_DIMENSION(ProcessModelCPU) #ifdef VIENNACORE_COMPILE_GPU namespace viennaps::gpu { -template +VIENNAPS_TEMPLATE_ND class ProcessModelGPU : public ProcessModelBase { private: std::vector> particles; diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index 60e70556..c08580e5 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -128,6 +128,12 @@ struct AtomicLayerProcessParameters { auto toMetaDataString() const { return util::metaDataToString(toMetaData()); } }; +template +concept ProcessParam = std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; + template class ProcessParams { private: std::vector scalarData; diff --git a/include/viennaps/process/psProcessStrategy.hpp b/include/viennaps/process/psProcessStrategy.hpp index 8fb92706..724b2b8c 100644 --- a/include/viennaps/process/psProcessStrategy.hpp +++ b/include/viennaps/process/psProcessStrategy.hpp @@ -17,7 +17,7 @@ namespace viennaps { -template class ProcessStrategy { +VIENNAPS_TEMPLATE_ND class ProcessStrategy { public: virtual ~ProcessStrategy() = default; diff --git a/include/viennaps/process/psSurfaceModel.hpp b/include/viennaps/process/psSurfaceModel.hpp index 3a465d0b..2e704486 100644 --- a/include/viennaps/process/psSurfaceModel.hpp +++ b/include/viennaps/process/psSurfaceModel.hpp @@ -1,6 +1,6 @@ #pragma once -#include "process/psProcessParams.hpp" +#include "psProcessParams.hpp" #include #include diff --git a/include/viennaps/process/psTranslationField.hpp b/include/viennaps/process/psTranslationField.hpp index f14b9156..80656864 100644 --- a/include/viennaps/process/psTranslationField.hpp +++ b/include/viennaps/process/psTranslationField.hpp @@ -14,7 +14,7 @@ namespace viennaps { using namespace viennacore; -template +VIENNAPS_TEMPLATE_ND class TranslationField final : public viennals::VelocityField { using TranslatorType = std::unordered_map; diff --git a/include/viennaps/process/psVelocityField.hpp b/include/viennaps/process/psVelocityField.hpp index 3104d01e..7348a7db 100644 --- a/include/viennaps/process/psVelocityField.hpp +++ b/include/viennaps/process/psVelocityField.hpp @@ -6,7 +6,7 @@ namespace viennaps { using namespace viennacore; -template class VelocityField { +VIENNAPS_TEMPLATE_ND class VelocityField { public: virtual ~VelocityField() = default; @@ -38,7 +38,7 @@ template class VelocityField { const NumericType processTime) {} }; -template +VIENNAPS_TEMPLATE_ND class DefaultVelocityField : public VelocityField { public: DefaultVelocityField() = default; diff --git a/include/viennaps/psCreateSurfaceMesh.hpp b/include/viennaps/psCreateSurfaceMesh.hpp index e850ed37..e82d44ea 100644 --- a/include/viennaps/psCreateSurfaceMesh.hpp +++ b/include/viennaps/psCreateSurfaceMesh.hpp @@ -1,5 +1,7 @@ #pragma once +#include "psPreCompileMacros.hpp" + #include #include #include @@ -38,11 +40,14 @@ inline void CopyTriangleMesh(const float gridDelta, triangleMesh.normals = *mesh->getCellData().getVectorData("Normals"); } -template class CreateSurfaceMesh { +template + requires Dimension +class CreateSurfaceMesh { - typedef viennals::Domain lsDomainType; - typedef typename viennals::Domain::DomainType hrleDomainType; - typedef KDTree> kdTreeType; + using lsDomainType = viennals::Domain; + using CellIteratorType = viennahrle::ConstSparseCellIterator< + typename viennals::Domain::DomainType>; + using kdTreeType = KDTree>; SmartPointer levelSet = nullptr; SmartPointer> mesh = nullptr; @@ -141,9 +146,8 @@ template class CreateSurfaceMesh { }; // iterate over all active surface points - for (viennahrle::ConstSparseCellIterator cellIt( - levelSet->getDomain()); - !cellIt.isFinished(); cellIt.next()) { + for (CellIteratorType cellIt(levelSet->getDomain()); !cellIt.isFinished(); + cellIt.next()) { for (int u = 0; u < D; u++) { while (!nodes[u].empty() && diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index 628115b4..e719c163 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 "psUtil.hpp" #include "psVTKRenderWindow.hpp" #include "psVersion.hpp" @@ -46,7 +47,7 @@ enum class MetaDataLevel { // If specified, each Level-Set is assigned a specific material, // which can be used in a process to implement material specific rates or // similar. -template class Domain { +VIENNAPS_TEMPLATE_ND class Domain { public: using lsDomainType = SmartPointer>; using lsDomainsType = std::vector; diff --git a/include/viennaps/psDomainSetup.hpp b/include/viennaps/psDomainSetup.hpp index 3b3706c7..da7f4727 100644 --- a/include/viennaps/psDomainSetup.hpp +++ b/include/viennaps/psDomainSetup.hpp @@ -1,6 +1,7 @@ #pragma once #include "psUtil.hpp" +#include "psPreCompileMacros.hpp" #include #include @@ -10,7 +11,9 @@ namespace viennaps { using namespace viennacore; using BoundaryType = viennahrle::BoundaryType; -template class DomainSetup { +template + requires Dimension +class DomainSetup { double gridDelta_; double bounds_[2 * D] = {0.}; BoundaryType boundaryCons_[D] = {}; diff --git a/include/viennaps/psElementToPointData.hpp b/include/viennaps/psElementToPointData.hpp index 68564665..11abcb2e 100644 --- a/include/viennaps/psElementToPointData.hpp +++ b/include/viennaps/psElementToPointData.hpp @@ -1,5 +1,7 @@ #pragma once +#include "psPreCompileMacros.hpp" + #include #include #include @@ -13,7 +15,7 @@ namespace viennaps { using namespace viennacore; -template class ElementToPointData { const std::vector dataLabels_; @@ -23,10 +25,14 @@ class ElementToPointData { SmartPointer> surfaceMesh_; const NumericType conversionRadius_; - std::vector> elementDataArrays_; - std::vector, std::vector, unsigned>> - closeElements_; + struct CloseElements { + std::vector indices; + std::vector weights; + unsigned numClosePoints; + }; + std::vector> elementDataArrays_; + std::vector closeElements_; static constexpr bool discard2 = d2; static constexpr bool discard4 = d4; @@ -92,9 +98,11 @@ class ElementToPointData { } } - assert(!weights.empty() && !elementIndices.empty()); - closeElements_[i] = - std::make_tuple(elementIndices, weights, numClosePoints); + assert(!weights.empty() && !elementIndices.empty() && + "Weights and element indices should not be empty here."); + closeElements_[i].indices = std::move(elementIndices); + closeElements_[i].weights = std::move(weights); + closeElements_[i].numClosePoints = numClosePoints; } } @@ -112,7 +120,7 @@ class ElementToPointData { #pragma omp parallel for schedule(static) for (unsigned i = 0; i < numPoints; i++) { - const auto &[closeElements, weights, numClosePoints] = closeElements_[i]; + const auto &[indices, weights, numClosePoints] = closeElements_[i]; for (unsigned j = 0; j < numData; ++j) { NumericType value = NumericType(0); @@ -120,17 +128,17 @@ class ElementToPointData { auto pointData = pointData_->getScalarData(j); // Discard outlier values if enabled - const auto weightsCopy = discardOutliers(weights, closeElements, - elementData, numClosePoints); + const auto weightsCopy = + discardOutliers(weights, indices, elementData, numClosePoints); // Compute weighted average const double sum = std::accumulate(weightsCopy.cbegin(), weightsCopy.cend(), 0.0); - if (sum > 1e-6) { - for (size_t k = 0; k < closeElements.size(); ++k) { + if (sum > 1e-6) [[likely]] { + for (size_t k = 0; k < indices.size(); ++k) { if (weightsCopy[k] > 0.0) { - value += weightsCopy[k] * elementData[closeElements[k]]; + value += weightsCopy[k] * elementData[indices[k]]; } } value /= sum; diff --git a/include/viennaps/psExtrude.hpp b/include/viennaps/psExtrude.hpp index 175f51ec..ba7ccc6f 100644 --- a/include/viennaps/psExtrude.hpp +++ b/include/viennaps/psExtrude.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -template class Extrude { +template class Extrude { SmartPointer> inputDomain; SmartPointer> outputDomain; Vec2D extent{NumericType(0)}; diff --git a/include/viennaps/psPlanarize.hpp b/include/viennaps/psPlanarize.hpp index 90e6df10..a587df9d 100644 --- a/include/viennaps/psPlanarize.hpp +++ b/include/viennaps/psPlanarize.hpp @@ -10,7 +10,7 @@ namespace viennaps { using namespace viennacore; -template class Planarize { +VIENNAPS_TEMPLATE_ND class Planarize { SmartPointer> pDomain_; NumericType cutoffPosition_ = 0.; diff --git a/include/viennaps/psPointToElementData.hpp b/include/viennaps/psPointToElementData.hpp index f62cedd1..65bee3d2 100644 --- a/include/viennaps/psPointToElementData.hpp +++ b/include/viennaps/psPointToElementData.hpp @@ -1,5 +1,7 @@ #pragma once +#include "psPreCompileMacros.hpp" + #include #include @@ -13,7 +15,7 @@ namespace viennaps { using namespace viennacore; -template +template class PointToElementDataBase { protected: viennals::PointData &pointData_; @@ -36,11 +38,12 @@ class PointToElementDataBase { const auto numData = pointData_.getScalarDataSize(); const auto &elements = surfaceMesh_->triangles; const auto numElements = elements.size(); + const bool insertToMesh = insertToMesh_; std::vector dataIdx(numData); prepareData(); - if (insertToMesh_) { + if (insertToMesh) { for (unsigned i = 0; i < numData; ++i) { std::vector data(numElements); const auto label = pointData_.getScalarDataLabel(i); @@ -63,11 +66,10 @@ class PointToElementDataBase { closestPoints[i] = closestPoint->first; #endif - const auto pointIdx = closestPoint->first; for (unsigned j = 0; j < numData; ++j) { - const auto value = pointData_.getScalarData(j)->at(pointIdx); + const auto value = pointData_.getScalarData(j)->at(closestPoint->first); setDataAtElement(i, j, value); - if (insertToMesh_) { + if (insertToMesh) { surfaceMesh_->getCellData().getScalarData(dataIdx[j])->at(i) = static_cast(value); } diff --git a/include/viennaps/psPreCompileMacros.hpp b/include/viennaps/psPreCompileMacros.hpp index 634cefd8..312eb412 100644 --- a/include/viennaps/psPreCompileMacros.hpp +++ b/include/viennaps/psPreCompileMacros.hpp @@ -32,3 +32,15 @@ typedef className className##_float; #endif + +#include + +template +concept Numeric = std::is_same_v || std::is_same_v; + +template +concept Dimension = (D == 2 || D == 3); + +#define VIENNAPS_TEMPLATE_ND \ + template \ + requires Dimension \ No newline at end of file diff --git a/include/viennaps/psRateGrid.hpp b/include/viennaps/psRateGrid.hpp index a2107694..8b50402d 100644 --- a/include/viennaps/psRateGrid.hpp +++ b/include/viennaps/psRateGrid.hpp @@ -13,7 +13,7 @@ namespace viennaps { using namespace viennacore; -template class RateGrid { +VIENNAPS_TEMPLATE_ND class RateGrid { public: enum class Interpolation { LINEAR, IDW, CUSTOM }; diff --git a/include/viennaps/psReader.hpp b/include/viennaps/psReader.hpp index d2c24390..717c4413 100644 --- a/include/viennaps/psReader.hpp +++ b/include/viennaps/psReader.hpp @@ -22,7 +22,7 @@ using namespace viennacore; /// /// This class handles reading a Process Simulation Domain (Domain) from a /// binary file previously created with psWriter. -template class Reader { +VIENNAPS_TEMPLATE_ND class Reader { private: SmartPointer> domain = nullptr; std::string fileName; diff --git a/include/viennaps/psSlice.hpp b/include/viennaps/psSlice.hpp index 37c4d4f4..041e35be 100644 --- a/include/viennaps/psSlice.hpp +++ b/include/viennaps/psSlice.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -template class Slice { +template class Slice { SmartPointer> inputDomain; SmartPointer> outputDomain; int sliceDimension = 0; diff --git a/include/viennaps/psSurfacePointValuesToLevelSet.hpp b/include/viennaps/psSurfacePointValuesToLevelSet.hpp index a7747853..dc7fd90a 100644 --- a/include/viennaps/psSurfacePointValuesToLevelSet.hpp +++ b/include/viennaps/psSurfacePointValuesToLevelSet.hpp @@ -1,5 +1,7 @@ #pragma once +#include "psPreCompileMacros.hpp" + #include #include #include @@ -12,7 +14,7 @@ namespace viennaps { using namespace viennacore; -template class SurfacePointValuesToLevelSet { +VIENNAPS_TEMPLATE_ND class SurfacePointValuesToLevelSet { using lsDomainType = SmartPointer>; lsDomainType levelSet; diff --git a/include/viennaps/psToDiskMesh.hpp b/include/viennaps/psToDiskMesh.hpp index 33d7a57f..5abe56f3 100644 --- a/include/viennaps/psToDiskMesh.hpp +++ b/include/viennaps/psToDiskMesh.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -template class ToDiskMesh { +VIENNAPS_TEMPLATE_ND class ToDiskMesh { using translatorType = SmartPointer>; using psDomainType = SmartPointer>; diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index 32abd77a..db9eb1a3 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -49,7 +49,7 @@ namespace viennaps { enum class RenderMode { SURFACE, INTERFACE, VOLUME }; // forward declaration of Domain -template class Domain; +VIENNAPS_TEMPLATE_ND class Domain; /// Lightweight VTK-based viewer for one or more ViennaPS domains. /// diff --git a/include/viennaps/psWriter.hpp b/include/viennaps/psWriter.hpp index f0831233..0ae1e5da 100644 --- a/include/viennaps/psWriter.hpp +++ b/include/viennaps/psWriter.hpp @@ -19,7 +19,7 @@ using namespace viennacore; /// This class handles serializing a Process Simulation Domain (Domain) to a /// binary file. The file format (.vpsd - ViennaPS Domain) contains all /// levelSets, cell data, material mappings and domain setup information. -template class Writer { +VIENNAPS_TEMPLATE_ND class Writer { private: SmartPointer> domain = nullptr; std::string fileName; From de35c4bba700d50e63e504867fc3c9302cdb1759 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Tue, 20 Jan 2026 21:36:41 +0100 Subject: [PATCH 02/11] refactor: make material map mandatory --- .../process/psFluxProcessStrategy.hpp | 2 +- .../viennaps/process/psTranslationField.hpp | 15 +-- include/viennaps/psDomain.hpp | 98 +++++-------------- include/viennaps/psDomainSetup.hpp | 2 +- include/viennaps/psExtrude.hpp | 13 +-- include/viennaps/psMaterials.hpp | 11 ++- include/viennaps/psReader.hpp | 16 +-- include/viennaps/psSlice.hpp | 9 +- 8 files changed, 59 insertions(+), 107 deletions(-) diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index 6dd2c0e8..b9fb0e29 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -13,7 +13,7 @@ namespace viennaps { VIENNAPS_TEMPLATE_ND class FluxProcessStrategy final : public ProcessStrategy { using TranslatorType = std::unordered_map; - static constexpr char *materialIdsLabel = "MaterialIds"; + static constexpr const char *materialIdsLabel = "MaterialIds"; AdvectionHandler advectionHandler_; CoverageManager coverageManager_; diff --git a/include/viennaps/process/psTranslationField.hpp b/include/viennaps/process/psTranslationField.hpp index 80656864..5eb63579 100644 --- a/include/viennaps/process/psTranslationField.hpp +++ b/include/viennaps/process/psTranslationField.hpp @@ -23,15 +23,18 @@ class TranslationField final : public viennals::VelocityField { SmartPointer<::viennaps::VelocityField> velocityField, SmartPointer const &materialMap, int translationMethod) : modelVelocityField_(velocityField), materialMap_(materialMap), - translationMethod_(translationMethod) {} + translationMethod_(translationMethod) { + if (!materialMap_) { + VIENNACORE_LOG_ERROR("TranslationField: material map is required."); + } + } NumericType getScalarVelocity(const Vec3D &coordinate, int material, const Vec3D &normalVector, unsigned long pointId) override { translateLsId(pointId, coordinate); - if (materialMap_) - material = static_cast(materialMap_->getMaterialAtIdx(material)); + material = materialMap_->getMaterialIdAtIdx(material); return modelVelocityField_->getScalarVelocity(coordinate, material, normalVector, pointId); } @@ -41,8 +44,7 @@ class TranslationField final : public viennals::VelocityField { const Vec3D &normalVector, unsigned long pointId) override { translateLsId(pointId, coordinate); - if (materialMap_) - material = static_cast(materialMap_->getMaterialAtIdx(material)); + material = materialMap_->getMaterialIdAtIdx(material); return modelVelocityField_->getVectorVelocity(coordinate, material, normalVector, pointId); } @@ -50,8 +52,7 @@ class TranslationField final : public viennals::VelocityField { NumericType getDissipationAlpha(int direction, int material, const Vec3D ¢ralDifferences) override { - if (materialMap_) - material = static_cast(materialMap_->getMaterialAtIdx(material)); + material = materialMap_->getMaterialIdAtIdx(material); return modelVelocityField_->getDissipationAlpha(direction, material, centralDifferences); } diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index e719c163..0886db3a 100644 --- a/include/viennaps/psDomain.hpp +++ b/include/viennaps/psDomain.hpp @@ -149,14 +149,10 @@ VIENNAPS_TEMPLATE_ND class Domain { } // Copy material map. - if (domain->materialMap_) { - materialMap_ = MaterialMapType::New(); - for (std::size_t i = 0; i < domain->materialMap_->size(); i++) { - materialMap_->insertNextMaterial( - domain->materialMap_->getMaterialAtIdx(i)); - } - } else { - materialMap_ = nullptr; + materialMap_ = MaterialMapType::New(); + for (std::size_t i = 0; i < domain->materialMap_->size(); i++) { + materialMap_->insertNextMaterial( + domain->materialMap_->getMaterialAtIdx(i)); } // Copy Cell-Set. @@ -169,28 +165,6 @@ VIENNAPS_TEMPLATE_ND class Domain { } } - // Will be deprecated in the future. Please use insertNextLevelSetAsMaterial - // instead. - void insertNextLevelSet(lsDomainType levelSet, - bool wrapLowerLevelSet = true) { - if (levelSets_.empty() && setup_.gridDelta() == 0.0) { - setup_.init(levelSet->getGrid()); - initMetaData(); - } - if (!levelSets_.empty() && wrapLowerLevelSet) { - viennals::BooleanOperation( - levelSet, levelSets_.back(), viennals::BooleanOperationEnum::UNION) - .apply(); - } - levelSets_.push_back(levelSet); - if (materialMap_) { - VIENNACORE_LOG_WARNING( - "Inserting non-material specific Level-Set in domain with material " - "mapping."); - materialMapCheck(); - } - } - void insertNextLevelSetAsMaterial(lsDomainType levelSet, const Material material, bool wrapLowerLevelSet = true) { @@ -235,9 +209,8 @@ VIENNAPS_TEMPLATE_ND class Domain { } levelSets_.pop_back(); - if (materialMap_) { - materialMap_->removeMaterial(); - } + materialMap_->removeMaterial(); + materialMapCheck(); } // Apply a boolean operation with the passed Level-Set to all @@ -268,16 +241,14 @@ VIENNAPS_TEMPLATE_ND class Domain { return; } - if (materialMap_) { - auto newMatMap = MaterialMapType::New(); - for (std::size_t i = 0; i < levelSets_.size(); i++) { - if (i == idx) - continue; + auto newMatMap = MaterialMapType::New(); + for (std::size_t i = 0; i < levelSets_.size(); i++) { + if (i == idx) + continue; - newMatMap->insertNextMaterial(materialMap_->getMaterialAtIdx(i)); - } - materialMap_ = newMatMap; + newMatMap->insertNextMaterial(materialMap_->getMaterialAtIdx(i)); } + materialMap_ = newMatMap; if (removeWrapped) { auto remove = levelSets_.at(idx); @@ -302,10 +273,7 @@ VIENNAPS_TEMPLATE_ND class Domain { } void removeMaterial(const Material material) { - if (!materialMap_) { - return; - } - + assert(materialMap_ != nullptr); for (int i = 0; i < materialMap_->size(); i++) { if (materialMap_->getMaterialAtIdx(i) == material) { removeLevelSet(i); @@ -375,9 +343,7 @@ VIENNAPS_TEMPLATE_ND class Domain { // Set the material of a specific Level-Set in the domain. void setMaterial(unsigned int lsId, const Material material) { - if (materialMap_) { - materialMap_ = MaterialMapType::New(); - } + assert(materialMap_ != nullptr); materialMap_->setMaterialAtIdx(lsId, material); materialMapCheck(); } @@ -449,10 +415,8 @@ VIENNAPS_TEMPLATE_ND class Domain { auto getMaterialsInDomain() const { std::set materials; - if (materialMap_) { - for (std::size_t i = 0; i < materialMap_->size(); i++) { - materials.insert(materialMap_->getMaterialAtIdx(i)); - } + for (std::size_t i = 0; i < materialMap_->size(); i++) { + materials.insert(materialMap_->getMaterialAtIdx(i)); } return materials; } @@ -462,14 +426,10 @@ VIENNAPS_TEMPLATE_ND class Domain { "*****************************************\n"; out << "Process Simulation Domain:\n" << separator; out << "Number of Level-Sets: " << levelSets_.size() << "\n"; - if (materialMap_) { - out << "Materials:\n"; - for (std::size_t i = 0; i < materialMap_->size(); i++) { - out << "\t" << i << ": " - << MaterialMap::toString(materialMap_->getMaterialAtIdx(i)) << "\n"; - } - } else { - out << "No Material Map available.\n"; + out << "Materials:\n"; + for (std::size_t i = 0; i < materialMap_->size(); i++) { + out << "\t" << i << ": " + << MaterialMap::toString(materialMap_->getMaterialAtIdx(i)) << "\n"; } auto bb = getBoundingBox(); out << "Bounding Box: [" << bb[0][0] << ", " << bb[0][1] << ", " << bb[0][2] @@ -534,15 +494,13 @@ VIENNAPS_TEMPLATE_ND class Domain { } meshConverter.insertNextLevelSet(lsCopy); } - if (materialMap_) - meshConverter.setMaterialMap(materialMap_->getMaterialMap()); + meshConverter.setMaterialMap(materialMap_->getMaterialMap()); meshConverter.apply(); } else { // Add material IDs to surface point data viennals::ToDiskMesh meshConverter; meshConverter.setMesh(mesh); - if (materialMap_) - meshConverter.setMaterialMap(materialMap_->getMaterialMap()); + meshConverter.setMaterialMap(materialMap_->getMaterialMap()); for (const auto ls : levelSets_) { meshConverter.insertNextLevelSet(ls); } @@ -579,8 +537,7 @@ VIENNAPS_TEMPLATE_ND class Domain { for (auto &ls : levelSets_) { writer.insertNextLevelSet(ls); } - if (materialMap_) - writer.setMaterialMap(materialMap_->getMaterialMap()); + writer.setMaterialMap(materialMap_->getMaterialMap()); writer.setMetaData(metaData_); writer.apply(); } @@ -596,8 +553,7 @@ VIENNAPS_TEMPLATE_ND class Domain { for (auto &ls : levelSets_) { writer.insertNextLevelSet(ls); } - if (materialMap_) - writer.setMaterialMap(materialMap_->getMaterialMap()); + writer.setMaterialMap(materialMap_->getMaterialMap()); writer.setMetaData(metaData_); writer.apply(); } @@ -627,8 +583,7 @@ VIENNAPS_TEMPLATE_ND class Domain { levelSets_.clear(); if (cellSet_) cellSet_ = csDomainType::New(); - if (materialMap_) - materialMap_ = MaterialMapType::New(); + materialMap_ = MaterialMapType::New(); clearMetaData(true); } @@ -640,9 +595,6 @@ VIENNAPS_TEMPLATE_ND class Domain { private: void materialMapCheck() const { - if (!materialMap_) - return; - if (materialMap_->size() != levelSets_.size()) { VIENNACORE_LOG_WARNING( "Size mismatch in material map and number of Level-Sets in domain."); diff --git a/include/viennaps/psDomainSetup.hpp b/include/viennaps/psDomainSetup.hpp index da7f4727..7306f739 100644 --- a/include/viennaps/psDomainSetup.hpp +++ b/include/viennaps/psDomainSetup.hpp @@ -1,7 +1,7 @@ #pragma once -#include "psUtil.hpp" #include "psPreCompileMacros.hpp" +#include "psUtil.hpp" #include #include diff --git a/include/viennaps/psExtrude.hpp b/include/viennaps/psExtrude.hpp index ba7ccc6f..3d8e42df 100644 --- a/include/viennaps/psExtrude.hpp +++ b/include/viennaps/psExtrude.hpp @@ -57,16 +57,17 @@ template class Extrude { } void apply() { - if (inputDomain == nullptr) { + if (!inputDomain) { VIENNACORE_LOG_ERROR("No input domain supplied to Extrude."); return; } - if (outputDomain == nullptr) { + if (!outputDomain) { VIENNACORE_LOG_ERROR("No output domain supplied to Extrude."); return; } auto materialMap = inputDomain->getMaterialMap(); + assert(materialMap != nullptr); outputDomain->clear(); for (std::size_t i = 0; i < inputDomain->getLevelSets().size(); i++) { @@ -83,12 +84,8 @@ template class Extrude { .apply(); } - if (materialMap) { - auto material = materialMap->getMaterialAtIdx(i); - outputDomain->insertNextLevelSetAsMaterial(tmpLS, material, false); - } else { - outputDomain->insertNextLevelSet(tmpLS, false); - } + auto material = materialMap->getMaterialAtIdx(i); + outputDomain->insertNextLevelSetAsMaterial(tmpLS, material, false); } } }; diff --git a/include/viennaps/psMaterials.hpp b/include/viennaps/psMaterials.hpp index e69ca772..66d0eff8 100644 --- a/include/viennaps/psMaterials.hpp +++ b/include/viennaps/psMaterials.hpp @@ -192,11 +192,14 @@ class MaterialMap { // 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 { + [[nodiscard]] int getMaterialIdAtIdx(std::size_t idx) const { if (idx >= size()) - return Material::GAS; - int matId = map_->getMaterialId(idx); - return mapToMaterial(matId); + return static_cast(Material::GAS); + return map_->getMaterialId(idx); + } + + [[nodiscard]] Material getMaterialAtIdx(std::size_t idx) const { + return mapToMaterial(getMaterialIdAtIdx(idx)); } void setMaterialAtIdx(std::size_t idx, const Material material) { diff --git a/include/viennaps/psReader.hpp b/include/viennaps/psReader.hpp index 717c4413..6e0e7341 100644 --- a/include/viennaps/psReader.hpp +++ b/include/viennaps/psReader.hpp @@ -96,11 +96,13 @@ VIENNAPS_TEMPLATE_ND class Reader { fin.read(reinterpret_cast(&numLevelSets), sizeof(uint32_t)); // Read each level set + std::vector>> levelSets; for (uint32_t i = 0; i < numLevelSets; i++) { auto ls = viennals::Domain::New(); ls->deserialize(fin); - domain->insertNextLevelSet(ls, false); // Don't wrap lower level sets + levelSets.push_back(ls); } + assert(levelSets.size() == numLevelSets); // Read material map if it exists char hasMaterialMap; @@ -110,18 +112,18 @@ VIENNAPS_TEMPLATE_ND class Reader { // Read number of materials uint32_t numMaterials; fin.read(reinterpret_cast(&numMaterials), sizeof(uint32_t)); + assert(numMaterials == numLevelSets); - // Create new material map - auto materialMap = SmartPointer::New(); - - // Read each material ID + // Read each material ID and insert corresponding level set for (uint32_t i = 0; i < numMaterials; i++) { int materialId; fin.read(reinterpret_cast(&materialId), sizeof(int)); - materialMap->insertNextMaterial(static_cast(materialId)); + domain->insertNextLevelSetAsMaterial( + levelSets[i], static_cast(materialId), false); } - domain->setMaterialMap(materialMap); + } else { + VIENNACORE_LOG_ERROR("No material map found in the file."); } // Check if cell set exists diff --git a/include/viennaps/psSlice.hpp b/include/viennaps/psSlice.hpp index 041e35be..ec84c0a8 100644 --- a/include/viennaps/psSlice.hpp +++ b/include/viennaps/psSlice.hpp @@ -57,6 +57,7 @@ template class Slice { } auto materialMap = inputDomain->getMaterialMap(); + assert(materialMap != nullptr); outputDomain->clear(); for (std::size_t i = 0; i < inputDomain->getLevelSets().size(); i++) { @@ -75,12 +76,8 @@ template class Slice { .apply(); } - if (materialMap) { - auto material = materialMap->getMaterialAtIdx(i); - outputDomain->insertNextLevelSetAsMaterial(tmpLS, material, false); - } else { - outputDomain->insertNextLevelSet(tmpLS, false); - } + auto material = materialMap->getMaterialAtIdx(i); + outputDomain->insertNextLevelSetAsMaterial(tmpLS, material, false); } } }; From 53496465014e91bd901c72b2b7630bb6649f8cf1 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Tue, 20 Jan 2026 22:15:24 +0100 Subject: [PATCH 03/11] perf: optimize coverage copying --- examples/holeEtching/holeEtching.cpp | 2 +- .../viennaps/process/psAdvectionHandler.hpp | 42 ++++++++++++------- include/viennaps/process/psCPUDiskEngine.hpp | 20 ++++----- .../viennaps/process/psCoverageManager.hpp | 20 +++++---- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/examples/holeEtching/holeEtching.cpp b/examples/holeEtching/holeEtching.cpp index 18b59df7..9e304029 100644 --- a/examples/holeEtching/holeEtching.cpp +++ b/examples/holeEtching/holeEtching.cpp @@ -10,7 +10,7 @@ int main(int argc, char *argv[]) { using NumericType = double; constexpr int D = 2; - Logger::setLogLevel(LogLevel::ERROR); + Logger::setLogLevel(LogLevel::WARNING); omp_set_num_threads(8); // Parse the parameters diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index a45ec712..672db6f1 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -101,8 +101,7 @@ VIENNAPS_TEMPLATE_ND class AdvectionHandler { if (context.advectionParams.velocityOutput) { auto mesh = viennals::Mesh::New(); - viennals::ToMesh(context.domain->getLevelSets().back(), - mesh) + viennals::ToMesh(context.domain->getSurface(), mesh) .apply(); viennals::VTKWriter( mesh, @@ -127,25 +126,31 @@ VIENNAPS_TEMPLATE_ND class AdvectionHandler { SmartPointer> const &translator) { // Move coverages to the top level set - auto topLS = context.domain->getLevelSets().back(); + auto topLS = context.domain->getSurface(); auto coverages = context.model->getSurfaceModel()->getCoverages(); assert(coverages != nullptr); assert(translator != nullptr); - for (size_t i = 0; i < coverages->getScalarDataSize(); i++) { + std::vector> levelSetCoverages( + coverages->getScalarDataSize()); + +#pragma omp parallel for + for (unsigned i = 0; i < levelSetCoverages.size(); i++) { auto covName = coverages->getScalarDataLabel(i); std::vector levelSetData(topLS->getNumberOfPoints(), 0); auto cov = coverages->getScalarData(covName); - for (const auto iter : *translator.get()) { - levelSetData[iter.first] = cov->at(iter.second); - } - if (auto data = topLS->getPointData().getScalarData(covName, true); - data != nullptr) { - *data = std::move(levelSetData); - } else { - topLS->getPointData().insertNextScalarData(std::move(levelSetData), - covName); + + for (const auto &[lsId, surfaceId] : *translator) { + levelSetData[lsId] = cov->at(surfaceId); } + + levelSetCoverages[i] = std::move(levelSetData); + } + + for (unsigned i = 0; i < levelSetCoverages.size(); i++) { + auto covName = coverages->getScalarDataLabel(i); + topLS->getPointData().insertReplaceScalarData( + std::move(levelSetCoverages[i]), covName); } return ProcessResult::SUCCESS; @@ -156,17 +161,22 @@ VIENNAPS_TEMPLATE_ND class AdvectionHandler { SmartPointer> const &translator) { // Update coverages from the advected surface - auto topLS = context.domain->getLevelSets().back(); + auto topLS = context.domain->getSurface(); auto coverages = context.model->getSurfaceModel()->getCoverages(); + assert(coverages != nullptr); + assert(translator != nullptr); + for (size_t i = 0; i < coverages->getScalarDataSize(); i++) { auto covName = coverages->getScalarDataLabel(i); auto levelSetData = topLS->getPointData().getScalarData(covName); auto covData = coverages->getScalarData(covName); covData->resize(translator->size()); - for (const auto it : *translator.get()) { - covData->at(it.second) = levelSetData->at(it.first); + + for (const auto &[lsId, surfaceId] : *translator) { + covData->at(surfaceId) = levelSetData->at(lsId); } } + return ProcessResult::SUCCESS; } auto &getTimer() const { return timer_; } diff --git a/include/viennaps/process/psCPUDiskEngine.hpp b/include/viennaps/process/psCPUDiskEngine.hpp index 78462d27..15c6d7d3 100644 --- a/include/viennaps/process/psCPUDiskEngine.hpp +++ b/include/viennaps/process/psCPUDiskEngine.hpp @@ -19,6 +19,7 @@ class CPUDiskEngine final : public FluxEngine { VIENNACORE_LOG_WARNING("Invalid process model."); return ProcessResult::INVALID_INPUT; } + model_ = model; return ProcessResult::SUCCESS; } @@ -47,20 +48,17 @@ class CPUDiskEngine final : public FluxEngine { if (!context.rayTracingParams.useRandomSeeds) rayTracer_.setRngSeed(context.rayTracingParams.rngSeed); - auto model = std::dynamic_pointer_cast>( - context.model); - - if (auto source = model->getSource()) { + if (auto source = model_->getSource()) { rayTracer_.setSource(source); VIENNACORE_LOG_INFO("Using custom source."); } - if (auto primaryDirection = model->getPrimaryDirection()) { + if (auto primaryDirection = model_->getPrimaryDirection()) { VIENNACORE_LOG_INFO("Using primary direction: " + util::arrayToString(primaryDirection.value())); rayTracer_.setPrimaryDirection(primaryDirection.value()); } - model->initializeParticleDataLogs(); + model_->initializeParticleDataLogs(); return ProcessResult::SUCCESS; } @@ -131,12 +129,9 @@ class CPUDiskEngine final : public FluxEngine { assert(fluxes != nullptr); fluxes->clear(); - auto model = std::dynamic_pointer_cast>( - context.model); - unsigned particleIdx = 0; - for (auto &particle : model->getParticleTypes()) { - int dataLogSize = model->getParticleLogSize(particleIdx); + for (auto &particle : model_->getParticleTypes()) { + int dataLogSize = model_->getParticleLogSize(particleIdx); if (dataLogSize > 0) { rayTracer_.getDataLog().data.resize(1); rayTracer_.getDataLog().data[0].resize(dataLogSize, 0.); @@ -172,7 +167,7 @@ class CPUDiskEngine final : public FluxEngine { localData.getVectorDataLabel(i)); } - model->mergeParticleData(rayTracer_.getDataLog(), particleIdx); + model_->mergeParticleData(rayTracer_.getDataLog(), particleIdx); ++particleIdx; } } @@ -203,6 +198,7 @@ class CPUDiskEngine final : public FluxEngine { private: viennaray::TraceDisk rayTracer_; + SmartPointer> model_; }; } // namespace viennaps \ No newline at end of file diff --git a/include/viennaps/process/psCoverageManager.hpp b/include/viennaps/process/psCoverageManager.hpp index 53f64001..577ca9f0 100644 --- a/include/viennaps/process/psCoverageManager.hpp +++ b/include/viennaps/process/psCoverageManager.hpp @@ -43,16 +43,18 @@ VIENNAPS_TEMPLATE_ND class CoverageManager { assert( deltaMetric.size() == context.model->getSurfaceModel()->getCoverages()->getScalarDataSize()); - logMetric(deltaMetric); - - std::stringstream stream; - stream << std::setprecision(4) << std::fixed; - stream << "Coverage delta metric: "; - for (int i = 0; i < coverages->getScalarDataSize(); i++) { - stream << coverages->getScalarDataLabel(i) << ": " << deltaMetric[i] - << "\t"; + + if (Logger::hasInfo()) { + logMetric(deltaMetric); + std::stringstream stream; + stream << std::setprecision(4) << std::fixed; + stream << "Coverage delta metric: "; + for (int i = 0; i < coverages->getScalarDataSize(); i++) { + stream << coverages->getScalarDataLabel(i) << ": " << deltaMetric[i] + << "\t"; + } + VIENNACORE_LOG_INFO(stream.str()); } - VIENNACORE_LOG_INFO(stream.str()); for (auto val : deltaMetric) { if (val > context.coverageParams.tolerance) From 17c36ceb7a0714f0330deb386adf48286c33c7b6 Mon Sep 17 00:00:00 2001 From: Tobias Reiter Date: Tue, 20 Jan 2026 22:24:21 +0100 Subject: [PATCH 04/11] refactor: template macro --- include/viennaps/process/psALPStrategy.hpp | 2 +- include/viennaps/process/psAdvectionCallback.hpp | 2 +- include/viennaps/process/psAdvectionHandler.hpp | 2 +- include/viennaps/process/psAnalyticProcessStrategy.hpp | 2 +- include/viennaps/process/psAtomicLayerProcess.hpp | 2 +- include/viennaps/process/psCPUDiskEngine.hpp | 2 +- include/viennaps/process/psCPUTriangleEngine.hpp | 2 +- include/viennaps/process/psCallbackOnlyStrategy.hpp | 2 +- include/viennaps/process/psCoverageManager.hpp | 2 +- include/viennaps/process/psFluxEngine.hpp | 2 +- include/viennaps/process/psFluxProcessStrategy.hpp | 2 +- include/viennaps/process/psGPUDiskEngine.hpp | 2 +- include/viennaps/process/psGPULineEngine.hpp | 2 +- include/viennaps/process/psGPUTriangleEngine.hpp | 2 +- include/viennaps/process/psGeometricModel.hpp | 2 +- include/viennaps/process/psGeometricProcessStrategy.hpp | 2 +- include/viennaps/process/psProcess.hpp | 2 +- include/viennaps/process/psProcessContext.hpp | 2 +- include/viennaps/process/psProcessModel.hpp | 6 +++--- include/viennaps/process/psProcessStrategy.hpp | 2 +- include/viennaps/process/psTranslationField.hpp | 2 +- include/viennaps/process/psVelocityField.hpp | 4 ++-- include/viennaps/psDomain.hpp | 2 +- include/viennaps/psPlanarize.hpp | 2 +- include/viennaps/psPreCompileMacros.hpp | 4 ++-- include/viennaps/psRateGrid.hpp | 2 +- include/viennaps/psReader.hpp | 2 +- include/viennaps/psSurfacePointValuesToLevelSet.hpp | 2 +- include/viennaps/psToDiskMesh.hpp | 2 +- include/viennaps/psVTKRenderWindow.hpp | 2 +- include/viennaps/psWriter.hpp | 2 +- 31 files changed, 35 insertions(+), 35 deletions(-) diff --git a/include/viennaps/process/psALPStrategy.hpp b/include/viennaps/process/psALPStrategy.hpp index 22966774..f2c891ff 100644 --- a/include/viennaps/process/psALPStrategy.hpp +++ b/include/viennaps/process/psALPStrategy.hpp @@ -8,7 +8,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class ALPStrategy final : public ProcessStrategy { using TranslatorType = std::unordered_map; diff --git a/include/viennaps/process/psAdvectionCallback.hpp b/include/viennaps/process/psAdvectionCallback.hpp index bff07bef..2b7ee69b 100644 --- a/include/viennaps/process/psAdvectionCallback.hpp +++ b/include/viennaps/process/psAdvectionCallback.hpp @@ -6,7 +6,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class AdvectionCallback { +VIENNAPS_TEMPLATE_ND(NumericType, D) class AdvectionCallback { protected: SmartPointer> domain = nullptr; diff --git a/include/viennaps/process/psAdvectionHandler.hpp b/include/viennaps/process/psAdvectionHandler.hpp index 672db6f1..54f24ece 100644 --- a/include/viennaps/process/psAdvectionHandler.hpp +++ b/include/viennaps/process/psAdvectionHandler.hpp @@ -8,7 +8,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND class AdvectionHandler { +VIENNAPS_TEMPLATE_ND(NumericType, D) class AdvectionHandler { viennals::Advect advectionKernel_; viennacore::Timer<> timer_; unsigned lsVelOutputCounter = 0; diff --git a/include/viennaps/process/psAnalyticProcessStrategy.hpp b/include/viennaps/process/psAnalyticProcessStrategy.hpp index 3d7fb06e..296e57cc 100644 --- a/include/viennaps/process/psAnalyticProcessStrategy.hpp +++ b/include/viennaps/process/psAnalyticProcessStrategy.hpp @@ -6,7 +6,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class AnalyticProcessStrategy final : public ProcessStrategy { viennals::ToDiskMesh meshConverter_; AdvectionHandler advectionHandler_; diff --git a/include/viennaps/process/psAtomicLayerProcess.hpp b/include/viennaps/process/psAtomicLayerProcess.hpp index 13dd9788..9786bcb7 100644 --- a/include/viennaps/process/psAtomicLayerProcess.hpp +++ b/include/viennaps/process/psAtomicLayerProcess.hpp @@ -21,7 +21,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class DesorptionSource : public viennaray::Source { public: DesorptionSource(const std::vector> &points, diff --git a/include/viennaps/process/psCPUDiskEngine.hpp b/include/viennaps/process/psCPUDiskEngine.hpp index 15c6d7d3..e379dce8 100644 --- a/include/viennaps/process/psCPUDiskEngine.hpp +++ b/include/viennaps/process/psCPUDiskEngine.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class CPUDiskEngine final : public FluxEngine { public: ProcessResult checkInput(ProcessContext &context) override { diff --git a/include/viennaps/process/psCPUTriangleEngine.hpp b/include/viennaps/process/psCPUTriangleEngine.hpp index 75f4daa1..d3916b9a 100644 --- a/include/viennaps/process/psCPUTriangleEngine.hpp +++ b/include/viennaps/process/psCPUTriangleEngine.hpp @@ -13,7 +13,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class CPUTriangleEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psCallbackOnlyStrategy.hpp b/include/viennaps/process/psCallbackOnlyStrategy.hpp index 21619785..74f9947f 100644 --- a/include/viennaps/process/psCallbackOnlyStrategy.hpp +++ b/include/viennaps/process/psCallbackOnlyStrategy.hpp @@ -4,7 +4,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class CallbackOnlyStrategy : public ProcessStrategy { public: DEFINE_CLASS_NAME(CallbackOnlyStrategy) diff --git a/include/viennaps/process/psCoverageManager.hpp b/include/viennaps/process/psCoverageManager.hpp index 577ca9f0..14eab8d9 100644 --- a/include/viennaps/process/psCoverageManager.hpp +++ b/include/viennaps/process/psCoverageManager.hpp @@ -4,7 +4,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND class CoverageManager { +VIENNAPS_TEMPLATE_ND(NumericType, D) class CoverageManager { std::ofstream covMetricFile_; SmartPointer> previousCoverages_; diff --git a/include/viennaps/process/psFluxEngine.hpp b/include/viennaps/process/psFluxEngine.hpp index 99f2adfd..4aa430d1 100644 --- a/include/viennaps/process/psFluxEngine.hpp +++ b/include/viennaps/process/psFluxEngine.hpp @@ -6,7 +6,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND class FluxEngine { +VIENNAPS_TEMPLATE_ND(NumericType, D) class FluxEngine { protected: viennacore::Timer<> timer_; diff --git a/include/viennaps/process/psFluxProcessStrategy.hpp b/include/viennaps/process/psFluxProcessStrategy.hpp index b9fb0e29..ded80f69 100644 --- a/include/viennaps/process/psFluxProcessStrategy.hpp +++ b/include/viennaps/process/psFluxProcessStrategy.hpp @@ -10,7 +10,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class FluxProcessStrategy final : public ProcessStrategy { using TranslatorType = std::unordered_map; static constexpr const char *materialIdsLabel = "MaterialIds"; diff --git a/include/viennaps/process/psGPUDiskEngine.hpp b/include/viennaps/process/psGPUDiskEngine.hpp index a3301b88..c59d9054 100644 --- a/include/viennaps/process/psGPUDiskEngine.hpp +++ b/include/viennaps/process/psGPUDiskEngine.hpp @@ -14,7 +14,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class GPUDiskEngine final : public FluxEngine { public: explicit GPUDiskEngine(std::shared_ptr deviceContext) diff --git a/include/viennaps/process/psGPULineEngine.hpp b/include/viennaps/process/psGPULineEngine.hpp index eb823390..110f7d16 100644 --- a/include/viennaps/process/psGPULineEngine.hpp +++ b/include/viennaps/process/psGPULineEngine.hpp @@ -17,7 +17,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class GPULineEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psGPUTriangleEngine.hpp b/include/viennaps/process/psGPUTriangleEngine.hpp index 1ab3ca4b..d00f76d7 100644 --- a/include/viennaps/process/psGPUTriangleEngine.hpp +++ b/include/viennaps/process/psGPUTriangleEngine.hpp @@ -21,7 +21,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class GPUTriangleEngine final : public FluxEngine { using KDTreeType = SmartPointer>>; diff --git a/include/viennaps/process/psGeometricModel.hpp b/include/viennaps/process/psGeometricModel.hpp index 0ac4d3da..cd29880a 100644 --- a/include/viennaps/process/psGeometricModel.hpp +++ b/include/viennaps/process/psGeometricModel.hpp @@ -8,7 +8,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class GeometricModel { +VIENNAPS_TEMPLATE_ND(NumericType, D) class GeometricModel { SmartPointer> domain = nullptr; SmartPointer> dist = nullptr; diff --git a/include/viennaps/process/psGeometricProcessStrategy.hpp b/include/viennaps/process/psGeometricProcessStrategy.hpp index 36f24277..b823cbaa 100644 --- a/include/viennaps/process/psGeometricProcessStrategy.hpp +++ b/include/viennaps/process/psGeometricProcessStrategy.hpp @@ -4,7 +4,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class GeometricProcessStrategy : public ProcessStrategy { public: DEFINE_CLASS_NAME(GeometricProcessStrategy) diff --git a/include/viennaps/process/psProcess.hpp b/include/viennaps/process/psProcess.hpp index cce519eb..90a68dfc 100644 --- a/include/viennaps/process/psProcess.hpp +++ b/include/viennaps/process/psProcess.hpp @@ -30,7 +30,7 @@ inline consteval bool gpuAvailable() { #endif } -VIENNAPS_TEMPLATE_ND class Process { +VIENNAPS_TEMPLATE_ND(NumericType, D) class Process { private: ProcessContext context_; std::vector>> strategies_; diff --git a/include/viennaps/process/psProcessContext.hpp b/include/viennaps/process/psProcessContext.hpp index 5c580919..13f00112 100644 --- a/include/viennaps/process/psProcessContext.hpp +++ b/include/viennaps/process/psProcessContext.hpp @@ -17,7 +17,7 @@ enum class ProcessResult { NOT_IMPLEMENTED }; -VIENNAPS_TEMPLATE_ND struct ProcessContext { +VIENNAPS_TEMPLATE_ND(NumericType, D) struct ProcessContext { // Core components SmartPointer> domain; SmartPointer> model; diff --git a/include/viennaps/process/psProcessModel.hpp b/include/viennaps/process/psProcessModel.hpp index 6b444d21..3bba369d 100644 --- a/include/viennaps/process/psProcessModel.hpp +++ b/include/viennaps/process/psProcessModel.hpp @@ -24,7 +24,7 @@ using namespace viennacore; /// The process model combines all models (particle types, surface model, /// geometric model, advection callback) -VIENNAPS_TEMPLATE_ND class ProcessModelBase { +VIENNAPS_TEMPLATE_ND(NumericType, D) class ProcessModelBase { protected: SmartPointer> surfaceModel = nullptr; SmartPointer> advectionCallback = nullptr; @@ -82,7 +82,7 @@ VIENNAPS_TEMPLATE_ND class ProcessModelBase { }; /// Process model for CPU-based particle tracing (or no particle tracing) -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class ProcessModelCPU : public ProcessModelBase { protected: std::vector>> @@ -176,7 +176,7 @@ PS_PRECOMPILE_PRECISION_DIMENSION(ProcessModelCPU) #ifdef VIENNACORE_COMPILE_GPU namespace viennaps::gpu { -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class ProcessModelGPU : public ProcessModelBase { private: std::vector> particles; diff --git a/include/viennaps/process/psProcessStrategy.hpp b/include/viennaps/process/psProcessStrategy.hpp index 724b2b8c..1a12db69 100644 --- a/include/viennaps/process/psProcessStrategy.hpp +++ b/include/viennaps/process/psProcessStrategy.hpp @@ -17,7 +17,7 @@ namespace viennaps { -VIENNAPS_TEMPLATE_ND class ProcessStrategy { +VIENNAPS_TEMPLATE_ND(NumericType, D) class ProcessStrategy { public: virtual ~ProcessStrategy() = default; diff --git a/include/viennaps/process/psTranslationField.hpp b/include/viennaps/process/psTranslationField.hpp index 5eb63579..09d2390d 100644 --- a/include/viennaps/process/psTranslationField.hpp +++ b/include/viennaps/process/psTranslationField.hpp @@ -14,7 +14,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class TranslationField final : public viennals::VelocityField { using TranslatorType = std::unordered_map; diff --git a/include/viennaps/process/psVelocityField.hpp b/include/viennaps/process/psVelocityField.hpp index 7348a7db..49803e23 100644 --- a/include/viennaps/process/psVelocityField.hpp +++ b/include/viennaps/process/psVelocityField.hpp @@ -6,7 +6,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class VelocityField { +VIENNAPS_TEMPLATE_ND(NumericType, D) class VelocityField { public: virtual ~VelocityField() = default; @@ -38,7 +38,7 @@ VIENNAPS_TEMPLATE_ND class VelocityField { const NumericType processTime) {} }; -VIENNAPS_TEMPLATE_ND +VIENNAPS_TEMPLATE_ND(NumericType, D) class DefaultVelocityField : public VelocityField { public: DefaultVelocityField() = default; diff --git a/include/viennaps/psDomain.hpp b/include/viennaps/psDomain.hpp index 0886db3a..7fbdf255 100644 --- a/include/viennaps/psDomain.hpp +++ b/include/viennaps/psDomain.hpp @@ -47,7 +47,7 @@ enum class MetaDataLevel { // If specified, each Level-Set is assigned a specific material, // which can be used in a process to implement material specific rates or // similar. -VIENNAPS_TEMPLATE_ND class Domain { +VIENNAPS_TEMPLATE_ND(NumericType, D) class Domain { public: using lsDomainType = SmartPointer>; using lsDomainsType = std::vector; diff --git a/include/viennaps/psPlanarize.hpp b/include/viennaps/psPlanarize.hpp index a587df9d..58af012e 100644 --- a/include/viennaps/psPlanarize.hpp +++ b/include/viennaps/psPlanarize.hpp @@ -10,7 +10,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class Planarize { +VIENNAPS_TEMPLATE_ND(NumericType, D) class Planarize { SmartPointer> pDomain_; NumericType cutoffPosition_ = 0.; diff --git a/include/viennaps/psPreCompileMacros.hpp b/include/viennaps/psPreCompileMacros.hpp index 312eb412..5437f744 100644 --- a/include/viennaps/psPreCompileMacros.hpp +++ b/include/viennaps/psPreCompileMacros.hpp @@ -41,6 +41,6 @@ concept Numeric = std::is_same_v || std::is_same_v; template concept Dimension = (D == 2 || D == 3); -#define VIENNAPS_TEMPLATE_ND \ - template \ +#define VIENNAPS_TEMPLATE_ND(N, D) \ + template \ requires Dimension \ No newline at end of file diff --git a/include/viennaps/psRateGrid.hpp b/include/viennaps/psRateGrid.hpp index 8b50402d..1c0bfb0f 100644 --- a/include/viennaps/psRateGrid.hpp +++ b/include/viennaps/psRateGrid.hpp @@ -13,7 +13,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class RateGrid { +VIENNAPS_TEMPLATE_ND(NumericType, D) class RateGrid { public: enum class Interpolation { LINEAR, IDW, CUSTOM }; diff --git a/include/viennaps/psReader.hpp b/include/viennaps/psReader.hpp index 6e0e7341..6d1210dd 100644 --- a/include/viennaps/psReader.hpp +++ b/include/viennaps/psReader.hpp @@ -22,7 +22,7 @@ using namespace viennacore; /// /// This class handles reading a Process Simulation Domain (Domain) from a /// binary file previously created with psWriter. -VIENNAPS_TEMPLATE_ND class Reader { +VIENNAPS_TEMPLATE_ND(NumericType, D) class Reader { private: SmartPointer> domain = nullptr; std::string fileName; diff --git a/include/viennaps/psSurfacePointValuesToLevelSet.hpp b/include/viennaps/psSurfacePointValuesToLevelSet.hpp index dc7fd90a..5ec1cedd 100644 --- a/include/viennaps/psSurfacePointValuesToLevelSet.hpp +++ b/include/viennaps/psSurfacePointValuesToLevelSet.hpp @@ -14,7 +14,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class SurfacePointValuesToLevelSet { +VIENNAPS_TEMPLATE_ND(NumericType, D) class SurfacePointValuesToLevelSet { using lsDomainType = SmartPointer>; lsDomainType levelSet; diff --git a/include/viennaps/psToDiskMesh.hpp b/include/viennaps/psToDiskMesh.hpp index 5abe56f3..0d7e65d5 100644 --- a/include/viennaps/psToDiskMesh.hpp +++ b/include/viennaps/psToDiskMesh.hpp @@ -9,7 +9,7 @@ namespace viennaps { using namespace viennacore; -VIENNAPS_TEMPLATE_ND class ToDiskMesh { +VIENNAPS_TEMPLATE_ND(NumericType, D) class ToDiskMesh { using translatorType = SmartPointer>; using psDomainType = SmartPointer>; diff --git a/include/viennaps/psVTKRenderWindow.hpp b/include/viennaps/psVTKRenderWindow.hpp index db9eb1a3..323efef7 100644 --- a/include/viennaps/psVTKRenderWindow.hpp +++ b/include/viennaps/psVTKRenderWindow.hpp @@ -49,7 +49,7 @@ namespace viennaps { enum class RenderMode { SURFACE, INTERFACE, VOLUME }; // forward declaration of Domain -VIENNAPS_TEMPLATE_ND class Domain; +VIENNAPS_TEMPLATE_ND(NumericType, D) class Domain; /// Lightweight VTK-based viewer for one or more ViennaPS domains. /// diff --git a/include/viennaps/psWriter.hpp b/include/viennaps/psWriter.hpp index 0ae1e5da..56821466 100644 --- a/include/viennaps/psWriter.hpp +++ b/include/viennaps/psWriter.hpp @@ -19,7 +19,7 @@ using namespace viennacore; /// This class handles serializing a Process Simulation Domain (Domain) to a /// binary file. The file format (.vpsd - ViennaPS Domain) contains all /// levelSets, cell data, material mappings and domain setup information. -VIENNAPS_TEMPLATE_ND class Writer { +VIENNAPS_TEMPLATE_ND(NumericType, D) class Writer { private: SmartPointer> domain = nullptr; std::string fileName; From c2a2648664ac477788b53ff148ed275da2d1663a Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 09:54:09 +0100 Subject: [PATCH 05/11] fix: python build --- include/viennaps/process/psProcess.hpp | 4 ++-- include/viennaps/process/psProcessParams.hpp | 9 +++++---- include/viennaps/psPreCompileMacros.hpp | 2 +- python/pyWrapDimension.hpp | 3 --- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/include/viennaps/process/psProcess.hpp b/include/viennaps/process/psProcess.hpp index 90a68dfc..b5a988f6 100644 --- a/include/viennaps/process/psProcess.hpp +++ b/include/viennaps/process/psProcess.hpp @@ -22,7 +22,7 @@ namespace viennaps { using namespace viennacore; -inline consteval bool gpuAvailable() { +inline constexpr bool gpuAvailable() { #ifdef VIENNACORE_COMPILE_GPU return true; #else @@ -62,7 +62,7 @@ VIENNAPS_TEMPLATE_ND(NumericType, D) class Process { context_.processDuration = duration; } - template + template void setParameters(const ParamType ¶ms) { if constexpr (std::is_same_v) { context_.rayTracingParams = params; diff --git a/include/viennaps/process/psProcessParams.hpp b/include/viennaps/process/psProcessParams.hpp index c08580e5..8b4323f9 100644 --- a/include/viennaps/process/psProcessParams.hpp +++ b/include/viennaps/process/psProcessParams.hpp @@ -129,10 +129,11 @@ struct AtomicLayerProcessParameters { }; template -concept ProcessParam = std::is_same_v || - std::is_same_v || - std::is_same_v || - std::is_same_v; +concept ProcessParamConcept = + std::is_same_v || + std::is_same_v || + std::is_same_v || + std::is_same_v; template class ProcessParams { private: diff --git a/include/viennaps/psPreCompileMacros.hpp b/include/viennaps/psPreCompileMacros.hpp index 5437f744..9744f45b 100644 --- a/include/viennaps/psPreCompileMacros.hpp +++ b/include/viennaps/psPreCompileMacros.hpp @@ -43,4 +43,4 @@ concept Dimension = (D == 2 || D == 3); #define VIENNAPS_TEMPLATE_ND(N, D) \ template \ - requires Dimension \ No newline at end of file + requires Dimension diff --git a/python/pyWrapDimension.hpp b/python/pyWrapDimension.hpp index 187a7fe8..a0e62574 100644 --- a/python/pyWrapDimension.hpp +++ b/python/pyWrapDimension.hpp @@ -489,9 +489,6 @@ template void bindApi(py::module &module) { "Setup the domain.") .def("getSetup", &Domain::getSetup, "Get the domain setup.") .def("deepCopy", &Domain::deepCopy) - .def("insertNextLevelSet", &Domain::insertNextLevelSet, - py::arg("levelset"), py::arg("wrapLowerLevelSet") = true, - "Insert a level set to domain.") .def("insertNextLevelSetAsMaterial", &Domain::insertNextLevelSetAsMaterial, py::arg("levelSet"), py::arg("material"), py::arg("wrapLowerLevelSet") = true, From 3f9463a9aa64a460128810a62d88b953c286170a Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 11:24:02 +0100 Subject: [PATCH 06/11] refactor: material map --- .../viennaps/process/psTranslationField.hpp | 3 ++ include/viennaps/psMaterials.hpp | 44 ++++++++++++------- tests/cpuDiskEngine/cpuDiskEngine.cpp | 24 +++++++--- tests/domain/domain.cpp | 4 -- tests/materialMap/materialMap.cpp | 23 ++++++---- 5 files changed, 65 insertions(+), 33 deletions(-) diff --git a/include/viennaps/process/psTranslationField.hpp b/include/viennaps/process/psTranslationField.hpp index 09d2390d..bb782003 100644 --- a/include/viennaps/process/psTranslationField.hpp +++ b/include/viennaps/process/psTranslationField.hpp @@ -35,6 +35,7 @@ class TranslationField final : public viennals::VelocityField { unsigned long pointId) override { translateLsId(pointId, coordinate); material = materialMap_->getMaterialIdAtIdx(material); + assert(material >= 0); return modelVelocityField_->getScalarVelocity(coordinate, material, normalVector, pointId); } @@ -45,6 +46,7 @@ class TranslationField final : public viennals::VelocityField { unsigned long pointId) override { translateLsId(pointId, coordinate); material = materialMap_->getMaterialIdAtIdx(material); + assert(material >= 0); return modelVelocityField_->getVectorVelocity(coordinate, material, normalVector, pointId); } @@ -53,6 +55,7 @@ class TranslationField final : public viennals::VelocityField { getDissipationAlpha(int direction, int material, const Vec3D ¢ralDifferences) override { material = materialMap_->getMaterialIdAtIdx(material); + assert(material >= 0); return modelVelocityField_->getDissipationAlpha(direction, material, centralDifferences); } diff --git a/include/viennaps/psMaterials.hpp b/include/viennaps/psMaterials.hpp index 66d0eff8..f20fd4e0 100644 --- a/include/viennaps/psMaterials.hpp +++ b/include/viennaps/psMaterials.hpp @@ -180,26 +180,27 @@ class MaterialMap { public: MaterialMap() { map_ = SmartPointer::New(); }; - void insertNextMaterial(Material material = Material::Undefined) { + void insertNextMaterial(Material material) { map_->insertNextMaterial(static_cast(material)); } - void removeMaterial() { - if (map_) { - map_->removeLastMaterial(); - } - } + void removeMaterial() { map_->removeLastMaterial(); } - // Returns the material at the given index. If the index is out of bounds, it - // returns Material::GAS. + // Returns the material **ID** at the given index. If the index is out of + // bounds, it returns -1 [[nodiscard]] int getMaterialIdAtIdx(std::size_t idx) const { - if (idx >= size()) - return static_cast(Material::GAS); return map_->getMaterialId(idx); } + // Returns the material **enum** at the given index. If the index is out of + // bounds, it returns Material::Undefined [[nodiscard]] Material getMaterialAtIdx(std::size_t idx) const { - return mapToMaterial(getMaterialIdAtIdx(idx)); + if (int id = getMaterialIdAtIdx(idx); id < 0) { + VIENNACORE_LOG_WARNING("Getting material with out-of-bounds index."); + return Material::Undefined; + } else { + return mapToMaterial(id); + } } void setMaterialAtIdx(std::size_t idx, const Material material) { @@ -218,12 +219,25 @@ class MaterialMap { return map_->getNumberOfLayers(); } + static inline bool isValidMaterial(const Material mat) { + switch (mat) { +#define ENUM_ELEM(id, sym, cat, dens, cond, color) \ + case Material::sym: \ + return true; + MATERIAL_LIST(ENUM_ELEM) +#undef ENUM_ELEM + default: + return false; + } + } + static inline Material mapToMaterial(const int matId) { - if (matId < 0 || matId > static_cast(kMaterialMaxId)) { - VIENNACORE_LOG_ERROR("Invalid material id " + std::to_string(matId)); - return Material::GAS; + auto mat = static_cast(matId); + if (Logger::hasDebug() && !isValidMaterial(mat)) { + VIENNACORE_LOG_DEBUG("mapToMaterial: Invalid material id " + + std::to_string(matId) + " mapped to Undefined."); } - return static_cast(matId); + return mat; } template static inline Material mapToMaterial(const T matId) { diff --git a/tests/cpuDiskEngine/cpuDiskEngine.cpp b/tests/cpuDiskEngine/cpuDiskEngine.cpp index c2aa5138..d941eda7 100644 --- a/tests/cpuDiskEngine/cpuDiskEngine.cpp +++ b/tests/cpuDiskEngine/cpuDiskEngine.cpp @@ -191,8 +191,10 @@ template void test_initialize() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Test with ignore flux boundaries @@ -216,9 +218,11 @@ template void test_updateSurface() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Initialize the engine first - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Create a disk mesh for the context @@ -250,9 +254,11 @@ template void test_calculateFluxes() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Initialize the engine - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Create disk mesh @@ -288,6 +294,8 @@ void test_calculateFluxesWithCoverages() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Enable coverages context.flags.useCoverages = true; @@ -299,7 +307,7 @@ void test_calculateFluxesWithCoverages() { surfModel->initializeCoverages(10); // Initialize with some points // Initialize the engine - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Create disk mesh @@ -327,12 +335,14 @@ template void test_fluxSmoothing() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Enable flux smoothing context.rayTracingParams.smoothingNeighbors = 2; // Initialize the engine - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Create disk mesh @@ -361,6 +371,8 @@ template void test_multipleParticleTypes() { CPUDiskEngine engine; auto context = createBasicContext(); + auto result = engine.checkInput(context); + VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Add second particle type to model auto mockModel = @@ -369,7 +381,7 @@ template void test_multipleParticleTypes() { mockModel->insertNextParticleType(particle2); // Initialize the engine - auto result = engine.initialize(context); + result = engine.initialize(context); VC_TEST_ASSERT(result == ProcessResult::SUCCESS); // Create disk mesh diff --git a/tests/domain/domain.cpp b/tests/domain/domain.cpp index 7ebf39a9..fa6266ed 100644 --- a/tests/domain/domain.cpp +++ b/tests/domain/domain.cpp @@ -68,10 +68,6 @@ template void RunTest() { VC_TEST_ASSERT(domain->getLevelSets().size() == 0); // insert level sets - domain->insertNextLevelSet(plane1); - VC_TEST_ASSERT(domain->getLevelSets().size() == 1); - - domain->clear(); domain->insertNextLevelSetAsMaterial(plane1, ps::Material::Si); VC_TEST_ASSERT(domain->getLevelSets().size() == 1); VC_TEST_ASSERT(domain->getMaterialMap()); diff --git a/tests/materialMap/materialMap.cpp b/tests/materialMap/materialMap.cpp index 9524c515..18ed8458 100644 --- a/tests/materialMap/materialMap.cpp +++ b/tests/materialMap/materialMap.cpp @@ -1,27 +1,34 @@ #include "psMaterials.hpp" -#include + +#include using namespace viennaps; int main() { // Constructor test MaterialMap materialMap; - assert(materialMap.size() == 0); + VC_TEST_ASSERT(materialMap.size() == 0); // InsertNextMaterial test materialMap.insertNextMaterial(Material::Si); - assert(materialMap.size() == 1); - assert(materialMap.getMaterialAtIdx(0) == Material::Si); + VC_TEST_ASSERT(materialMap.size() == 1); + VC_TEST_ASSERT(materialMap.getMaterialAtIdx(0) == Material::Si); // GetMaterialAtIdx test materialMap.insertNextMaterial(Material::SiO2); - assert(materialMap.getMaterialAtIdx(0) == Material::Si); - assert(materialMap.getMaterialAtIdx(1) == Material::SiO2); - assert(materialMap.getMaterialAtIdx(2) == Material::GAS); + VC_TEST_ASSERT(materialMap.getMaterialAtIdx(0) == Material::Si); + VC_TEST_ASSERT(materialMap.getMaterialAtIdx(1) == Material::SiO2); + VC_TEST_ASSERT(materialMap.getMaterialAtIdx(2) == Material::Undefined); + + materialMap.removeMaterial(); + VC_TEST_ASSERT(materialMap.size() == 1); // SetMaterialAtIdx test materialMap.setMaterialAtIdx(0, Material::SiO2); - assert(materialMap.getMaterialAtIdx(0) == Material::SiO2); + VC_TEST_ASSERT(materialMap.getMaterialAtIdx(0) == Material::SiO2); + + VC_TEST_ASSERT(MaterialMap::isValidMaterial(Material::Si)); + VC_TEST_ASSERT(!MaterialMap::isValidMaterial(static_cast(999))); return 0; } \ No newline at end of file From dbbb5d5e2d6328750356bc829bdf44e54b8453d6 Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 11:52:23 +0100 Subject: [PATCH 07/11] chore: update stubs --- python/pyWrap.cpp | 3 ++- python/viennaps/_core/__init__.pyi | 15 ++++++--------- python/viennaps/d2/__init__.pyi | 4 ---- python/viennaps/d3/__init__.pyi | 4 ---- 4 files changed, 8 insertions(+), 18 deletions(-) diff --git a/python/pyWrap.cpp b/python/pyWrap.cpp index 3af71fe6..b0c16a28 100644 --- a/python/pyWrap.cpp +++ b/python/pyWrap.cpp @@ -101,7 +101,8 @@ PYBIND11_MODULE(VIENNAPS_MODULE_NAME, module) { py::class_>(module, "MaterialMap") .def(py::init<>()) .def("insertNextMaterial", &MaterialMap::insertNextMaterial, - py::arg("material") = Material::Undefined) + py::arg("material")) + .def("getMaterialIdAtIdx", &MaterialMap::getMaterialIdAtIdx) .def("getMaterialAtIdx", &MaterialMap::getMaterialAtIdx) .def("getMaterialMap", &MaterialMap::getMaterialMap) .def("size", &MaterialMap::size) diff --git a/python/viennaps/_core/__init__.pyi b/python/viennaps/_core/__init__.pyi index c9039544..c5672ee6 100644 --- a/python/viennaps/_core/__init__.pyi +++ b/python/viennaps/_core/__init__.pyi @@ -6,10 +6,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 @@ -347,6 +347,7 @@ class CF4O2ParametersSiGe: def x(self, arg0: typing.SupportsFloat) -> None: ... class CoverageParameters: + initialized: bool def __init__(self) -> None: ... def toMetaData(self) -> dict[str, list[float]]: @@ -364,12 +365,6 @@ 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 @@ -960,9 +955,11 @@ class MaterialMap: ... def getMaterialAtIdx(self, arg0: typing.SupportsInt) -> Material: ... + def getMaterialIdAtIdx(self, arg0: typing.SupportsInt) -> int: + ... def getMaterialMap(self) -> viennals._core.MaterialMap: ... - def insertNextMaterial(self, material: Material = ...) -> None: + def insertNextMaterial(self, material: Material) -> None: ... def size(self) -> int: ... diff --git a/python/viennaps/d2/__init__.pyi b/python/viennaps/d2/__init__.pyi index d94f560f..2c03c551 100644 --- a/python/viennaps/d2/__init__.pyi +++ b/python/viennaps/d2/__init__.pyi @@ -334,10 +334,6 @@ class Domain: """ Get the surface mesh of the domain """ - def insertNextLevelSet(self, levelset: viennals.d2.Domain, wrapLowerLevelSet: bool = True) -> None: - """ - Insert a level set to domain. - """ def insertNextLevelSetAsMaterial(self, levelSet: viennals.d2.Domain, material: viennaps._core.Material, wrapLowerLevelSet: bool = True) -> None: """ Insert a level set to domain as a material. diff --git a/python/viennaps/d3/__init__.pyi b/python/viennaps/d3/__init__.pyi index f1725af2..4cd85047 100644 --- a/python/viennaps/d3/__init__.pyi +++ b/python/viennaps/d3/__init__.pyi @@ -334,10 +334,6 @@ class Domain: """ Get the surface mesh of the domain """ - def insertNextLevelSet(self, levelset: viennals.d3.Domain, wrapLowerLevelSet: bool = True) -> None: - """ - Insert a level set to domain. - """ def insertNextLevelSetAsMaterial(self, levelSet: viennals.d3.Domain, material: viennaps._core.Material, wrapLowerLevelSet: bool = True) -> None: """ Insert a level set to domain as a material. From 3912ccbb24c6edc582ad1dff23abe0fa1254a8af Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 15:40:08 +0100 Subject: [PATCH 08/11] refactor: coding style in CreateSurfaceMesh --- include/viennaps/process/psCPUDiskEngine.hpp | 13 +- .../viennaps/process/psCPUTriangleEngine.hpp | 1 + include/viennaps/psCreateSurfaceMesh.hpp | 132 ++++++++---------- 3 files changed, 65 insertions(+), 81 deletions(-) diff --git a/include/viennaps/process/psCPUDiskEngine.hpp b/include/viennaps/process/psCPUDiskEngine.hpp index e379dce8..60ce3959 100644 --- a/include/viennaps/process/psCPUDiskEngine.hpp +++ b/include/viennaps/process/psCPUDiskEngine.hpp @@ -68,6 +68,7 @@ class CPUDiskEngine final : public FluxEngine { this->timer_.start(); auto &diskMesh = context.diskMesh; assert(diskMesh != nullptr); + assert(model_ != nullptr); auto points = diskMesh->getNodes(); auto normals = *diskMesh->getCellData().getVectorData("Normals"); @@ -90,6 +91,7 @@ class CPUDiskEngine final : public FluxEngine { ProcessResult calculateFluxes( ProcessContext &context, SmartPointer> &fluxes) override { + assert(model_ != nullptr); this->timer_.start(); viennaray::TracingData rayTracingData; auto surfaceModel = context.model->getSurfaceModel(); @@ -127,6 +129,7 @@ class CPUDiskEngine final : public FluxEngine { void runRayTracer(ProcessContext const &context, SmartPointer> &fluxes) { assert(fluxes != nullptr); + assert(model_ != nullptr); fluxes->clear(); unsigned particleIdx = 0; @@ -154,14 +157,13 @@ class CPUDiskEngine final : public FluxEngine { auto &localData = rayTracer_.getLocalData(); int numFluxes = particle->getLocalDataLabels().size(); for (int i = 0; i < numFluxes; ++i) { - auto flux = std::move(localData.getVectorData(i)); + auto &flux = localData.getVectorData(i); // normalize and smooth rayTracer_.normalizeFlux(flux, context.rayTracingParams.normalizationType); - if (context.rayTracingParams.smoothingNeighbors > 0) - rayTracer_.smoothFlux(flux, - context.rayTracingParams.smoothingNeighbors); + rayTracer_.smoothFlux(flux, + context.rayTracingParams.smoothingNeighbors); fluxes->insertNextScalarData(std::move(flux), localData.getVectorDataLabel(i)); @@ -182,8 +184,7 @@ class CPUDiskEngine final : public FluxEngine { rayData.setVectorData(i, std::move(*pointData->getScalarData(label)), label); } - - return std::move(rayData); + return rayData; } static void moveRayDataToPointData( diff --git a/include/viennaps/process/psCPUTriangleEngine.hpp b/include/viennaps/process/psCPUTriangleEngine.hpp index d3916b9a..e4c8903e 100644 --- a/include/viennaps/process/psCPUTriangleEngine.hpp +++ b/include/viennaps/process/psCPUTriangleEngine.hpp @@ -34,6 +34,7 @@ class CPUTriangleEngine final : public FluxEngine { } ProcessResult initialize(ProcessContext &context) override { + assert(model_ != nullptr); // Map the domain boundary to the ray tracing boundaries viennaray::BoundaryCondition rayBoundaryCondition[D]; if (context.rayTracingParams.ignoreFluxBoundaries) { diff --git a/include/viennaps/psCreateSurfaceMesh.hpp b/include/viennaps/psCreateSurfaceMesh.hpp index e82d44ea..94075c9c 100644 --- a/include/viennaps/psCreateSurfaceMesh.hpp +++ b/include/viennaps/psCreateSurfaceMesh.hpp @@ -17,6 +17,8 @@ using namespace viennacore; inline viennaray::TriangleMesh CreateTriangleMesh(const float gridDelta, const SmartPointer> &mesh) { + assert(mesh->getCellData().getVectorData("Normals") != nullptr && + "Mesh normals not found in cell data under label 'Normals'."); viennaray::TriangleMesh triangleMesh; triangleMesh.gridDelta = gridDelta; @@ -26,7 +28,7 @@ CreateTriangleMesh(const float gridDelta, triangleMesh.maximumExtent = mesh->maximumExtent; triangleMesh.normals = *mesh->getCellData().getVectorData("Normals"); - return std::move(triangleMesh); + return triangleMesh; } inline void CopyTriangleMesh(const float gridDelta, @@ -95,7 +97,6 @@ class CreateSurfaceMesh { } mesh->clear(); - const auto gridDelta = levelSet->getGrid().getGridDelta(); mesh->minimumExtent = Vec3D{std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max()}; @@ -118,11 +119,10 @@ class CreateSurfaceMesh { typedef std::map, unsigned> nodeContainerType; nodeContainerType nodes[D]; - const MeshNT minNodeDistance = gridDelta * minNodeDistanceFactor; + const auto gridDelta = levelSet->getGrid().getGridDelta(); + const MeshNT invMinNodeDistance = 1. / (gridDelta * minNodeDistanceFactor); std::unordered_map nodeIdByBin; - typename nodeContainerType::iterator nodeIt; - std::vector> triangleCenters; std::vector> normals; @@ -136,13 +136,13 @@ class CreateSurfaceMesh { nodeIdByBin.reserve(estimatedTriangles * 4); } - const bool buildKdTreeFlag = kdTree != nullptr; + const bool buildKdTreeFlag = kdTree != nullptr && D == 3; const bool checkNodeFlag = minNodeDistanceFactor > 0; auto quantize = [&](const Vec3D &p) -> I3 { - const MeshNT inv = MeshNT(1) / minNodeDistance; - return {(int)std::llround(p[0] * inv), (int)std::llround(p[1] * inv), - (int)std::llround(p[2] * inv)}; + return {(int)std::llround(p[0] * invMinNodeDistance), + (int)std::llround(p[1] * invMinNodeDistance), + (int)std::llround(p[2] * invMinNodeDistance)}; }; // iterate over all active surface points @@ -194,8 +194,7 @@ class CreateSurfaceMesh { auto p0B = viennahrle::BitMaskToIndex(p0); d += p0B; - nodeIt = nodes[dir].find(d); - if (nodeIt != nodes[dir].end()) { + if (auto nodeIt = nodes[dir].find(d); nodeIt != nodes[dir].end()) { nod_numbers[n] = nodeIt->second; } else { // if node does not exist yet @@ -225,7 +224,7 @@ class CreateSurfaceMesh { cc[z] = std::max(cc[z], cellIt.getIndices(z) + epsilon); cc[z] = std::min(cc[z], (cellIt.getIndices(z) + 1) - epsilon); } - cc[z] = gridDelta * cc[z]; + cc[z] *= gridDelta; } int nodeIdx = -1; @@ -239,82 +238,58 @@ class CreateSurfaceMesh { nod_numbers[n] = nodeIdx; } else { // insert new node - nod_numbers[n] = - mesh->insertNextNode(cc); // insert new surface node + nod_numbers[n] = mesh->insertNextNode(cc); nodes[dir][d] = nod_numbers[n]; if (checkNodeFlag) nodeIdByBin.emplace(quantize(cc), nod_numbers[n]); + // update mesh extents for (int a = 0; a < D; a++) { - if (cc[a] < mesh->minimumExtent[a]) - mesh->minimumExtent[a] = cc[a]; - if (cc[a] > mesh->maximumExtent[a]) - mesh->maximumExtent[a] = cc[a]; + mesh->minimumExtent[a] = + std::min(mesh->minimumExtent[a], cc[a]); + mesh->maximumExtent[a] = + std::max(mesh->maximumExtent[a], cc[a]); } } } } - if constexpr (D == 2) { - if (nod_numbers[0] != nod_numbers[1]) { - auto const &p0 = mesh->nodes[nod_numbers[0]]; - auto const &p1 = mesh->nodes[nod_numbers[1]]; - auto const dd = p1 - p0; - auto normal = Vec3D{-dd[1], dd[0], MeshNT(0)}; - auto n2 = Norm2(normal); - if (n2 > epsilon) { - MeshNT invn = - static_cast(1.) / std::sqrt(static_cast(n2)); - for (int d = 0; d < D; d++) { - normal[d] *= invn; - } - normals.push_back(normal); - mesh->insertNextElement( - nod_numbers); // insert new surface element + if (!triangleMisformed(nod_numbers)) { + auto normal = calculateNormal(mesh->nodes, nod_numbers); + auto n2 = Norm2(normal); + if (n2 > epsilon) { + MeshNT invn = static_cast(1. / std::sqrt(n2)); + for (int d = 0; d < D; d++) { + normal[d] *= invn; } - } - } else { - if (!triangleMisformed(nod_numbers)) { - auto normal = calculateNormal(mesh->nodes[nod_numbers[0]], - mesh->nodes[nod_numbers[1]], - mesh->nodes[nod_numbers[2]]); - auto n2 = Norm2(normal); - if (n2 > epsilon) { - mesh->insertNextElement( - nod_numbers); // insert new surface element - MeshNT invn = - static_cast(1.) / std::sqrt(static_cast(n2)); - for (int d = 0; d < D; d++) { - normal[d] *= invn; - } - normals.push_back(normal); - - if (buildKdTreeFlag) { - triangleCenters.push_back( - {static_cast(mesh->nodes[nod_numbers[0]][0] + - mesh->nodes[nod_numbers[1]][0] + - mesh->nodes[nod_numbers[2]][0]) / - static_cast(3.), - static_cast(mesh->nodes[nod_numbers[0]][1] + - mesh->nodes[nod_numbers[1]][1] + - mesh->nodes[nod_numbers[2]][1]) / - static_cast(3.), - static_cast(mesh->nodes[nod_numbers[0]][2] + - mesh->nodes[nod_numbers[1]][2] + - mesh->nodes[nod_numbers[2]][2]) / - static_cast(3.)}); - } + normals.push_back(normal); + mesh->insertNextElement(nod_numbers); // insert new surface element + + if (buildKdTreeFlag) { + triangleCenters.push_back( + {static_cast((mesh->nodes[nod_numbers[0]][0] + + mesh->nodes[nod_numbers[1]][0] + + mesh->nodes[nod_numbers[2]][0]) / + 3.), + static_cast((mesh->nodes[nod_numbers[0]][1] + + mesh->nodes[nod_numbers[1]][1] + + mesh->nodes[nod_numbers[2]][1]) / + 3.), + static_cast((mesh->nodes[nod_numbers[0]][2] + + mesh->nodes[nod_numbers[1]][2] + + mesh->nodes[nod_numbers[2]][2]) / + 3.)}); } } } - } - } + } // for each triangle + } // for each active cell mesh->cellData.insertNextVectorData(normals, "Normals"); mesh->nodes.shrink_to_fit(); mesh->triangles.shrink_to_fit(); - if (D == 3 && buildKdTreeFlag) { + if (buildKdTreeFlag) { kdTree->setPoints(triangleCenters); kdTree->build(); } @@ -323,19 +298,26 @@ class CreateSurfaceMesh { private: static inline bool triangleMisformed(const std::array &nod_numbers) noexcept { - if constexpr (D == 3) { + if constexpr (D == 2) { + return nod_numbers[0] == nod_numbers[1]; + } else { return nod_numbers[0] == nod_numbers[1] || nod_numbers[0] == nod_numbers[2] || nod_numbers[1] == nod_numbers[2]; - } else { - return nod_numbers[0] == nod_numbers[1]; } } static inline Vec3D - calculateNormal(const Vec3D &nodeA, const Vec3D &nodeB, - const Vec3D &nodeC) noexcept { - return CrossProduct(nodeB - nodeA, nodeC - nodeA); + calculateNormal(const std::vector> &nodes, + const std::array &nod_numbers) noexcept { + if constexpr (D == 2) { + auto const &p0 = nodes[nod_numbers[0]]; + auto const &p1 = nodes[nod_numbers[1]]; + return Vec3D{-(p1[1] - p0[1]), (p1[0] - p0[0]), MeshNT(0)}; + } else { + return CrossProduct(nodes[nod_numbers[1]] - nodes[nod_numbers[0]], + nodes[nod_numbers[2]] - nodes[nod_numbers[0]]); + } } }; From 8a0aaeab53b7d62753e1c2e4b17f3700015a84c8 Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 16:00:58 +0100 Subject: [PATCH 09/11] refactor: small codings style fixes in models --- include/viennaps/models/psIonBeamEtching.hpp | 1 + include/viennaps/models/psSelectiveEpitaxy.hpp | 2 +- include/viennaps/models/psSingleParticleALD.hpp | 1 + include/viennaps/models/psSingleParticleProcess.hpp | 1 + include/viennaps/models/psTEOSDeposition.hpp | 2 +- include/viennaps/models/psTEOSPECVD.hpp | 2 +- include/viennaps/models/psWetEtching.hpp | 2 +- 7 files changed, 7 insertions(+), 4 deletions(-) diff --git a/include/viennaps/models/psIonBeamEtching.hpp b/include/viennaps/models/psIonBeamEtching.hpp index dcb36c5e..039cb1cc 100644 --- a/include/viennaps/models/psIonBeamEtching.hpp +++ b/include/viennaps/models/psIonBeamEtching.hpp @@ -40,6 +40,7 @@ class IBESurfaceModel : public SurfaceModel { auto velocity = SmartPointer>::New(materialIds.size(), 0.); auto flux = rates->getScalarData(fluxLabel); + assert(flux && flux->size() == materialIds.size()); std::vector redeposition(materialIds.size(), 0.); if (params_.redepositionRate > 0.) { redeposition = *rates->getScalarData(redepositionLabel); diff --git a/include/viennaps/models/psSelectiveEpitaxy.hpp b/include/viennaps/models/psSelectiveEpitaxy.hpp index 8e5451d0..42610bdb 100644 --- a/include/viennaps/models/psSelectiveEpitaxy.hpp +++ b/include/viennaps/models/psSelectiveEpitaxy.hpp @@ -30,7 +30,7 @@ class EpitaxyVelocityField : public VelocityField { NumericType getScalarVelocity(const Vec3D &coordinate, int material, const Vec3D &nv, unsigned long pointID) override { - for (auto epitaxyMaterial : materials) { + for (auto const &epitaxyMaterial : materials) { if (MaterialMap::isMaterial(material, epitaxyMaterial.first)) { double vel = std::max(std::abs(nv[0]), std::abs(nv[D - 1])); vel = (vel - low) * factor + R111; diff --git a/include/viennaps/models/psSingleParticleALD.hpp b/include/viennaps/models/psSingleParticleALD.hpp index dabcc048..6b127eea 100644 --- a/include/viennaps/models/psSingleParticleALD.hpp +++ b/include/viennaps/models/psSingleParticleALD.hpp @@ -46,6 +46,7 @@ class SingleParticleALDSurfaceModel : public SurfaceModel { std::vector depoRate(numPoints, 0.); auto Coverage = coverages->getScalarData("Coverage"); + assert(Coverage && Coverage->size() == numPoints); for (size_t i = 0; i < numPoints; ++i) { depoRate[i] = gpc_ * Coverage->at(i); diff --git a/include/viennaps/models/psSingleParticleProcess.hpp b/include/viennaps/models/psSingleParticleProcess.hpp index 5cc85dbe..6d52f4a0 100644 --- a/include/viennaps/models/psSingleParticleProcess.hpp +++ b/include/viennaps/models/psSingleParticleProcess.hpp @@ -29,6 +29,7 @@ class SingleParticleSurfaceModel : public viennaps::SurfaceModel { auto velocity = SmartPointer>::New(materialIds.size(), 0.); auto flux = rates->getScalarData("particleFlux"); + assert(flux && velocity->size() == flux->size()); #pragma omp parallel for for (size_t i = 0; i < velocity->size(); i++) { diff --git a/include/viennaps/models/psTEOSDeposition.hpp b/include/viennaps/models/psTEOSDeposition.hpp index 79be5537..38f83984 100644 --- a/include/viennaps/models/psTEOSDeposition.hpp +++ b/include/viennaps/models/psTEOSDeposition.hpp @@ -33,7 +33,7 @@ class SingleTEOSSurfaceModel : public SurfaceModel { depositionRate * std::pow(particleFlux->at(i), reactionOrder); } - return SmartPointer>::New(velocity); + return SmartPointer>::New(std::move(velocity)); } void updateCoverages(SmartPointer> rates, diff --git a/include/viennaps/models/psTEOSPECVD.hpp b/include/viennaps/models/psTEOSPECVD.hpp index d4c01c64..d6103896 100644 --- a/include/viennaps/models/psTEOSPECVD.hpp +++ b/include/viennaps/models/psTEOSPECVD.hpp @@ -41,7 +41,7 @@ class PECVDSurfaceModel : public SurfaceModel { ionRate_ * std::pow(particleFluxIon->at(i), ionReactionOrder_); } - return SmartPointer>::New(velocity); + return SmartPointer>::New(std::move(velocity)); } }; diff --git a/include/viennaps/models/psWetEtching.hpp b/include/viennaps/models/psWetEtching.hpp index 7482472b..92c484ce 100644 --- a/include/viennaps/models/psWetEtching.hpp +++ b/include/viennaps/models/psWetEtching.hpp @@ -47,7 +47,7 @@ class WetEtchingVelocityField : public VelocityField { NumericType getScalarVelocity(const Vec3D &coordinate, int material, const Vec3D &nv, unsigned long pointID) override { - for (auto etchingMaterial : materials) { + for (auto const &etchingMaterial : materials) { if (MaterialMap::isMaterial(material, etchingMaterial.first)) { if (std::abs(Norm(nv) - 1.) > 1e-4) return 0.; From 38fdb98a2f29747660302a264b6cdcc443c15445 Mon Sep 17 00:00:00 2001 From: reiter Date: Wed, 21 Jan 2026 16:25:23 +0100 Subject: [PATCH 10/11] perf: improve GDS reader point lookup --- include/viennaps/gds/psGDSReader.hpp | 23 +++++++++++-------- include/viennaps/process/psCPUDiskEngine.hpp | 5 ++-- .../viennaps/process/psCPUTriangleEngine.hpp | 2 +- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/include/viennaps/gds/psGDSReader.hpp b/include/viennaps/gds/psGDSReader.hpp index a8d749f4..f48ff07f 100644 --- a/include/viennaps/gds/psGDSReader.hpp +++ b/include/viennaps/gds/psGDSReader.hpp @@ -1,8 +1,10 @@ #pragma once +#include #include #include #include +#include #include "psGDSGeometry.hpp" #include "psGDSUtils.hpp" @@ -63,14 +65,17 @@ template class GDSReader { float currentWidth = 0; char *tempStr = nullptr; - static bool contains(int32_t X, int32_t Y, - const std::vector> &uniPoints) { - for (const auto &p : uniPoints) { - if (p[0] == X && p[1] == Y) - return true; - } + static constexpr std::uint64_t packPointKey(int32_t x, int32_t y) noexcept { + return (static_cast(static_cast(x)) << 32) | + static_cast(y); + } - return false; + // Returns true if the point already existed; inserts otherwise. + static bool contains(int32_t x, int32_t y, + std::unordered_set &uniquePointKeys) { + const auto key = packPointKey(x, y); + const auto [_, inserted] = uniquePointKeys.insert(key); + return !inserted; } void resetCurrentStructure() { @@ -204,7 +209,8 @@ template class GDSReader { void parseXYBoundary() { const unsigned int numPoints = currentRecordLen / 8; auto ¤tElPointCloud = currentStructure.elements.back().pointCloud; - std::vector> uniquePoints; + std::unordered_set uniquePoints; + uniquePoints.reserve(numPoints); // do not include the last point since it // is just a copy of the first @@ -213,7 +219,6 @@ template class GDSReader { const auto pY = readFourByteSignedInt(); if (!contains(pX, pY, uniquePoints)) { - uniquePoints.push_back({pX, pY}); float X = units * static_cast(pX); float Y = units * static_cast(pY); diff --git a/include/viennaps/process/psCPUDiskEngine.hpp b/include/viennaps/process/psCPUDiskEngine.hpp index 60ce3959..2bb51f08 100644 --- a/include/viennaps/process/psCPUDiskEngine.hpp +++ b/include/viennaps/process/psCPUDiskEngine.hpp @@ -162,8 +162,9 @@ class CPUDiskEngine final : public FluxEngine { // normalize and smooth rayTracer_.normalizeFlux(flux, context.rayTracingParams.normalizationType); - rayTracer_.smoothFlux(flux, - context.rayTracingParams.smoothingNeighbors); + if (context.rayTracingParams.smoothingNeighbors > 0) + rayTracer_.smoothFlux(flux, + context.rayTracingParams.smoothingNeighbors); fluxes->insertNextScalarData(std::move(flux), localData.getVectorDataLabel(i)); diff --git a/include/viennaps/process/psCPUTriangleEngine.hpp b/include/viennaps/process/psCPUTriangleEngine.hpp index e4c8903e..a22db214 100644 --- a/include/viennaps/process/psCPUTriangleEngine.hpp +++ b/include/viennaps/process/psCPUTriangleEngine.hpp @@ -246,7 +246,7 @@ class CPUTriangleEngine final : public FluxEngine { auto &localData = rayTracer_.getLocalData(); int numFluxes = particle->getLocalDataLabels().size(); for (int i = 0; i < numFluxes; ++i) { - auto flux = std::move(localData.getVectorData(i)); + auto &flux = localData.getVectorData(i); // normalize rayTracer_.normalizeFlux(flux, From db608a3cf02673eb297a2770d2f1cd96db912a7e Mon Sep 17 00:00:00 2001 From: reiter Date: Thu, 22 Jan 2026 13:58:49 +0100 Subject: [PATCH 11/11] chore: format --- include/viennaps/psCreateSurfaceMesh.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/viennaps/psCreateSurfaceMesh.hpp b/include/viennaps/psCreateSurfaceMesh.hpp index 94075c9c..f4acfd2f 100644 --- a/include/viennaps/psCreateSurfaceMesh.hpp +++ b/include/viennaps/psCreateSurfaceMesh.hpp @@ -282,8 +282,8 @@ class CreateSurfaceMesh { } } } - } // for each triangle - } // for each active cell + } + } mesh->cellData.insertNextVectorData(normals, "Normals"); mesh->nodes.shrink_to_fit();