From b1d61c67c28a9ba4a1de834e401d97cfc9e84764 Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Sun, 21 Dec 2025 20:53:50 +0100 Subject: Reworking some structures. adding particle tests again --- default.nix | 2 +- examples/poiseulle_2d_gpu/poiseulle_2d_gpu.cpp | 36 ++++- .../poiseulle_2d_gpu.cpp | 2 +- lib/core/c++/particle/particle.hpp | 14 +- lib/core/tests/particles.cpp | 171 +++++++++++++++++++++ lib/core/tests/particles.dummy | 114 -------------- util/build.sh | 49 ------ util/podman/build.sh | 50 ++++++ util/vtk_renderer/.nix/derivation.nix | 25 +++ util/vtk_renderer/Makefile | 12 ++ util/vtk_renderer/kel_vtk_renderer.cpp | 80 ++++++++++ 11 files changed, 382 insertions(+), 173 deletions(-) create mode 100644 lib/core/tests/particles.cpp delete mode 100644 lib/core/tests/particles.dummy delete mode 100755 util/build.sh create mode 100755 util/podman/build.sh create mode 100644 util/vtk_renderer/.nix/derivation.nix create mode 100644 util/vtk_renderer/Makefile create mode 100644 util/vtk_renderer/kel_vtk_renderer.cpp diff --git a/default.nix b/default.nix index bc8130b..8724de1 100644 --- a/default.nix +++ b/default.nix @@ -13,7 +13,7 @@ let forstio = (import ((builtins.fetchTarball { url = "https://git.keldu.de/forstio-forstio/snapshot/master.tar.gz"; - sha256 = "sha256:0p9k04q4jhxzypawjg2rjpff1f3plrr1azigjlb4l2l9r128jmkm"; + sha256 = "sha256:19050mb1j4qq9j9y24y0ffhlj997bzn4my2wiprsgml58azf600m"; }) + "/default.nix"){ inherit stdenv; inherit clang-tools; diff --git a/examples/poiseulle_2d_gpu/poiseulle_2d_gpu.cpp b/examples/poiseulle_2d_gpu/poiseulle_2d_gpu.cpp index 89ad709..1d525ad 100644 --- a/examples/poiseulle_2d_gpu/poiseulle_2d_gpu.cpp +++ b/examples/poiseulle_2d_gpu/poiseulle_2d_gpu.cpp @@ -199,7 +199,7 @@ void step( using namespace kel::lbm; using dfi = df_info; - constexpr saw::data frequency{1.0 / 0.5384}; + constexpr saw::data frequency{1.0 / 0.8}; bool is_even = ((time_step % 2u) == 0u); /** @@ -209,8 +209,8 @@ void step( component coll{0.5384}; component bb; */ - component> inlet{1.1 * dfi::cs2}; - component> outlet{1.0 * dfi::cs2}; + component> inlet{1.01 * dfi::cs2 * 2.0/3.0}; + component> outlet{1.0 * dfi::cs2 * 2.0/3.0}; // auto collision_ev = @@ -257,10 +257,36 @@ void step( } case 3u: { inlet.apply(cells, {{i,j}}, meta, time_step); + auto& dfs_old = is_even ? c.template get<"dfs_old">() : c.template get<"dfs">(); + + auto& macro_c = macro_cells[acc_id]; + + saw::data& rho = macro_c.template get<"pressure">(); + saw::data>& vel = macro_c.template get<"velocity">(); + + compute_rho_u(dfs_old,rho,vel); + auto eq = equilibrium(rho,vel); + + for(uint64_t k = 0u; k < Desc::Q; ++k){ + dfs_old({k}) = dfs_old({k}) + frequency * (eq.at({k}) - dfs_old({k})); + } break; } case 4u: { outlet.apply(cells, {{i,j}}, meta, time_step); + auto& dfs_old = is_even ? c.template get<"dfs_old">() : c.template get<"dfs">(); + + auto& macro_c = macro_cells[acc_id]; + + saw::data& rho = macro_c.template get<"pressure">(); + saw::data>& vel = macro_c.template get<"velocity">(); + + compute_rho_u(dfs_old,rho,vel); + auto eq = equilibrium(rho,vel); + + for(uint64_t k = 0u; k < Desc::Q; ++k){ + dfs_old({k}) = dfs_old({k}) + frequency * (eq.at({k}) - dfs_old({k})); + } break; } default: @@ -323,8 +349,8 @@ saw::error_or kel_main(int argc, char** argv){ {{1.0}} }; - uint64_t x_d = 256u; - uint64_t y_d = 64u; + uint64_t x_d = 512u; + uint64_t y_d = 128u; saw::data> meta{{x_d,y_d}}; diff --git a/examples/poiseulle_particles_2d_gpu/poiseulle_2d_gpu.cpp b/examples/poiseulle_particles_2d_gpu/poiseulle_2d_gpu.cpp index 71854a8..1fcfd9c 100644 --- a/examples/poiseulle_particles_2d_gpu/poiseulle_2d_gpu.cpp +++ b/examples/poiseulle_particles_2d_gpu/poiseulle_2d_gpu.cpp @@ -203,7 +203,7 @@ void step( using namespace kel::lbm; using dfi = df_info; - constexpr saw::data frequency{1.0 / 0.5384}; + constexpr saw::data frequency{1.0 / 0.51}; bool is_even = ((time_step % 2u) == 0u); /** diff --git a/lib/core/c++/particle/particle.hpp b/lib/core/c++/particle/particle.hpp index b647ebe..3089378 100644 --- a/lib/core/c++/particle/particle.hpp +++ b/lib/core/c++/particle/particle.hpp @@ -51,7 +51,7 @@ constexpr auto verlet_step_lambda = [](saw::data>& particle, auto& pos = body.template get<"position">(); auto& pos_old = body.template get<"position_old">(); - // auto& rot = body.template get<"rotation">(); + auto& rot = body.template get<"rotation">(); auto& acc = body.template get<"acceleration">(); auto tsd_squared = time_step_delta * time_step_delta; @@ -70,7 +70,7 @@ constexpr auto verlet_step_lambda = [](saw::data>& particle, * * */ -template +template constexpr auto broadphase_collision_check = [](saw::data>& left, saw::data>& right){ auto rad_l = left.template get<"collision">().template get<"radius">(); auto rad_r = right.template get<"collision">().template get<"radius">(); @@ -80,7 +80,15 @@ constexpr auto broadphase_collision_check = [](saw::data>& le auto& pos_l = rb_l.template get<"position">(); auto& pos_r = rb_r.template get<"position">(); -} + + auto pos_dist = pos_l - pos_r; + + auto norm_2 = saw::math::dot(pos_dist,pos_dist); + + auto rad_ab_2 = rad_l * rad_l + rad_r * rad_r + rad_r * rad_l * static_cast::type>(2); + + return (norm_2.at({}).get() < rad_ab_2.get()); +}; template > class particle_system { diff --git a/lib/core/tests/particles.cpp b/lib/core/tests/particles.cpp new file mode 100644 index 0000000..0806375 --- /dev/null +++ b/lib/core/tests/particles.cpp @@ -0,0 +1,171 @@ +#include + +#include +//#include "../c++/particle/geometry/circle.hpp" +#include "../c++/particle/particle.hpp" +#include + +namespace { +namespace sch { +using namespace kel::lbm::sch; + +using T = Float64; +} +SAW_TEST("Verlet step 2D - Planar"){ + using namespace kel; + + saw::data> particle; + auto& body = particle.template get<"rigid_body">(); + auto& pos = body.template get<"position">(); + auto& pos_old = body.template get<"position_old">(); + + // auto& rot = body.template get<"rotation">(); + auto& acc = body.template get<"acceleration">(); + + acc.at({{0}}).set({1.0}); + + lbm::verlet_step_lambda(particle,{0.5}); + + SAW_EXPECT(pos.at({{0}}).get() == 0.25, std::string{"Incorrect Pos X: "} + std::to_string(pos.at({{0}}).get())); + SAW_EXPECT(pos.at({{1}}).get() == 0.0, std::string{"Incorrect Pos Y: "} + std::to_string(pos.at({{1}}).get())); +} + +SAW_TEST("No Collision Spheroid 2D"){ + using namespace kel; + + saw::data> part_a; + { + auto& body = part_a.template get<"rigid_body">(); + auto& pos = body.template get<"position">(); + auto& coll = part_a.template get<"collision">(); + auto& radius = coll.template get<"radius">(); + + radius.set(1.0); + + pos.at({{0u}}) = 0.1; + pos.at({{1u}}) = 0.2; + + } + saw::data> part_b; + { + auto& body = part_b.template get<"rigid_body">(); + auto& pos = body.template get<"position">(); + auto& coll = part_b.template get<"collision">(); + auto& radius = coll.template get<"radius">(); + + radius.set(1.0); + + pos.at({{0u}}) = -2.1; + pos.at({{1u}}) = 0.0; + } + + bool have_collided = lbm::broadphase_collision_check(part_a,part_b); + SAW_EXPECT(not have_collided, "Particles shouldn't collide"); +} + +SAW_TEST("Collision Spheroid 2D"){ + using namespace kel; + + saw::data> part_a; + { + auto& body = part_a.template get<"rigid_body">(); + auto& pos = body.template get<"position">(); + auto& coll = part_a.template get<"collision">(); + auto& radius = coll.template get<"radius">(); + + radius.set(1.0); + + pos.at({{0u}}) = 0.1; + pos.at({{1u}}) = 0.2; + + } + saw::data> part_b; + { + auto& body = part_b.template get<"rigid_body">(); + auto& pos = body.template get<"position">(); + auto& coll = part_b.template get<"collision">(); + auto& radius = coll.template get<"radius">(); + + radius.set(1.0); + + pos.at({{0u}}) = -1.5; + pos.at({{1u}}) = 0.0; + } + + bool have_collided = lbm::broadphase_collision_check(part_a,part_b); + SAW_EXPECT(have_collided, "Particles should collide"); +} + +/* +SAW_TEST("Minor Test for mask"){ + using namespace kel; + + lbm::particle_circle_geometry geo; + + auto mask = geo.generate_mask(9u,1u); + + auto& grid = mask.template get<"grid">(); + + for(saw::data i{0u}; i < grid.template get_dim_size<0>(); ++i){ + for(saw::data j{0u}; j < grid.template get_dim_size<1>(); ++j){ + std::cout<> reference_mask{{{4+2,4+2}}}; + //reference_mask.at({{0,0}}); +} +*/ +/* +SAW_TEST("Verlet integration test 2D"){ + using namespace kel; + lbm::particle_system> system; + + { + saw::data> particle; + auto& rb = particle.template get<"rigid_body">(); + auto& acc = rb.template get<"acceleration">(); + auto& pos = rb.template get<"position">(); + auto& pos_old = rb.template get<"position_old">(); + pos = {{1e-1,1e-1}}; + pos_old = {{0.0, 0.0}}; + acc = {{0.0,-1e1}}; + + auto eov = system.add_particle(std::move(particle)); + SAW_EXPECT(eov.is_value(), "Expected no error :)"); + } + { + auto& p = system.at({0u}); + auto& rb = p.template get<"rigid_body">(); + auto& pos = rb.template get<"position">(); + + for(saw::data i{0u}; i < saw::data{2u}; ++i){ + std::cout<{1e-1}); + + { + auto& p = system.at({0u}); + auto& rb = p.template get<"rigid_body">(); + auto& pos = rb.template get<"position">(); + + for(saw::data i{0u}; i < saw::data{2u}; ++i){ + std::cout< - -#include -//#include "../c++/particle/geometry/circle.hpp" - - -namespace { -namespace sch { -using namespace kel::lbm::sch; - -using T = Float64; -} -SAW_TEST("Verlet step 2D - Planar"){ -/* - using namespace kel; - - - saw::data> particle; - auto& body = particle.template get<"rigid_body">(); - auto& pos = body.template get<"position">(); - auto& pos_old = body.template get<"position_old">(); - - // auto& rot = body.template get<"rotation">(); - auto& acc = body.template get<"acceleration">(); - - acc.at({{0}}).set({1.0}); - - lbm::verlet_step_lambda(particle,{0.5}); - - SAW_EXPECT(pos.at({{0}}).get() == 0.25, std::string{"Incorrect Pos X: "} + std::to_string(pos.at({{0}}).get())); - SAW_EXPECT(pos.at({{1}}).get() == 0.0, std::string{"Incorrect Pos Y: "} + std::to_string(pos.at({{1}}).get())); -*/ -} - -SAW_TEST("Collision spheroid Test"){ - using namespace kel; - - saw::data part_a; - saw::data part_b; -} - -/* -SAW_TEST("Minor Test for mask"){ - using namespace kel; - - lbm::particle_circle_geometry geo; - - auto mask = geo.generate_mask(9u,1u); - - auto& grid = mask.template get<"grid">(); - - for(saw::data i{0u}; i < grid.template get_dim_size<0>(); ++i){ - for(saw::data j{0u}; j < grid.template get_dim_size<1>(); ++j){ - std::cout<> reference_mask{{{4+2,4+2}}}; - //reference_mask.at({{0,0}}); -} -*/ -/* -SAW_TEST("Verlet integration test 2D"){ - using namespace kel; - lbm::particle_system> system; - - { - saw::data> particle; - auto& rb = particle.template get<"rigid_body">(); - auto& acc = rb.template get<"acceleration">(); - auto& pos = rb.template get<"position">(); - auto& pos_old = rb.template get<"position_old">(); - pos = {{1e-1,1e-1}}; - pos_old = {{0.0, 0.0}}; - acc = {{0.0,-1e1}}; - - auto eov = system.add_particle(std::move(particle)); - SAW_EXPECT(eov.is_value(), "Expected no error :)"); - } - { - auto& p = system.at({0u}); - auto& rb = p.template get<"rigid_body">(); - auto& pos = rb.template get<"position">(); - - for(saw::data i{0u}; i < saw::data{2u}; ++i){ - std::cout<{1e-1}); - - { - auto& p = system.at({0u}); - auto& rb = p.template get<"rigid_body">(); - auto& pos = rb.template get<"position">(); - - for(saw::data i{0u}; i < saw::data{2u}; ++i){ - std::cout</dev/null); then - echo "Error: Not inside a git repository." - exit 1 -fi -cd "$GIT_ROOT" - -# --- Ensure default.nix exists --- -if [[ ! -f default.nix ]]; then - echo "Error: no default.nix in Git root ($GIT_ROOT)" - exit 1 -fi - -# --- Run build + packaging inside container --- -podman run --rm -it \ - -v "$GIT_ROOT":/workspace \ - -w /workspace \ - -e USER=nix \ - -e PKG_NAME="$PKG_NAME" \ - -e PKG_VERSION="$PKG_VERSION" \ - docker.io/nixos/nix:latest \ - nix-shell -p bash --run " - set -euo pipefail - - # Build the derivation - nix-build default.nix -A release.examples --out-link result - - # Install fpm if missing - if ! command -v fpm >/dev/null 2>&1; then - nix-shell -p fpm --run 'true' - fi - - # Create .deb package - nix-shell -p fpm --run \"fpm -s dir -t deb -n \$PKG_NAME -v \$PKG_VERSION -C result --prefix /usr/local .\" - - # Create .rpm package - # nix-shell -p fpm rpm --run \"fpm -s dir -t rpm -n \$PKG_NAME -v \$PKG_VERSION -C result --prefix /usr/local .\" - " - -echo "✅ Build complete!" -echo " - result -> $GIT_ROOT/result" -echo " - ${PKG_NAME}_${PKG_VERSION}.deb and ${PKG_NAME}-${PKG_VERSION}.rpm are in $GIT_ROOT" diff --git a/util/podman/build.sh b/util/podman/build.sh new file mode 100755 index 0000000..1f36f2a --- /dev/null +++ b/util/podman/build.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +# --- Configuration: package name and version --- +PKG_NAME="kel-lbm" +PKG_VERSION="0.0.3" + +# --- Ensure we're in the Git root --- +if ! GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null); then + echo "Error: Not inside a git repository." + exit 1 +fi +cd "$GIT_ROOT" + +# --- Ensure default.nix exists --- +if [[ ! -f default.nix ]]; then + echo "Error: no default.nix in Git root ($GIT_ROOT)" + exit 1 +fi + +# --- Run build + packaging inside container --- +podman run --rm -it \ + -v "$GIT_ROOT":/workspace \ + -w /workspace \ + -e USER=nix \ + -e PKG_NAME="$PKG_NAME" \ + -e PKG_VERSION="$PKG_VERSION" \ + docker.io/nixos/nix:latest \ + nix-shell -p bash --run " + set -euo pipefail + + # Build the derivation + nix-build default.nix -A release.examples --out-link result + + # Install fpm if missing + if ! command -v fpm >/dev/null 2>&1; then + nix-shell -p fpm --run 'true' + fi + + # Create .deb package + nix-shell -p fpm --run \"fpm -s dir -t deb -n \$PKG_NAME -v \$PKG_VERSION -C result --prefix /usr/local .\" + + # Create .rpm package + # Turned off right now (Well, commented) + # nix-shell -p fpm rpm --run \"fpm -s dir -t rpm -n \$PKG_NAME -v \$PKG_VERSION -C result --prefix /usr/local .\" + " + +echo "✅ Build complete!" +echo " - result -> $GIT_ROOT/result" +echo " - ${PKG_NAME}_${PKG_VERSION}.deb and ${PKG_NAME}-${PKG_VERSION}.rpm are in $GIT_ROOT" diff --git a/util/vtk_renderer/.nix/derivation.nix b/util/vtk_renderer/.nix/derivation.nix new file mode 100644 index 0000000..e56ee0c --- /dev/null +++ b/util/vtk_renderer/.nix/derivation.nix @@ -0,0 +1,25 @@ +{ lib +, stdenv +, gnumake +, pkg-config +, vtk +}: + +stdenv.mkDerivation { + pname = "kel-vtk-renderer"; + version = "0.0.1"; + + nativeBuildInputs = [ + gnumake + pkg-config + ]; + + buildInputs = [ + vtk + ]; + + installPhase = '' + mkdir -p $out/bin + cp kel_vtk_renderer $out/bin + ''; +} diff --git a/util/vtk_renderer/Makefile b/util/vtk_renderer/Makefile new file mode 100644 index 0000000..00ec9c4 --- /dev/null +++ b/util/vtk_renderer/Makefile @@ -0,0 +1,12 @@ +.PHONY: all + +CXX = c++ +CXXFLAGS=-std=c++20 -O3 -I/nix/store/31vfnljfr5jjh74h4j4v5a1r6w57g6zp-vtk-9.2.6/include/vtk +LIBS=-I/nix/store/31vfnljfr5jjh74h4j4v5a1r6w57g6zp-vtk-9.2.6/lib -lvtkCommonCore -lvtkRenderingCore -lvtkRenderingOpenGL2 -lvtksys -lvtkFiltersGeometry -lvtkCommonExecutionModel -lvtkIOImage -lvtkIOCore -lvtkIOGeometry -lvtkIOLegacy + +TARGET = kel_vtk_renderer + +all: ${TARGET} + +${TARGET}: ${TARGET}.cpp + ${CXX} ${CXXFLAGS} ${LIBS} -o $@ $^ diff --git a/util/vtk_renderer/kel_vtk_renderer.cpp b/util/vtk_renderer/kel_vtk_renderer.cpp new file mode 100644 index 0000000..516e4c3 --- /dev/null +++ b/util/vtk_renderer/kel_vtk_renderer.cpp @@ -0,0 +1,80 @@ +#include +#include +#include // Use vtkXMLStructuredGridReader for .vts +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + // Renderer & offscreen window + auto renderer = vtkSmartPointer::New(); + renderer->SetBackground(0.1, 0.2, 0.4); + + auto renderWindow = vtkSmartPointer::New(); + renderWindow->AddRenderer(renderer); + renderWindow->SetSize(800, 600); + renderWindow->OffScreenRenderingOn(); // No GUI + + auto windowToImage = vtkSmartPointer::New(); + windowToImage->SetInput(renderWindow); + windowToImage->SetInputBufferTypeToRGB(); + windowToImage->ReadFrontBufferOff(); + + auto writer = vtkSmartPointer::New(); + writer->SetInputConnection(windowToImage->GetOutputPort()); + + // Camera setup (fixed) + renderer->GetActiveCamera()->SetPosition(0, 0, 10); + renderer->GetActiveCamera()->SetFocalPoint(0, 0, 0); + renderer->ResetCamera(); + + int startIndex = 0; + int endIndex = 1024; // adjust to your sequence length + + for (int i = startIndex; i <= endIndex; ++i) + { + // Format input filename + std::ostringstream vtkFile; + vtkFile << "poiseulle_2d_gpu_" << (i*4) << ".vtk"; + + // Read structured points (equidistant grid) + auto reader = vtkSmartPointer::New(); + reader->SetFileName(vtkFile.str().c_str()); + reader->Update(); + + // Convert structured grid to surface for rendering + auto surfaceFilter = vtkSmartPointer::New(); + surfaceFilter->SetInputConnection(reader->GetOutputPort()); + surfaceFilter->Update(); + + auto mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(surfaceFilter->GetOutputPort()); + + auto actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + // Clear previous frame + renderer->RemoveAllViewProps(); + renderer->AddActor(actor); + + // Render offscreen + renderWindow->Render(); + windowToImage->Modified(); + + // Save PNG + std::ostringstream pngFile; + pngFile << "tmp/png/frame_" << std::setw(8) << std::setfill('0') << i << ".png"; + writer->SetFileName(pngFile.str().c_str()); + writer->Write(); + } + + return 0; +} -- cgit v1.2.3