aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Kummerlaender2019-06-09 23:57:04 +0200
committerAdrian Kummerlaender2019-06-09 23:57:04 +0200
commit71a678256d71d3942d040bbbe42d6a0270feb3cc (patch)
tree93b64ec3ebd09b8fcbd7cef4bdc3743b714074d3
parent05cf82b1f6b14f01c13e438b16ac8cf86acb9544 (diff)
downloadsymlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar.gz
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar.bz2
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar.lz
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar.xz
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.tar.zst
symlbm_playground-71a678256d71d3942d040bbbe42d6a0270feb3cc.zip
First test of partially generated LBM kernel
A kernel extracted from `lbn_codegen.ipynb` yields ~665 MLUPS compared to the ~600 MLUPS produced by a manually optimized kernel. Note that this new kernel currently doesn't handle boundary conditions (but dropping in a density condition doesn't impact performance).
-rw-r--r--codegen_lbm.py221
-rw-r--r--lbm_codegen.ipynb1557
-rw-r--r--lid_driven_cavity.py14
3 files changed, 1041 insertions, 751 deletions
diff --git a/codegen_lbm.py b/codegen_lbm.py
new file mode 100644
index 0000000..cd93649
--- /dev/null
+++ b/codegen_lbm.py
@@ -0,0 +1,221 @@
+import pyopencl as cl
+mf = cl.mem_flags
+
+from string import Template
+
+import numpy
+import matplotlib.pyplot as plt
+
+import time
+
+kernel = """
+unsigned int indexOfDirection(int i, int j) {
+ return (i+1) + 3*(1-j);
+}
+
+unsigned int indexOfCell(int x, int y)
+{
+ return y * $nX + x;
+}
+
+unsigned int idx(int x, int y, int i, int j) {
+ return indexOfDirection(i,j)*$nCells + indexOfCell(x,y);
+}
+
+__global float f_i(__global __read_only float* f, int x, int y, int i, int j) {
+ return f[idx(x,y,i,j)];
+}
+
+__kernel void collide_and_stream(__global __write_only float* f_a,
+ __global __read_only float* f_b,
+ __global __write_only float* moments,
+ __global __read_only int* material)
+{
+ const unsigned int gid = indexOfCell(get_global_id(0), get_global_id(1));
+
+ const uint2 cell = (uint2)(get_global_id(0), get_global_id(1));
+
+ const int m = material[gid];
+
+ if ( m == 0 ) {
+ return;
+ }
+
+ const float f_curr_0 = f_i(f_b, cell.x+1, cell.y-1, -1, 1);
+ const float f_curr_1 = f_i(f_b, cell.x , cell.y-1, 0, 1);
+ const float f_curr_2 = f_i(f_b, cell.x-1, cell.y-1, 1, 1);
+ const float f_curr_3 = f_i(f_b, cell.x+1, cell.y , -1, 0);
+ const float f_curr_4 = f_i(f_b, cell.x , cell.y , 0, 0);
+ const float f_curr_5 = f_i(f_b, cell.x-1, cell.y , 1, 0);
+ const float f_curr_6 = f_i(f_b, cell.x+1, cell.y+1, -1,-1);
+ const float f_curr_7 = f_i(f_b, cell.x , cell.y+1, 0,-1);
+ const float f_curr_8 = f_i(f_b, cell.x-1, cell.y+1, 1,-1);
+
+ const float x0 = f_curr_0 + f_curr_1 + f_curr_2 + f_curr_3 + f_curr_4 + f_curr_5 + f_curr_6 + f_curr_7 + f_curr_8;
+ const float x1 = 2*f_curr_0;
+ const float x2 = 2*f_curr_8;
+ const float x3 = -f_curr_3 + f_curr_5;
+ const float x4 = pow(x0, -2);
+ const float x5 = 9*x4;
+ const float x6 = f_curr_0 - f_curr_8;
+ const float x7 = f_curr_1 - f_curr_7;
+ const float x8 = f_curr_2 - f_curr_6;
+ const float x9 = x6 + x7 + x8;
+ const float x10 = 6/x0;
+ const float x11 = x10*x9;
+ const float x12 = f_curr_3 - f_curr_5;
+ const float x13 = -f_curr_2 + f_curr_6 + x12 + x6;
+ const float x14 = pow(x13, 2);
+ const float x15 = 3*x4;
+ const float x16 = -x14*x15 + 2;
+ const float x17 = x11 + x16;
+ const float x18 = pow(x9, 2);
+ const float x19 = x15*x18;
+ const float x20 = -x19;
+ const float x21 = x10*x13;
+ const float x22 = x20 + x21;
+ const float x23 = 1.0/$tau;
+ const float x24 = (1.0/72.0)*x23;
+ const float x25 = 6*x4;
+ const float x26 = x18*x25;
+ const float x27 = (1.0/18.0)*x23;
+ const float x28 = x5*pow(2*f_curr_2 - 2*f_curr_6 + x3 + x7, 2);
+ const float x29 = x20 - x21;
+ const float x30 = x14*x25 + 2;
+ const float x31 = -f_curr_0 + f_curr_8 + x3 + x8;
+ const float x32 = x15*pow(x31, 2) - 2;
+ const float x33 = x19 + x32;
+
+ f_a[0*$nCells + gid] = f_curr_0 - x24*(72*f_curr_0 - x0*(x17 + x22 + x5*pow(-f_curr_1 + f_curr_7 - x1 + x2 + x3, 2)));
+ f_a[1*$nCells + gid] = f_curr_1 - x27*(18*f_curr_1 - x0*(x17 + x26));
+ f_a[2*$nCells + gid] = f_curr_2 - x24*(72*f_curr_2 - x0*(x17 + x28 + x29));
+ f_a[3*$nCells + gid] = f_curr_3 - x27*(18*f_curr_3 - x0*(x22 + x30));
+ f_a[4*$nCells + gid] = f_curr_4 - 1.0/9.0*x23*(9*f_curr_4 + 2*x0*x33);
+ f_a[5*$nCells + gid] = f_curr_5 - x27*(18*f_curr_5 - x0*(x29 + x30));
+ f_a[6*$nCells + gid] = f_curr_6 - x24*(72*f_curr_6 + x0*(x10*x31 + x11 - x28 + x33));
+ f_a[7*$nCells + gid] = f_curr_7 - x27*(18*f_curr_7 + x0*(x11 - x26 + x32));
+ f_a[8*$nCells + gid] = f_curr_8 - x24*(72*f_curr_8 - x0*(-x11 + x16 + x29 + x5*pow(x1 + x12 - x2 + x7, 2)));
+
+ moments[gid] = x0;
+}"""
+
+
+class D2Q9_BGK_Lattice:
+ def idx(self, x, y):
+ return y * self.nX + x;
+
+ def __init__(self, nX, nY):
+ self.nX = nX
+ self.nY = nY
+ self.nCells = nX * nY
+ self.tick = True
+
+ self.platform = cl.get_platforms()[0]
+ self.context = cl.Context(properties=[(cl.context_properties.PLATFORM, self.platform)])
+ self.queue = cl.CommandQueue(self.context)
+
+ self.np_pop_a = numpy.ndarray(shape=(9, self.nCells), dtype=numpy.float32)
+ self.np_pop_b = numpy.ndarray(shape=(9, self.nCells), dtype=numpy.float32)
+
+ self.np_moments = numpy.ndarray(shape=(3, self.nCells), dtype=numpy.float32)
+ self.np_material = numpy.ndarray(shape=(self.nCells, 1), dtype=numpy.int32)
+
+ self.setup_geometry()
+
+ self.equilibrilize()
+ self.setup_anomaly()
+
+ self.cl_pop_a = cl.Buffer(self.context, mf.READ_WRITE | mf.USE_HOST_PTR, hostbuf=self.np_pop_a)
+ self.cl_pop_b = cl.Buffer(self.context, mf.READ_WRITE | mf.USE_HOST_PTR, hostbuf=self.np_pop_b)
+
+ self.cl_material = cl.Buffer(self.context, mf.READ_ONLY | mf.USE_HOST_PTR, hostbuf=self.np_material)
+ self.cl_moments = cl.Buffer(self.context, mf.READ_WRITE | mf.USE_HOST_PTR, hostbuf=self.np_moments)
+
+ self.build_kernel()
+
+ def setup_geometry(self):
+ self.np_material[:] = 0
+ for x in range(1,self.nX-1):
+ for y in range(1,self.nY-1):
+ if x == 1 or y == 1 or x == self.nX-2 or y == self.nY-2:
+ self.np_material[self.idx(x,y)] = 2
+ else:
+ self.np_material[self.idx(x,y)] = 1
+
+ def equilibrilize(self):
+ self.np_pop_a[(0,2,6,8),:] = 1./36.
+ self.np_pop_a[(1,3,5,7),:] = 1./9.
+ self.np_pop_a[4,:] = 4./9.
+
+ self.np_pop_b[(0,2,6,8),:] = 1./36.
+ self.np_pop_b[(1,3,5,7),:] = 1./9.
+ self.np_pop_b[4,:] = 4./9.
+
+ def setup_anomaly(self):
+ bubbles = [ [ self.nX//4, self.nY//4],
+ [ self.nX//4,self.nY-self.nY//4],
+ [self.nX-self.nX//4, self.nY//4],
+ [self.nX-self.nX//4,self.nY-self.nY//4] ]
+
+ for x in range(0,self.nX-1):
+ for y in range(0,self.nY-1):
+ for [a,b] in bubbles:
+ if numpy.sqrt((x-a)*(x-a)+(y-b)*(y-b)) < self.nX//10:
+ self.np_pop_a[:,self.idx(x,y)] = 1./24.
+ self.np_pop_b[:,self.idx(x,y)] = 1./24.
+
+ def build_kernel(self):
+ self.program = cl.Program(self.context, Template(kernel).substitute({
+ 'nX' : self.nX,
+ 'nY' : self.nY,
+ 'nCells': self.nCells,
+ 'tau': '0.8f'
+ })).build() #'-cl-single-precision-constant -cl-fast-relaxed-math')
+
+ def evolve(self):
+ if self.tick:
+ self.tick = False
+ self.program.collide_and_stream(self.queue, (self.nX,self.nY), (64,1), self.cl_pop_a, self.cl_pop_b, self.cl_moments, self.cl_material)
+ else:
+ self.tick = True
+ self.program.collide_and_stream(self.queue, (self.nX,self.nY), (64,1), self.cl_pop_b, self.cl_pop_a, self.cl_moments, self.cl_material)
+
+ def sync(self):
+ self.queue.finish()
+
+ def show(self, i):
+ cl.enqueue_copy(LBM.queue, LBM.np_moments, LBM.cl_moments).wait();
+
+ density = numpy.ndarray(shape=(self.nX-2, self.nY-2))
+ for y in range(1,self.nY-1):
+ for x in range(1,self.nX-1):
+ density[y-1,x-1] = self.np_moments[0,self.idx(x,y)]
+
+ plt.imshow(density, vmin=0.2, vmax=2.0, cmap=plt.get_cmap("seismic"))
+ plt.savefig("result/density_" + str(i) + ".png")
+
+
+def MLUPS(cells, steps, time):
+ return cells * steps / time * 1e-6
+
+nUpdates = 1000
+nStat = 100
+
+print("Initializing simulation...\n")
+
+LBM = D2Q9_BGK_Lattice(1024, 1024)
+
+print("Starting simulation using %d cells...\n" % LBM.nCells)
+
+lastStat = time.time()
+
+for i in range(1,nUpdates+1):
+ if i % nStat == 0:
+ LBM.sync()
+ #LBM.show(i)
+ print("i = %4d; %3.0f MLUPS" % (i, MLUPS(LBM.nCells, nStat, time.time() - lastStat)))
+ lastStat = time.time()
+
+ LBM.evolve()
+
+LBM.show(nUpdates)
diff --git a/lbm_codegen.ipynb b/lbm_codegen.ipynb
index efc1200..7d13f70 100644
--- a/lbm_codegen.ipynb
+++ b/lbm_codegen.ipynb
@@ -14,40 +14,39 @@
},
{
"cell_type": "code",
- "execution_count": 2,
+ "execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
- "c = [Matrix((x,)) for x in [(-1, 1), ( 0, 1), ( 1, 1), (-1, 0), ( 0, 0), ( 1, 0), (-1, 0), ( 0, -1), ( 1, -1)]]"
+ "c = [Matrix((x,)) for x in [(-1, 1), ( 0, 1), ( 1, 1), (-1, 0), ( 0, 0), ( 1, 0), (-1,-1), ( 0, -1), ( 1, -1)]]"
]
},
{
"cell_type": "code",
- "execution_count": 3,
+ "execution_count": 31,
"metadata": {},
"outputs": [
{
"data": {
- "image/png": "iVBORw0KGgoAAAANSUhEUgAAAA0AAAASCAYAAACAa1QyAAAABHNCSVQICAgIfAhkiAAAAHZJREFUKJFjYKACCGFgYJjMwMBwmIGB4RMDA8N/BgaGJYQ0XYAq/MzAwHCdWE2ODAwMqgwMDIwMDAwOuDSxoPH3EzKVgYGBgYkYRaOaBlwTeuQGQDEDAwODBJS2ZGBgWABlv2FgYChBN6SBAZJ0cOEH5LiMzgAA6XoX52TB9a4AAAAASUVORK5CYII=\n",
"text/latex": [
- "$$1$$"
+ "$$\\left [ \\left[\\begin{matrix}-1 & 1\\end{matrix}\\right], \\quad \\left[\\begin{matrix}0 & 1\\end{matrix}\\right], \\quad \\left[\\begin{matrix}1 & 1\\end{matrix}\\right], \\quad \\left[\\begin{matrix}-1 & 0\\end{matrix}\\right], \\quad \\left[\\begin{matrix}0 & 0\\end{matrix}\\right], \\quad \\left[\\begin{matrix}1 & 0\\end{matrix}\\right], \\quad \\left[\\begin{matrix}-1 & -1\\end{matrix}\\right], \\quad \\left[\\begin{matrix}0 & -1\\end{matrix}\\right], \\quad \\left[\\begin{matrix}1 & -1\\end{matrix}\\right]\\right ]$$"
],
"text/plain": [
- "1"
+ "[[-1 1], [0 1], [1 1], [-1 0], [0 0], [1 0], [-1 -1], [0 -1], [1 -1]]"
]
},
- "execution_count": 3,
+ "execution_count": 31,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
- "c[1][1]"
+ "c"
]
},
{
"cell_type": "code",
- "execution_count": 4,
+ "execution_count": 32,
"metadata": {},
"outputs": [],
"source": [
@@ -56,7 +55,7 @@
},
{
"cell_type": "code",
- "execution_count": 5,
+ "execution_count": 33,
"metadata": {},
"outputs": [
{
@@ -69,7 +68,7 @@
"[1/36, 1/9, 1/36, 1/9, 4/9, 1/9, 1/36, 1/9, 1/36]"
]
},
- "execution_count": 5,
+ "execution_count": 33,
"metadata": {},
"output_type": "execute_result"
}
@@ -80,7 +79,7 @@
},
{
"cell_type": "code",
- "execution_count": 6,
+ "execution_count": 34,
"metadata": {},
"outputs": [
{
@@ -93,7 +92,7 @@
"1"
]
},
- "execution_count": 6,
+ "execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
@@ -104,7 +103,7 @@
},
{
"cell_type": "code",
- "execution_count": 8,
+ "execution_count": 35,
"metadata": {},
"outputs": [
{
@@ -119,7 +118,7 @@
"3 "
]
},
- "execution_count": 8,
+ "execution_count": 35,
"metadata": {},
"output_type": "execute_result"
}
@@ -131,7 +130,7 @@
},
{
"cell_type": "code",
- "execution_count": 9,
+ "execution_count": 36,
"metadata": {},
"outputs": [],
"source": [
@@ -140,7 +139,7 @@
},
{
"cell_type": "code",
- "execution_count": 10,
+ "execution_count": 37,
"metadata": {},
"outputs": [
{
@@ -150,7 +149,7 @@
" f_next_6, f_next_7, f_next_8], dtype=object)"
]
},
- "execution_count": 10,
+ "execution_count": 37,
"metadata": {},
"output_type": "execute_result"
}
@@ -162,7 +161,7 @@
},
{
"cell_type": "code",
- "execution_count": 11,
+ "execution_count": 38,
"metadata": {},
"outputs": [
{
@@ -172,7 +171,7 @@
" f_curr_6, f_curr_7, f_curr_8], dtype=object)"
]
},
- "execution_count": 11,
+ "execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
@@ -184,7 +183,7 @@
},
{
"cell_type": "code",
- "execution_count": 12,
+ "execution_count": 39,
"metadata": {},
"outputs": [
{
@@ -198,7 +197,7 @@
"_curr_7 + f_curr_8"
]
},
- "execution_count": 12,
+ "execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
@@ -210,7 +209,7 @@
},
{
"cell_type": "code",
- "execution_count": 13,
+ "execution_count": 40,
"metadata": {},
"outputs": [
{
@@ -229,7 +228,7 @@
"_curr_7 + f_curr_8"
]
},
- "execution_count": 13,
+ "execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
@@ -241,26 +240,26 @@
},
{
"cell_type": "code",
- "execution_count": 14,
+ "execution_count": 41,
"metadata": {},
"outputs": [
{
"data": {
- "image/png": "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\n",
+ "image/png": "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\n",
"text/latex": [
- "$$\\frac{f_{curr 0} + f_{curr 1} + f_{curr 2} - f_{curr 7} - f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}$$"
+ "$$\\frac{f_{curr 0} + f_{curr 1} + f_{curr 2} - f_{curr 6} - f_{curr 7} - f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}$$"
],
"text/plain": [
- " f_curr_0 + f_curr_1 + f_curr_2 - f_curr_7 - f_curr_8 \n",
+ " f_curr_0 + f_curr_1 + f_curr_2 - f_curr_6 - f_curr_7 - f_curr_\n",
"──────────────────────────────────────────────────────────────────────────────\n",
"f_curr_0 + f_curr_1 + f_curr_2 + f_curr_3 + f_curr_4 + f_curr_5 + f_curr_6 + f\n",
"\n",
- " \n",
+ "8 \n",
"──────────────────\n",
"_curr_7 + f_curr_8"
]
},
- "execution_count": 14,
+ "execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
@@ -272,20 +271,20 @@
},
{
"cell_type": "code",
- "execution_count": 15,
+ "execution_count": 42,
"metadata": {},
"outputs": [
{
"data": {
"text/latex": [
- "$$\\left[\\begin{matrix}\\frac{- f_{curr 0} + f_{curr 2} - f_{curr 3} + f_{curr 5} - f_{curr 6} + f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}\\\\\\frac{f_{curr 0} + f_{curr 1} + f_{curr 2} - f_{curr 7} - f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}\\end{matrix}\\right]$$"
+ "$$\\left[\\begin{matrix}\\frac{- f_{curr 0} + f_{curr 2} - f_{curr 3} + f_{curr 5} - f_{curr 6} + f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}\\\\\\frac{f_{curr 0} + f_{curr 1} + f_{curr 2} - f_{curr 6} - f_{curr 7} - f_{curr 8}}{f_{curr 0} + f_{curr 1} + f_{curr 2} + f_{curr 3} + f_{curr 4} + f_{curr 5} + f_{curr 6} + f_{curr 7} + f_{curr 8}}\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ -f_curr_0 + f_curr_2 - f_curr_3 + f_curr_5 - f_curr_6 + f_cur\n",
"⎢─────────────────────────────────────────────────────────────────────────────\n",
"⎢f_curr_0 + f_curr_1 + f_curr_2 + f_curr_3 + f_curr_4 + f_curr_5 + f_curr_6 + \n",
"⎢ \n",
- "⎢ f_curr_0 + f_curr_1 + f_curr_2 - f_curr_7 - f_curr_8 \n",
+ "⎢ f_curr_0 + f_curr_1 + f_curr_2 - f_curr_6 - f_curr_7 - f_curr\n",
"⎢─────────────────────────────────────────────────────────────────────────────\n",
"⎣f_curr_0 + f_curr_1 + f_curr_2 + f_curr_3 + f_curr_4 + f_curr_5 + f_curr_6 + \n",
"\n",
@@ -293,12 +292,12 @@
"───────────────────⎥\n",
"f_curr_7 + f_curr_8⎥\n",
" ⎥\n",
- " ⎥\n",
+ "_8 ⎥\n",
"───────────────────⎥\n",
"f_curr_7 + f_curr_8⎦"
]
},
- "execution_count": 15,
+ "execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
@@ -310,311 +309,311 @@
},
{
"cell_type": "code",
- "execution_count": 16,
+ "execution_count": 43,
"metadata": {},
"outputs": [
{
"data": {
- "image/png": "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