summaryrefslogtreecommitdiff
path: root/c++/examples/cavity_2d.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'c++/examples/cavity_2d.cpp')
-rw-r--r--c++/examples/cavity_2d.cpp357
1 files changed, 219 insertions, 138 deletions
diff --git a/c++/examples/cavity_2d.cpp b/c++/examples/cavity_2d.cpp
index 53f2f91..add5ad5 100644
--- a/c++/examples/cavity_2d.cpp
+++ b/c++/examples/cavity_2d.cpp
@@ -1,8 +1,11 @@
#include "../descriptor.h"
+/**
+ */
#include <forstio/codec/data.hpp>
#include <iostream>
+#include <cmath>
namespace kel {
namespace lbm {
@@ -20,12 +23,13 @@ using namespace saw::schema;
*/
using T = Float32;
using D2Q5 = Descriptor<2,5>;
+using D2Q9 = Descriptor<2,9>;
template<typename Desc>
using DfCell = Cell<T, Desc, 0, 0, 1>;
template<typename Desc>
-using CellInfo = Cell<UInt8, D2Q5, 1, 0, 0>;
+using CellInfo = Cell<UInt8, D2Q9, 1, 0, 0>;
/**
* Basic type for simulation
@@ -37,15 +41,77 @@ using CellStruct = Struct<
>;
-using CavityFieldD2Q5 = Field<D2Q5, CellStruct<D2Q5>>;
+using CavityFieldD2Q9 = Field<D2Q9, CellStruct<D2Q9>>;
+}
+
+/**
+ * Calculate the macroscopic variables rho and u in Lattice Units.
+ */
+template<typename Desc>
+void compute_rho_u (
+ saw::data<sch::DfCell<Desc>>& dfs,
+ typename saw::native_data_type<sch::T>::type& rho,
+ std::array<typename saw::native_data_type<sch::T>::type, 2>& vel
+ )
+{
+ using dfi = df_info<sch::T, Desc>;
+
+ rho = 0;
+ std::fill(vel.begin(), vel.end(), 0);
+
+ for(size_t i = 0; i < Desc::Q; ++i){
+ rho += dfs(i).get();
+ vel[0] += dfi::directions[i][0] * dfs(i).get();
+ vel[1] += dfi::directions[i][1] * dfs(i).get();
+ }
+
+ vel[0] /= rho;
+ vel[1] /= rho;
}
+/**
+ * Calculates the equilibrium for each direction
+ */
+template<typename Desc>
+std::array<typename saw::native_data_type<sch::T>::type,Desc::Q> equilibrium(
+ typename saw::native_data_type<sch::T>::type rho,
+ const std::array<typename saw::native_data_type<sch::T>::type, Desc::D>& vel
+){
+ using dfi = df_info<sch::T, Desc>;
+
+ typename std::array<saw::native_data_type<sch::T>::type,Desc::Q> eq;
+
+ for(std::size_t i = 0; i < eq.size(); ++i){
+ auto vel_c = (vel[0]*dfi::directions[i][0] + vel[1]*dfi::directions[i][1]);
+ auto vel_c_cs2 = vel_c * dfi::inv_cs2;
+ eq[i] = dfi::weights[i] * rho * (
+ 1
+ + vel_c_cs2
+ + vel_c_cs2 * vel_c_cs2 * 0.5
+ - dfi::inv_cs2 * 0.5 * ( vel[0] * vel[0] + vel[1] * vel[1] )
+ );
+ }
+
+ return eq;
+}
+
+/**
+ * A reason for why a component based design is really good can be seen in my LR solver example
+ *
+ * Add Expression Templates and you're golden.
+ */
+template<typename Kind, typename Desc>
+class component;
+
/*
template<typename T, typename Encode>
class df_cell_view;
*/
/**
- * Minor helper for the AA-Pull Pattern
+ * Minor helper for the AA-Pull Pattern, so I can use only one lattice
+ *
+ * Am I sure I want to use AA this way?
+ * Esoteric Twist technically reduces the needed memory access footprint
*/
/*
template<typename Desc, size_t SN, size_t DN, size_t QN, typename Encode>
@@ -60,9 +126,18 @@ public:
{}
};
*/
+namespace cmpt {
+struct BounceBack{};
+template<typename ColliderComponent>
+struct MovingWall {};
+struct BGK {};
+}
+/**
+ * Full-Way BounceBack. I suspect that the moving wall requires half-way bounce back.
+ */
template<typename Desc>
-class bounce_back {
+class component<cmpt::BounceBack,Desc> {
public:
void apply(saw::data<sch::DfCell<Desc>>& dfs){
@@ -77,104 +152,39 @@ public:
}
};
-template<typename Desc>
-class cavity_boundary {
+/**
+ * Full-Way moving wall Bounce back, something is not right here.
+ * Technically it should reflect properly.
+ */
+template<typename CollisionCmp, typename Desc>
+class component<cmpt::MovingWall<CollisionCmp>, Desc> {
public:
- std::array<typename saw::native_data_type<sch::T>::type, Desc::D> lid_vel;
+ component<CollisionCmp, Desc>* collision_;
+ std::array<typename saw::native_data_type<sch::T>::type, Desc::D> lid_vel;
public:
- void compute_rho_u(
- saw::data<sch::DfCell<Desc>>& dfs,
- typename saw::native_data_type<sch::T>::type& rho,
- std::array<typename saw::native_data_type<sch::T>::type, 2>& vel
- ){
- using dfi = df_info<sch::T, Desc>;
-
- rho = 0;
- std::fill(vel.begin(), vel.end(), 0);
-
- for(size_t i = 0; i < Desc::Q; ++i){
- rho += dfs(i).get();
- vel[0] += dfi::directions[i][0] * dfs(i).get();
- vel[1] += dfi::directions[i][1] * dfs(i).get();
- }
-
- vel[0] /= rho;
- vel[1] /= rho;
- }
-
void apply(
saw::data<sch::DfCell<Desc>>& dfs
){
using dfi = df_info<sch::T,Desc>;
+
+ collision_->apply(dfs);
// Technically use .copy()
- auto df_cpy = dfs;
-
- typename saw::native_data_type<sch::T>::type rho;
- std::array<typename saw::native_data_type<sch::T>::type, Desc::D> vel;
- compute_rho_u(dfs,rho,vel);
-
- for(uint64_t i = 1u; i < Desc::Q; ++i){
- dfs({i}) = df_cpy({dfi::opposite_index.at(i)}) - dfi::weights[i] * rho * ( lid_vel[0] * dfi::directions[i][0] + lid_vel[1] * dfi::directions[i][1]) / dfi::cs2;
- }
}
};
template<typename Desc>
-class collision {
+class component<cmpt::BGK, Desc> {
public:
typename saw::native_data_type<sch::T>::type relaxation_;
public:
-
- std::array<typename saw::native_data_type<sch::T>::type,Desc::Q> equilibrium(
- typename saw::native_data_type<sch::T>::type rho,
- const std::array<typename saw::native_data_type<sch::T>::type, Desc::D>& vel
- ){
- using dfi = df_info<sch::T, Desc>;
-
- typename std::array<saw::native_data_type<sch::T>::type,Desc::Q> eq;
-
- for(std::size_t i = 0; i < eq.size(); ++i){
- auto vel_c = (vel[0]*dfi::directions[i][0] + vel[1]*dfi::directions[i][1]);
- auto vel_c_cs2 = vel_c * dfi::inv_cs2;
- eq[i] = dfi::weights[i] * rho * (
- 1
- + vel_c_cs2
- + vel_c_cs2 * vel_c_cs2 * 0.5
- - dfi::inv_cs2 * 0.5 * ( vel[0] * vel[0] + vel[1] * vel[1] )
- );
- }
-
- return eq;
- }
-
- void compute_rho_u(
- saw::data<sch::DfCell<Desc>>& dfs,
- typename saw::native_data_type<sch::T>::type& rho,
- std::array<typename saw::native_data_type<sch::T>::type, 2>& vel
- ){
- using dfi = df_info<sch::T, Desc>;
-
- rho = 0;
- std::fill(vel.begin(), vel.end(), 0);
-
- for(size_t i = 0; i < Desc::Q; ++i){
- rho += dfs(i).get();
- vel[0] += dfi::directions[i][0] * dfs(i).get();
- vel[1] += dfi::directions[i][1] * dfs(i).get();
- }
-
- vel[0] /= rho;
- vel[1] /= rho;
- }
-
void apply(saw::data<sch::DfCell<Desc>>& dfs){
for(uint64_t i = 0u; i < Desc::Q; ++i){
typename saw::native_data_type<sch::T>::type rho;
std::array<typename saw::native_data_type<sch::T>::type, Desc::D> vel;
- compute_rho_u(dfs,rho,vel);
- auto eq = equilibrium(rho,vel);
+ compute_rho_u<Desc>(dfs,rho,vel);
+ auto eq = equilibrium<Desc>(rho,vel);
dfs({i}).set(dfs({i}).get() + (1.0 / relaxation_) * (eq[i] - dfs({i}).get()));
}
@@ -184,23 +194,12 @@ public:
}
constexpr size_t dim_size = 2;
-constexpr size_t dim_x = 64;
-constexpr size_t dim_y = 64;
+constexpr size_t dim_x = 128;
+constexpr size_t dim_y = 128;
-struct rectangle {
- std::array<size_t,4> data_;
-
- rectangle(size_t x, size_t y, size_t w, size_t h):
- data_{x,y,w,h}
- {}
-
- bool inside(size_t i, size_t j) const {
- return !(i < data_[0] || i > (data_[0]+data_[2]) || j < data_[1] || j > (data_[1] +data_[3]));
- }
-};
template<typename Func>
-void apply_for_cells(Func&& func, saw::data<kel::lbm::sch::CavityFieldD2Q5>& dat){
+void apply_for_cells(Func&& func, saw::data<kel::lbm::sch::CavityFieldD2Q9>& dat){
for(std::size_t i = 0; i < dat.template get_dim_size<0>().get(); ++i){
for(std::size_t j = 0; j < dat.template get_dim_size<1>().get(); ++j){
saw::data<saw::schema::UInt64> di{i};
@@ -211,57 +210,94 @@ void apply_for_cells(Func&& func, saw::data<kel::lbm::sch::CavityFieldD2Q5>& dat
}
}
-void set_geometry(saw::data<kel::lbm::sch::CavityFieldD2Q5>& latt){
+void set_geometry(saw::data<kel::lbm::sch::CavityFieldD2Q9>& latt){
using namespace kel::lbm;
apply_for_cells([](auto& cell, std::size_t i, std::size_t j){
uint8_t val = 0;
if(i == 1){
- val = 2u;
+ if( j > 2 && (j+3) < dim_y ){
+ val = 2u;
+ }else{
+ val = 3u;
+ }
}
if(j == 1 || (i+2) == dim_x || (j+2) == dim_y){
val = 3u;
}
if(i == 0 || j == 0 || (i+1) == dim_x || (j+1) == dim_y){
+ val = 0u;
+ }
+ if(i > 1 && (i+2) < dim_x && j > 1 && (j+2) < dim_y){
val = 1u;
}
cell.template get<"info">()(0u).set(val);
}, latt);
}
-void set_initial_conditions(saw::data<kel::lbm::sch::CavityFieldD2Q5>& latt){
+void set_initial_conditions(saw::data<kel::lbm::sch::CavityFieldD2Q9>& latt){
using namespace kel::lbm;
- apply_for_cells([](auto& cell, std::size_t i, std::size_t j){
- (void) i;
- (void) j;
- auto& dfs = cell.template get<"dfs">();
- dfs(0).set(1.0);
- }, latt);
+
+ typename saw::native_data_type<sch::T>::type rho = 1.0;
+ {
+ std::array<typename saw::native_data_type<sch::T>::type, sch::D2Q9::D> vel = {0.0, 0.0};
+ auto eq = equilibrium<sch::D2Q9>(rho, vel);
+
+ apply_for_cells([&eq](auto& cell, std::size_t i, std::size_t j){
+ (void) i;
+ (void) j;
+ auto& dfs = cell.template get<"dfs">();
+ for(uint64_t i = 0; i < sch::D2Q9::Q; ++i){
+ dfs(i).set(eq[i]);
+ }
+ }, latt);
+ }
+
+ {
+ std::array<typename saw::native_data_type<sch::T>::type, sch::D2Q9::D> vel = {0.1, 0.0};
+ auto eq = equilibrium<sch::D2Q9>(rho, vel);
+
+ apply_for_cells([&eq](auto& cell, std::size_t i, std::size_t j){
+ (void) i;
+ (void) j;
+ auto& dfs = cell.template get<"dfs">();
+ auto info = cell.template get<"info">()(0u).get();
+ if(info == 2u){
+ for(uint64_t i = 0; i < sch::D2Q9::Q; ++i){
+ dfs(i).set(eq[i]);
+ }
+ }
+ }, latt);
+ }
+
}
void lbm_step(
- saw::data<kel::lbm::sch::CavityFieldD2Q5>& old_latt,
- saw::data<kel::lbm::sch::CavityFieldD2Q5>& new_latt
+ saw::data<kel::lbm::sch::CavityFieldD2Q9>& old_latt,
+ saw::data<kel::lbm::sch::CavityFieldD2Q9>& new_latt
){
using namespace kel::lbm;
- using dfi = df_info<sch::T,sch::D2Q5>;
+ using dfi = df_info<sch::T,sch::D2Q9>;
- collision<sch::D2Q5> coll;
- coll.relaxation_ = 1.0;
+ component<cmpt::BGK,sch::D2Q9> coll;
+ coll.relaxation_ = 0.5384;
- bounce_back<sch::D2Q5> bb;
- cavity_boundary<sch::D2Q5> bb_lid;
+ component<cmpt::BounceBack,sch::D2Q9> bb;
+ component<cmpt::MovingWall<cmpt::BGK>,sch::D2Q9> bb_lid;
+ bb_lid.collision_ = &coll;
bb_lid.lid_vel = {0.1,0.0};
+ // Collide
apply_for_cells([&](auto& cell, std::size_t i, std::size_t j){
auto& df = cell.template get<"dfs">();
auto& info = cell.template get<"info">();
auto info_val = info({0u}).get();
switch(info_val){
- case 0u:
+ case 1u:
coll.apply(df);
break;
case 2u:
+ // bb.apply(df);
bb_lid.apply(df);
break;
case 3u:
@@ -270,15 +306,27 @@ void lbm_step(
}
}, old_latt);
+ // Stream
for(uint64_t i = 1; (i+1) < old_latt.template get_dim_size<0>().get(); ++i){
for(uint64_t j = 1; (j+1) < old_latt.template get_dim_size<1>().get(); ++j){
- auto& df_new = new_latt({{i,j}}).template get<"dfs">();
+ auto& cell_new = new_latt({{i,j}});
+ auto& df_new = cell_new.template get<"dfs">();
+ auto& info_new = cell_new.template get<"info">();
+ auto df_cpy_old = old_latt({{i,j}}).template get<"dfs">();
- for(uint64_t k = 0u; k < sch::D2Q5::Q; ++k){
+ for(uint64_t k = 0u; k < sch::D2Q9::Q; ++k){
auto dir = dfi::directions[dfi::opposite_index[k]];
- auto& df_old = old_latt({{i+dir[0],j+dir[1]}}).template get<"dfs">();
- df_new({k}) = df_old({k});
+ auto& cell_old = old_latt({{i+dir[0],j+dir[1]}});
+ auto& df_old = cell_old.template get<"dfs">();
+ auto& info_old = cell_old.template get<"info">();
+
+ if(info_new({0}).get() == 2u && info_old({0}).get() == 0u){
+ // Density set to 1.0
+ df_new({dfi::opposite_index.at(i)}) = df_cpy_old({i}) - 2.0 * dfi::weights[i] * 1.0 * ( bb_lid.lid_vel[0] * dfi::directions[i][0] + bb_lid.lid_vel[1] * dfi::directions[i][1]) * dfi::inv_cs2;
+ }else{
+ df_new({k}) = df_old({k});
+ }
}
}
}
@@ -287,10 +335,10 @@ void lbm_step(
int main(){
using namespace kel::lbm;
- saw::data<sch::FixedArray<sch::UInt64,sch::D2Q5::D>> dim{{dim_x, dim_y}};
+ saw::data<sch::FixedArray<sch::UInt64,sch::D2Q9::D>> dim{{dim_x, dim_y}};
- saw::data<sch::CavityFieldD2Q5, saw::encode::Native> old_lattice{dim};
- saw::data<sch::CavityFieldD2Q5, saw::encode::Native> new_lattice{dim};
+ saw::data<sch::CavityFieldD2Q9, saw::encode::Native> old_lattice{dim};
+ saw::data<sch::CavityFieldD2Q9, saw::encode::Native> new_lattice{dim};
// auto& df_field = lattices.at(0).template get<"dfs">();
//for(uint64_t i = 0; i < df_field.get_dim_size<0u>(); ++i){
@@ -326,37 +374,70 @@ int main(){
}
}, old_lattice);
- std::cout<<"\n";
- apply_for_cells([](auto& cell, std::size_t i, std::size_t j){
- // Not needed
- (void) i;
- std::cout<<cell.template get<"dfs">()({0}).get();
- if( (j+1) < dim_y){
- std::cout<<" ";
- }else{
- std::cout<<"\n";
- }
- }, old_lattice);
-
- uint64_t lattice_steps = 16u;
+ uint64_t lattice_steps = 37000u;
bool even_step = true;
+ uint64_t print_every = 128u;
+
for(uint64_t step = 0; step < lattice_steps; ++step){
auto& old_lat = even_step ? old_lattice : new_lattice;
auto& new_lat = even_step ? new_lattice : old_lattice;
std::cout<<"\n";
- apply_for_cells([](auto& cell, std::size_t i, std::size_t j){
- // Not needed
- (void) i;
- std::cout<<cell.template get<"dfs">()({0}).get();
+
+ if(step % print_every == 0u){
+ typename saw::native_data_type<sch::T>::type sum = 0.0;
+
+ apply_for_cells([&](auto& cell, std::size_t i, std::size_t j){
+ auto& dfs = cell.template get<"dfs">();
+ typename saw::native_data_type<sch::T>::type rho;
+ std::array<typename saw::native_data_type<sch::T>::type, sch::D2Q9::D> vel;
+ compute_rho_u<sch::D2Q9>(dfs,rho,vel);
+
+ if(i > 1 && (i+2) < dim_x && j > 1 && (j+2) < dim_y){
+ sum += rho;
+ }
+ auto angle = std::atan2(vel[1],vel[0]);
+
+ auto dir_char = [&]() -> std::string_view {
+ constexpr auto pi = M_PI;
+ if((vel[1] * vel[1] + vel[0]*vel[0]) < 1e-16){
+ return "•";
+ }
+ if(angle > 7.0 / 8.0 * pi){
+ return "←";
+ }
+ if(angle > 5.0 / 8.0 * pi){
+ return "↖";
+ }
+ if(angle > 3.0 / 8.0 * pi){
+ return "↑";
+ }
+ if(angle > 1.0 / 8.0 * pi){
+ return "↗";
+ }
+ if(angle > -1.0 / 8.0 * pi){
+ return "→";
+ }
+ if(angle > -3.0 / 8.0 * pi){
+ return "↘";
+ }
+ if(angle > -5.0 / 8.0 * pi){
+ return "↓";
+ }
+ return "←";
+ }();
+ std::cout<<dir_char;
if( (j+1) < dim_y){
std::cout<<" ";
}else{
std::cout<<"\n";
}
- }, old_lat);
+ }, old_lat);
+
+ std::cout<<"Average rho: "<<(sum / ((dim_x-4)*(dim_y-4)))<<std::endl;
+ }
lbm_step(old_lat, new_lat);