From c0549d71b2109f10c1238db8b22362e7826ba61b Mon Sep 17 00:00:00 2001 From: "Claudius \"keldu\" Holeksa" Date: Sun, 5 Jul 2026 15:59:23 +0200 Subject: Just rename from lib to modules --- modules/core/c++/particle/aabb.hpp | 55 ++++++ modules/core/c++/particle/blur.hpp | 37 ++++ modules/core/c++/particle/common.hpp | 3 + modules/core/c++/particle/geometry/circle.hpp | 85 +++++++++ modules/core/c++/particle/geometry/cube.hpp | 22 +++ modules/core/c++/particle/particle.hpp | 246 ++++++++++++++++++++++++++ modules/core/c++/particle/particle_opa.hpp | 49 +++++ modules/core/c++/particle/porosity.hpp | 129 ++++++++++++++ modules/core/c++/particle/schema.hpp | 68 +++++++ 9 files changed, 694 insertions(+) create mode 100644 modules/core/c++/particle/aabb.hpp create mode 100644 modules/core/c++/particle/blur.hpp create mode 100644 modules/core/c++/particle/common.hpp create mode 100644 modules/core/c++/particle/geometry/circle.hpp create mode 100644 modules/core/c++/particle/geometry/cube.hpp create mode 100644 modules/core/c++/particle/particle.hpp create mode 100644 modules/core/c++/particle/particle_opa.hpp create mode 100644 modules/core/c++/particle/porosity.hpp create mode 100644 modules/core/c++/particle/schema.hpp (limited to 'modules/core/c++/particle') diff --git a/modules/core/c++/particle/aabb.hpp b/modules/core/c++/particle/aabb.hpp new file mode 100644 index 0000000..1773dea --- /dev/null +++ b/modules/core/c++/particle/aabb.hpp @@ -0,0 +1,55 @@ +#pragma once + +#include "common.hpp" +#include "schema.hpp" + +namespace kel { +namespace lbm { +template +class particle_aabb final { + static_assert(saw::always_false, "Not supported"); +}; + +template +class particle_aabb< + sch::ParticleGroup> +> final { +public: + using Schema = sch::ParticleGroup>; + + using AABB = sch::Struct< + sch::Member,"a">, + sch::Member,"b"> + >; +public: + template + static constexpr saw::data calculate(const saw::data& p_grp, const saw::data>& i, const saw::data>& meta){ + + saw::data aabb; + auto& parts = p_grp.template get<"particles">(); + + auto& pi = parts.at(i); + auto& pirb = pi.template get<"rigid_body">(); + auto& pirb_pos = pirb.template get<"position">(); + + auto& a = aabb.template get<"a">(); + auto& b = aabb.template get<"b">(); + + const saw::data>& rad_d = p_grp.template get<"collision">().template get<"radius">().at({0u}); + + saw::data> lower; + saw::data> upper; + + for(uint64_t i{0u}; i < D; ++i){ + lower.at({{i}}) = pirb_pos.at({{i}}) >= rad_d.at({}) ? (pirb_pos.at({{i}}) - rad_d.at({})) : saw::data{0}; + a.at({i}) = lower.at({{i}}).template cast_to(); + upper.at({{i}}) = pirb_pos.at({{i}}) + rad_d.at({}); + b.at({i}) = (upper.at({{i}})+saw::data{1}).template cast_to(); + } + + return aabb; + + } +}; +} +} diff --git a/modules/core/c++/particle/blur.hpp b/modules/core/c++/particle/blur.hpp new file mode 100644 index 0000000..b7a1988 --- /dev/null +++ b/modules/core/c++/particle/blur.hpp @@ -0,0 +1,37 @@ +#pragma once + +namespace kel { +namespace lbm { +template +void blur_mask(saw::data>& p_mask){ + + saw::data mid{2.0/3.0}; + saw::data edge{1.0/6.0}; + + // saw::data,2u> blur_weights{{2.0/3.0},{1.0/6.0}}; + + auto meta = p_mask.dims(); + saw::data> blurred_mask{meta}; + + /* 1D blur into N-D Blur*/ + for(saw::data i{0u}; i < saw::data{D}; ++i){ + iterator::apply([&](const auto& index){ + blurred_mask.at(index) = p_mask.at(index) * mid; + + if(index.at({i}).get() > 0u){ + auto l_ind = index; + l_ind.at({i}) = ind.at({i}) - 1u; + blurred_mask.at(index) = blurred_mask.at(index) + p_mask.at(l_ind) * edge; + } + if((index.at({i}).get() + 1u) < meta.at({i})){ + auto r_ind = index; + r_ind.at({i}) = ind.at({i}) + 1u; + blurred_mask.at(index) = blurred_mask.at(index) + p_mask.at(r_ind) * edge; + } + },{},meta); + + p_mask = blurred_mask; + } +} +} +} diff --git a/modules/core/c++/particle/common.hpp b/modules/core/c++/particle/common.hpp new file mode 100644 index 0000000..9e673c2 --- /dev/null +++ b/modules/core/c++/particle/common.hpp @@ -0,0 +1,3 @@ +#pragma once + +#include "../common.hpp" diff --git a/modules/core/c++/particle/geometry/circle.hpp b/modules/core/c++/particle/geometry/circle.hpp new file mode 100644 index 0000000..cf9b87e --- /dev/null +++ b/modules/core/c++/particle/geometry/circle.hpp @@ -0,0 +1,85 @@ +#pragma once + +#include "../particle.hpp" + +namespace kel { +namespace lbm { + +template +class particle_circle_geometry { +private: +public: + particle_circle_geometry() + {} + + template + saw::data> generate_mask(uint64_t resolution, uint64_t boundary_nodes = 0) const { + saw::data> mask; + + auto& grid = mask.template get<"grid">(); + auto& com = mask.template get<"center_of_mass">(); + com = {}; + + //uint64_t rad_i = static_cast(resolution * radius_.get())+1u; + uint64_t diameter_i = resolution; + uint64_t size = diameter_i + 2*boundary_nodes; + grid = {{{size,size}}}; + + saw::data delta_x{static_cast::type>(2.0 / static_cast(diameter_i))}; + saw::data center = (saw::data{1.0} + saw::data{2.0} * saw::data{static_cast::type>(boundary_nodes)/diameter_i}); + + saw::data> boundary_arr; + for(uint64_t i = 0u; i < D; ++i){ + boundary_arr.set(boundary_nodes); + } + + iterator::apply([&](const auto& index){ + grid.at(index).set(0); + }, {}, grid.dims()); + + iterator::apply([&](const auto& index){ + saw::data> f_ind; + for(uint64_t i = 0u; i < D; ++i){ + f_ind.at({{i}}) = (index.at({{i}}) + 0.5) * delta_x - center; + } + + auto norm_f_ind = saw::math::norm(f_ind); + }, {}, grid.dims(),boundary_arr); + + for(uint64_t i = 0; i < size; ++i){ + for(uint64_t j = 0; j < size; ++j){ + grid.at({{i,j}}).set(0); + if(i >= boundary_nodes and j >= boundary_nodes and i < (diameter_i + boundary_nodes) and j < (diameter_i + boundary_nodes) ){ + saw::data fi = saw::data{static_cast::type>(0.5+i)} * delta_x - center; + saw::data fj = saw::data{static_cast::type>(0.5+j)} * delta_x - center; + + auto norm_f_ij = fi*fi + fj*fj; + if(norm_f_ij.get() <= 1){ + grid.at({{i,j}}).set(1); + } + } + } + } + + // I don't fully remember what this did + saw::data total_mass{}; + iterator::apply::apply([&](const saw::data>& index){ + auto ind_vec = saw::math::vectorize_data(index).template cast_to(); + for(uint64_t i{0u}; i < D; ++i){ + ind_vec.at({{i}}) = ind_vec.at({{i}}) * grid.at(index); + } + com = com + ind_vec; + + total_mass = total_mass + grid.at(index); + },{}, grid.dims()); + + for(uint64_t i{0u}; i < D; ++i){ + com.at({{i}}) = com.at({{i}}) / total_mass; + } + + return mask; + } +}; + +} +} diff --git a/modules/core/c++/particle/geometry/cube.hpp b/modules/core/c++/particle/geometry/cube.hpp new file mode 100644 index 0000000..6392de8 --- /dev/null +++ b/modules/core/c++/particle/geometry/cube.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "../particle.hpp" + +namespace kel { +namespace lbm { +template +class particle_cubic_geometry { +private: +public: + template + saw::data> generate_mask(uint64_t resolution, uint64_t bound_nodes = 0u){ + + saw::data> mask; + + auto& grid = mask.template get<"grid">(); + auto& com = mask.template get<"center_of_mass">(); + + + } +} +} diff --git a/modules/core/c++/particle/particle.hpp b/modules/core/c++/particle/particle.hpp new file mode 100644 index 0000000..8e75e5a --- /dev/null +++ b/modules/core/c++/particle/particle.hpp @@ -0,0 +1,246 @@ +#pragma once + +#include +#include +#include + +#include "../iterator.hpp" + +#include "schema.hpp" +#include "aabb.hpp" +#include "particle_opa.hpp" + +namespace kel { +namespace lbm { + +template +saw::data>> create_spheroid_particle_group( + saw::data> radius_p, + saw::data> density_p, + const saw::data& mask_resolution +){ + saw::data>> part; + + auto& rad_s = part.template get<"collision">().at({0u}).template get<"radius">(); + rad_s = radius_p; + + auto& mask = part.template get<"mask">(); + auto& density = part.template get<"density">().at({{0u}}); + + auto& total_mass = part.template get<"total_mass">().at({{0u}}); + // Paranoia + total_mass.at({}) = {}; + + static_assert(D >= 1u and D <= 3u, "Dimensions only supported for Dim 1,2 & 3."); + density = density_p; + + saw::data> mask_dims; + for(uint64_t i = 0u; i < D; ++i){ + mask_dims.at({i}) = mask_resolution; + } + saw::data rad_d = radius_p.at({}); + saw::data dia_d = rad_d * 2; + + mask = {mask_dims}; + + auto& mask_step = part.template get<"mask_step">().at({{0u}}); + mask_step.at({}) = dia_d / mask_resolution.template cast_to(); + + auto& com = part.template get<"center_of_mass">().at({{0u}}); + // Paranoia + for(uint64_t i = 0u; i < D; ++i){ + com.at({{i}}) = {}; + } + saw::data ele_ctr{0u}; + + // Radius ^ 2 + saw::data> rad_2_d; + rad_2_d.at({}) = rad_d * rad_d; + + saw::data> center; + for(uint64_t i = 0u; i < D; ++i){ + center.at({{i}}) = rad_d; + } + + iterator::apply([&](const auto& index){ + ++ele_ctr; + + saw::data> offset_index = saw::math::vectorize_data(index).template cast_to() - center; + + auto& dpi = mask.at(index); + + for(uint64_t i = 0u; i < D; ++i){ + com.at({{i}}) = com.at({{i}}) + index.at({i}).template cast_to() * dpi; + } + + total_mass.at({}) = total_mass.at({}) + dpi; + + },{},mask_dims); + + for(uint64_t i = 0u; i < D; ++i){ + com.at({{i}}) = com.at({{i}}) / total_mass.at({}); + } + return part; +} + +/* +template +saw::data>> create_spheroid_particle( + saw::data> pos_p, + saw::data> vec_p, + saw::data> acc_p, + saw::data> rot_pos_p, + saw::data> rot_vel_p, + saw::data> rot_acc_p, + saw::data> rad_p, + saw::data> density_p, + saw::data> dt + ){ + + saw::data> part; + auto& body = part.template get<"rigid_body">(); + auto& mass = part.template get<"mass">(); + + auto& pos = body.template get<"position">(); + auto& pos_old = body.template get<"position_old">(); + auto& acc = body.template get<"acceleration">(); + + auto& rot = body.template get<"rotation">(); + auto& rot_old = body.template get<"rotation_old">(); + + auto& coll = part.template get<"collision">(); + auto& rad = coll.template get<"radius">(); + + pos = pos_p; + pos_old = pos - vec_p * dt; + acc = acc_p; + rad = rad_p; + + if constexpr ( D == 1u){ + saw::data> c; + c.at({}).set(2.0); + mass = rad_p * c * density_p; + } else if constexpr ( D == 2u){ + saw::data> pi; + pi.at({}).set(3.14159); + mass = rad_p * rad_p * pi * density_p; + } else if constexpr ( D == 3u ){ + saw::data> c; + c.at({}).set(3.14159 * 4.0 / 3.0); + mass = rad_p * rad_p * rad_p * c * density_p; + } else { + static_assert(D == 0u or D > 3u, "Dimensions only supported for Dim 1,2 & 3."); + } + + return part; +} +*/ + +template +constexpr auto verlet_step_lambda = [](saw::data>& particle, saw::data> time_step_delta){ + auto& body = particle.template get<"rigid_body">(); + + auto& pos = body.template get<"position">(); + auto& pos_old = body.template get<"position_old">(); + + auto& pos_acc = body.template get<"acceleration">(); + + auto& rot = body.template get<"rotation">(); + auto& rot_old = body.template get<"rotation_old">(); + + auto& rot_acc = body.template get<"angular_acceleration">(); + + auto tsd_squared = time_step_delta * time_step_delta; + + saw::data> pos_new; + // Actual step + saw::data> two; + two.at({}).set(2.0); + pos_new = pos * two - pos_old + pos_acc * tsd_squared; + + // Angular + saw::data::Schema> rot_new; + rot_new = rot * two - rot_old + rot_acc * tsd_squared; + + // Swap - Could be std::swap? + pos_old = pos; + pos = pos_new; + + rot_old = rot; + rot = rot_new; +}; + +template +constexpr auto handle_collision = []( + saw::data>& left, const saw::data>& mass_l, + saw::data>& right, const saw::data>& mass_r, + saw::data> unit_pos_rel, saw::data> vel_rel, + saw::data> d_t +){ + auto& rb_l = left.template get<"rigid_body">(); + auto& pos_l = rb_l.template get<"position">(); + auto& pos_old_l = rb_l.template get<"position_old">(); + auto vel_l = (pos_l-pos_old_l)/d_t; + + auto& rb_r = right.template get<"rigid_body">(); + auto& pos_r = rb_r.template get<"position">(); + auto& pos_old_r = rb_r.template get<"position_old">(); + auto vel_r = (pos_r-pos_old_r)/d_t; + + auto vel_pos_rel_dot = saw::math::dot(unit_pos_rel,vel_rel); + + if( vel_pos_rel_dot.at({{0u}}).get() < 0.0 ){ + pos_l = pos_l + vel_rel * unit_pos_rel * d_t; + pos_r = pos_r - vel_rel * unit_pos_rel * d_t; + } +}; + + +template +constexpr auto broadphase_collision_distance_squared = []( + saw::data>& left, + const saw::data& coll_l, + saw::data>& right, + const saw::data& coll_r +) -> std::pair>>{ + + auto rad_l = coll_l.template get<"radius">(); + auto rad_r = coll_r.template get<"radius">(); + + auto& rb_l = left.template get<"rigid_body">(); + auto& rb_r = right.template get<"rigid_body">(); + + 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); + + saw::data> two; + two.at({}) = 2.0; + auto rad_ab_2 = rad_l * rad_l + rad_r * rad_r + rad_r * rad_l * two; + + return std::make_pair((norm_2.at({}).get() < rad_ab_2.at({}).get()), norm_2); +}; +/** +* +* +*/ +template +constexpr auto broadphase_collision_check = []( + saw::data>& left, + const saw::data& coll_l, + saw::data>& right, + const saw::data& coll_r +) -> bool{ + return broadphase_collision_distance_squared(left,coll_l,right,coll_r).first; +}; + + + +namespace impl { +} + +} +} diff --git a/modules/core/c++/particle/particle_opa.hpp b/modules/core/c++/particle/particle_opa.hpp new file mode 100644 index 0000000..a5e6c28 --- /dev/null +++ b/modules/core/c++/particle/particle_opa.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "../component.hpp" +#include "common.hpp" +#include "schema.hpp" +#include "porosity.hpp" + +namespace kel { +namespace lbm { +namespace cmpt { +struct OneParticleAt {}; +} + +template + +class component final { +private: + saw::data> pos_; + saw::data> rad_; + saw::data> eps_; +public: + component( + const saw::data> pos__, + const saw::data> rad__, + const saw::data> eps__ + ): + pos_{pos__}, + rad_{rad__}, + eps_{eps__} + {} + + template + void apply(const saw::data& macros, const saw::data> index, saw::data time_step) const { + using dfi = df_info; + + auto& porous_f = macros.template get<"porosity">(); + + auto& porous = porous_f.at(index); + + auto pos_ind = saw::math::vectorize_data(index); + + // Write out value + auto diff = pos_ind.template cast_to() - pos_; + auto diff_dot = saw::math::dot(diff,diff); + porous = particle_porosity>::calculate(diff, rad_, eps_); + } +}; +} +} diff --git a/modules/core/c++/particle/porosity.hpp b/modules/core/c++/particle/porosity.hpp new file mode 100644 index 0000000..2f39d2e --- /dev/null +++ b/modules/core/c++/particle/porosity.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include "common.hpp" +#include "schema.hpp" +#include "../math/n_closest.hpp" + +namespace kel { +namespace lbm { +namespace por { +template +struct ParticleSpheroid {}; +} + +template +class particle_porosity { +public: + + static saw::data> calculate(const saw::data>& part_group, uint64_t p_i, const saw::data>& lbm_pos){ + auto& mask = part_group.template get<"mask">(); + + auto& particles = part_group.template get<"particles">(); + auto& part_i = particles.at({p_i}); + + auto& part_i_rb = part_i.template get<"rigid_body">(); + auto& pirb = part_i_rb.template get<"position">(); + + auto dist = lbm_pos - pirb; + + // index 0 is at + + return {}; + } +}; + +template +class particle_porosity> final { +public: + static saw::data> calculate(const saw::data>& lbm_rel_dist, saw::data> rad, saw::data> eps){ + saw::data> por; + + auto s_dist_2 = saw::math::dot(lbm_rel_dist,lbm_rel_dist); + auto s_dist = saw::math::sqrt(s_dist_2); + + saw::data> eps_h; + eps_h.at({}) = eps.at({}).get() / 2; + + auto rad_low = rad - eps_h; + auto rad_high = rad + eps_h; + + if(s_dist.at({}) <= rad_low.at({})){ + por.at({}).set(0); + return por; + } + if(s_dist.at({}) >= rad_high.at({})){ + por.at({}).set(1); + return por; + } + + { + typename saw::native_data_type::type inner = (std::numbers::pi / ( 2 * eps.at({}).get() )) * (s_dist - rad_low).at({}).get(); + auto cos_inner = std::sin(inner); + auto cos_i_2 = cos_inner * cos_inner; + por.at({}).set(cos_i_2); + } + + return por; + } +}; + + +template +class particle_porosity> final { +public: + static saw::data> calculate(const saw::data > >& part_group, uint64_t i, const saw::data>& lbm_pos) { + saw::data> por; + + auto& parts = part_group.template get<"particles">(); + auto& pi = parts.at({i}); + auto& pi_rb = pi.template get<"rigid_body">(); + + auto& pi_rb_pos = pi_rb.template get<"position">(); + + // Basically the queried position minus the center of the particle + auto dist = lbm_pos - pi_rb_pos; + + saw::data> dist_len = saw::math::dot(dist,dist); + dist_len.at({}).set(std::sqrt(dist_len.at({}).get())); + + auto& coll = part_group.template get<"collision">(); + const saw::data>& rad_d = coll.template get<"radius">(); + const auto& eps = part_group.template get<"epsilon">(); + // Move this somewhere + + saw::data> eps_h; + eps_h.at({}) = eps.at({}).get() / 2; + + saw::data> rad_d_eps_p = rad_d + eps_h; + saw::data> rad_d_eps_n = rad_d - eps_h; + + // saw::data> rad_d_eps_p_2 = rad_d_eps_p * rad_d_eps_p; + // saw::data> rad_d_eps_n_2 = rad_d_eps_n * rad_d_eps_n; + // saw::data> rad_2; + // rad_2 = rad_d * rad_d; + + saw::data> inside; + if(dist_len.at({}) <= rad_d_eps_n.at({})){ + inside.at({}).set(0); + return inside; + } + if(dist_len.at({}) > rad_d_eps_p.at({})){ + inside.at({}).set(1); + return inside; + } + + /* + * cos^2 ( ||x-X(t)||_2 - (R-eps/2) ) + */ + { + typename saw::native_data_type::type inner = (std::numbers::pi / (eps)) * (dist_len - rad_d_eps_n).at({}).get(); + auto cos_inner = std::cos(inner); + auto cos_i_2 = cos_inner * cos_inner; + inside.at({}).set(cos_i_2); + } + return inside; + } +}; + +} +} diff --git a/modules/core/c++/particle/schema.hpp b/modules/core/c++/particle/schema.hpp new file mode 100644 index 0000000..714a16f --- /dev/null +++ b/modules/core/c++/particle/schema.hpp @@ -0,0 +1,68 @@ +#pragma once + +#include "common.hpp" + +namespace kel { +namespace lbm { + +namespace coll { +template +struct Spheroid { + using ValueSchema = T; + using Schema = sch::Struct< + sch::Member,"radius"> + >; +}; +} + +namespace sch { +using namespace saw::schema; + +namespace impl { +template +struct rotation_type_helper; + +template +struct rotation_type_helper { + using Schema = Scalar; +}; + +template +struct rotation_type_helper { + using Schema = Vector; +}; +} + +template +using ParticleRigidBody = Struct< + Member, "position">, + Member, "position_old">, + Member::Schema, "rotation">, + Member::Schema, "rotation_old">, + + Member, "acceleration">, + Member::Schema, "angular_acceleration"> +>; + + +template +using Particle = Struct< + Member, "rigid_body"> + // Problem is that dynamic data would two layered + // Member, "mask">, +>; + +template> +using ParticleGroup = Struct< + Member, "mask">, + Member, "collision">, + Member,1u>, "epsilon">, + Member,1u>, "mask_step">, + Member,1u>, "density">, + Member,1u>, "center_of_mass">, + Member,1u>, "total_mass">, + Member,1u>, "particles"> +>; +} +} +} -- cgit v1.2.3