#pragma once #include "common.hpp" #include "particle/particle.hpp" #include "iterator.hpp" namespace kel { namespace lbm { namespace cmpt { struct FpLbmReset{}; struct FpLbm {}; struct FpLbmOneParticle {}; struct FpLbmOneParticleImplicit {}; struct FpLbmOneParticleNoVelocity{}; } namespace method { struct FpLbm {}; } template class component final { public: using Component = cmpt::FpLbmReset; private: public: component() = default; template void apply(const saw::data& field, const saw::data& macros, saw::data> index, saw::data time_step) const { auto& por_f = macros.template get<"porosity">(); auto& por = por_f.at(index); por.at({}) = 1.0; auto& force_f = macros.template get<"force">(); auto& force = force_f.at(index); for(uint64_t i{0u}; i < Descriptor::D; ++i){ force.at({{i}}) = 0.0; } auto info = field.template get<"info">().at(index).get(); if(info == 2u){ 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); auto& rho_f = macros.template get<"density">(); auto& rho = rho_f.at(index); auto& vel_f = macros.template get<"velocity">(); auto& vel = vel_f.at(index); compute_rho_u(dfs,rho,vel); } } }; template class component final { private: saw::data relaxation_; saw::data frequency_; public: component(typename saw::native_data_type::type relaxation__): relaxation_{{relaxation__}}, frequency_{saw::data{1} / relaxation_} {} component(const saw::data& relaxation__): relaxation_{relaxation__}, frequency_{saw::data{1} / relaxation_} {} using Component = cmpt::FpLbm; 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& dfs = dfs_old_f.at(index); auto& rho_f = macros.template get<"density">(); saw::data>& rho = rho_f.at(index); auto& vel_f = macros.template get<"velocity">(); saw::data>& vel = vel_f.at(index); // compute_rho_u(dfs,rho,vel); auto eq = equilibrium(rho,vel); using dfi = df_info; auto& force_f = macros.template get<"force">(); auto& force = force_f.at(index); auto& por_f = macros.template get<"porosity">(); auto& por = por_f.at(index); saw::data> dfi_inv_cs2; dfi_inv_cs2.at({}).set(dfi::inv_cs2); for(uint64_t i{0u}; i < Descriptor::Q; ++i){ saw::data> ci; for(uint64_t d{0u}; d < Descriptor::D; ++d){ ci.at({{d}}).set(static_cast::type>(dfi::directions[i][d])); } auto ci_dot_u = saw::math::dot(ci,vel); saw::data> w; w.at({}).set(dfi::weights[i]); auto term1 = (ci-vel) * dfi_inv_cs2; auto term2 = ci * (ci_dot_u * dfi_inv_cs2 * dfi_inv_cs2); auto force_projection = saw::math::dot(term1 + term2, force); auto F_i = w * force_projection; dfs.at({i}) = dfs.at({i}) + frequency_ * (eq.at(i) - dfs.at({i}) ) + F_i.at({}) * (saw::data{1} - saw::data{0.5f} * frequency_); } } }; template class component final { public: using Component = cmpt::FpLbmOneParticle; private: public: component() = default; template void apply(const saw::data& field, const saw::data& macros, const saw::data& pg, saw::data> index, saw::data time_step, saw::data sub_steps) const { // void apply(saw::data& field, saw::data> index, saw::data time_step){ 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); auto& rho_f = macros.template get<"density">(); auto& vel_f = macros.template get<"velocity">(); auto& por_f = macros.template get<"porosity">(); auto& force_f = macros.template get<"force">(); /** * The other methods all work with a flipped porosity. * For compat reasons this is also flipped */ // TODO - Change to tuple later auto parts = pg.template get<"particles">(); auto parts_size = parts.meta().at({0u}); auto& pi = parts.at(index); auto& pirb = pi.template get<"rigid_body">(); auto& pirb_pos = pirb.template get<"position">(); auto& pirb_pos_old = pirb.template get<"position_old">(); auto& p_coll = pg.template get<"collision">().at({}); auto& p_rad = p_coll.template get<"radius">(); auto eo_aabb = particle_aabb::calculate(pg,{{0u}},vel_f.meta()); if(eo_aabb.is_error()){ return; } auto& aabb = eo_aabb.get_value(); saw::data> two; two.at({}).set(2.0f); saw::data> one; one.at({}) = 1.0; saw::data> eps; eps.at({}) = 1.5f; saw::data> sss; sss.at({}) = one.at({}) / sub_steps.template cast_to(); auto vel_s = (pirb_pos-pirb_pos_old) / sss; saw::data> force_p{}; iterator::apply([&](const auto& index_f) -> void { auto& force = force_f.at(index_f); auto& vel = vel_f.at(index_f); auto& por = por_f.at(index_f); auto& rho = rho_f.at(index_f); saw::data> rel_dist = saw::math::vectorize_data(index_f).template cast_to() - pirb_pos; por = particle_porosity>::calculate(rel_dist,p_rad,eps); auto flip_por = one - por; // vel_s is technically time the density of the particle? force = ( vel_s * rho - vel * rho ) * two * flip_por; force_p = force_p - force; }, aabb.template get<"a">(), aabb.template get<"b">()); auto& pirb_acc = pirb.template get<"acceleration">(); pirb_acc = force_p / pg.template get<"total_mass">().at({}); for(saw::data i{0u}; i < sub_steps; ++i){ //verlet_step_lambda(pi,sss); } } }; template class component final { public: using Component = cmpt::FpLbmOneParticle; private: public: component() = default; template void apply(const saw::data& field, const saw::data& macros, const saw::data& pg, saw::data> index, saw::data time_step, saw::data sub_steps) const { // void apply(saw::data& field, saw::data> index, saw::data time_step){ 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); auto& rho_f = macros.template get<"density">(); auto& vel_f = macros.template get<"velocity">(); auto& por_f = macros.template get<"porosity">(); auto& force_f = macros.template get<"force">(); /** * The other methods all work with a flipped porosity. * For compat reasons this is also flipped */ // TODO - Change to tuple later auto parts = pg.template get<"particles">(); auto parts_size = parts.meta().at({0u}); auto& pi = parts.at(index); auto& pirb = pi.template get<"rigid_body">(); auto& pirb_pos = pirb.template get<"position">(); auto& pirb_pos_old = pirb.template get<"position_old">(); auto& p_coll = pg.template get<"collision">().at({}); auto& p_rad = p_coll.template get<"radius">(); auto eo_aabb = particle_aabb::calculate(pg,{{0u}},vel_f.meta()); if(eo_aabb.is_error()){ return; } auto& aabb = eo_aabb.get_value(); saw::data> two; two.at({}).set(2.0f); saw::data> one; one.at({}) = 1.0; saw::data> eps; eps.at({}) = 1.5f; saw::data> sss; sss.at({}) = one.at({}) / sub_steps.template cast_to(); auto vel_s = (pirb_pos-pirb_pos_old) / sss; saw::data> force_p{}; iterator::apply([&](const auto& index_f) -> void { auto& force = force_f.at(index_f); auto& vel = vel_f.at(index_f); auto& por = por_f.at(index_f); auto& rho = rho_f.at(index_f); saw::data> rel_dist = saw::math::vectorize_data(index_f).template cast_to() - pirb_pos; por = particle_porosity>::calculate(rel_dist,p_rad,eps); auto flip_por = one - por; // vel_s is technically time the density of the particle? force = ( vel_s * rho - vel * rho ) * flip_por / (one + flip_por / two); // force = ( vel_s * rho - vel * rho ) * two * flip_por; force_p = force_p - force; }, aabb.template get<"a">(), aabb.template get<"b">()); auto& pirb_acc = pirb.template get<"acceleration">(); pirb_acc = force_p / pg.template get<"total_mass">().at({}); for(saw::data i{0u}; i < sub_steps; ++i){ verlet_step_lambda(pi,sss); } } }; template class component final { private: saw::data relaxation_; saw::data frequency_; public: component(typename saw::native_data_type::type relaxation__): relaxation_{{relaxation__}}, frequency_{saw::data{1} / relaxation_} {} component(const saw::data& relaxation__): relaxation_{relaxation__}, frequency_{saw::data{1} / relaxation_} {} using Component = cmpt::FpLbmOneParticleNoVelocity; template void apply(const saw::data& field, const saw::data& macros, saw::data> index, saw::data time_step) const { // void apply(saw::data& field, saw::data> index, saw::data time_step){ 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); auto& rho_f = macros.template get<"density">(); auto& vel_f = macros.template get<"velocity">(); auto& por_f = macros.template get<"porosity">(); // Temporary find a better way auto& force_f = macros.template get<"force">(); /** * The other methods all work with a flipped porosity. * For compat reasons this is also flipped */ auto porosity = por_f.at(index); saw::data> one; one.at({}) = 1.0; auto flip_porosity = one - porosity; saw::data>& rho = rho_f.at(index); saw::data> half; half.at({}).set(0.5); saw::data>& vel = vel_f.at(index);// + total_force * ( half / rho ); compute_rho_u(dfs_old_f.at(index),rho,vel); auto eq = equilibrium(rho,vel); using dfi = df_info; saw::data> min_two; min_two.at({}).set(-2); auto& force = force_f.at(index); force = vel * rho * min_two * flip_porosity; saw::data> dfi_inv_cs2; dfi_inv_cs2.at({}).set(dfi::inv_cs2); for(uint64_t i = 0u; i < Descriptor::Q; ++i){ // saw::data ci_min_u{0}; saw::data> ci; for(uint64_t d = 0u; d < Descriptor::D; ++d){ ci.at({{d}}).set(static_cast::type>(dfi::directions[i][d])); } auto ci_dot_u = saw::math::dot(ci,vel); // saw::data> F_i; // F_i = f * ((c_i - u) * ics2 + * c_i * ics2 * ics2) * w_i; saw::data> w; w.at({}).set(dfi::weights[i]); /* saw::data> F_i_sum; for(uint64_t d = 0u; d < Descriptor::D; ++d){ saw::data> F_i_d; F_i_d.at({}) = F_i.at({{d}}); F_i_sum = F_i_sum + F_i_d; } */ auto term1 = (ci-vel) * dfi_inv_cs2; auto term2 = ci * (ci_dot_u * dfi_inv_cs2 * dfi_inv_cs2); auto force_projection = saw::math::dot(term1 + term2, force); auto F_i = w * force_projection; dfs.at({i}) = dfs.at({i}) + frequency_ * (eq.at(i) - dfs.at({i}) ) + F_i.at({}) * (saw::data{1} - saw::data{0.5f} * frequency_); } } }; } }