From 6e6624e5f90565e6b022f26fca1f32c5b28abed9 Mon Sep 17 00:00:00 2001 From: Adrian Kummerlaender Date: Tue, 23 Jul 2019 23:20:24 +0200 Subject: Generate basic example in plain C++ An attempt to produce a minimal LBM implementation to benchmark various memory and vectorization schemes on the CPU. --- standalone_cpp_codegen.py | 32 ++++++++++++++ template/standalone.mako | 109 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) create mode 100644 standalone_cpp_codegen.py create mode 100644 template/standalone.mako diff --git a/standalone_cpp_codegen.py b/standalone_cpp_codegen.py new file mode 100644 index 0000000..b38898a --- /dev/null +++ b/standalone_cpp_codegen.py @@ -0,0 +1,32 @@ +import sympy +from mako.template import Template +from pathlib import Path + +from simulation import Geometry +from symbolic.generator import LBM + +import symbolic.D2Q9 as D2Q9 + +lbm = LBM(D2Q9) + +moments = lbm.moments(optimize = False) +collide = lbm.bgk(f_eq = lbm.equilibrium(), tau = 0.6) + +geometry = Geometry(512, 512) + +program_src = Template(filename = str(Path(__file__).parent/'template/standalone.mako')).render( + descriptor = lbm.descriptor, + geometry = geometry, + + steps = 100, + + moments_subexpr = moments[0], + moments_assignment = moments[1], + collide_subexpr = collide[0], + collide_assignment = collide[1], + + float_type = 'double', + ccode = sympy.ccode +) + +print(program_src) diff --git a/template/standalone.mako b/template/standalone.mako new file mode 100644 index 0000000..6750de9 --- /dev/null +++ b/template/standalone.mako @@ -0,0 +1,109 @@ +#include +#include +#include + +<% +def pop_offset(i): + return i * geometry.volume +%> + +void equilibrilize(${float_type}* f_next, + ${float_type}* f_prev, + const std::size_t gid) +{ + ${float_type}* preshifted_f_next = f_next + gid; + ${float_type}* preshifted_f_prev = f_prev + gid; + +% for i, w_i in enumerate(descriptor.w): + preshifted_f_next[${pop_offset(i)}] = ${w_i}.f; + preshifted_f_prev[${pop_offset(i)}] = ${w_i}.f; +% endfor +} + +<% +def neighbor_offset(c_i): + return { + 2: lambda: c_i[1]*geometry.size_x + c_i[0], + 3: lambda: c_i[2]*geometry.size_x*geometry.size_y + c_i[1]*geometry.size_x + c_i[0] + }.get(descriptor.d)() + +%> + +void collide_and_stream( ${float_type}* f_next, + const ${float_type}* f_prev, + const int* material, + const std::size_t gid) +{ + const int m = material[gid]; + + if ( m == 0 ) { + return; + } + + ${float_type}* preshifted_f_next = f_next + gid; + const ${float_type}* preshifted_f_prev = f_prev + gid; + +% for i, c_i in enumerate(descriptor.c): + const ${float_type} f_curr_${i} = preshifted_f_prev[${pop_offset(i) + neighbor_offset(-c_i)}]; +% endfor + +% for i, expr in enumerate(moments_subexpr): + const ${float_type} ${expr[0]} = ${ccode(expr[1])}; +% endfor + +% for i, expr in enumerate(moments_assignment): + ${float_type} ${ccode(expr)} +% endfor + +% for i, expr in enumerate(collide_subexpr): + const ${float_type} ${expr[0]} = ${ccode(expr[1])}; +% endfor + +% for i, expr in enumerate(collide_assignment): + const ${float_type} ${ccode(expr)} +% endfor + +% for i in range(0,descriptor.q): + preshifted_f_next[${pop_offset(i)}] = f_next_${i}; +% endfor +} + +int main() +{ + auto f_a = std::make_unique<${float_type}[]>(${geometry.volume*descriptor.q}); + auto f_b = std::make_unique<${float_type}[]>(${geometry.volume*descriptor.q}); + auto material = std::make_unique(${geometry.volume}); + + ${float_type}* f_prev = f_a.get(); + ${float_type}* f_next = f_b.get(); + + for (int iX = 0; iX < ${geometry.size_x}; ++iX) { + for (int iY = 0; iY < ${geometry.size_x}; ++iY) { + if (iX == 0 || iY == 0 || iX == ${geometry.size_x-1} || iY == ${geometry.size_y-1}) { + material[iY*${geometry.size_x} + iX] = 0; + } else { + material[iY*${geometry.size_x} + iX] = 1; + } + } + } + + for (std::size_t iCell = 0; iCell < ${geometry.volume}; ++iCell) { + equilibrilize(f_prev, f_next, iCell); + } + + for (std::size_t iStep = 0; iStep < ${steps}; ++iStep) { + if (iStep % 2 == 0) { + f_next = f_a.get(); + f_prev = f_b.get(); + } else { + f_next = f_b.get(); + f_prev = f_a.get(); + } + + for (std::size_t iCell = 0; iCell < ${geometry.volume}; ++iCell) { + collide_and_stream(f_next, f_prev, material.get(), iCell); + } + } + + return 0; +} -- cgit v1.2.3