#pragma once #include "macroscopic.hpp" #include "component.hpp" #include "equilibrium.hpp" #include "particle/particle.hpp" #include namespace kel { namespace lbm { namespace cmpt { struct HlbmReset {}; struct Hlbm {}; struct HlbmOneParticle {}; struct HlbmParticle {}; struct HlbmOneParticleMomentumExchange {}; } template class component final { public: component() = default; template void apply(const saw::data& field, const saw::data& macros, saw::data> index, saw::data time_step) const { auto& porosity_f = macros.template get<"porosity">(); auto& particle_N_f = field.template get<"particle_N">(); auto& particle_D_f = field.template get<"particle_D">(); auto& por = porosity_f.at(index); por.at({}) = 1.0; auto& pnf = particle_N_f.at(index); for(uint64_t i{0u}; i < Descriptor::D; ++i){ pnf.at({{i}}) = 0.0; } auto& pnd = particle_D_f.at(index); pnd.at({}) = 0.0; } }; /** * HLBM collision operator for LBM */ template class component final { private: typename saw::native_data_type::type relaxation_; saw::data frequency_; public: component(typename saw::native_data_type::type relaxation__): relaxation_{relaxation__}, frequency_{typename saw::native_data_type::type(1) / relaxation_} {} template void apply(const saw::data& field, const saw::data& macros, saw::data> index, saw::data time_step) const { bool is_even = ((time_step.get() % 2) == 0); auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); auto& particle_N_f = field.template get<"particle_N">(); auto& particle_D_f = field.template get<"particle_D">(); auto& porosity_f = macros.template get<"porosity">(); auto& rho_f = macros.template get<"density">(); auto& vel_f = macros.template get<"velocity">(); saw::data>& rho = rho_f.at(index); saw::data>& vel = vel_f.at(index); compute_rho_u(dfs_old_f.at(index), rho, vel); auto& porosity = porosity_f.at(index); saw::data> one; one.at({}) = 1.0; auto flip_porosity = one - porosity; auto& N = particle_N_f.at(index); auto& D = particle_D_f.at(index); // Convex combination of velocities vel = vel * porosity + [&]() -> saw::data> { return (D.at({}).get() > 0.0) ? ( N * flip_porosity / D ): N; }(); // Equilibrium auto eq = equilibrium(rho,vel); for(uint64_t i = 0u; i < Desc::Q; ++i){ dfs_old_f.at(index).at({i}) = dfs_old_f.at(index).at({i}) + frequency_ * (eq.at(i) - dfs_old_f.at(index).at({i})); } } }; template class component final { private: /* template void apply_i(const saw::data& field, const saw::data& macros, const saw::data& part_groups, saw::data> index, saw::data time_step) const { // if constexpr ( i < ) } */ public: template void apply(const saw::data& field, const saw::data& macros, const saw::data& part_group, saw::data> index, saw::data time_step, saw::data sub_steps) const { /// Figure out how to access the particle list // auto& p = particles.at(i); /// Iterate over the grid bounds // auto& grid = p.template get<"grid">(); using dfi = df_info; bool is_even = ((time_step.get() % 2) == 0); saw::data> one; one.at({}) = 1.0; 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& mrho_f = macros.template get<"density">(); auto& mpor_f = macros.template get<"porosity">(); auto& particle_N_f = field.template get<"particle_N">(); auto& particle_D_f = field.template get<"particle_D">(); { auto parts = part_spheroid_group.template get<"particles">(); auto parts_size = parts.meta().at({0u}); auto& p_coll = part_spheroid_group.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>& pirb_pos = pirb.template get<"position">(); auto& pirb_pos_old = pirb.template get<"position_old">(); // TODO !!!! Divide by actual time step - for now it's ok saw::data> ts; ts.at({}) = one.at({}) / sub_steps.template cast_to(); saw::data> start; saw::data> stop; auto eo_aabb = particle_aabb::calculate(part_spheroid_group,{{0u}},mvel_f.meta()); if(eo_aabb.is_error()){ return; } auto& aabb = eo_aabb.get_value(); /// 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">(); saw::data> force_p; for(uint64_t i{0u}; i < Desc::D; ++i){ force_p.at({{i}}) = 0.0; } auto vel_p_old = (pirb_pos-pirb_pos_old) / ts; iterator::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: "<> rel_dist = saw::math::vectorize_data(index_f).template cast_to() - pirb_pos; saw::data> eps; eps.at({}) = 1.5f; auto& mpor = mpor_f.at(index_f); mpor = particle_porosity>::calculate(rel_dist,p_rad,eps); if(mpor.at({}).get() >= 1.0f){ return; } saw::data> momentum; for(uint64_t i{0u}; i < Desc::D; ++i){ momentum.at({{i}}) = 0.0; } for(uint64_t i{0u}; i < Desc::Q; ++i){ saw::data> e_i; saw::data> n_ind_i; for(uint64_t k{0u}; k < Desc::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 dfs_added = dfs.at({i})*(saw::data{1}-u_p_e.at({})) + dfs_old_f.at(n_ind_i).at({i_opp})*(saw::data{1}+u_p_e.at({})); saw::data> 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& rho = mrho_f.at(index_f); force_p = force_p + momentum; },start,stop); auto& pirb_acc = pirb.template get<"acceleration">(); pirb_acc = - force_p / part_spheroid_group.template get<"total_mass">().at({}); for(saw::data i{0u}; i < sub_steps; ++i){ verlet_step_lambda(pi,ts); } auto vel_p = (pirb_pos-pirb_pos_old) / ts; iterator::apply([&](const auto& index_f){ auto& N = particle_N_f.at(index_f); auto& D = particle_D_f.at(index_f); auto& mpor = mpor_f.at(index_f); auto flip_porosity = one - mpor; D = D + flip_porosity; N = N + vel_p * flip_porosity; },start,stop); // Check } } }; template class component final { public: template void apply(const saw::data& field, const saw::data& macros, saw::data> index, saw::data time_step) const { // using dfi = df_info; bool is_even = ((time_step.get() % 2) == 0); auto& dfs_old_f = (is_even) ? field.template get<"dfs_old">() : field.template get<"dfs">(); auto& dfs = dfs_old_f.at(index); saw::data> momentum; for(uint64_t i = 0u; i < Desc::Q; ++i){ saw::data> e_i; saw::data> n_ind_i; for(uint64_t k{0u}; k < Desc::D; ++k){ e_i.at({{k}}) = dfi::directions[i][k]; n_ind_i.at({k}) = (dfi::directions[i])[k]; } uint64_t i_opp = dfi::opposite_index[i]; saw::data dfs_added = dfs.at({i}) - dfs_old_f.at(n_ind_i).at({i_opp}); saw::data> dfs_added_v; dfs_added_v.at({}) = dfs_added; auto ei_dfs = e_i * dfs_added_v; momentum = momentum + ei_dfs; } auto& force_f = macros.template get<"force">(); // Set Force force_f.at(index) = momentum * macros.template get<"porosity">().at(index); } }; } }