Commit 9c8de04d authored by Jakub Klinkovský's avatar Jakub Klinkovský
Browse files

LBM section - added figures for streaming patterns

parent 8ad1a13b
Loading
Loading
Loading
Loading
+28 −2
Original line number Diff line number Diff line
@@ -140,7 +140,7 @@ The alternative, yet equivalent can be formulated as:
\end{enumerate}
\end{subequations}
This scheme is called the \emph{pull scheme}, since the streaming step propagates the values to the reference lattice site $\vec x \in \hat\Omega$ from its neighbors.
The visualization of the difference between the push and pull streaming schemes is illustrated in ...\todo{draw a figure for each streaming pattern}
The visualization of the difference between the push and pull streaming schemes is illustrated in \cref{fig:lbm:AB push,fig:lbm:AB pull} for a D2Q9 velocity set.

Note that regardless of the chosen streaming scheme, the collision step is \emph{local} in terms of the lattice sites $\vec x \in \hat\Omega$ (i.e., collisions in different lattice sites are independent of each other), but collective for all $q = 1, \ldots, Q$ since collision operator $\mathcal C_q$ depends on the whole set of distribution functions in given lattice site.
On the other hand, the operations in the streaming step are \emph{non-local}, but trivial as they do not require any computation (the post-collision values are merely transferred from one place to another).
@@ -154,6 +154,19 @@ Hence, this approach is named the \emph{A-B pattern}.
The difference between the push and pull schemes is that while the arrays A and B in the push scheme contain the values of $f_q$ at two successive time levels, the arrays in the pull scheme contain the values of $f_q^\ast$.
However, this is not a problem since these values are not directly visualized, correct values are still used thanks to the placement of the streaming in the time step, and the relevant macroscopic quantities computed just before the collision step can be output for consistent visualization of the results.

\begin{figure}[tb]
    \centering
    \includegraphics[width=\textwidth]{figures/lbm/pattern_AB_push.pdf}
    \caption{Illustration of the \emph{push} streaming scheme with the \emph{A-B pattern}.}
    \label{fig:lbm:AB push}
\end{figure}
\begin{figure}[tb]
    \centering
    \includegraphics[width=\textwidth]{figures/lbm/pattern_AB_pull.pdf}
    \caption{Illustration of the \emph{pull} streaming scheme with the \emph{A-B pattern}.}
    \label{fig:lbm:AB pull}
\end{figure}

\subsubsection{A-A pattern}

The \emph{A-A pattern} \cite{bailey:2009accelerating,wittmann:2013comparison} is an alternative approach which allows to perform the streaming step in-place using just one storage array for the density distribution functions.
@@ -203,10 +216,23 @@ The time-stepping procedure using the A-A pattern can be formalized as follows:
\end{enumerate}
\end{subequations}
Note that for each lattice site $\vec x \in \hat\Omega$, the steps \cref{eq:lbm:AA-pattern:odd pre-collision step,eq:lbm:AA-pattern:odd post-collision step} access exactly the same memory locations in the array \ic{A}, since for the whole set of density distribution functions, we can invert the direction $q$ in \cref{eq:lbm:AA-pattern:odd pre-collision step} to obtain $f_{\overline q}(\vec x, t) = \texttt{A[}q, \vec x + \Delta t \vec \xi_q\texttt{]}$, which uses the same array access indices as \cref{eq:lbm:AA-pattern:odd post-collision step}.
The operations in the A-A pattern streaming scheme in the even and odd iterations are visualized for a D2Q9 velocity set in \cref{fig:lbm:AA even,fig:lbm:AA odd}, respectively.

\inline{add a figure for the visualization of the A-A pattern}
\inline{add a note regarding the implementation of boundary conditions (and investigate it in our code)}

\begin{figure}[tb]
    \centering
    \includegraphics[width=\textwidth]{figures/lbm/pattern_AA_even.pdf}
    \caption{Illustration of the \emph{A-A pattern} streaming scheme in the \emph{even iteration}.}
    \label{fig:lbm:AA even}
\end{figure}
\begin{figure}[tb]
    \centering
    \includegraphics[width=\textwidth]{figures/lbm/pattern_AA_odd.pdf}
    \caption{Illustration of the \emph{A-A pattern} streaming scheme in the \emph{odd iteration}.}
    \label{fig:lbm:AA odd}
\end{figure}

\subsubsection{Other patterns}

The A-A pattern is not the only technique that allows to perform streaming in-place in a single array.
+243 −0
Original line number Diff line number Diff line
// fonts used in the thesis
usepackage("libertine", options="tt=false, type1=true");
usepackage("zi4", options="varqu");
usepackage("newtxmath", options="libertine");

import texcolors;

pen PEN_NEIGHBOR = fontsize(10) + linewidth(1.5)+miterjoin + gray;
pen PEN_REF = fontsize(10) + linewidth(2)+miterjoin;
pen PEN_ARROW = fontsize(10) + linewidth(3) + gray;
pen PEN_ARROW_HL = fontsize(10) + linewidth(3) + RoyalBlue;
var ARROW = Arrow(size=12bp);

// important - normalizes the size of picture based on the length of the axis
transform normalize(picture p, real w, real h)
{
    pair m=point(p,NE)-point(p,SW);
    return xscale(w/m.x)*yscale(h/m.y);
}

bool check_hl(pair value, pair array[])
{
    for (pair item : array)
        if (item == value)
            return true;
    return false;
}

picture make_node(pen pen_boundary, pen pen_arrow, pen pen_arrow_hl, pair hl_arrows[] = {}, bool reverse=false)
{
    picture p = new picture;

    // draw frame around the node
    draw(p, (-1,-1)--(1,-1)--(1,1)--(-1,1)--cycle, pen_boundary);

    // parameters for arrow sizes
    real a = 0.2;
    real b = 1 - a;
    if (reverse) {
        real c = a;
        a = b;
        b = c;
    }

    // mm
    if (check_hl(SW, hl_arrows))
        draw(p, (-a,-a)--(-b,-b), pen_arrow_hl, ARROW);
    else
        draw(p, (-a,-a)--(-b,-b), pen_arrow, ARROW);
    // mz
    if (check_hl(W, hl_arrows))
        draw(p, (-a, 0)--(-b, 0), pen_arrow_hl, ARROW);
    else
        draw(p, (-a, 0)--(-b, 0), pen_arrow, ARROW);
    // mp
    if (check_hl(NW, hl_arrows))
        draw(p, (-a, a)--(-b, b), pen_arrow_hl, ARROW);
    else
        draw(p, (-a, a)--(-b, b), pen_arrow, ARROW);
    // zm
    if (check_hl(S, hl_arrows))
        draw(p, ( 0,-a)--( 0,-b), pen_arrow_hl, ARROW);
    else
        draw(p, ( 0,-a)--( 0,-b), pen_arrow, ARROW);
    // zz
    if (check_hl((0,0), hl_arrows))
        draw(p, ( 0, 0)--( 0, 0), pen_arrow_hl+linewidth(5), ARROW);
    else
        draw(p, ( 0, 0)--( 0, 0), pen_arrow, ARROW);
    // zp
    if (check_hl(N, hl_arrows))
        draw(p, ( 0, a)--( 0, b), pen_arrow_hl, ARROW);
    else
        draw(p, ( 0, a)--( 0, b), pen_arrow, ARROW);
    // pm
    if (check_hl(SE, hl_arrows))
        draw(p, ( a,-a)--( b,-b), pen_arrow_hl, ARROW);
    else
        draw(p, ( a,-a)--( b,-b), pen_arrow, ARROW);
    // pz
    if (check_hl(E, hl_arrows))
        draw(p, ( a, 0)--( b, 0), pen_arrow_hl, ARROW);
    else
        draw(p, ( a, 0)--( b, 0), pen_arrow, ARROW);
    // pp
    if (check_hl(NE, hl_arrows))
        draw(p, ( a, a)--( b, b), pen_arrow_hl, ARROW);
    else
        draw(p, ( a, a)--( b, b), pen_arrow, ARROW);

    return p;
}

picture make_patch_central(bool reverse=false)
{
    picture mm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture mz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture mp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture zm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    pair hl_arrows[] = {SW, W, NW, N, NE, E, SE, S, (0,0)};
    picture zz = make_node(PEN_REF,      PEN_ARROW, PEN_ARROW_HL, hl_arrows, reverse=reverse);
    picture zp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture pm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture pz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);
    picture pp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, reverse=reverse);

    picture p = new picture;
    real side = 2cm;
    real u = side/side;  // dimless

    add(p, mm.fit(normalize(mm,side,side)), (-u,-u), SW);
    add(p, mz.fit(normalize(mm,side,side)), (-u, 0),  W);
    add(p, mp.fit(normalize(mm,side,side)), (-u, u), NW);
    add(p, zm.fit(normalize(mm,side,side)), ( 0,-u), S );
    add(p, zp.fit(normalize(mm,side,side)), ( 0, u), N );
    add(p, pm.fit(normalize(mm,side,side)), ( u,-u), SE);
    add(p, pz.fit(normalize(mm,side,side)), ( u, 0),  E);
    add(p, pp.fit(normalize(mm,side,side)), ( u, u), NE);
    // central is drawn last to overdraw the gray
    add(p, zz.fit(normalize(mm,side,side)), ( 0, 0)    );

    return p;
}

picture make_patch_AB_push()
{
    pair hl_mm[] = {SW};
    pair hl_mz[] = { W};
    pair hl_mp[] = {NW};
    pair hl_zm[] = {S};
    pair hl_zz[] = {(0,0)};
    pair hl_zp[] = {N};
    pair hl_pm[] = {SE};
    pair hl_pz[] = { E};
    pair hl_pp[] = {NE};

    picture mm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mm);
    picture mz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mz);
    picture mp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mp);
    picture zm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zm);
    picture zz = make_node(PEN_REF,      PEN_ARROW, PEN_ARROW_HL, hl_zz);
    picture zp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zp);
    picture pm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pm);
    picture pz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pz);
    picture pp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pp);

    picture p = new picture;
    real side = 2cm;
    real u = side/side;  // dimless

    add(p, mm.fit(normalize(mm,side,side)), (-u,-u), SW);
    add(p, mz.fit(normalize(mm,side,side)), (-u, 0),  W);
    add(p, mp.fit(normalize(mm,side,side)), (-u, u), NW);
    add(p, zm.fit(normalize(mm,side,side)), ( 0,-u), S );
    add(p, zp.fit(normalize(mm,side,side)), ( 0, u), N );
    add(p, pm.fit(normalize(mm,side,side)), ( u,-u), SE);
    add(p, pz.fit(normalize(mm,side,side)), ( u, 0),  E);
    add(p, pp.fit(normalize(mm,side,side)), ( u, u), NE);
    // central is drawn last to overdraw the gray
    add(p, zz.fit(normalize(mm,side,side)), ( 0, 0)    );

    return p;
}

picture make_patch_AB_pull()
{
    pair hl_mm[] = {NE};
    pair hl_mz[] = { E};
    pair hl_mp[] = {SE};
    pair hl_zm[] = {N};
    pair hl_zz[] = {(0,0)};
    pair hl_zp[] = {S};
    pair hl_pm[] = {NW};
    pair hl_pz[] = { W};
    pair hl_pp[] = {SW};

    picture mm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mm);
    picture mz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mz);
    picture mp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mp);
    picture zm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zm);
    picture zz = make_node(PEN_REF,      PEN_ARROW, PEN_ARROW_HL, hl_zz);
    picture zp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zp);
    picture pm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pm);
    picture pz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pz);
    picture pp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pp);

    picture p = new picture;
    real side = 2cm;
    real u = side/side;  // dimless

    add(p, mm.fit(normalize(mm,side,side)), (-u,-u), SW);
    add(p, mz.fit(normalize(mm,side,side)), (-u, 0),  W);
    add(p, mp.fit(normalize(mm,side,side)), (-u, u), NW);
    add(p, zm.fit(normalize(mm,side,side)), ( 0,-u), S );
    add(p, zp.fit(normalize(mm,side,side)), ( 0, u), N );
    add(p, pm.fit(normalize(mm,side,side)), ( u,-u), SE);
    add(p, pz.fit(normalize(mm,side,side)), ( u, 0),  E);
    add(p, pp.fit(normalize(mm,side,side)), ( u, u), NE);
    // central is drawn last to overdraw the gray
    add(p, zz.fit(normalize(mm,side,side)), ( 0, 0)    );

    return p;
}

picture make_patch_AA_pull()
{
    pair hl_mm[] = {SW};
    pair hl_mz[] = { W};
    pair hl_mp[] = {NW};
    pair hl_zm[] = {S};
    pair hl_zz[] = {(0,0)};
    pair hl_zp[] = {N};
    pair hl_pm[] = {SE};
    pair hl_pz[] = { E};
    pair hl_pp[] = {NE};

    picture mm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mm, reverse=true);
    picture mz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mz, reverse=true);
    picture mp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_mp, reverse=true);
    picture zm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zm, reverse=true);
    picture zz = make_node(PEN_REF,      PEN_ARROW, PEN_ARROW_HL, hl_zz, reverse=true);
    picture zp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_zp, reverse=true);
    picture pm = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pm, reverse=true);
    picture pz = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pz, reverse=true);
    picture pp = make_node(PEN_NEIGHBOR, PEN_ARROW, PEN_ARROW_HL, hl_pp, reverse=true);

    picture p = new picture;
    real side = 2cm;
    real u = side/side;  // dimless

    add(p, mm.fit(normalize(mm,side,side)), (-u,-u), SW);
    add(p, mz.fit(normalize(mm,side,side)), (-u, 0),  W);
    add(p, mp.fit(normalize(mm,side,side)), (-u, u), NW);
    add(p, zm.fit(normalize(mm,side,side)), ( 0,-u), S );
    add(p, zp.fit(normalize(mm,side,side)), ( 0, u), N );
    add(p, pm.fit(normalize(mm,side,side)), ( u,-u), SE);
    add(p, pz.fit(normalize(mm,side,side)), ( u, 0),  E);
    add(p, pp.fit(normalize(mm,side,side)), ( u, u), NE);
    // central is drawn last to overdraw the gray
    add(p, zz.fit(normalize(mm,side,side)), ( 0, 0)    );

    return p;
}
+22 −0
Original line number Diff line number Diff line
include 'pattern.asy';

unitsize(1cm);

picture p1 = make_patch_central();
add(p1.fit(normalize(p1,2cm,2cm)), position=(-3,0), align=W);

pair hl_arrows[] = {SW, W, NW, N, NE, E, SE, S, (0,0)};
picture p2 = make_node(PEN_REF, PEN_ARROW, PEN_ARROW_HL, hl_arrows);
add(p2.fit(normalize(p2,2cm,2cm)), position=(0,0));

picture p3 = make_patch_central(reverse=true);
add(p3.fit(normalize(p3,2cm,2cm)), position=(3,0), align=E);

string l1 = minipage("(a) Values read from the global memory (array A)", width=5.5cm);
label(l1, (-6,-3.5), S);

string l2 = minipage("(b) Values stored in the registers", width=5.5cm);
label(l2, (0,-3.5), S);

string l3 = minipage("(c) Values stored into the global memory (array A)", width=5.5cm);
label(l3, (6,-3.5), S);
+12.2 KiB

File added.

No diff preview for this file type.

+22 −0
Original line number Diff line number Diff line
include 'pattern.asy';

unitsize(1cm);

picture p1 = make_patch_AA_pull();
add(p1.fit(normalize(p1,2cm,2cm)), position=(-3,0), align=W);

pair hl_arrows[] = {SW, W, NW, N, NE, E, SE, S, (0,0)};
picture p2 = make_node(PEN_REF, PEN_ARROW, PEN_ARROW_HL, hl_arrows);
add(p2.fit(normalize(p2,2cm,2cm)), position=(0,0));

picture p3 = make_patch_AB_push();
add(p3.fit(normalize(p3,2cm,2cm)), position=(3,0), align=E);

string l1 = minipage("(a) Values read from the global memory (array A)", width=5.5cm);
label(l1, (-6,-3.5), S);

string l2 = minipage("(b) Values stored in the registers", width=5.5cm);
label(l2, (0,-3.5), S);

string l3 = minipage("(c) Values stored into the global memory (array A)", width=5.5cm);
label(l3, (6,-3.5), S);
Loading