1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
|
\documentclass[letterpaper,11pt]{article}
\usepackage{amsmath}
\usepackage{cite}
\usepackage[margin=1in]{geometry}
\usepackage{graphicx}
\usepackage{subfigure}
\usepackage{tikz}
\usepackage{url}
\usepackage{xspace}
\usetikzlibrary{fit}
\usetikzlibrary{positioning}
\usetikzlibrary{trees}
\input{tikzstyles}
\newcommand{\dealii}{\texttt{deal.II}\xspace}
\newcommand{\pforest}{\texttt{p4est}\xspace}
\newcommand{\figref}[1]{Figure~\ref{fig:#1}}
\author{Carsten Burstedde}
\title{Brief \pforest interface schematics}
\begin{document}
\maketitle
\begin{abstract}
We describe the general procedure of using \pforest from application codes.
\pforest is a software library that stores and modifies a forest-of-octrees
refinement structure using distributed (MPI) parallelism. It expects the
description of the domain as a coarse mesh of conforming hexahedra.
Non-conforming adaptive mesh refinement (AMR), coarsening, and other operations
that modify the forest are implemented as \pforest API functions. To inform
the application about the refinement structure, several methods are provided
that encode this information.
\end{abstract}
\section{Starting point}
We generally separate the adaptive mesh refinement (AMR) topology from any
numerical information. The former is stored and modified internally by the
\pforest software library, while an application is free to define the way it
uses this information and arranges numerical and other data. This document is
intended to describe the interface by which \pforest relates mesh information
to the application.
The general, modular AMR pipeline is described in
\cite{BursteddeGhattasStadlerEtAl08}, which is not specific to \pforest but can
in principle be applied to any AMR provider. The \pforest algorithms and main
interface routines are described in \cite{BursteddeWilcoxGhattas11}.
% \cite{IsaacBursteddeGhattas12}
An example usage of \pforest as scalable mesh backend for the general-purpose
finite element software \dealii is described in
\cite{BangerthBursteddeHeisterEtAl11}. A reference implementation of \pforest
in \texttt{C} can be freely downloaded \cite{Burstedde10} and used and extended
under the GNU General Public License. This code contains commented header
files and simple examples and use cases. This software is best installed
standalone into a dedicated directory, where an application code can then find
the header and library files to compile and link against, respectively.
In this document, we document the three distinct tasks to
\begin{description}
\item[A] create a coarse mesh (\figref{partA}),
\item[B] modify the refinement and partition structure internal to \pforest
(\figref{partB}),
\item[C] and to relate the mesh information to an application (\figref{partC}).
\end{description}
Unless indicated otherwise, all operations described below are understood as
MPI collectives, that is, they are called on all processors simultaneously.
Currently, part A needs to be performed redundantly on all processors, which is
acceptable for up to $10^5$--$10^6$ coarse cells (octree roots). Parts B and C
strictly implement distributed parallelism, where runtime and per-processor
memory are roughly proportional to the number of local elements (octree leaves)
on a given processor, independent of the number of octrees, the total number of
elements, or the refinement depth. Partitioning the forest into equal numbers
of elements per processor is a core \pforest operation and essentially free in
terms of execution time, so we suggest to call it whenever load balance is
desirable for subsequent operations.
\begin{figure}
\begin{center}
\begin{tikzpicture}[node distance=3ex,
grow via three points = {one child at (0.5,-1.5) and
two children at (0.5,-1.5) and (0.5,-3.0)},
edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
\tikzstyle{every node}=[action, anchor=west]
\tikzstyle{every child}=[arrseq]
\node (createconn) {\texttt{c =} (choose one below)}
child {
%\node (CAD) {CAD / mesh generator / \ldots}
% child {
node (connnew) { \texttt{c = p4est\_connectivity\_new (\ldots)} }
child {
node (connfill) { \parbox{5.2cm}{\texttt{c.tree\_to\_tree[\ldots]~= \ldots}\\
%\texttt{c\ldots}\\
etc.\ (populate members)}}
}
}
%\draw [arrseq] (CAD) -- (connnew);
%\draw [arrseq] (connnew) -- (connfill);
%\node[group, fit=(CAD) (connnew) (connfill)] (cadpipe) {};
child [missing] {}
child {
node (newunit) { \texttt{c = p4est\_connectivity\_new\_unitcube ()} }
}
child {
node (newstar) { \texttt{c = p4est\_connectivity\_new\_\ldots ()} }
}
child {
node (conndestroy) { \texttt{p4est\_connectivity\_destroy (c)} }
edge from parent[dashed]
};
\node[robject, xshift=12.5cm] (theconn) { \texttt{c} };
\draw[arrdat] (createconn) -- (theconn);
%\draw[arrdat] (newunit.east) -- (theconn);
%\draw[arrdat] (newstar.east) -- (theconn);
\node[object] at (0, -1.5-.75) (cadinput) {CAD};
\node[object] at (0, -4.5-.75) (predef) {predef.};
%\node[object, right=of theconn] (topartb) { Part B };
%\draw[arrdat, dashed] (theconn.east) -- (topartb.west);
%\draw[arrdat] (theconn) -- (conndestroy.east);
\draw[arrdat] (cadinput) -- (connnew);
\draw[arrdat] (cadinput) -- (connfill);
\draw[arrdat] (predef) -- (newunit);
\draw[arrdat] (predef) -- (newstar);
\end{tikzpicture}
\end{center}
\caption{Part A, creating the coarse mesh connectivity. The \pforest connectivity
\texttt{c} is a \texttt{C struct} that contains numbers and orientations of
neighboring coarse cells. It can be created by translating CAD or mesh data
file formats or by using one of several predefined \pforest
functions. The data format is documented in the extensive comment blocks in
\texttt{p4est\_connectivity.h} (2D) and \texttt{p8est\_connectivity.h} (3D);
see also \cite{BursteddeWilcoxGhattas11}.
In the following, \texttt{p4est} always refers to both 2D and 3D.
}%
\label{fig:partA}%
\end{figure}%
\begin{figure}
\begin{center}
\begin{tikzpicture}[%node distance=3ex,
grow via three points = {one child at (0.5,-1.5) and
two children at (0.5,-1.5) and (0.5,-3.0)},
edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
\tikzstyle{every node}=[action, anchor=west]
\tikzstyle{every child}=[arrseq]
\node (p4estnew) {\parbox{4.5cm}{\texttt{p = p4est\_new (c)}\\
(modify \texttt{p} in-place below)}}
child {
node (p4estrefine) {\texttt{p4est\_refine (p)}}
}
child {
node (p4estcoarsen) {\texttt{p4est\_coarsen (p)}}
}
child {
node (p4estbalance) {\texttt{p4est\_balance (p)}}
}
child {
node (p4estpartition) {\texttt{p4est\_partition (p)}}
}
child {
node (ghostnew) {\parbox{4.6cm}{\texttt{g = p4est\_ghost\_new (p)}\\
(does not modify \texttt{p})}}
child {
node (ghostdestroy) {\texttt{p4est\_ghost\_destroy (g)}}
edge from parent[dashed]
}
}
child [missing] {}
child {
node (p4estdestroy) {\texttt{p4est\_destroy (p)}}
edge from parent[dashed]
};
\node[object, xshift=-1.5cm] (cinput) {\texttt{c}};
\draw[arrdat] (cinput) -- (p4estnew);
\node[robject, xshift=11.2cm] (poutput) {\texttt{p}};
\draw[arrdat] (p4estnew) -- (poutput);
\node[robject, xshift=11.2cm, yshift=-7.5cm] (goutput) {\texttt{g}};
\draw[arrdat] (ghostnew) -- (goutput);
\node[robject, xshift=11.2cm, yshift=-1.5cm-.75cm] (flags) {flags};
\draw[arrdat] (flags) -- (p4estrefine);
\draw[arrdat] (flags) -- (p4estcoarsen);
\end{tikzpicture}
\end{center}
\caption{Part B, changing the refinement structure and partition. With the
connectivity \texttt{c} created in part A, we can create the distributed
\pforest structure. Several functions for its modification exist. For a
given \pforest snapshot, we can create a ghost layer \texttt{g} of off-processor
leaves, which will be outdated and should be destroyed once \texttt{p} is
changed again. Refinement and coarsening are controlled by callback functions
that usually query flags
determined by the application. The \texttt{C struct}s \texttt{p} and \texttt{g}
can be inspected directly by an application, for example to loop
through data associated with local and ghost leaves.
}%
\label{fig:partB}%
\end{figure}%
\begin{figure}
\begin{center}
\begin{tikzpicture}[%node distance=3ex,
grow via three points = {one child at (0.5,-1.5) and
two children at (0.5,-1.5) and (0.5,-3.0)},
edge from parent path={(\tikzparentnode.south) |- (\tikzchildnode.west)}]
\tikzstyle{every node}=[action, anchor=west]
\tikzstyle{every child}=[arrseq]
\node (createmesh) {%\parbox{8cm}{
\texttt{n =} %(numbering of degrees of freedom)\\
(choose one below)}
child {
node (nodesnew) {\texttt{n = p4est\_nodes\_new (p, g)}}
}
child {
node (lnodesnew) {\texttt{n = p4est\_lnodes\_new (p, g)}}
}
child {
node (iterate) {\parbox{4cm}{\texttt{n =} (custom allocation)\\
\texttt{p4est\_iterate (p, g)}}}
}
child {
node (custom) {\texttt{n =} (custom allocation and code)}
}
child {
node (ndestroy) {(call appropriate destructor on \texttt{n})}
edge from parent[dashed]
}
;
\node[object, xshift=-2.0cm] (pginput) {\texttt{p, g}};
\draw[arrdat] (pginput) -- (createmesh);
\node[robject, xshift=9.0cm] (themesh) {\texttt{n}};
\draw[arrdat] (createmesh) -- (themesh);
\end{tikzpicture}
\end{center}
\caption{Part C, creating an application-specific numbering of degrees of freedom.
The \texttt{nodes} and \texttt{lnodes} constructors create a processor-local
view of globally unique node numbers and the dependency lists for hanging
nodes for continuous tensor-product piecewise linear and piecewise polynomial
finite elements, respectively.
The iterator provides a generic way to traverse the refinement structure and to
have callbacks executed for every face, edge, and corner neighborhood, which can
then be used to identify node locations and their hanging status for any custom
element type. The \texttt{C}
prototypes and documentation can be found in the respective \pforest
\texttt{.h} files.% Custom traversal and numbering can work as well.
}%
\label{fig:partC}%
\end{figure}%
\begin{figure}
\begin{center}
\subfigure[Generating the initial refinement structure and mesh.]{%
\includegraphics[width=.9\columnwidth]{plots/adaptivity/amr_octor1}%
}
\\
\subfigure[A-posteriori change of refinement structure and mesh.]{%
\includegraphics[width=.9\columnwidth]{plots/adaptivity/amr_octor2}%
}
\end{center}
\caption{Separation between \pforest on one hand and application-specific mesh
and numerical information on the other.
The dark blue nodes in the picture correspond to in-place operations on the
forest \texttt{p} that fall under part B (\figref{partB}). The dark green node
labeled
ExtractMesh refers to creating a node numbering structure \texttt{n} (part C;
see \figref{partC}) and the allocation of numerical space in application
memory guided by \texttt{n}. The bright green fields in the bottom-most row refer
to moving the application-specific numerical information from the old mesh to
the new one. We suggest doing this in two steps: Interpolation works
processor-local since the partition has not been changed at this point. Then,
after partitioning, transfer moves data to the new owner processors of the
respective degrees of freedom without changing the refinement pattern any
further. Both operations require the existence of both the old and
new \texttt{n} structures, and allow for freeing the older one afterwards.
(Plots originally published in \cite{BursteddeGhattasStadlerEtAl08}.)
}%
\label{fig:meshes}%
\end{figure}%
The definition and organisation of numerical data is entirely left up to the
application. The application calls modification operations for the forest
(part B), guided by the numerical state related to the local leaves. A
numerical application will require its own numbering scheme for degrees of
freedom, which is most of the time defined via node locations on a reference
element and dependencies between hanging nodes and the independent nodes they
are interpolated from. \pforest provides several paths for aiding the
application in defining their data layout, henceforth called the mesh (part C),
and not to be confused with the coarse octree mesh (part A). \figref{meshes}
contains illustrations on the sequence of operations that are required to
create a new refinement pattern from scratch or by modifying an existing one,
and to move the application-specific numerical data from an old to a new mesh.
\bibliographystyle{siam}
\bibliography{ccgo}
\end{document}
|