diff options
| author | Claudius "keldu" Holeksa <mail@keldu.de> | 2026-08-14 23:43:54 +0200 |
|---|---|---|
| committer | Claudius "keldu" Holeksa <mail@keldu.de> | 2026-08-14 23:43:54 +0200 |
| commit | 0e9322fe0d024a06f23430285a055c16cf1e3eeb (patch) | |
| tree | 657a33098c96b14c0e09748c6b9d4a7e9cd16160 /modules/core | |
| parent | 0d15416f60491bd4d17bd8b45a9487c98b8132b0 (diff) | |
| parent | c634aac438972b7bafb5fbbeba7962d174cc0d03 (diff) | |
| download | libs-lbm-0e9322fe0d024a06f23430285a055c16cf1e3eeb.tar.gz | |
Merge branch 'dev'
Diffstat (limited to 'modules/core')
| -rw-r--r-- | modules/core/c++/boundary.hpp | 545 | ||||
| -rw-r--r-- | modules/core/c++/boundary/common.hpp | 8 | ||||
| -rw-r--r-- | modules/core/c++/boundary/zou_he_pressure.hpp | 9 | ||||
| -rw-r--r-- | modules/core/c++/collision.hpp | 4 | ||||
| -rw-r--r-- | modules/core/c++/component/psm.hpp | 2 | ||||
| -rw-r--r-- | modules/core/c++/fplbm.hpp | 10 | ||||
| -rw-r--r-- | modules/core/c++/hlbm.hpp | 4 | ||||
| -rw-r--r-- | modules/core/c++/macroscopic.hpp | 1 | ||||
| -rw-r--r-- | modules/core/c++/particle.hpp | 2 | ||||
| -rw-r--r-- | modules/core/c++/psm.hpp | 516 | ||||
| -rw-r--r-- | modules/core/c++/write_csv.hpp | 2 | ||||
| -rw-r--r-- | modules/core/c++/write_vtk.hpp | 2 | ||||
| -rw-r--r-- | modules/core/tests/equilibrium.cpp | 2 | ||||
| -rw-r--r-- | modules/core/tests/vtk_write.cpp | 10 |
14 files changed, 969 insertions, 148 deletions
diff --git a/modules/core/c++/boundary.hpp b/modules/core/c++/boundary.hpp index 22a6f34..e7567c9 100644 --- a/modules/core/c++/boundary.hpp +++ b/modules/core/c++/boundary.hpp @@ -133,14 +133,14 @@ template<typename FP, typename Descriptor, typename Encode> class component<FP, Descriptor, cmpt::Equilibrium, Encode> final { private: saw::data<sch::Scalar<FP>> density_; - saw::data<sch::Vector<FP,Descriptor::D>> velocity_; + saw::data<sch::Vector<FP,Descriptor::D>> momentum_; public: component( saw::data<sch::Scalar<FP>> density__, - saw::data<sch::Vector<FP,Descriptor::D>> velocity__ + saw::data<sch::Vector<FP,Descriptor::D>> momentum__ ): density_{density__}, - velocity_{velocity__} + momentum_{momentum__} {} template<typename CellFieldSchema> @@ -151,7 +151,7 @@ public: auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); - auto eq = equilibrium<FP,Descriptor>(density_,velocity_); + auto eq = equilibrium<FP,Descriptor>(density_,momentum_); dfs_old_f.at(index) = eq; } @@ -169,8 +169,10 @@ public: * 0 - 2 - 2 * */ -template<typename FP, typename Descriptor, bool Dir, typename Encode> -class component<FP, Descriptor, cmpt::ZouHeHorizontal<Dir>, Encode> final { +template<typename FP, bool Dir, typename Encode> +class component<FP, sch::Descriptor<2u,9u>, cmpt::ZouHeHorizontal<Dir>, Encode> final { +public: + using Descriptor = sch::Descriptor<2u,9u>; private: saw::data<FP> rho_setting_; public: @@ -179,7 +181,7 @@ public: {} template<typename CellFieldSchema> - void apply(const saw::data<CellFieldSchema, Encode>& field, saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> index, saw::data<sch::UInt64> time_step) const { + void apply(const saw::data<CellFieldSchema, Encode>& field, saw::data<sch::FixedArray<sch::UInt64,2u>> index, saw::data<sch::UInt64> time_step) const { using dfi = df_info<FP,Descriptor>; bool is_even = ((time_step.get() % 2) == 0); @@ -207,7 +209,7 @@ public: return {}; }(); - static_assert(Descriptor::D == 2u and Descriptor::Q == 9u, "Some parts are hard coded sadly"); + // static_assert(Descriptor::D == 2u and Descriptor::Q == 9u, "Some parts are hard coded sadly"); if constexpr (Dir) { dfs_old.at({2u}) = dfs_old.at({1u}) + saw::data<FP>{2.0 / 3.0} * rho_vel_x; @@ -221,16 +223,515 @@ public: } }; +template<typename FP, bool East, typename Encode> +class component<FP, sch::Descriptor<3u,27u>, cmpt::ZouHeHorizontal<East>, Encode> final { +public: + using Descriptor = sch::Descriptor<3u,27u>; +private: + saw::data<FP> rho_setting_; +public: + component(const saw::data<FP>& rho_setting__): + rho_setting_{rho_setting__} + {} + + template<typename CellFieldSchema> + void apply(const saw::data<CellFieldSchema, Encode>& field, saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> index, saw::data<sch::UInt64> time_step) const { + using dfi = df_info<FP,Descriptor>; + + bool is_even = ((time_step.get() % 2) == 0); + + auto& info_f = field.template get<"info">(); + + // auto& dfs_f = (is_even) ? field.template get<"dfs">() : field.template get<"dfs_old">(); + auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); + auto& f = dfs_old_f.at(index); + + /* + * D3Q27 indexing + * + * x=-1 x=0 x=+1 + * + * z=+1: 19 22 25 18 21 24 20 23 26 + * + * z= 0: 1 4 7 0 3 6 2 5 8 + * + * z=-1: 10 13 16 9 12 15 11 14 17 + * + * Boundary normal is x. + * + * East: + * known: cx = +1 + * unknown: cx = -1 + * + * West: + * known: cx = -1 + * unknown: cx = +1 + */ + + + /* + * ============================================================ + * rho * ux + * ============================================================ + * + * rho = S + 2 * sum(unknown) + * + * Therefore: + * + * East: + * rho*ux = rho - S + * + * West: + * rho*ux = S - rho + */ + + saw::data<FP> S; + + if constexpr (East) { + + S = + // cx = 0 + f.at({0u}) + + f.at({3u}) + + f.at({6u}) + + f.at({9u}) + + f.at({12u}) + + f.at({15u}) + + f.at({18u}) + + f.at({21u}) + + f.at({24u}) + + // cx = +1 + + saw::data<FP>{2.0} * ( + f.at({2u}) + + f.at({5u}) + + f.at({8u}) + + f.at({11u}) + + f.at({14u}) + + f.at({17u}) + + f.at({20u}) + + f.at({23u}) + + f.at({26u}) + ); + + } else { + + S = + // cx = 0 + f.at({0u}) + + f.at({3u}) + + f.at({6u}) + + f.at({9u}) + + f.at({12u}) + + f.at({15u}) + + f.at({18u}) + + f.at({21u}) + + f.at({24u}) + + // cx = -1 + + saw::data<FP>{2.0} * ( + f.at({1u}) + + f.at({4u}) + + f.at({7u}) + + f.at({10u}) + + f.at({13u}) + + f.at({16u}) + + f.at({19u}) + + f.at({22u}) + + f.at({25u}) + ); + } + + saw::data<FP> rho_ux; + + if constexpr (East) { + rho_ux = rho_setting_ - S; + } else { + rho_ux = S - rho_setting_; + } + + + /* + * ============================================================ + * Tangential momentum: rho * uy + * ============================================================ + * + * For a pressure boundary, uy and uz are obtained from the + * known populations. + * + * rho*uy: + * + * East: + * + * x=0 contribution + * + 2*x=+1 contribution + * + * West: + * + * x=0 contribution + * + 2*x=-1 contribution + */ + + saw::data<FP> rho_uy; + saw::data<FP> rho_uz; + + if constexpr (East) { + + rho_uy = + // cx = 0 + -f.at({3u}) + + f.at({6u}) + -f.at({12u}) + + f.at({15u}) + -f.at({21u}) + + f.at({24u}) + + // cx = +1 + + saw::data<FP>{2.0} * ( + -f.at({5u}) + + f.at({8u}) + -f.at({14u}) + + f.at({17u}) + -f.at({23u}) + + f.at({26u}) + ); + + rho_uz = + // cx = 0 + -f.at({9u}) + -f.at({12u}) + -f.at({15u}) + + f.at({18u}) + + f.at({21u}) + + f.at({24u}) + + // cx = +1 + + saw::data<FP>{2.0} * ( + -f.at({11u}) + -f.at({14u}) + -f.at({17u}) + +f.at({20u}) + +f.at({23u}) + +f.at({26u}) + ); + + } else { + + rho_uy = + // cx = 0 + -f.at({3u}) + + f.at({6u}) + - f.at({12u}) + + f.at({15u}) + - f.at({21u}) + + f.at({24u}) + + // cx = -1 + + saw::data<FP>{2.0} * ( + -f.at({4u}) + + f.at({7u}) + -f.at({13u}) + + f.at({16u}) + -f.at({22u}) + + f.at({25u}) + ); + + rho_uz = + // cx = 0 + -f.at({9u}) + -f.at({12u}) + -f.at({15u}) + +f.at({18u}) + +f.at({21u}) + +f.at({24u}) + + // cx = -1 + + saw::data<FP>{2.0} * ( + -f.at({10u}) + -f.at({13u}) + -f.at({16u}) + +f.at({19u}) + +f.at({22u}) + +f.at({25u}) + ); + } + + + /* + * ============================================================ + * Velocity + * ============================================================ + */ + + saw::data<FP> ux = rho_ux / rho_setting_; + saw::data<FP> uy = rho_uy / rho_setting_; + saw::data<FP> uz = rho_uz / rho_setting_; + + + /* + * ============================================================ + * Reconstruct unknown distributions + * ============================================================ + * + * Zou/He non-equilibrium bounce-back: + * + * f_i = f_opp + * + (f_eq_i - f_eq_opp) + * + * For D3Q27: + * + * axis: + * + * 6*w*rho*u = 1/6 * rho*u + * + * face diagonal: + * + * 6*w*rho*(c.u) + * = 1/9 * rho*(c.u) + * + * body diagonal: + * + * 6*w*rho*(c.u) + * = 1/36 * rho*(c.u) + * + * The factors below therefore use: + * + * 1/6 + * 1/9 + * 1/36 + * + * ============================================================ + */ + + if constexpr (East) { + + /* + * -------------------------------------------------------- + * (-1, 0, 0) <- (+1, 0, 0) + * -------------------------------------------------------- + */ + + f.at({1u}) = + f.at({2u}) + - saw::data<FP>{1.0 / 6.0} * rho_ux; + + + /* + * -------------------------------------------------------- + * (-1, -1, 0) <- (+1, -1, 0) + * -------------------------------------------------------- + */ + + f.at({4u}) = + f.at({5u}) + - saw::data<FP>{1.0 / 9.0} + * (rho_ux + rho_uy); + + + /* + * -------------------------------------------------------- + * (-1, +1, 0) <- (+1, +1, 0) + * -------------------------------------------------------- + */ + + f.at({7u}) = + f.at({8u}) + + saw::data<FP>{1.0 / 9.0} + * (-rho_ux + rho_uy); + + + /* + * -------------------------------------------------------- + * (-1, 0, -1) <- (+1, 0, -1) + * -------------------------------------------------------- + */ + + f.at({10u}) = + f.at({11u}) + - saw::data<FP>{1.0 / 9.0} + * (rho_ux + rho_uz); + + + /* + * -------------------------------------------------------- + * (-1, -1, -1) <- (+1, -1, -1) + * -------------------------------------------------------- + */ + + f.at({13u}) = + f.at({14u}) + - saw::data<FP>{1.0 / 36.0} + * (rho_ux + rho_uy + rho_uz); + + + /* + * -------------------------------------------------------- + * (-1, +1, -1) <- (+1, +1, -1) + * -------------------------------------------------------- + */ + + f.at({16u}) = + f.at({17u}) + + saw::data<FP>{1.0 / 36.0} + * (-rho_ux + rho_uy + rho_uz); + + + /* + * -------------------------------------------------------- + * (-1, 0, +1) <- (+1, 0, +1) + * -------------------------------------------------------- + */ + + f.at({19u}) = + f.at({20u}) + + saw::data<FP>{1.0 / 9.0} + * (-rho_ux + rho_uz); + + + /* + * -------------------------------------------------------- + * (-1, -1, +1) <- (+1, -1, +1) + * -------------------------------------------------------- + */ + + f.at({22u}) = + f.at({23u}) + + saw::data<FP>{1.0 / 36.0} + * (-rho_ux - rho_uy + rho_uz); + + + /* + * -------------------------------------------------------- + * (-1, +1, +1) <- (+1, +1, +1) + * -------------------------------------------------------- + */ + + f.at({25u}) = + f.at({26u}) + + saw::data<FP>{1.0 / 36.0} + * (-rho_ux + rho_uy + rho_uz); + + } else { + + /* + * -------------------------------------------------------- + * (+1, 0, 0) <- (-1, 0, 0) + * -------------------------------------------------------- + */ + + f.at({2u}) = + f.at({1u}) + + saw::data<FP>{1.0 / 6.0} * rho_ux; + + + /* + * -------------------------------------------------------- + * (+1, -1, 0) <- (-1, -1, 0) + * -------------------------------------------------------- + */ + + f.at({5u}) = + f.at({4u}) + + saw::data<FP>{1.0 / 9.0} + * (rho_ux - rho_uy); + + + /* + * -------------------------------------------------------- + * (+1, +1, 0) <- (-1, +1, 0) + * -------------------------------------------------------- + */ + + f.at({8u}) = + f.at({7u}) + + saw::data<FP>{1.0 / 9.0} + * (rho_ux + rho_uy); + + + /* + * -------------------------------------------------------- + * (+1, 0, -1) <- (-1, 0, -1) + * -------------------------------------------------------- + */ + + f.at({11u}) = + f.at({10u}) + + saw::data<FP>{1.0 / 9.0} + * (rho_ux - rho_uz); + + + /* + * -------------------------------------------------------- + * (+1, -1, -1) <- (-1, -1, -1) + * -------------------------------------------------------- + */ + + f.at({14u}) = + f.at({13u}) + + saw::data<FP>{1.0 / 36.0} + * (rho_ux - rho_uy - rho_uz); + + + /* + * -------------------------------------------------------- + * (+1, +1, -1) <- (-1, +1, -1) + * -------------------------------------------------------- + */ + + f.at({17u}) = + f.at({16u}) + + saw::data<FP>{1.0 / 36.0} + * (rho_ux + rho_uy - rho_uz); + + + /* + * -------------------------------------------------------- + * (+1, 0, +1) <- (-1, 0, +1) + * -------------------------------------------------------- + */ + + f.at({20u}) = + f.at({19u}) + + saw::data<FP>{1.0 / 9.0} + * (rho_ux + rho_uz); + + + /* + * -------------------------------------------------------- + * (+1, -1, +1) <- (-1, -1, +1) + * -------------------------------------------------------- + */ + + f.at({23u}) = + f.at({22u}) + + saw::data<FP>{1.0 / 36.0} + * (rho_ux - rho_uy + rho_uz); + + + /* + * -------------------------------------------------------- + * (+1, +1, +1) <- (-1, +1, +1) + * -------------------------------------------------------- + */ + + f.at({26u}) = + f.at({25u}) + + saw::data<FP>{1.0 / 36.0} + * (rho_ux + rho_uy + rho_uz); + } + } +}; + template<typename T, typename Descriptor, bool East, typename Encode> class component<T, Descriptor, cmpt::ZouHeVelocityX<East>, Encode> final { private: - saw::data<sch::Vector<T,Descriptor::D>> velocity_; + saw::data<sch::Vector<T,Descriptor::D>> momentum_; public: component( - saw::data<sch::Vector<T,Descriptor::D>> velocity__ + saw::data<sch::Vector<T,Descriptor::D>> momentum__ ): - velocity_{velocity__} + momentum_{momentum__} {} template<typename CellFieldSchema> @@ -252,20 +753,20 @@ public: } saw::data<sch::Scalar<T>> rho; - rho.at({}) = (dfs.at({0u}) + dfs.at({4u}) + dfs.at({3u}) + dir_sum * 2) / (velocity_.at({{0u}}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0)}); + rho.at({}) = (dfs.at({0u}) + dfs.at({4u}) + dfs.at({3u}) + dir_sum * 2) / (momentum_.at({{0u}}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0)}); if constexpr (East) { - dfs.at({2u}) = dfs.at({1u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(2.0 / 3.0)} * rho.at({}) * velocity_.at({{0u}}); - dfs.at({6u}) = dfs.at({5u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * velocity_.at({{0u}}) - + (dfs.at({3u}) - dfs.at({4u}) + rho.at({}) * velocity_.at({{1u}})) * 0.5f; - dfs.at({8u}) = dfs.at({7u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * velocity_.at({{0u}}) - + (dfs.at({4u}) - dfs.at({3u}) + rho.at({}) * velocity_.at({{1u}})) * 0.5f; + dfs.at({2u}) = dfs.at({1u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(2.0 / 3.0)} * rho.at({}) * momentum_.at({{0u}}); + dfs.at({6u}) = dfs.at({5u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * momentum_.at({{0u}}) + + (dfs.at({3u}) - dfs.at({4u}) + rho.at({}) * momentum_.at({{1u}})) * 0.5f; + dfs.at({8u}) = dfs.at({7u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * momentum_.at({{0u}}) + + (dfs.at({4u}) - dfs.at({3u}) + rho.at({}) * momentum_.at({{1u}})) * 0.5f; }else if constexpr ( not East ){ - dfs.at({1u}) = dfs.at({2u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(2.0 / 3.0)} * rho.at({}) * velocity_.at({{0u}}); - dfs.at({5u}) = dfs.at({6u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * velocity_.at({{0u}}) - + (dfs.at({4u}) - dfs.at({3u}) + rho.at({}) * velocity_.at({{1u}}))*0.5f; - dfs.at({7u}) = dfs.at({8u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * velocity_.at({{0u}}) - + (dfs.at({3u}) - dfs.at({4u}) + rho.at({}) * velocity_.at({{1u}}))*0.5f; + dfs.at({1u}) = dfs.at({2u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(2.0 / 3.0)} * rho.at({}) * momentum_.at({{0u}}); + dfs.at({5u}) = dfs.at({6u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * momentum_.at({{0u}}) + + (dfs.at({4u}) - dfs.at({3u}) + rho.at({}) * momentum_.at({{1u}}))*0.5f; + dfs.at({7u}) = dfs.at({8u}) + saw::data<T>{static_cast<saw::native_data_type<T>::type>(1.0 / 6.0)} * rho.at({}) * momentum_.at({{0u}}) + + (dfs.at({3u}) - dfs.at({4u}) + rho.at({}) * momentum_.at({{1u}}))*0.5f; } } }; diff --git a/modules/core/c++/boundary/common.hpp b/modules/core/c++/boundary/common.hpp new file mode 100644 index 0000000..3feb451 --- /dev/null +++ b/modules/core/c++/boundary/common.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "../common.hpp" + +namespace kel { +namespace lbm { +} +} diff --git a/modules/core/c++/boundary/zou_he_pressure.hpp b/modules/core/c++/boundary/zou_he_pressure.hpp new file mode 100644 index 0000000..7fc8591 --- /dev/null +++ b/modules/core/c++/boundary/zou_he_pressure.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "common.hpp" + +namespace kel { +namespace lbm { + +} +} diff --git a/modules/core/c++/collision.hpp b/modules/core/c++/collision.hpp index 023f61f..39514b8 100644 --- a/modules/core/c++/collision.hpp +++ b/modules/core/c++/collision.hpp @@ -75,7 +75,7 @@ public: auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); saw::data<sch::Vector<T,Descriptor::D>>& vel = vel_f.at(index); @@ -135,7 +135,7 @@ public: auto& dfs = dfs_old_f.at(index); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); diff --git a/modules/core/c++/component/psm.hpp b/modules/core/c++/component/psm.hpp index cada53c..5832760 100644 --- a/modules/core/c++/component/psm.hpp +++ b/modules/core/c++/component/psm.hpp @@ -39,7 +39,7 @@ public: auto& porous_f = macros.template get<"porosity">(); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); saw::data<sch::Vector<T,Descriptor::D>>& vel = vel_f.at(index); diff --git a/modules/core/c++/fplbm.hpp b/modules/core/c++/fplbm.hpp index 37074b0..382d067 100644 --- a/modules/core/c++/fplbm.hpp +++ b/modules/core/c++/fplbm.hpp @@ -46,7 +46,7 @@ public: auto& rho_f = macros.template get<"density">(); auto& rho = rho_f.at(index); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); auto& vel = vel_f.at(index); compute_rho_u<T,Descriptor>(dfs,rho,vel); @@ -86,7 +86,7 @@ public: auto& rho_f = macros.template get<"density">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Vector<T,Descriptor::D>> vel = vel_f.at(index); auto& force_f = macros.template get<"force">(); @@ -148,7 +148,7 @@ public: // auto& dfs = dfs_old_f.at(index); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); auto& por_f = macros.template get<"porosity">(); auto& force_f = macros.template get<"force">(); @@ -204,7 +204,7 @@ public: // vel_s is technically time the density of the particle? - force = ( vel_s * rho - vel * rho ) * two * flip_por; + force = ( vel_s * rho - vel * rho ) /* two */ * flip_por; force_p = force_p - force; }, aabb.template get<"a">(), aabb.template get<"b">()); @@ -245,7 +245,7 @@ public: auto& dfs = dfs_old_f.at(index); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); auto& por_f = macros.template get<"porosity">(); // Temporary find a better way diff --git a/modules/core/c++/hlbm.hpp b/modules/core/c++/hlbm.hpp index cc21dcf..e8ea66a 100644 --- a/modules/core/c++/hlbm.hpp +++ b/modules/core/c++/hlbm.hpp @@ -70,7 +70,7 @@ public: auto& porosity_f = macros.template get<"porosity">(); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); saw::data<sch::Vector<T,Desc::D>>& vel = vel_f.at(index); @@ -125,7 +125,7 @@ public: auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); auto& part_spheroid_group = part_group; - auto& mvel_f = macros.template get<"velocity">(); + auto& mvel_f = macros.template get<"momentum">(); auto& mrho_f = macros.template get<"density">(); auto& mpor_f = macros.template get<"porosity">(); diff --git a/modules/core/c++/macroscopic.hpp b/modules/core/c++/macroscopic.hpp index 19ab3e9..768fef0 100644 --- a/modules/core/c++/macroscopic.hpp +++ b/modules/core/c++/macroscopic.hpp @@ -28,6 +28,7 @@ void compute_rho_u ( } } + // TODO - Change to momentum, but that needs checks in every impacted function for(size_t i = 0; i < Desc::D; ++i){ vel().at({{i}}) = vel().at({{i}}) / rho().at({}); } diff --git a/modules/core/c++/particle.hpp b/modules/core/c++/particle.hpp index 2c60884..efcc3fb 100644 --- a/modules/core/c++/particle.hpp +++ b/modules/core/c++/particle.hpp @@ -25,7 +25,7 @@ public: // Compute forces - // Update particle velocity + // Update particle momentum verlet_step_lambda_old<T,Descriptor::D>(p,{1.0}); // Update porosity over lattice nodes diff --git a/modules/core/c++/psm.hpp b/modules/core/c++/psm.hpp index 15ad0f8..2daff5e 100644 --- a/modules/core/c++/psm.hpp +++ b/modules/core/c++/psm.hpp @@ -55,7 +55,7 @@ public: auto& porous_f = macros.template get<"porosity">(); auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); + auto& vel_f = macros.template get<"momentum">(); saw::data<sch::Scalar<T>>& rho = rho_f.at(index); saw::data<sch::Vector<T,Descriptor::D>>& vel = vel_f.at(index); @@ -105,116 +105,418 @@ public: component() = default; template<typename CellFieldSchema, typename MacroFieldSchema, typename ParticleSchema> - void apply(const saw::data<CellFieldSchema, Encode>& field, const saw::data<MacroFieldSchema,Encode>& macros, const saw::data<ParticleSchema,Encode>& pg, saw::data<sch::FixedArray<sch::UInt64,1u>> index, saw::data<sch::UInt64> time_step, saw::data<sch::UInt64> sub_steps) const { - - using dfi = df_info<T,Descriptor>; - bool is_even = ((time_step.get() % 2) == 0); - - saw::data<sch::Scalar<T>> one; - one.at({}) = 1.0; +void apply( + const saw::data<CellFieldSchema, Encode>& field, + const saw::data<MacroFieldSchema, Encode>& macros, + const saw::data<ParticleSchema, Encode>& pg, + saw::data<sch::FixedArray<sch::UInt64,1u>> index, + saw::data<sch::UInt64> time_step, + saw::data<sch::UInt64> sub_steps +) const { - auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); + using dfi = df_info<T,Descriptor>; - auto& por_f = macros.template get<"porosity">(); - auto& rho_f = macros.template get<"density">(); - auto& vel_f = macros.template get<"velocity">(); - auto& force_f = macros.template get<"force">(); - - { - auto parts = pg.template get<"particles">(); - auto parts_size = parts.meta().at({0u}); - - auto& p_coll = pg.template get<"collision">().at({}); - auto& p_rad = p_coll.template get<"radius">(); - - auto& pi = parts.at(index); - auto& pirb = pi.template get<"rigid_body">(); - saw::data<sch::Vector<T,Descriptor::D>>& pirb_pos = pirb.template get<"position">(); - auto& pirb_pos_old = pirb.template get<"position_old">(); - - saw::data<sch::Scalar<T>> ts; - ts.at({}) = one.at({}) / sub_steps.template cast_to<T>(); - - saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> start; - saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> stop; - - auto eo_aabb = particle_aabb<typename ParticleSchema::ValueType>::calculate(pg,{{0u}},vel_f.meta()); - if(eo_aabb.is_error()){ - return; - } - auto& aabb = eo_aabb.get_value(); + bool is_even = ((time_step.get() % 2u) == 0u); - /// Ok, I iterate over the space which covers our particle? So lower bounds to upper bounds - start = aabb.template get<"a">(); - stop = aabb.template get<"b">(); + /* + * ------------------------------------------------------------ + * Fields + * ------------------------------------------------------------ + */ - saw::data<sch::Vector<T,Descriptor::D>> force_p; - for(uint64_t i{0u}; i < Descriptor::D; ++i){ - force_p.at({{i}}) = 0.0; - } - auto vel_p_old = (pirb_pos-pirb_pos_old) / ts; - - iterator<Descriptor::D>::apply([&](const auto& index_f) -> void{ - // ask for the d_k value here. - // For every value im iterating over I need sth - // std::cout<<"Pos: "<<index.at({0u}).get()<<" "<<index.at({1u}).get()<<std::endl; - - auto& dfs = dfs_old_f.at(index_f); - saw::data<sch::Vector<T,Descriptor::D>> rel_dist = saw::math::vectorize_data(index_f).template cast_to<T>() - pirb_pos; - saw::data<sch::Scalar<T>> eps; - eps.at({}) = 1.5f; - - auto& por = por_f.at(index_f); - por = particle_porosity<T,Descriptor::D,1u,por::ParticleSpheroid<T>>::calculate(rel_dist,p_rad,eps); - - if(por.at({}).get() >= 1.0f){ - return; - } - - saw::data<sch::Vector<T,Descriptor::D>> momentum; - for(uint64_t i{0u}; i < Descriptor::D; ++i){ - momentum.at({{i}}) = 0.0; - } - - for(uint64_t i{0u}; i < Descriptor::Q; ++i){ - saw::data<sch::Vector<T,Descriptor::D>> e_i; - saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> n_ind_i; - for(uint64_t k{0u}; k < Descriptor::D; ++k){ - e_i.at({{k}}) = (dfi::directions[i])[k]; - n_ind_i.at({k}) = index_f.at({k}) + (dfi::directions[i])[k]; - } - - uint64_t i_opp = dfi::opposite_index[i]; - - auto u_p_e = saw::math::dot(e_i,vel_p_old); - - saw::data<T> dfs_added = dfs.at({i})*(saw::data<T>{1}-u_p_e.at({})) + dfs_old_f.at(n_ind_i).at({i_opp})*(saw::data<T>{1}+u_p_e.at({})); - saw::data<sch::Scalar<T>> dfs_added_v; - dfs_added_v.at({}) = dfs_added; - auto ei_dfs = e_i * dfs_added_v; - - momentum = momentum + ei_dfs; - } - // technically needs to adjust for rotation as well - - auto& force = force_f.at(index_f); - auto& rho = rho_f.at(index_f); - // To Fluid - - auto flip_por = one - por; - force = momentum * flip_por; - // To Particle - force_p = force_p - force; - },start,stop); - - auto& pirb_acc = pirb.template get<"acceleration">(); - pirb_acc = force_p / pg.template get<"total_mass">().at({}); - - for(saw::data<sch::UInt64> i{0u}; i < sub_steps; ++i){ - verlet_step_lambda<T,Descriptor::D>(pi,ts); - } - } - } + auto& dfs_old_f = + (is_even) + ? field.template get<"dfs_old">() + : field.template get<"dfs">(); + + auto& por_f = macros.template get<"porosity">(); + auto& rho_f = macros.template get<"density">(); + auto& vel_f = macros.template get<"momentum">(); + auto& force_f = macros.template get<"force">(); + + saw::data<sch::Scalar<T>> one; + one.at({}) = 1.0; + + saw::data<sch::Scalar<T>> half; + half.at({}) = 0.5; + + /* + * ------------------------------------------------------------ + * Particle + * ------------------------------------------------------------ + */ + + { + auto parts = pg.template get<"particles">(); + + auto& p_coll = + pg.template get<"collision">().at({}); + + auto& p_rad = + p_coll.template get<"radius">(); + + auto& pi = parts.at(index); + + auto& pirb = + pi.template get<"rigid_body">(); + + saw::data<sch::Vector<T,Descriptor::D>>& pirb_pos = + pirb.template get<"position">(); + + auto& pirb_pos_old = + pirb.template get<"position_old">(); + + + /* + * -------------------------------------------------------- + * Particle timestep + * -------------------------------------------------------- + */ + + saw::data<sch::Scalar<T>> ts; + + ts.at({}) = + one.at({}) + / sub_steps.template cast_to<T>(); + + + /* + * -------------------------------------------------------- + * Particle momentum + * -------------------------------------------------------- + */ + + auto vel_p_old = + (pirb_pos - pirb_pos_old) / ts; + + + /* + * -------------------------------------------------------- + * Find particle AABB + * -------------------------------------------------------- + */ + + auto eo_aabb = + particle_aabb< + typename ParticleSchema::ValueType + >::calculate( + pg, + {{0u}}, + vel_f.meta() + ); + + if(eo_aabb.is_error()){ + return; + } + + auto& aabb = eo_aabb.get_value(); + + saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> start; + saw::data<sch::FixedArray<sch::UInt64,Descriptor::D>> stop; + + start = aabb.template get<"a">(); + stop = aabb.template get<"b">(); + + + /* + * -------------------------------------------------------- + * Total force acting on particle + * -------------------------------------------------------- + */ + + saw::data<sch::Vector<T,Descriptor::D>> force_p; + + for(uint64_t k = 0u; k < Descriptor::D; ++k){ + force_p.at({{k}}) = 0.0; + } + + + /* + * -------------------------------------------------------- + * Iterate over particle AABB + * -------------------------------------------------------- + */ + + iterator<Descriptor::D>::apply( + [&](const auto& index_f) -> void { + + /* + * ------------------------------------------------ + * Distribution function at current cell + * ------------------------------------------------ + */ + + auto& dfs = + dfs_old_f.at(index_f); + + + /* + * ------------------------------------------------ + * Particle relative position + * ------------------------------------------------ + */ + + saw::data<sch::Vector<T,Descriptor::D>> rel_dist = + saw::math::vectorize_data(index_f) + .template cast_to<T>() + - pirb_pos; + + + /* + * ------------------------------------------------ + * PSM particle porosity + * ------------------------------------------------ + */ + + saw::data<sch::Scalar<T>> eps; + eps.at({}) = 1.5; + + auto& por = + por_f.at(index_f); + + por = + particle_porosity< + T, + Descriptor::D, + 1u, + por::ParticleSpheroid<T> + >::calculate( + rel_dist, + p_rad, + eps + ); + + + /* + * Outside particle. + */ + + if(por.at({}).get() >= 1.0){ + return; + } + + + /* + * ------------------------------------------------ + * Momentum exchange for this cell + * ------------------------------------------------ + */ + + saw::data<sch::Vector<T,Descriptor::D>> momentum; + + for(uint64_t k = 0u; k < Descriptor::D; ++k){ + momentum.at({{k}}) = 0.0; + } + + + /* + * ------------------------------------------------ + * D3Q27 / general Q momentum exchange + * + * We exclude i=0 because the rest population has + * no momentum. + * + * The original code summed both directions of + * every opposite pair. Therefore we apply 1/2 + * after the sum. + * ------------------------------------------------ + */ + + for(uint64_t i = 1u; i < Descriptor::Q; ++i){ + + uint64_t i_opp = + dfi::opposite_index[i]; + + + /* + * Direction vector e_i. + */ + + saw::data<sch::Vector<T,Descriptor::D>> e_i; + + saw::data< + sch::FixedArray< + sch::UInt64, + Descriptor::D + > + > n_ind_i; + + + for(uint64_t k = 0u; + k < Descriptor::D; + ++k){ + + e_i.at({{k}}) = + dfi::directions[i][k]; + + /* + * Neighbor in direction e_i. + */ + + n_ind_i.at({k}) = + index_f.at({k}) + + dfi::directions[i][k]; + } + + + /* + * ------------------------------------------------ + * Particle momentum projected onto e_i + * ------------------------------------------------ + */ + + auto u_p_e = + saw::math::dot( + e_i, + vel_p_old + ); + + + /* + * ------------------------------------------------ + * Momentum-exchange population + * + * f_i(x) + * + * + f_-i(x + e_i) + * + * with moving-wall correction. + * ------------------------------------------------ + */ + + saw::data<T> dfs_added = + dfs.at({i}) + * ( + saw::data<T>{1.0} + - u_p_e.at({}) + ) + + + dfs_old_f + .at(n_ind_i) + .at({i_opp}) + * ( + saw::data<T>{1.0} + + u_p_e.at({}) + ); + + + /* + * Convert scalar into vector multiplication. + */ + + saw::data<sch::Scalar<T>> dfs_added_v; + + dfs_added_v.at({}) = + dfs_added; + + + /* + * ------------------------------------------------ + * Delta p_i + * + * ------------------------------------------------ + */ + + momentum = + momentum + + e_i * dfs_added_v; + } + + + /* + * ------------------------------------------------ + * Since both i and i_opp were included above, + * compensate for double counting. + * + * This is the important change from your original + * implementation. + * ------------------------------------------------ + */ + + + + momentum = + momentum * half; + + + /* + * ------------------------------------------------ + * PSM solid fraction + * + * por = 1 -> fluid + * por = 0 -> particle + * + * Therefore: + * + * flip_por = 1 - por + * ------------------------------------------------ + */ + + auto flip_por = + one - por; + + + /* + * ------------------------------------------------ + * Force transferred TO FLUID + * ------------------------------------------------ + */ + + auto& force = + force_f.at(index_f); + + force = + momentum * flip_por; + + + /* + * ------------------------------------------------ + * Force transferred TO PARTICLE + * + * Newton's third law. + * ------------------------------------------------ + */ + + force_p = + force_p - force; + + }, + start, + stop + ); + + + /* + * ------------------------------------------------------------ + * Particle acceleration + * ------------------------------------------------------------ + */ + + auto& pirb_acc = + pirb.template get<"acceleration">(); + + pirb_acc = + force_p + / pg.template get<"total_mass">().at({}); + + + /* + * ------------------------------------------------------------ + * Integrate particle + * ------------------------------------------------------------ + */ + + for(saw::data<sch::UInt64> i{0u}; + i < sub_steps; + ++i){ + + verlet_step_lambda<T,Descriptor::D>( + pi, + ts + ); + } + } +} }; } diff --git a/modules/core/c++/write_csv.hpp b/modules/core/c++/write_csv.hpp index a60e208..aa28613 100644 --- a/modules/core/c++/write_csv.hpp +++ b/modules/core/c++/write_csv.hpp @@ -91,7 +91,7 @@ struct lbm_csv_writer<sch::Chunk<T,Ghost,D...>> { template<typename T, uint64_t D> struct lbm_csv_writer<sch::Vector<T,D>> { static saw::error_or<void> apply(std::ostream& csv_file, const saw::data<sch::Vector<T,D>>& field){ - static_assert(D > 0, "Non-dimensionality is bad for velocity."); + static_assert(D > 0, "Non-dimensionality is bad for momentum."); // csv_file<<"VECTORS "<<name<<" float\n"; for(uint64_t i = 0u; i < D; ++i){ diff --git a/modules/core/c++/write_vtk.hpp b/modules/core/c++/write_vtk.hpp index e852172..67e8a2f 100644 --- a/modules/core/c++/write_vtk.hpp +++ b/modules/core/c++/write_vtk.hpp @@ -115,7 +115,7 @@ struct lbm_vtk_writer<sch::Vector<T,D>> { return saw::make_void(); } static saw::error_or<void> apply(std::ostream& vtk_file, const saw::data<sch::Vector<T,D>>& field){ - static_assert(D > 0, "Non-dimensionality is bad for velocity."); + static_assert(D > 0, "Non-dimensionality is bad for momentum."); static_assert(D <= 3, "4th dimension as well. Mostly due to vtk."); // vtk_file<<"VECTORS "<<name<<" float\n"; diff --git a/modules/core/tests/equilibrium.cpp b/modules/core/tests/equilibrium.cpp index 20a1f08..7d36600 100644 --- a/modules/core/tests/equilibrium.cpp +++ b/modules/core/tests/equilibrium.cpp @@ -20,7 +20,7 @@ void check_equilibrium(){ auto eq = lbm::equilibrium<lbm::sch::Float64,Descriptor>(rho,vel); for(saw::data<lbm::sch::UInt64> i{0u}; i.get() < Descriptor::Q; ++i){ - SAW_EXPECT(eq.at(i).get() == dfi::weights[i.get()], std::string{"No velocity and normalized rho should be exactly the weights: "} + std::to_string(eq.at(i).get()) + std::string{" "} + std::to_string(dfi::weights[i.get()])); + SAW_EXPECT(eq.at(i).get() == dfi::weights[i.get()], std::string{"No momentum and normalized rho should be exactly the weights: "} + std::to_string(eq.at(i).get()) + std::string{" "} + std::to_string(dfi::weights[i.get()])); } } diff --git a/modules/core/tests/vtk_write.cpp b/modules/core/tests/vtk_write.cpp index c99d752..1de25bf 100644 --- a/modules/core/tests/vtk_write.cpp +++ b/modules/core/tests/vtk_write.cpp @@ -31,7 +31,7 @@ using CellStruct = Struct< template<typename T, uint64_t D> using MacroStruct = Struct< - Member<FixedArray<T,D>, "velocity">, + Member<FixedArray<T,D>, "momentum">, Member<T, "pressure"> >; @@ -47,7 +47,7 @@ SAW_TEST("VTK Write test example"){ saw::data<sch::Array<sch::MacroStruct<sch::T,2>, 2>> cells{{{2u,2u}}}; auto& cell_0 = cells.at({{{0,0}}}); - cell_0.template get<"velocity">()= {{0.5,-0.1}}; + cell_0.template get<"momentum">()= {{0.5,-0.1}}; cell_0.template get<"pressure">().set(1.1); auto eov = lbm::impl::lbm_vtk_writer<sch::Array<sch::MacroStruct<sch::T,2>, 2>>::apply(sstream, cells); @@ -56,7 +56,7 @@ SAW_TEST("VTK Write test example"){ // I want to print it to see it for myself. For now I have no tooling to more easily view associated and potentially generated files std::cout<<sstream.str()<<std::endl; - static std::string_view comparison_str = "# vtk DataFile Version 3.0\nLBM File\nASCII\nDATASET STRUCTURED_POINTS\nSPACING 1.0 1.0 1.0\nORIGIN 0.0 0.0 0.0\nDIMENSIONS 2 2 1\nPOINT_DATA 4\n\nVECTORS velocity float\n0.5 -0.1 0\n0 0 0\n0 0 0\n0 0 0\nSCALARS pressure float\nLOOKUP_TABLE default\n1.1\n0\n0\n0\n"; + static std::string_view comparison_str = "# vtk DataFile Version 3.0\nLBM File\nASCII\nDATASET STRUCTURED_POINTS\nSPACING 1.0 1.0 1.0\nORIGIN 0.0 0.0 0.0\nDIMENSIONS 2 2 1\nPOINT_DATA 4\n\nVECTORS momentum float\n0.5 -0.1 0\n0 0 0\n0 0 0\n0 0 0\nSCALARS pressure float\nLOOKUP_TABLE default\n1.1\n0\n0\n0\n"; SAW_EXPECT(sstream.str() == comparison_str, "Expected different encoding"); // using Type = typename parameter_pack_type<i,T...>::type; @@ -74,7 +74,7 @@ SAW_TEST("VTK Write raw test example"){ auto meta = cells.dims(); auto& cell_0 = cells.at({{{0,0}}}); - cell_0.template get<"velocity">()= {{0.5,-0.1}}; + cell_0.template get<"momentum">()= {{0.5,-0.1}}; cell_0.template get<"pressure">().set(1.1); auto eov = lbm::impl::lbm_vtk_writer_raw<sch::MacroStruct<sch::T,2u>,2u>::apply(sstream, &cell_0, meta); @@ -83,7 +83,7 @@ SAW_TEST("VTK Write raw test example"){ // I want to print it to see it for myself. For now I have no tooling to more easily view associated and potentially generated files std::cout<<sstream.str()<<std::endl; - static std::string_view comparison_str = "# vtk DataFile Version 3.0\nLBM File\nASCII\nDATASET STRUCTURED_POINTS\nSPACING 1.0 1.0 1.0\nORIGIN 0.0 0.0 0.0\nDIMENSIONS 2 2 1\nPOINT_DATA 4\n\nVECTORS velocity float\n0.5 -0.1 0\n0 0 0\n0 0 0\n0 0 0\nSCALARS pressure float\nLOOKUP_TABLE default\n1.1\n0\n0\n0\n"; + static std::string_view comparison_str = "# vtk DataFile Version 3.0\nLBM File\nASCII\nDATASET STRUCTURED_POINTS\nSPACING 1.0 1.0 1.0\nORIGIN 0.0 0.0 0.0\nDIMENSIONS 2 2 1\nPOINT_DATA 4\n\nVECTORS momentum float\n0.5 -0.1 0\n0 0 0\n0 0 0\n0 0 0\nSCALARS pressure float\nLOOKUP_TABLE default\n1.1\n0\n0\n0\n"; SAW_EXPECT(sstream.str() == comparison_str, "Expected different encoding"); // using Type = typename parameter_pack_type<i,T...>::type; |
