+++ /dev/null
-\documentclass{article}
-\usepackage{times}
-\usepackage{amsmath}
-\usepackage{amsfonts}
-\usepackage{a4}
-\newcommand{\leftpartial}{\overleftarrow \partial}
-\newcommand{\rightpartial}{\overrightarrow \partial}
-\renewcommand{\div}{\nabla\cdot}
-\renewcommand{\vec}[1]{{\mathbf #1}}
-\begin{document}
-
-
-\begin{center}
- \begin{huge}
- Assembling matrices in \texttt{deal.II}
- \end{huge}
-
- \vspace*{0.5cm}
-
- \begin{large}
- Wolfgang Bangerth\\
- ETH Z\"urich, Switzerland\\[12pt]
- May 2002
- \end{large}
-\end{center}
-
-
-\section{Introduction}
-
-Assembling the system matrix for finite element discretizations is standard,
-at least as far as scalar problems are concerned. However, things become a
-little more complicated in implementations once problems are vector-valued,
-and in particular if finite elements are used in which different components of
-vector-valued shape functions are coupled, such as for example for
-divergence-free elements.
-
-It is this case that we are interested in in this report, and we will discuss
-the implementational details user programs must follow if they want to use
-such elements with \texttt{deal.II}. In order to explain the problem in a
-simple way, we start by reviewing the algorithms that are used, first for the
-scalar case, then for the case of ``simple'' vector-valued finite elements,
-and finally for the most general case. However, we do not intend to give an
-introduction into the derivation of finite element methods, or of posing a
-partial differential equation in weak form.
-
-The interface for vector-valued finite element shape functions with more than
-one non-zero component that is described in this report is presently being
-implemented, and will be merged with the library after version 3.4 is
-released. Thus, it will be part of version 3.5 or 4.0 of the library,
-depending on which version number we will assign to the successor of 3.4. By
-then, the library will also contain an implementation of Nedelec elements, for
-which these techniques are necessary. The interface for primitive
-vector-valued shape functions, for which only one vector component is
-non-zero, has been part of the library since its publication with version 3.0.
-
-
-
-
-\section{Linear systems for finite element methods}
-
-We start by briefly introducing the way finite element matrices are assembled
-``on paper''. As usual in finite elements, we take the weak form of the partial
-differential equation. In the most general case, it reads: \textit{find $u\in
- V$ such that}
-\begin{gather*}
- a(u, v) = (f,v)_\Omega \qquad \forall v\in V,
-\end{gather*}
-where $a(\cdot,\cdot)$ is the bilinear form associated with the partial
-differential equations, and $V$ is the space of test functions. For
-simplicity, we have here assumed that the problem is linear and that then
-$a(\cdot,\cdot)$ is a bilinear form; if the problem is nonlinear, it is
-usually solved using a sequence of linear problems, so this is no restriction.
-
-In finite elements, we define an approximation of the solution $u$ by choosing
-a finite dimensional subspace $V_h$ spanned by the basis functions
-$\{\varphi_i\}$, and searching $u_h\in V_h$ by testing the weak form by the
-test functions from $V_h$. The problem then reads: \textit{find $u_h\in V_h$
-such that}
-\begin{gather*}
- a(u_h, v_h) = (f,v_h)_\Omega \qquad \forall v_h\in V_h.
-\end{gather*}
-
-Now, $\{\varphi_i\}$ is a basis of $V_h$. We denote the dimension of $V_h$ by
-$N$, and will henceforth let all sums be over the range $0\ldots N-1$, to keep
-with the standard notation of the C/C++ programming languages. With this, we
-can expand the solution $u_h=\sum_{j=0}^{N-1} U_j \varphi_j$, and by
-bilinearity of the form $a(\cdot,\cdot)$, the problem above is equivalent to
-\begin{gather}
- \label{eq:lin-1}
- \sum_{j=0}^{N-1} U_j a(\varphi_j,\varphi_i) = (f, \varphi_i)
- \qquad
- \forall i=0\ldots N-1.
-\end{gather}
-Denoting
-\begin{gather*}
- A_{ij} = a(\varphi_j,\varphi_i),
- \qquad
- \qquad
- F_j = (f, \varphi_j),
-\end{gather*}
-the equations determining the expansion coefficients $U_i$ are therefore:
-\begin{gather}
- \label{eq:lin-2}
- A U = F.
-\end{gather}
-
-Note that we have taken a reverted order of indices in the definition of $A$,
-since we want the linear system \eqref{eq:lin-2} with the solution to the
-right of the matrix, to keep with standard notation, instead of to the left as
-in \eqref{eq:lin-1}. For symmetric problems, there is no difference, but for
-non-symmetric ones this is a common source for problems and a rather common
-trap.
-
-For partial differential equations, the bilinear form used in \eqref{eq:lin-1}
-involves an integral over the domain $\Omega$ on which the problem is
-posed. For example, for the Laplace equation we have
-\begin{gather*}
- A_{ij}
- =
- a(\varphi_j, \varphi_i)
- =
- (\nabla \varphi_j, \nabla \varphi_i)_\Omega
- =
- \int_\Omega \nabla \varphi_j \cdot \nabla \varphi_i \; dx.
-\end{gather*}
-For practical purposes, we split this equation into integrals over the
-individual cells $K$ of the triangulation $\mathbb T$ we use for the
-discretization. In \texttt{deal.II}, these cells are always lines,
-quadrilaterals, or hexahedra. With this, we have that
-\begin{gather*}
- A = \sum_{K \in {\mathbb T}} A^K,
- \qquad\qquad
- A^K_{ij} = a_K(\varphi_j, \varphi_i)
- \qquad
- 0\le i,j\le N-1,
-\end{gather*}
-where the bilinear form $a_K(\cdot,\cdot)$ only involves an integral over the
-cell $K$. The important point is that we do so since for the localized basis
-functions used in finite elements, $A^K$ is a matrix with almost only zeros.
-The only elements which are not zero are those corresponding to indices $i,j$
-indicating those shape functions that have support also on the element $K$.
-For example, in 2d and using the usual bilinear shape functions for a scalar
-problem, only the four shape functions associated with the vertices of the
-cell $K$ are nonzero on $K$, and thus only the entries in $A^K$ are nonzero
-where the four rows corresponding to these indices and the respective four
-columns intersect.
-
-In general, assume that there are $N_K$ shape functions with support on cell
-$K$, and let the set of their indices be denoted by $I_K$. Then we can define
-a matrix $\hat A^K$ of (small dimension) $N_K\times N_K$ holding these nonzero
-entries, and we can obtain back the original contribution $A_K$ to $A$ by the
-transformation
-\begin{gather*}
- A^K_{ij} =
- \left\{
- \begin{array}{ll}
- 0 & \text{if $i\not\in I_K$ or $j\not\in I_K$,} \\
- \hat A^K_{local(i),local(j)} & \text{otherwise},
- \end{array}
- \right.
- \qquad 0\le i,j\le N-1.
-\end{gather*}
-Here, $local(i)$ gives the number of the global degree of freedom $i$ on the
-cell $K$, i.e. the position of $i$ in the index set $I_K$. One could call
-$\hat A^K$ the \texttt{reduced} form of $A^K$, since the many zero rows and
-column have been stripped.
-
-In general, when assembling the global matrix, the reverse way is used: when
-adding up $A^K$ to $A$, we do so only with $\hat A^K$ by
-\begin{gather*}
- A_{global(i),global(j)}
- +\!\!=
- \hat A^K_{ij}
- \qquad
- \qquad
- 0\le i,j\le N_K-1.
-\end{gather*}
-Thus, indices only run over the (small) range $0\ldots N_K-1$ instead of
-$0\ldots N-1$. Here, $global(i)$ denotes the global number of the degree of
-freedom with number $i$ on this cell $K$, i.e. $global(i)=I_K[i]$, where the
-bracket operator returns the $i$th element of the set $I_K$.
-
-The main part of assembling finite element matrices is therefore to assemble
-the local matrix $\hat A^K$. Before we go on with discussing how this is done
-in \texttt{deal.II}, we would like to comment on the evaluation of the
-integrals involved. Since the integrals are usually too complex to be
-evaluated exactly (they may depend on coefficients appearing in the equation,
-or the solution of previous steps in nonlinear or time-dependent problems),
-they are approximated by quadrature. Assume we have a quadrature formula with
-$N_q$ points $x_q$ defined on cell in real space (as opposed to the unit cell)
-and weights $w_q$. Then, for example for the Laplace equation, we approximate
-\begin{gather}
- \hat A^K_{ij}
- \equiv
- \int_K \nabla\varphi_i \cdot \nabla \varphi_j \; dx
- \approx
- \sum_{q=0}^{N_q-1}
- \nabla\varphi_i(x_q) \cdot \nabla \varphi_j(x_q)
- \ w_q |\text{det} \ J(\hat x_q)|.
-\end{gather}
-For other problems, the integrand is different, but the principle remains the
-same. $\text{det}\ J(\hat x_q)$ denotes the determinant of the Jacobian of the
-transformation between the unit cell on which the quadrature weights are
-defined, and the real cell, and $\hat x_q$ is the point on the unit cell
-corresponding to the quadrature point $x_q$ in real space.
-
-Since all matrices and right hand side vectors only require knowledge of the
-values and gradients of shape functions at quadrature points, this is all that
-\texttt{deal.II} usually provides. One can see this as a kind of \textit{view}
-on a finite element, as it only provides a certain perspective on the actual
-definition of a shape function. Nevertheless, this is entirely sufficient for
-all purposes of programming finite element programs.
-
-In \texttt{deal.II} the \texttt{FEValues} class does this: you give it a
-finite element definition, a quadrature formula object, and an object defining
-the transformation between unit and real cell, and it provides you with the
-values, gradient, and second derivatives of shape functions at the quadrature
-points. It also gives access to the determinant of the Jacobian, although only
-multiplied with $w_q$ as these two are always used in conjunction. It also
-provides you with many other fields, such as normal vectors to the outer
-boundary. In practice you do not need them all computed on each cell; thus,
-you have to specify explicitly in which data you are interested when
-constructing \texttt{FEValues} objects.
-
-In the following, we provide a list of connections between the symbols introduced
-above, and the respective functions and variable names used in typical
-\texttt{deal.II} programs. With this, we will subsequently show the basic
-structure of an assembly routine. If you have already taken a look at the
-example programs provided with \texttt{deal.II}, you will recognize all these
-names. If you haven't, this would be a good time to look at the first
-three of them.
-
-
-\begin{center}
- \begin{tabular}{|ll|}
- \hline
- $A$ & \texttt{system\_matrix} \\
- $\hat A^K$ & \texttt{cell\_matrix} \\
- $K$ & \texttt{cell} \\
- $N$ & \texttt{dof\_handler.n\_dofs()} \\
- $N_K$ & \texttt{fe.dofs\_per\_cell} \\
- $I_K$ & \texttt{local\_dof\_indices} \\
- $N_q$ & \texttt{quadrature\_formula.n\_quadrature\_points} \\
- $\varphi_i(x_q)$ & \texttt{fe\_values.shape\_value(i,q)} \\
- $\nabla\varphi_i(x_q)$ & \texttt{fe\_values.shape\_grad(i,q)} \\
- $x_q$ & \texttt{fe\_values.quadrature\_point(q)} \\
- $|\text{det} J(\hat x_q)| w_q$ & \texttt{fe\_values.JxW(q)} \\
- \hline
- \end{tabular}
-\end{center}
-
-With this vocabulary, the typical matrix assembly loop in \texttt{deal.II} has
-the following form: first declare a quadrature object and use it for the
-initialization of a \texttt{FEValues} object as discussed above:
-\begin{verbatim}
- QGauss2<2> quadrature_formula;
- FEValues<2> fe_values (fe, quadrature_formula,
- UpdateFlags(update_values |
- update_gradients |
- update_JxW_values));
-\end{verbatim}
-In practice, you may want to use a different set of fields to be updated on
-each cell. For example if you do not need the values of shape functions on a
-cell, you may omit \texttt{update\_values} from the list. Also note that by
-default a bi- or tri-linear (depending on space dimension) mapping between
-unit and real cell is used. Other mappings are possible, for example quadratic
-ones, or a mapping that makes use of the fact that in many cases cells are
-actually rectangular, rather than arbitrary quadrilaterals; in order to use
-them, another constructor of the \texttt{FEValues} class can be used, which
-takes a mapping object as first argument, before the other arguments listed
-above.
-
-Next we define abbreviations for the values of $N_K$ and $N_q$:
-\begin{verbatim}
- const unsigned int
- dofs_per_cell = fe.dofs_per_cell,
- n_q_points = quadrature_formula.n_quadrature_points;
-\end{verbatim}
-Then have an object to store the matrix $\hat A^K$, which is of size
-$N_K\times N_K$:
-\begin{verbatim}
- FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
-\end{verbatim}
-And an object representing the set of global indices of degrees of freedom,
-previously denoted by $I_K$, that have support on the present cell, i.e. those
-degrees of freedom local to the present cell:
-\begin{verbatim}
- std::vector<unsigned int> local_dof_indices (dofs_per_cell);
-\end{verbatim}
-The next step is then to loop over all cells:
-\begin{verbatim}
- typename DoFHandler<dim>::active_cell_iterator
- cell = dof_handler.begin_active(),
- endc = dof_handler.end();
- for (; cell!=endc; ++cell)
- {
-\end{verbatim}
-On each cell, first tell the \texttt{FEValues} object to compute the values of
-the various fields for this particular cell, and do not forget to reset the
-local matrix $\hat A^K$ to zero before adding it up:
-\begin{verbatim}
- fe_values.reinit (cell);
- cell_matrix.clear ();
-\end{verbatim}
-Now comes the main part, assembling the local matrix $\hat A^K$. It consists
-of a loop over all indices $0\le i,j \le N_K$ and all quadrature points $0\le
-q\le N_q$, and summing up the contributions. As this is what we will discuss
-in detail later on, we only denote it here by an ellipse:
-\begin{verbatim}
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- for (unsigned int j=0; j<dofs_per_cell; ++j)
- for (unsigned int q=0; q<n_q_points; ++q)
- cell_matrix(i,j) += ...;
-
-\end{verbatim}
-After we have $\hat A^K$, we still have to sum it into the global matrix
-$A$. This is done by first getting the set $I_K$ of the global indices of the
-shape functions that were active on this cell, and then distributing $\hat
-A^K$:
-\begin{verbatim}
- cell->get_dof_indices (local_dof_indices);
-
- for (unsigned int i=0; i<dofs_per_cell; ++i)
- for (unsigned int j=0; j<dofs_per_cell; ++j)
- system_matrix.add (local_dof_indices[i],
- local_dof_indices[j],
- cell_matrix(i,j));
- };
-\end{verbatim}
-When this is done, we go on to the next cell.
-
-Within this framework, the only open point is assembling $\hat A^K$ on one
-quadrature point. This will be subject of the rest of this report.
-
-
-\section{Assembling scalar problems}
-
-For scalar problems, assembling $\hat A^K$ is relatively simple. With the
-terms introduced above, and for the Laplace equation, this looks as follows:
-\begin{verbatim}
- local_matrix(i,j) += (fe_values.shape_grad(i,q_point) *
- fe_values.shape_grad(j,q_point) *
- fe_values.JxW (q_point));
-\end{verbatim}
-This term is placed in the innermost loop, i.e. is performed for all indices
-$i,j$, and all quadrature points \texttt{q\_point}.
-
-For nonsymmetric problems, the order of terms has to be considered, as
-mentioned above. For example, for the advection equation
-\begin{gather*}
- \beta \cdot \nabla u = f,
-\end{gather*}
-with which the bilinear form
-\begin{gather*}
- a(u,v) = (\beta \cdot \nabla u, v)_\Omega
-\end{gather*}
-is associated, the local matrix is assembled as
-\begin{verbatim}
- local_matrix(i,j) += (fe_values.shape_values(i,q_point) *
- ( beta * fe_values.shape_grad(j,q_point) ) *
- fe_values.JxW (q_point));
-\end{verbatim}
-Here, \texttt{beta} is an object of type \texttt{Tensor<1,dim>}, which
-represents a tensor of rank 1 in \texttt{dim} space dimensions.
-
-Assembling matrices for scalar problems is also shown from a practical
-perspective in many of the example programs of \texttt{deal.II}, where it is
-also demonstrated how to do this for the right hand side vectors. Thus, scalar
-problems are not too interesting, and we now turn to vector-valued problems.
-
-
-
-\section{Vector-valued problems}
-
-Since we need some problems at which we will explain assembling the matrix for
-the vector-valued case, we now briefly introduce two simple equations. The
-first are the Lam\'e equations of elasticity, which are taken for the symmetric
-case, then we briefly introduce the Stokes equations as a nonsymmetric problem.
-
-\subsection{The elastic equations}
-\label{sec:elastic}
-
-As first example for the methods we are going to discuss for vector-valued
-problems, we consider the elastic Lam\'e equations for isotropic materials,
-which read in strong form:
-$$
- -
- \nabla (\lambda+\mu) (\div \vec u)
- -
- (\nabla \cdot \mu \nabla) \vec u
- =
- \vec f.
-$$
-These equations describe the three-dimensional deformation $\vec u$ of an
-elastic body under a body force $\vec f$. The respective bilinear form
-associated with this operator is then
-$$
- a(\vec u, \vec v) =
- \left(
- (\lambda+\mu) \div \vec u, \div \vec v
- \right)_\Omega
- +
- \sum_k
- \left(
- \mu \nabla u_k, \nabla v_k
- \right)_\Omega,
-$$
-or as a sum over components:
-$$
- a(\vec u, \vec v) =
- \sum_{k,l}
- \left(
- (\lambda+\mu) \partial_l u_l, \partial_k v_k
- \right)_\Omega
- +
- \sum_{k,l}
- \left(
- \mu \partial_l u_k, \partial_l v_k
- \right)_\Omega.
-$$
-
-When assembling matrices, it is advantageous to write the weak form
-(i.e. after integration by parts) as a kind of operator. This is since matrix
-elements after discretization are defined as
-\begin{gather*}
- A_{ij} = a(\varphi_j,\varphi_i)_\Omega,
-\end{gather*}
-where $\varphi_i,\varphi_j$ are two vector-valued trial functions, and it
-would be nice if we could write the bilinear form $a(\cdot,\cdot)$ as a kind
-of scalar product $(\varphi_i, Q \varphi_j)$, where $Q$ is a differential
-operator. This is trivial if we take $Q$ as the operator of the strong form,
-$Q=-\nabla (\lambda+\mu) \div - (\nabla \cdot \mu \nabla)$, but we wanted to
-do this for the weak form. For this, we introduce some notation that is used
-in quantum field theory: for differential operators, we indicate by an arrow
-placed atop of it whether it shall act on the object to the left or to the
-right of it. Thus,
-$\varphi \overleftarrow\nabla \cdot \overrightarrow\nabla \psi
-=(\nabla\varphi)\cdot(\nabla\psi)$. With this, a simple computation shows
-that
-\begin{multline*}
- a(\vec u,\vec v)
- =
- (\lambda+\mu)
- \left(
- \begin{pmatrix}
- u_1 \\ u_2
- \end{pmatrix}
- \mid
- \begin{pmatrix}
- \leftpartial_1 \rightpartial_1 &
- \leftpartial_1 \rightpartial_2 \\
- \leftpartial_2 \rightpartial_1 &
- \leftpartial_2 \rightpartial_2
- \end{pmatrix}
- \mid
- \begin{pmatrix}
- v_1 \\ v_2
- \end{pmatrix}
- \right)_\Omega
- \\
- +
- \mu
- \left(
- \begin{pmatrix}
- u_1 \\ u_2
- \end{pmatrix}
- \mid
- \left(
- \leftpartial_1 \rightpartial_1 +
- \leftpartial_2 \rightpartial_2
- \right)
- \begin{pmatrix}
- 1 & 0 \\
- 0 & 1
- \end{pmatrix}
- \mid
- \begin{pmatrix}
- v_1 \\ v_2
- \end{pmatrix}
- \right)_\Omega.
-\end{multline*}
-The sought operator $Q$ is then
-\begin{gather*}
- Q
- =
- (\lambda+\mu)
- \begin{pmatrix}
- \leftpartial_1 \rightpartial_1 &
- \leftpartial_1 \rightpartial_2 \\
- \leftpartial_2 \rightpartial_1 &
- \leftpartial_2 \rightpartial_2
- \end{pmatrix}
- +
- \mu
- \begin{pmatrix}
- \leftpartial_1 \rightpartial_1 +
- \leftpartial_2 \rightpartial_2 & 0 \\
- 0 & \leftpartial_1 \rightpartial_1 +
- \leftpartial_2 \rightpartial_2
- \end{pmatrix},
-\end{gather*}
-and $a(\vec u,\vec v)=(\vec u | Q | \vec v)$. We demonstrate the fact that $Q$
-acts to both sides by placing it in the middle of the scalar product, just as
-in the bra-ket notation of quantum physics.
-
-The advantages of this formulation will become clear when discussing
-assembling matrices below. For now, we remark that the symmetry of the weak
-form is equally apparent from the form of $Q$ as well as from the initial
-definition of $a(\cdot,\cdot)$.
-
-
-
-\subsection{The Stokes equations}
-\label{sec:stokes}
-
-For a nonsymmetric problem, we take the Stokes equations:
-\begin{align*}
- -\Delta \vec u + \nabla p &= 0,
- \\
- \text{div } \vec u &= 0.
-\end{align*}
-We denote by $\vec w=\{\vec u,p\}$ the entire solution vector. In the weak
-form, the above equations read
-\begin{gather*}
- a(\vec u,p; \vec v, q)
- =
- \nu(\nabla \vec u_1, \nabla \vec v_1)
- +\nu(\nabla \vec u_2, \nabla \vec v_2)
- - (p, \nabla\cdot \vec v)
- + (\nabla\cdot\vec u, q).
-\end{gather*}
-Since we integrated the gradient term in the first equation by parts, but not
-the divergence term in the second equation, the problem is now
-nonsymmetric. If we would have liked, we could have made the problem symmetric
-again by multiplying the entire second equation by $-1$, but we don't want to
-do that for now for illustrational purposes.
-
-Again, we introduce the operator $Q$ for this problem, which after some
-computations turns out to be
-\begin{gather*}
- Q
- =
- \begin{pmatrix}
- \nu(\leftpartial_1 \rightpartial_1 +
- \leftpartial_2 \rightpartial_2) & 0 & -\leftpartial_1 \\
- 0 & \nu(\leftpartial_1 \rightpartial_1 +
- \leftpartial_2 \rightpartial_2) & -\leftpartial_2 \\
- \rightpartial_1 & \rightpartial_2 & 0
- \end{pmatrix}.
-\end{gather*}
-Again, it is clear from this form that we could have made the operator
-symmetric by multiplying the last row by $-1$. Note when checking the symmetry
-of $Q$ that taking the transpose of such an operator means reverting the
-directions of the arrows over the operators, and exchanging their order.
-For example, using the first term, these two steps are
-$\leftpartial_1 \rightpartial_1 \rightarrow \rightpartial_1 \leftpartial_1
-\rightarrow \leftpartial_1 \rightpartial_1$.
-
-
-\section{Assembling vector-valued problems: The simple case}
-
-The simple case in assembling vector-valued problems is when the (also
-vector-valued) shape functions are chosen such that only one component in the
-vector is nonzero. This is usually the case, if we choose the shape functions
-to be the outer product of scalar shape functions, such as independent
-bilinear ansatz spaces for each component of a finite element space.
-
-In this case, each shape function $\Phi_i$ has the representation
-\begin{gather*}
- \Phi_i(\vec x) =
- \left( 0, \dots, 0, \varphi_i(\vec x), 0, \ldots, 0\right)^T,
-\end{gather*}
-where $\Phi_i$ is the vector-valued shape function, and $\varphi_i$ its
-only non-zero component. Let us denote by $c(i)$ the index of this non-zero
-component, then $\Phi_i$ can also be written as
-\begin{gather*}
- \left(\Phi_i(\vec x)\right)_l
- =
- \varphi_i(\vec x) \delta_{c(i),l},
-\end{gather*}
-with the Kronecker delta function $\delta_{jk}$.
-
-With this simple form, the cell matrix on cell $K$ has a simple form:
-\begin{gather*}
- A^K_{ij}
- =
- a_K(\Phi_i,\Phi_j)
- =
- \left(\Phi_i \mid Q \mid \Phi_j \right)_K
- =
- \left(\varphi_i \mid Q_{c(i),c(j)} \mid \varphi_j \right)_K.
-\end{gather*}
-Thus, in assembling the local cell matrices, we only have to determine the
-single components in which the two shape functions are non-zero, and
-pick one element from the matrix $Q$ to assemble each entry of the cell
-matrix with the help of the values of the functions $\varphi_i$ at the
-quadrature points. Here, it comes handy that we have written the operator as a
-matrix operator $Q$, since this makes it very clear how shape functions $i$
-and $j$ couple: if $Q_{c(i),c(j)}$ is zero, then they do not couple at all for
-this operator. Otherwise, it is easily visible which derivative acts on which
-shape function for this combination of shape functions.
-
-In \texttt{deal.II}, these two actions mentioned above (getting the non-zero
-component of a shape function, and the value of this component at a given
-quadrature point) are done as follows:
-\begin{itemize}
-\item \textit{Determining the non-zero component:} Given the shape function
- with number $i$ (i.e. its index local to the degrees of freedom on the
- present cell), its only non-zero component is obtained by the function call
-\begin{verbatim}
- const unsigned int nonzero_component_i
- = fe.system_to_component_index(i).first;
-\end{verbatim}
- The \texttt{FiniteElement::system\_to\_component\_index} returns a pair of
- numbers for each index $0\le i < N_K$, the first of which denotes the only
- non-zero component of the shape function $i$. Since for the case described
- in this section, the individual components of the vector-valued finite
- element are independent, we consider each component as a set of scalar shape
- functions; the second number of the pair returned by the function then
- denotes the index of the shape function $\varphi_i$ within the shape
- functions corresponding to this component.
-
- If, for example, our finite element in use is a $Q^2/Q^2/Q^1$ combination
- (for example for 2d flow computations: bi-quadratic ansatz functions for the
- velocities, bi-linear for the pressure), then we have a total of 22 shape
- functions (9+9+4). For each $0\le i < 22$, the first part of the pair
- returned by the function described above, $c(i)$, may then either be 0, 1,
- or 2, denoting the three possible components of the finite element. If
- $c(i)$ is either 0 or 1, then the component to which the shape function $i$
- belongs is a bi-quadratic one, and the second index is between $0$ and $8$
- (inclusive) as the $Q^2$ element has 9 shape functions. If $c(i)==2$, then
- the second part is between 0 and 3 (inclusive).
-
-\item \textit{Getting the value of $\varphi_i(\vec x_q)$:} Since only one
- component of $\Phi_i$ is non-zero, we can use the same function as before,
- i.e. \texttt{FEValues::shape\_value(i,q)}, which in the scalar case returned
- the value of shape function $i$ at quadrature point $q$. Likewise, the
- \texttt{FEValues::shape\_grad(i,q)} function returns the gradient of this
- particular component.
-
- In other words, whether the finite element is scalar or not, the two
- indicated functions return value and gradient of the only non-zero component
- of a shape function. If the finite element is scalar, then it is of course
- clear which component this is (since there $c(i)==0$ for all valid indices
- $i$), in the vector-valued case, it is component $c(i)$.
-\end{itemize}
-
-
-\subsection{The elastic equations}
-\label{sec:elastic-simple}
-
-With this, and the definition of the ``bi-directional'' operator $Q$ in
-Section~\ref{sec:elastic}, the local matrix assembly function for the elastic
-equations would then read as follows:
-\begin{verbatim}
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- for (unsigned int q=0; q<n_q_points; ++q)
- {
- const unsigned int
- comp_i = fe.system_to_component_index(i).first,
- comp_j = fe.system_to_component_index(j).first;
-
- // first assemble part with lambda+mu
- cell_matrix(i,j) += ((lambda+mu) *
- fe_values.shape_grad(i,q)[comp_i] *
- fe_values.shape_grad(j,q)[comp_j] *
- fe_values.JxW(q));
-
- // then part with mu only
- if (comp_i == comp_j)
- cell_matrix(i,j) += (mu *
- (fe_values.shape_grad(i,q) *
- fe_values.shape_grad(j,q) )*
- fe_values.JxW(q));
- };
-\end{verbatim}
-Note that this code works in any space dimension, not only for
-\texttt{dim==2}. Optimization of this is possible by hoisting the computation
-of \texttt{comp\_i} and \texttt{comp\_j}, denoting $c(i)$ and $c(j)$,
-respectively, out of the inner loops. Also, if the coefficients are
-non-constant, they need to be computed at each quadrature point; this may be
-done using this fragment in the innermost loop:
-\begin{verbatim}
- const double
- lambda_value = lambda.value(fe_values.quadrature_point(q)),
- mu_value = mu.value(fe_values.quadrature_point(q));
-\end{verbatim}
-assuming that \texttt{lambda,mu} are variables of classes describing space
-dependent functions, and which are derived
-from the \texttt{Function<dim>} class.
-
-
-\subsection{The Stokes equations}
-\label{sec:stokes-simple}
-
-For the Stokes equation, things are slightly more complicated since the three
-components denote different quantities, and the operator $Q$ does not have
-such a simple form, but the case is still simple enough. We present its
-generalization to an arbitrary number of space dimensions, i.e. assume that
-there are \texttt{dim} velocity variables and one scalar pressure:
-\begin{verbatim}
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- for (unsigned int q=0; q<n_q_points; ++q)
- {
- const unsigned int
- comp_i = fe.system_to_component_index(i).first,
- comp_j = fe.system_to_component_index(j).first;
-
- // velocity-velocity coupling?
- if ((comp_i<dim) && (comp_j<dim))
- if (comp_i == comp_j)
- cell_matrix(i,j) += (nu *
- (fe_values.shape_grad(i,q) *
- fe_values.shape_grad(j,q) ) *
- fe_values.JxW(q));
-
- // velocity-pressure coupling
- if ((comp_i<dim) && (comp_j==dim))
- cell_matrix(i,j) += (-fe_values.shape_grad(i,q)[comp_i] *
- fe_values.shape_value(j,q) *
- fe_values.JxW(q));
-
- // pressure-velocity coupling
- if ((comp_i==dim) && (comp_j<dim))
- cell_matrix(i,j) += (fe_values.shape_value(i,q) *
- fe_values.shape_grad(j,q)[comp_j] *
- fe_values.JxW(q));
- };
-\end{verbatim}
-Again, optimization is possible by observing that only one of the outer
-\texttt{if}s in the body can be true, for example using \texttt{else} clauses,
-or \texttt{break} statements.
-
-
-\section{Assembling vector-valued problems: The complicated case}
-
-The more complicated case is when more than one component of a vector-valued
-shape function is non-zero, i.e. the representation
-\begin{gather*}
- \Phi_i(\vec x) =
- \left( 0, \dots, 0, \varphi_i(\vec x), 0, \ldots, 0\right)^T,
-\end{gather*}
-does not hold any more. The usual case where this happens is when shape
-functions have to satisfy certain constraints, such as that they should have
-zero divergence or curl, or when the normal fluxes at some points, e.g. the
-face centers, are the degrees of freedom:
-$\vec n\cdot \Phi_i(x_a) = \delta_{ia}$. In this case, the individual
-components of a shape function are no more independent, and thus cannot be
-chosen such that only one component is non-zero.
-
-What happens in this case? First, the function
-\texttt{FiniteElement::system\_\-to\_\-component\_\-index} does not make much sense
-any more, since a shape function $\Phi_i$ cannot be associated with only one
-vector component any more. Calling this function for basis functions $\Phi_i$
-that are not restricted to only one non-zero component will thus yield an
-exception being thrown.
-
-Second, the functions \texttt{FEValues::shape\_value} and
-\texttt{FEValues::shape\_grad} returning the values and gradients of the only
-non-zero component of a shape function at a quadrature point cannot work any
-more, since there are now more than only one non-zero components for some or
-all values of $i$. For those shape function for which this holds, you will
-again get an exception upon calling these functions.
-
-
-\subsubsection*{Getting information about shape functions}
-
-So how do you find out whether calling these functions is ok or not? In other
-words, how do you know whether shape function $\Phi_i$ has only one non-zero
-component, or more? For this, there are two functions:
-\texttt{FiniteElement::is\_primitive(i)} returns as a \texttt{bool} whether
-the shape function has only one non-zero component. For example, for a
-$Q^2/Q^2/Q^1$ element, this would be \texttt{true} for all 22 shape functions.
-For a finite element for which every shape function is non-zero in more than
-one component, it would be \texttt{false} for all indices $i$. It might also
-be \texttt{true} for only some shape functions, for example if the velocity
-components of the Stokes discretization are done using some more complicated
-element, but the pressure component with a $Q^1$, then it would be
-\texttt{true} for the pressure shape functions, but \texttt{false} otherwise.
-
-Second, the \texttt{FiniteElement::n\_nonzero\_components(i)} function returns
-in how many components the $i$th shape function is non-zero. Again, for the
-$Q^2/Q^2/Q^1$ combination, this would yield the value 1 for all allowed
-indices $i$. For coupled elements, it would be greater than 1.
-
-Third, you may sometimes want to know in which components a certain shape
-function is non-zero. For this, the
-\texttt{FiniteElement::get\_nonzero\_components(i)} function is the right thing: it
-returns a reference to a vector of boolean values, one for each component of
-the vector-valued finite element, and the values indicate whether the shape
-function is non-zero for each of them.
-
-Note that if you have the result of
-\texttt{FiniteElement::get\_\-nonzero\_\-components(i)}, then the result of
-\texttt{FiniteElement::n\_nonzero\_components(i)} is simply the number of
-\texttt{true} values in the array returned by the first function. In the same
-way,
-\texttt{FiniteElement::\-is\_primitive(i)} is simply whether
-\texttt{FiniteElement::\-n\_nonzero\_\-components(i)} returned a value other than
-1. The functions are thus redundant in some way, but useful nevertheless. Of
-course, the values of the \texttt{FiniteElement::\-is\_primitive(i)}
-and \texttt{FiniteElement::n\_nonzero\_components(i)} functions are not
-recomputed every time based on the result of some other function, but are
-cached once at the time of construction of a finite element object.
-
-
-\subsubsection*{Evaluating shape functions}
-
-Now, we have seen which functions cannot be called for non-primitive shape
-functions, and also how to find out about shape functions and whether they are
-primitive and the like. Yet, we don't have replacements for the functions that
-cannot be called, so here they are: instead of \texttt{FEValues::shape\_value}
-and \texttt{FEValues::shape\_grad}, call
-\texttt{FEValues::shape\_value\_component} and
-\texttt{FEValues::shape\_grad\_component}. These functions take as arguments
-first the number of the shape function, and second the number of the
-quadrature point (these are also the arguments of the original functions), but
-now as additional third argument the vector component.
-
-Of course, these functions can be called on primitive shape functions as
-well. In that case, the following holds:
-\begin{itemize}
-\item The value of \texttt{FEValues::shape\_value\_component(i,q,c)} is equal
- to \texttt{FEValues::\-shape\_value(i,q)} if and only if the component
- \texttt{c} is equal to \texttt{fe.system\_to\_\-component\_\-index(i).first},
- i.e. if \texttt{c} is the only non-zero component of the shape function
- \texttt{i}.
-\item For all other components \texttt{c}, the returned value of
- \texttt{FEValues::shape\_\-value\_\-component(i,q,c)} is zero.
-\end{itemize}
-The same of course also holds for
-\texttt{FEValues::shape\_grad\_component(i,q,c)} and
-\texttt{FEValues::shape\_2nd\_derivative\_component(i,q,c)}.
-
-
-\subsection{The elastic equations}
-
-With the above, we can now assemble the matrix for the elastic equation in
-mostly the same way as before. The difference is that for each shape function,
-we have to loop over all components. The code then looks like this (compare
-this with the one in Section~\ref{sec:elastic-simple}):
-\begin{verbatim}
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int comp_i=0; comp_i<fe.n_components(); ++comp_i)
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- for (unsigned int comp_j=0; comp_j<fe.n_components(); ++comp_j)
- for (unsigned int q=0; q<n_q_points; ++q)
- {
- // first assemble part with lambda+mu
- cell_matrix(i,j)
- += ((lambda+mu) *
- fe_values.shape_grad_component(i,q,comp_i)[comp_i] *
- fe_values.shape_grad_component(j,q,comp_j)[comp_j] *
- fe_values.JxW(q));
-
- // then part with mu only
- if (comp_i == comp_j)
- cell_matrix(i,j)
- += (mu *
- (fe_values.shape_grad_component(i,q,comp_i) *
- fe_values.shape_grad_component(j,q,comp_j) )*
- fe_values.JxW(q));
- };
-\end{verbatim}
-If you dislike this particular order of the loops, you can reorder them as you
-like, as they are independent.
-
-The code as shown above can be optimized. For example, instead of
-unconditionally performing the loop over all components of shape functions $i$
-of $j$, we might first ask whether these shape functions are primitive, using
-\texttt{fe.is\_primitive(i)}, and use the loop only if the result is false;
-if, on the other hand, the result is true, we only need to set
-\texttt{comp\_i} to the fixed value
-\texttt{fe.system\_to\_component\_index(i).first}, and likewise for shape
-function $j$.
-
-Another possibility for optimization would be to ask whether a certain
-component over which we loop is actually non-zero, or if the shape function is
-a non-primitive one but happens to be zero in the present component
-nevertheless. For this, we could replace the loop over \texttt{comp\_i} by
-this:
-\begin{verbatim}
- for (unsigned int comp_i=0; comp_i<fe.n_components(); ++comp_i)
- if (fe.get_nonzero_components(i)[comp_i] == true)
-\end{verbatim}
-If the if-clause does not succeed then this component of the shape function is
-definitely zero, and there will not be a contribution to the matrix anyway, so
-we can also skip the computations.
-
-
-\subsection{The Stokes equations}
-
-Likewise, this is now the code for the Stokes equations:
-\begin{verbatim}
- for (unsigned int i=0; i<fe.dofs_per_cell; ++i)
- for (unsigned int comp_i=0; comp_i<fe.n_components(); ++comp_i)
- for (unsigned int j=0; j<fe.dofs_per_cell; ++j)
- for (unsigned int comp_j=0; comp_j<fe.n_components(); ++comp_j)
- for (unsigned int q=0; q<n_q_points; ++q)
- {
- // velocity-velocity coupling?
- if ((comp_i<dim) && (comp_j<dim))
- if (comp_i == comp_j)
- cell_matrix(i,j)
- += (nu *
- (fe_values.shape_grad_component(i,q,comp_i) *
- fe_values.shape_grad_component(j,q,comp_j) ) *
- fe_values.JxW(q));
-
- // velocity-pressure coupling
- if ((comp_i<dim) && (comp_j==dim))
- cell_matrix(i,j)
- += (-fe_values.shape_grad_component(i,q,comp_i)[comp_i] *
- fe_values.shape_value_component(j,q,comp_j) *
- fe_values.JxW(q));
-
- // pressure-velocity coupling
- if ((comp_i==dim) && (comp_j<dim))
- cell_matrix(i,j)
- += (fe_values.shape_value_component(i,q,comp_i) *
- fe_values.shape_grad_component(j,q,comp_j)[comp_j] *
- fe_values.JxW(q));
- };
-\end{verbatim}
-Again, the same optimizations as above are possible. Here, they even seem
-worthwhile, since it is often the case that the velocity variables are
-discretized using a non-primitive finite element, while the pressure uses a
-primitive element. In that case, some shape functions are primitive (namely
-those discretizing the pressure), and of the non-primitive shape functions
-(those for the velocity variables) some vector components (the pressure
-components) are always zero. Thus, both optimizations described above would be
-useful. We leave the implementation of this to the reader.
-
-
-\section{Conclusions}
-
-We have shown how finite element matrices are assembled using the
-functionality of the \texttt{deal.II} library. For the scalar case, and, in
-the vector-valued case, if the
-finite element shape functions are such that only one vector component of each
-shape function is non-zero, assembling is relatively simple. In the other
-case, when there are shape functions with more than one non-zero component,
-some more care is necessary, but assembling is still straightforward and
-follows the same pattern as before.
-
-\end{document}
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 1d-dof.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 16:17:22 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 514 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--8.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 9692 -1000 l 9692 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-7.500 slw
-n 3705 1500 m 3600 1500 3600 1770 105 arcto 4 {pop} repeat
- 3600 1875 5895 1875 105 arcto 4 {pop} repeat
- 6000 1875 6000 1605 105 arcto 4 {pop} repeat
- 6000 1500 3705 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 4800 1875 m 2400 2700 l gs col0 s gr
-% Polyline
-n 2400 3075 m 2400 3900 l gs col0 s gr
-% Polyline
-7.500 slw
-n 255 1500 m 150 1500 150 1770 105 arcto 4 {pop} repeat
- 150 1875 2145 1875 105 arcto 4 {pop} repeat
- 2250 1875 2250 1605 105 arcto 4 {pop} repeat
- 2250 1500 255 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 1200 1875 m 2400 2700 l gs col0 s gr
-% Polyline
-7.500 slw
-n 1155 3900 m 1050 3900 1050 4170 105 arcto 4 {pop} repeat
- 1050 4275 3645 4275 105 arcto 4 {pop} repeat
- 3750 4275 3750 4005 105 arcto 4 {pop} repeat
- 3750 3900 1155 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 955 2700 m 850 2700 850 2970 105 arcto 4 {pop} repeat
- 850 3075 3845 3075 105 arcto 4 {pop} repeat
- 3950 3075 3950 2805 105 arcto 4 {pop} repeat
- 3950 2700 955 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 1-dimensional Case, Part 2) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-4800 1800 m
-gs 1 -1 sc (DoFAccessor<1>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-1200 1800 m
-gs 1 -1 sc (CellAccessor<1>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-2400 3000 m
-gs 1 -1 sc (DoFObjectAccessor<1,1>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-2400 4200 m
-gs 1 -1 sc (DoFCellAccessor<1>) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6000 1875 6000 1500 3600 1500 3600 1875 6000 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 2400 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 2400 3075 2400 3900
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 2250 1875 2250 1500 150 1500 150 1875 2250 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 1200 1875 2400 2700
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3750 4275 3750 3900 1050 3900 1050 4275 3750 4275
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3950 3075 850 3075 850 2700 3950 2700 3950 3075
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 1-dimensional Case, Part 2\001
-4 1 0 0 0 0 20 0.0000 4 195 1995 4800 1800 DoFAccessor<1>\001
-4 1 0 0 0 0 20 0.0000 4 195 1950 1200 1800 CellAccessor<1>\001
-4 1 0 0 0 0 20 0.0000 4 255 2940 2400 3000 DoFObjectAccessor<1,1>\001
-4 1 0 0 0 0 20 0.0000 4 195 2460 2400 4200 DoFCellAccessor<1>\001
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 1d-tria.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 15:49:56 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 513 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--9.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 9692 -1000 l 9692 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-7.500 slw
-n 3705 1500 m 3600 1500 3600 1770 105 arcto 4 {pop} repeat
- 3600 1875 5895 1875 105 arcto 4 {pop} repeat
- 6000 1875 6000 1605 105 arcto 4 {pop} repeat
- 6000 1500 3705 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 4800 1875 m 1800 2700 l gs col0 s gr
-% Polyline
-n 1800 3075 m 1800 3900 l gs col0 s gr
-% Polyline
-7.500 slw
-n 280 2700 m 175 2700 175 2970 105 arcto 4 {pop} repeat
- 175 3075 3345 3075 105 arcto 4 {pop} repeat
- 3450 3075 3450 2805 105 arcto 4 {pop} repeat
- 3450 2700 280 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 755 3900 m 650 3900 650 4170 105 arcto 4 {pop} repeat
- 650 4275 2845 4275 105 arcto 4 {pop} repeat
- 2950 4275 2950 4005 105 arcto 4 {pop} repeat
- 2950 3900 755 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-4800 1800 m
-gs 1 -1 sc (TriaAccessor<1>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 1-dimensional Case, Part 1) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-1800 3000 m
-gs 1 -1 sc (TriaObjectAccessor<1,1>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-1800 4200 m
-gs 1 -1 sc (CellAccessor<1>) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6000 1875 6000 1500 3600 1500 3600 1875 6000 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 1800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 1800 3075 1800 3900
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3450 3075 175 3075 175 2700 3450 2700 3450 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 2950 4275 650 4275 650 3900 2950 3900 2950 4275
-4 1 0 0 0 0 20 0.0000 4 195 1980 4800 1800 TriaAccessor<1>\001
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 1-dimensional Case, Part 1\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 1800 3000 TriaObjectAccessor<1,1>\001
-4 1 0 0 0 0 20 0.0000 4 195 1950 1800 4200 CellAccessor<1>\001
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 2d-dof.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 16:24:04 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 560 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--8.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 10462 -1000 l 10462 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-15.000 slw
-n 6825 3075 m 6825 3900 l gs col0 s gr
-% Polyline
-7.500 slw
-n 5380 2700 m 5275 2700 5275 2970 105 arcto 4 {pop} repeat
- 5275 3075 8270 3075 105 arcto 4 {pop} repeat
- 8375 3075 8375 2805 105 arcto 4 {pop} repeat
- 8375 2700 5380 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 5580 3900 m 5475 3900 5475 4170 105 arcto 4 {pop} repeat
- 5475 4275 8070 4275 105 arcto 4 {pop} repeat
- 8175 4275 8175 4005 105 arcto 4 {pop} repeat
- 8175 3900 5580 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-6825 3000 m
-gs 1 -1 sc (DoFObjectAccessor<2,2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-6825 4200 m
-gs 1 -1 sc (DoFCellAccessor<2>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 1480 2700 m 1375 2700 1375 2970 105 arcto 4 {pop} repeat
- 1375 3075 4370 3075 105 arcto 4 {pop} repeat
- 4475 3075 4475 2805 105 arcto 4 {pop} repeat
- 4475 2700 1480 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-2925 3000 m
-gs 1 -1 sc (DoFObjectAccessor<1,2>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 3705 1500 m 3600 1500 3600 1770 105 arcto 4 {pop} repeat
- 3600 1875 5895 1875 105 arcto 4 {pop} repeat
- 6000 1875 6000 1605 105 arcto 4 {pop} repeat
- 6000 1500 3705 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 7455 1500 m 7350 1500 7350 1770 105 arcto 4 {pop} repeat
- 7350 1875 9345 1875 105 arcto 4 {pop} repeat
- 9450 1875 9450 1605 105 arcto 4 {pop} repeat
- 9450 1500 7455 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 255 1500 m 150 1500 150 1770 105 arcto 4 {pop} repeat
- 150 1875 3045 1875 105 arcto 4 {pop} repeat
- 3150 1875 3150 1605 105 arcto 4 {pop} repeat
- 3150 1500 255 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 4800 1875 m 2800 2700 l gs col0 s gr
-% Polyline
-n 1200 1875 m 2800 2700 l gs col0 s gr
-% Polyline
-n 4800 1875 m 6800 2700 l gs col0 s gr
-% Polyline
-n 8400 1875 m 6800 2700 l gs col0 s gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 2-dimensional Case, Part 2) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-4800 1800 m
-gs 1 -1 sc (DoFAccessor<2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-8400 1800 m
-gs 1 -1 sc (CellAccessor<2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-1650 1800 m
-gs 1 -1 sc (TriaObjectAccessor<1,2>) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-6 5250 2700 8400 4275
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 6825 3075 6825 3900
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 8375 3075 5275 3075 5275 2700 8375 2700 8375 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 8175 4275 8175 3900 5475 3900 5475 4275 8175 4275
-4 1 0 0 0 0 20 0.0000 4 255 2940 6825 3000 DoFObjectAccessor<2,2>\001
-4 1 0 0 0 0 20 0.0000 4 195 2460 6825 4200 DoFCellAccessor<2>\001
--6
-6 1350 2700 4500 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 4475 3075 1375 3075 1375 2700 4475 2700 4475 3075
-4 1 0 0 0 0 20 0.0000 4 255 2940 2925 3000 DoFObjectAccessor<1,2>\001
--6
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6000 1875 6000 1500 3600 1500 3600 1875 6000 1875
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9450 1875 9450 1500 7350 1500 7350 1875 9450 1875
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3150 1875 150 1875 150 1500 3150 1500 3150 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 2800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 1200 1875 2800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 6800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 8400 1875 6800 2700
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 2-dimensional Case, Part 2\001
-4 1 0 0 0 0 20 0.0000 4 195 1995 4800 1800 DoFAccessor<2>\001
-4 1 0 0 0 0 20 0.0000 4 195 1950 8400 1800 CellAccessor<2>\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 1650 1800 TriaObjectAccessor<1,2>\001
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 2d-tria.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 15:59:56 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 552 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--15.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 10437 -1000 l 10437 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-7.500 slw
-n 3705 1500 m 3600 1500 3600 1770 105 arcto 4 {pop} repeat
- 3600 1875 5895 1875 105 arcto 4 {pop} repeat
- 6000 1875 6000 1605 105 arcto 4 {pop} repeat
- 6000 1500 3705 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 4800 1875 m 1800 2700 l gs col0 s gr
-% Polyline
-n 4800 1875 m 7800 2700 l gs col0 s gr
-% Polyline
-n 7800 3075 m 7800 3900 l gs col0 s gr
-% Polyline
-7.500 slw
-n 6855 3900 m 6750 3900 6750 4170 105 arcto 4 {pop} repeat
- 6750 4275 8745 4275 105 arcto 4 {pop} repeat
- 8850 4275 8850 4005 105 arcto 4 {pop} repeat
- 8850 3900 6855 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 380 2700 m 275 2700 275 2970 105 arcto 4 {pop} repeat
- 275 3075 3245 3075 105 arcto 4 {pop} repeat
- 3350 3075 3350 2805 105 arcto 4 {pop} repeat
- 3350 2700 380 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 6330 2700 m 6225 2700 6225 2970 105 arcto 4 {pop} repeat
- 6225 3075 9320 3075 105 arcto 4 {pop} repeat
- 9425 3075 9425 2805 105 arcto 4 {pop} repeat
- 9425 2700 6330 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-4800 1800 m
-gs 1 -1 sc (TriaAccessor<2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 2-dimensional Case, Part 1) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-1800 3000 m
-gs 1 -1 sc (TriaObjectAccessor<1,2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-7800 3000 m
-gs 1 -1 sc (TriaObjectAccessor<2,2>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-7800 4200 m
-gs 1 -1 sc (CellAccessor<2>) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6000 1875 6000 1500 3600 1500 3600 1875 6000 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 1800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 4800 1875 7800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 7800 3075 7800 3900
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 8850 4275 8850 3900 6750 3900 6750 4275 8850 4275
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3350 3075 275 3075 275 2700 3350 2700 3350 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9425 3075 6225 3075 6225 2700 9425 2700 9425 3075
-4 1 0 0 0 0 20 0.0000 4 195 1980 4800 1800 TriaAccessor<2>\001
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 2-dimensional Case, Part 1\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 1800 3000 TriaObjectAccessor<1,2>\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 7800 3000 TriaObjectAccessor<2,2>\001
-4 1 0 0 0 0 20 0.0000 4 195 1950 7800 4200 CellAccessor<2>\001
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 3d-dof.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 16:33:48 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 592 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--12.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 11062 -1000 l 11062 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-15.000 slw
-n 1500 1125 m 1875 2700 l 6525 1875 l gs col0 s gr
-% Polyline
-n 3375 1575 m 5250 2700 l 6525 1875 l gs col0 s gr
-% Polyline
-n 6525 1875 m 8400 2700 l 8925 1350 l gs col0 s gr
-% Polyline
-7.500 slw
-n 5430 1500 m 5325 1500 5325 1770 105 arcto 4 {pop} repeat
- 5325 1875 7620 1875 105 arcto 4 {pop} repeat
- 7725 1875 7725 1605 105 arcto 4 {pop} repeat
- 7725 1500 5430 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-6525 1800 m
-gs 1 -1 sc (DoFAccessor<3>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 330 750 m 225 750 225 1020 105 arcto 4 {pop} repeat
- 225 1125 3120 1125 105 arcto 4 {pop} repeat
- 3225 1125 3225 855 105 arcto 4 {pop} repeat
- 3225 750 330 750 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-1725 1050 m
-gs 1 -1 sc (TriaObjectAccessor<1,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 2130 1200 m 2025 1200 2025 1470 105 arcto 4 {pop} repeat
- 2025 1575 4920 1575 105 arcto 4 {pop} repeat
- 5025 1575 5025 1305 105 arcto 4 {pop} repeat
- 5025 1200 2130 1200 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-3525 1500 m
-gs 1 -1 sc (TriaObjectAccessor<1,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 8055 975 m 7950 975 7950 1245 105 arcto 4 {pop} repeat
- 7950 1350 9945 1350 105 arcto 4 {pop} repeat
- 10050 1350 10050 1080 105 arcto 4 {pop} repeat
- 10050 975 8055 975 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-9000 1275 m
-gs 1 -1 sc (CellAccessor<3>) dup sw pop 2 div neg 0 rm col0 sh gr
-% Polyline
-n 3805 2700 m 3700 2700 3700 2970 105 arcto 4 {pop} repeat
- 3700 3075 6695 3075 105 arcto 4 {pop} repeat
- 6800 3075 6800 2805 105 arcto 4 {pop} repeat
- 6800 2700 3805 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 580 2700 m 475 2700 475 2970 105 arcto 4 {pop} repeat
- 475 3075 3470 3075 105 arcto 4 {pop} repeat
- 3575 3075 3575 2805 105 arcto 4 {pop} repeat
- 3575 2700 580 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 6980 2700 m 6875 2700 6875 2970 105 arcto 4 {pop} repeat
- 6875 3075 9870 3075 105 arcto 4 {pop} repeat
- 9975 3075 9975 2805 105 arcto 4 {pop} repeat
- 9975 2700 6980 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 7155 3900 m 7050 3900 7050 4170 105 arcto 4 {pop} repeat
- 7050 4275 9645 4275 105 arcto 4 {pop} repeat
- 9750 4275 9750 4005 105 arcto 4 {pop} repeat
- 9750 3900 7155 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 8400 3075 m 8400 3900 l gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-2025 3000 m
-gs 1 -1 sc (DoFObjectAccessor<1,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-5250 3000 m
-gs 1 -1 sc (DoFObjectAccessor<2,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-8400 3000 m
-gs 1 -1 sc (DoFObjectAccessor<3,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-8400 4200 m
-gs 1 -1 sc (DoFCellAccessor<3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 3-dimensional Case, Part 2) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-6 5325 1500 7725 1875
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 7725 1875 7725 1500 5325 1500 5325 1875 7725 1875
-4 1 0 0 0 0 20 0.0000 4 195 1995 6525 1800 DoFAccessor<3>\001
--6
-6 225 750 3225 1125
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3225 1125 225 1125 225 750 3225 750 3225 1125
-4 1 0 0 0 0 20 0.0000 4 255 2925 1725 1050 TriaObjectAccessor<1,3>\001
--6
-6 2025 1200 5025 1575
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 5025 1575 2025 1575 2025 1200 5025 1200 5025 1575
-4 1 0 0 0 0 20 0.0000 4 255 2925 3525 1500 TriaObjectAccessor<1,3>\001
--6
-6 7950 975 10050 1350
-6 7950 975 10050 1350
-6 7950 975 10050 1350
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 10050 1350 10050 975 7950 975 7950 1350 10050 1350
--6
--6
-4 1 0 0 0 0 20 0.0000 4 195 1950 9000 1275 CellAccessor<3>\001
--6
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6800 3075 3700 3075 3700 2700 6800 2700 6800 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3575 3075 475 3075 475 2700 3575 2700 3575 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9975 3075 6875 3075 6875 2700 9975 2700 9975 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9750 4275 9750 3900 7050 3900 7050 4275 9750 4275
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 8400 3075 8400 3900
-2 1 0 2 0 7 100 0 -1 0.000 0 0 -1 0 0 3
- 1500 1125 1875 2700 6525 1875
-2 1 0 2 0 7 100 0 -1 0.000 0 0 -1 0 0 3
- 3375 1575 5250 2700 6525 1875
-2 1 0 2 0 7 100 0 -1 0.000 0 0 -1 0 0 3
- 6525 1875 8400 2700 8925 1350
-4 1 0 0 0 0 20 0.0000 4 255 2940 2025 3000 DoFObjectAccessor<1,3>\001
-4 1 0 0 0 0 20 0.0000 4 255 2940 5250 3000 DoFObjectAccessor<2,3>\001
-4 1 0 0 0 0 20 0.0000 4 255 2940 8400 3000 DoFObjectAccessor<3,3>\001
-4 1 0 0 0 0 20 0.0000 4 195 2460 8400 4200 DoFCellAccessor<3>\001
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 3-dimensional Case, Part 2\001
+++ /dev/null
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: 3d-tria.eps
-%%Creator: fig2dev Version 3.2 Patchlevel 1
-%%CreationDate: Sun Dec 19 16:06:42 1999
-%%For: wolf@adaptive (Wolfgang Bangerth)
-%%Orientation: Portrait
-%%BoundingBox: 0 0 576 239
-%%Pages: 0
-%%BeginSetup
-%%EndSetup
-%%Magnification: 1.0000
-%%EndComments
-/$F2psDict 200 dict def
-$F2psDict begin
-$F2psDict /mtrx matrix put
-/col-1 {0 setgray} bind def
-/col0 {0.000 0.000 0.000 srgb} bind def
-/col1 {0.000 0.000 1.000 srgb} bind def
-/col2 {0.000 1.000 0.000 srgb} bind def
-/col3 {0.000 1.000 1.000 srgb} bind def
-/col4 {1.000 0.000 0.000 srgb} bind def
-/col5 {1.000 0.000 1.000 srgb} bind def
-/col6 {1.000 1.000 0.000 srgb} bind def
-/col7 {1.000 1.000 1.000 srgb} bind def
-/col8 {0.000 0.000 0.560 srgb} bind def
-/col9 {0.000 0.000 0.690 srgb} bind def
-/col10 {0.000 0.000 0.820 srgb} bind def
-/col11 {0.530 0.810 1.000 srgb} bind def
-/col12 {0.000 0.560 0.000 srgb} bind def
-/col13 {0.000 0.690 0.000 srgb} bind def
-/col14 {0.000 0.820 0.000 srgb} bind def
-/col15 {0.000 0.560 0.560 srgb} bind def
-/col16 {0.000 0.690 0.690 srgb} bind def
-/col17 {0.000 0.820 0.820 srgb} bind def
-/col18 {0.560 0.000 0.000 srgb} bind def
-/col19 {0.690 0.000 0.000 srgb} bind def
-/col20 {0.820 0.000 0.000 srgb} bind def
-/col21 {0.560 0.000 0.560 srgb} bind def
-/col22 {0.690 0.000 0.690 srgb} bind def
-/col23 {0.820 0.000 0.820 srgb} bind def
-/col24 {0.500 0.190 0.000 srgb} bind def
-/col25 {0.630 0.250 0.000 srgb} bind def
-/col26 {0.750 0.380 0.000 srgb} bind def
-/col27 {1.000 0.500 0.500 srgb} bind def
-/col28 {1.000 0.630 0.630 srgb} bind def
-/col29 {1.000 0.750 0.750 srgb} bind def
-/col30 {1.000 0.880 0.880 srgb} bind def
-/col31 {1.000 0.840 0.000 srgb} bind def
-
-end
-save
--15.0 258.0 translate
-1 -1 scale
-
-/cp {closepath} bind def
-/ef {eofill} bind def
-/gr {grestore} bind def
-/gs {gsave} bind def
-/sa {save} bind def
-/rs {restore} bind def
-/l {lineto} bind def
-/m {moveto} bind def
-/rm {rmoveto} bind def
-/n {newpath} bind def
-/s {stroke} bind def
-/sh {show} bind def
-/slc {setlinecap} bind def
-/slj {setlinejoin} bind def
-/slw {setlinewidth} bind def
-/srgb {setrgbcolor} bind def
-/rot {rotate} bind def
-/sc {scale} bind def
-/sd {setdash} bind def
-/ff {findfont} bind def
-/sf {setfont} bind def
-/scf {scalefont} bind def
-/sw {stringwidth} bind def
-/tr {translate} bind def
-/tnt {dup dup currentrgbcolor
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add
- 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
- bind def
-/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
- 4 -2 roll mul srgb} bind def
-/reencdict 12 dict def /ReEncode { reencdict begin
-/newcodesandnames exch def /newfontname exch def /basefontname exch def
-/basefontdict basefontname findfont def /newfont basefontdict maxlength dict def
-basefontdict { exch dup /FID ne { dup /Encoding eq
-{ exch dup length array copy newfont 3 1 roll put }
-{ exch newfont 3 1 roll put } ifelse } { pop pop } ifelse } forall
-newfont /FontName newfontname put newcodesandnames aload pop
-128 1 255 { newfont /Encoding get exch /.notdef put } for
-newcodesandnames length 2 idiv { newfont /Encoding get 3 1 roll put } repeat
-newfontname newfont definefont pop end } def
-/isovec [
-8#200 /grave 8#201 /acute 8#202 /circumflex 8#203 /tilde
-8#204 /macron 8#205 /breve 8#206 /dotaccent 8#207 /dieresis
-8#210 /ring 8#211 /cedilla 8#212 /hungarumlaut 8#213 /ogonek 8#214 /caron
-8#220 /dotlessi 8#230 /oe 8#231 /OE
-8#240 /space 8#241 /exclamdown 8#242 /cent 8#243 /sterling
-8#244 /currency 8#245 /yen 8#246 /brokenbar 8#247 /section 8#250 /dieresis
-8#251 /copyright 8#252 /ordfeminine 8#253 /guillemotleft 8#254 /logicalnot
-8#255 /endash 8#256 /registered 8#257 /macron 8#260 /degree 8#261 /plusminus
-8#262 /twosuperior 8#263 /threesuperior 8#264 /acute 8#265 /mu 8#266 /paragraph
-8#267 /periodcentered 8#270 /cedilla 8#271 /onesuperior 8#272 /ordmasculine
-8#273 /guillemotright 8#274 /onequarter 8#275 /onehalf
-8#276 /threequarters 8#277 /questiondown 8#300 /Agrave 8#301 /Aacute
-8#302 /Acircumflex 8#303 /Atilde 8#304 /Adieresis 8#305 /Aring
-8#306 /AE 8#307 /Ccedilla 8#310 /Egrave 8#311 /Eacute
-8#312 /Ecircumflex 8#313 /Edieresis 8#314 /Igrave 8#315 /Iacute
-8#316 /Icircumflex 8#317 /Idieresis 8#320 /Eth 8#321 /Ntilde 8#322 /Ograve
-8#323 /Oacute 8#324 /Ocircumflex 8#325 /Otilde 8#326 /Odieresis 8#327 /multiply
-8#330 /Oslash 8#331 /Ugrave 8#332 /Uacute 8#333 /Ucircumflex
-8#334 /Udieresis 8#335 /Yacute 8#336 /Thorn 8#337 /germandbls 8#340 /agrave
-8#341 /aacute 8#342 /acircumflex 8#343 /atilde 8#344 /adieresis 8#345 /aring
-8#346 /ae 8#347 /ccedilla 8#350 /egrave 8#351 /eacute
-8#352 /ecircumflex 8#353 /edieresis 8#354 /igrave 8#355 /iacute
-8#356 /icircumflex 8#357 /idieresis 8#360 /eth 8#361 /ntilde 8#362 /ograve
-8#363 /oacute 8#364 /ocircumflex 8#365 /otilde 8#366 /odieresis 8#367 /divide
-8#370 /oslash 8#371 /ugrave 8#372 /uacute 8#373 /ucircumflex
-8#374 /udieresis 8#375 /yacute 8#376 /thorn 8#377 /ydieresis] def
-/Times-Roman /Times-Roman-iso isovec ReEncode
-/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
-/$F2psEnd {$F2psEnteredState restore end} def
-%%EndProlog
-
-$F2psBegin
-10 setmiterlimit
-n -1000 5287 m -1000 -1000 l 10837 -1000 l 10837 5287 l cp clip
- 0.06000 0.06000 sc
-% Polyline
-15.000 slw
-n 5100 1875 m 5100 2700 l gs col0 s gr
-% Polyline
-7.500 slw
-n 380 2700 m 275 2700 275 2970 105 arcto 4 {pop} repeat
- 275 3075 3245 3075 105 arcto 4 {pop} repeat
- 3350 3075 3350 2805 105 arcto 4 {pop} repeat
- 3350 2700 380 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 3480 2700 m 3375 2700 3375 2970 105 arcto 4 {pop} repeat
- 3375 3075 6470 3075 105 arcto 4 {pop} repeat
- 6575 3075 6575 2805 105 arcto 4 {pop} repeat
- 6575 2700 3480 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 6730 2700 m 6625 2700 6625 2970 105 arcto 4 {pop} repeat
- 6625 3075 9720 3075 105 arcto 4 {pop} repeat
- 9825 3075 9825 2805 105 arcto 4 {pop} repeat
- 9825 2700 6730 2700 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-n 4005 1500 m 3900 1500 3900 1770 105 arcto 4 {pop} repeat
- 3900 1875 6195 1875 105 arcto 4 {pop} repeat
- 6300 1875 6300 1605 105 arcto 4 {pop} repeat
- 6300 1500 4005 1500 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-% Polyline
-15.000 slw
-n 5100 1875 m 1800 2700 l gs col0 s gr
-% Polyline
-n 5100 1875 m 8200 2700 l gs col0 s gr
-% Polyline
-n 8250 3075 m 8250 3900 l gs col0 s gr
-% Polyline
-7.500 slw
-n 7305 3900 m 7200 3900 7200 4170 105 arcto 4 {pop} repeat
- 7200 4275 9195 4275 105 arcto 4 {pop} repeat
- 9300 4275 9300 4005 105 arcto 4 {pop} repeat
- 9300 3900 7305 3900 105 arcto 4 {pop} repeat
- cp gs col0 s gr
-/Times-Roman-iso ff 300.00 scf sf
-1800 3000 m
-gs 1 -1 sc (TriaObjectAccessor<1,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-8250 3000 m
-gs 1 -1 sc (TriaObjectAccessor<3,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-5100 1800 m
-gs 1 -1 sc (TriaAccessor<3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-8250 4200 m
-gs 1 -1 sc (CellAccessor<3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 300.00 scf sf
-5025 3000 m
-gs 1 -1 sc (TriaObjectAccessor<2,3>) dup sw pop 2 div neg 0 rm col0 sh gr
-/Times-Roman-iso ff 375.00 scf sf
-4800 600 m
-gs 1 -1 sc (Class Hierarchy for the 3-dimensional Case, Part 1) dup sw pop 2 div neg 0 rm col0 sh gr
-$F2psEnd
-rs
+++ /dev/null
-#FIG 3.2
-Landscape
-Center
-Inches
-Letter
-100.00
-Single
-0
-1200 2
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 3350 3075 275 3075 275 2700 3350 2700 3350 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6575 3075 3375 3075 3375 2700 6575 2700 6575 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9825 3075 6625 3075 6625 2700 9825 2700 9825 3075
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 6300 1875 6300 1500 3900 1500 3900 1875 6300 1875
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 5100 1875 1800 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 5100 1875 8200 2700
-2 1 0 2 0 7 0 0 -1 0.000 0 0 -1 0 0 2
- 8250 3075 8250 3900
-2 4 0 1 0 7 0 0 -1 0.000 0 0 7 0 0 5
- 9300 4275 9300 3900 7200 3900 7200 4275 9300 4275
-2 1 0 2 0 7 100 0 -1 0.000 0 0 -1 0 0 2
- 5100 1875 5100 2700
-4 1 0 0 0 0 20 0.0000 4 255 2925 1800 3000 TriaObjectAccessor<1,3>\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 8250 3000 TriaObjectAccessor<3,3>\001
-4 1 0 0 0 0 20 0.0000 4 195 1980 5100 1800 TriaAccessor<3>\001
-4 1 0 0 0 0 20 0.0000 4 195 1950 8250 4200 CellAccessor<3>\001
-4 1 0 0 0 0 20 0.0000 4 255 2925 5025 3000 TriaObjectAccessor<2,3>\001
-4 1 0 0 0 0 25 0.0000 4 345 7590 4800 600 Class Hierarchy for the 3-dimensional Case, Part 1\001
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Frameset//EN"
- "http://www.w3.org/TR/REC-html40/frameset.dtd">
-<html>
- <head>
- <link href="../../screen.css" rel="StyleSheet" media="screen">
- <title>The deal.II Homepage</title>
- <meta name="author" content="the deal.II authors <authors@dealii.org>">
- <meta name="keywords" content="deal.II"></head>
-
- </head>
-<BODY LINK="#0000ff" VLINK="#800080">
-
-<H1 ALIGN="CENTER">
-Description of the C++ class hierarchy for the
-accessor classes
-</H1>
-
-
-<p ALIGN="CENTER">
- <strong> Wolfgang Bangerth, 1998, 1999, 2000</strong>
-</p>
-
-
-<p>
-The class hierarchy of the accessor classes used to retrieve and store
-data in the triangulation and degree of freedom handler objects is one
-of the more complicated parts of the library. It makes heavy use of
-class templates with integers as template parameters as well as of
-explicit specialization of classes and member functions. Therefore,
-it is not so easy to see the connections and inheritance relations
-within this part of the class tree; this document tries to shed a bit
-of light onto this.
-</p>
-
-<p>
-Furthermore, it lists the member functions that can be queried to
-obtain information from an iterator.
-</p>
-
-
-<strong>Table of contents</strong>
-<ul>
- <li> <a href="#intro" target="body">What iterators and accessors
- are</a>
- <li> <a href="#tria-accessors" target="body">The triangulation
- accessor hierarchy</a>
- <li> <a href="#tria-typedefs" target="body">Typedefs of the
- Triangulation class to iterators and accessors</a>
- <li> <a href="#tria-functions" target="body">Functions offered by
- triangulation accessors</a>
- <li> <a href="#dof-accessors" target="body">The degree of freedom
- accessor hierarchy</a>
- <li> <a href="#dof-typedefs" target="body">Typedefs of the
- DoFHandler class to iterators and accessors</a>
- <li> <a href="#dof-functions" target="body">Functions offered by
- degree of freedom accessors</a>
-</ul>
-
-
-<a name="intro"></a>
-<H3>
-What iterators and accessors are
-</H3>
-
-<p>
-When using adative finite elements, the data structures often are
-extremely complex, requiring multiply indirected access and complex
-relationships between the different places where data is stored. The
-traditional way to handle this is to put all data which belongs
-together somehow into a structure or object; however, sometimes this
-can not be done efficiently, leading to either higher memory
-consumption (when you have to store many small data pieces and because
-you have to store a lot of pointers to other objects) or higher coding
-requirements (when you want to follow all those pointers to the object
-you desire).
-</p>
-
-<p>
-Therefore, we took over a concept which was already used in the C++
-standard template library, namely iterators and accessors. An accessor
-is an object that looks like if it had all the information stored but
-really only delegates the access to the right places; in fact, within
-this library, accessor store almost no information but know where to
-get everything from the complex and nested data structures the
-triangulation object offers. They have a simple interface which allows
-to extract any desired information from the triangulation and
-therefore makes access much easier and safer in three ways: first it
-performs range and parameter checking when in debugging mode; second,
-it encapsulates the access to the real data from the user, hiding the
-true data structures and thus allowing them without changing the user
-programs as well as those parts of the library which only act through
-accessors; and third by reducing the coding errors because of reduced
-complexity, since the chains of indirect access are replaces by simple
-commands.
-</p>
-
-<p>
-Iterators are a related concept: while accessors act as if they were
-structures with data contained in them, iterators act as if they were
-pointers pointing to accessors. You can dereference them using the
--> and * operators as with any other pointer, but they have more
-functionality. Essentially, they have overloaded ++ and -- operators,
-which allow the next or previous object pointed to to be just about
-anywhere in memory. A good introductory example are the iterators of
-the STL <CODE>list<T></CODE> class, which act on a linked list
-as if it were a contiguous array. The iterators in this library go
-even a step further: they do not point to different objects but rather
-tell the associated accessor object which data to look at
-next.
-</p>
-
-<p>
-Additionally, there are different versions of the iterators which
-behave differently when being incremented or decremented: while
-<I>raw</I> iterators let the associated accessor point to any of the
-objects it is made for, <I>normal</I> iterators always point to
-objects which are in use. Usually, you will not want to see cells or
-lines which are there but are unused by the triangulation (these cells
-are somewhat like holes in the arrays of the triangulation; such
-things happen when unrefining a cell, the freed memory is then kept
-for a while because of better efficiency), so you will almost never
-want to use raw iterators; they are mostly there for internal use in
-the library. Normal iterators are almost like raw iterators, but
-whenever you call the ++ or -- operator, the look at what they are
-pointing at and skip all unused elements by increasing or decreasing
-the pointer as often as necessary to reach the next used object.
-</p>
-
-<p>
-Finally, there are <I>active</I> iterators, which are the most
-important ones. They are like normal iterators but only point to
-active cells or lines. By active we mean that they have no children;
-in the context in which this library is used, this is equivalent to
-the fact that we do computations on these cells, lines or
-whatever. Active iterators are normal iterators which skip over all
-non-active cells, lines, etc when being incremented or decremented.
-</p>
-
-
-
-<a name="tria-accessors"></a>
-<H3>
-The triangulation accessor hierarchy
-</H3>
-
-<p>
-The triangulation accessors are used to retrieve and store data in the
-triangulation. There exist accessors for lines in one and higher
-dimensions, accessors for quads in two and higher dimensions, and so
-on. The general naming scheme is as follows:
-<ul>
-<li> <code>TriaAccessor<dim></code> is a general base class
- which is of not much interest.
-<li> <code>TriaObjectAccessor<objectdim,spacedim></code> denotes
- an accessor for an object with dimension
- <code>objectdim</code> in a <code>spacedim</code> dimensional
- space. It is derived from <code>TriaAccessor<spacedim></code>.
-<li> <code>CellAccessor<dim></code> presents the special
- properties that a cell has. It is therefore derived from
- <code>TriaObjectAccessor<spacedimdim,spacedim></code>.
-</ul>
-</p>
-
-<p>
-Their inheritance trees in the different space dimensions therefore
-look like this:
-</p>
-
-<hr>
-
-<CENTER>
-<IMG SRC="1d-tria.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-<hr>
-
-<CENTER>
-<IMG SRC="2d-tria.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-<hr>
-
-<CENTER>
-<IMG SRC="3d-tria.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-<hr>
-
-<p>
-Some of the data is only useful if an object is a cell. For example,
-neighborship is only accessible for cells, while faces (e.g. lines in
-2D) can't access their neighbors (neither the adjacent cells, nor the
-other faces it touches). Therefore, the CellAccessor classes are
-derived from whatever object a cell is in the respective dimension,
-i.e. from lines in 1D, from quads in 2D, and so on.
-</p>
-
-
-
-<a name="tria-typedefs"></a>
-<H4>
-Typedefs of the Triangulation class to iterators and accessors
-</H4>
-
-<p>
-The <CODE>Triangulation<1></CODE> class declares the following data
-types which involve accessors:
-<PRE>
- typedef TriaRawIterator <1,CellAccessor<1> > raw_line_iterator;
- typedef TriaIterator <1,CellAccessor<1> > line_iterator;
- typedef TriaActiveIterator<1,CellAccessor<1> > active_line_iterator;
-
- typedef raw_line_iterator raw_cell_iterator;
- typedef line_iterator cell_iterator;
- typedef active_line_iterator active_cell_iterator;
-</PRE>
-Since lines are cells in one space dimension, all line iterators are
-cell iterators as well.
-</p>
-
-<p>
-In two space dimensions, the following types are declared by the
-<CODE>Triangulation<2></CODE> class:
-<PRE>
- typedef TriaRawIterator <2,TriaObjectAccessor<1, 2> > raw_line_iterator;
- typedef TriaIterator <2,TriaObjectAccessor<1, 2> > line_iterator;
- typedef TriaActiveIterator<2,TriaObjectAccessor<1, 2> > active_line_iterator;
-
- typedef TriaRawIterator <2,CellAccessor<2> > raw_quad_iterator;
- typedef TriaIterator <2,CellAccessor<2> > quad_iterator;
- typedef TriaActiveIterator<2,CellAccessor<2> > active_quad_iterator;
-
- typedef raw_quad_iterator raw_cell_iterator;
- typedef quad_iterator cell_iterator;
- typedef active_quad_iterator active_cell_iterator;
-
- typedef raw_line_iterator raw_face_iterator;
- typedef line_iterator face_iterator;
- typedef active_line_iterator active_face_iterator;
-</PRE>
-Since in this space dimension, quads are cells and lines are the faces
-of cells, the appropriate face and cell iterators are declared in
-terms of the underlying accessor types.
-</p>
-
-
-<p>
-In three space dimensions, the following types are declared by the
-<CODE>Triangulation<3></CODE> class:
-<PRE>
- typedef TriaRawIterator <3,TriaObjectAccessor<1, 3> > raw_line_iterator;
- typedef TriaIterator <3,TriaObjectAccessor<1, 3> > line_iterator;
- typedef TriaActiveIterator<3,TriaObjectAccessor<1, 3> > active_line_iterator;
-
- typedef TriaRawIterator <3,TriaObjectAccessor<2, 3> > raw_quad_iterator;
- typedef TriaIterator <3,TriaObjectAccessor<2, 3> > quad_iterator;
- typedef TriaActiveIterator<3,TriaObjectAccessor<2, 3> > active_quad_iterator;
-
- typedef TriaRawIterator <3,CellAccessor<3> > raw_hex_iterator;
- typedef TriaIterator <3,CellAccessor<3> > hex_iterator;
- typedef TriaActiveIterator<3,CellAccessor<3> > active_hex_iterator;
-
- typedef raw_hex_iterator raw_cell_iterator;
- typedef hex_iterator cell_iterator;
- typedef active_hex_iterator active_cell_iterator;
-
- typedef raw_quad_iterator raw_face_iterator;
- typedef quad_iterator face_iterator;
- typedef active_quad_iterator active_face_iterator;
-</PRE>
-Since in this space dimension, hexes are cells and quads are the faces
-of cells, the appropriate face and cell iterators are declared in
-terms of the underlying accessor types.
-</p>
-
-
-
-<a name="tria-functions"></a>
-<h4>Functions offered by triangulation accessors</h4>
-
-<p>
-We briefly state a short list of the functions offered by the
-triangulation accessors. For a more complete discussion of these
-functions, please refer to the online
-<a href="../../documentation.html" target="body">API
-documentation of the `grid' classes</a>. These functions can be
-accessed by <code>iterator->function()</code> if <code>iterator</code>
-is a cell-, face-, hex-, quad-, or line-iterator. Some functions are
-not available for all iterator types, which is noted for the
-individual entries.
-</p>
-
-<dl>
- <dt><em>
- level ()
- </em></dt>
-
- <dd>
- Return the hierarchical refinement level on
- which this object lives.
- </dd>
-
-
- <dt><em>
- index ()
- </em></dt>
-
- <dd>
- Return the index within the hierarchical refinement level on
- which this object lives.
- </dd>
-
-
- <dt><em>
- get_triangulation ()
- </em></dt>
-
- <dd>
- Return a reference to the triangulation to which this object belongs.
- </dd>
-
-
- <dt><em>
- vertex_index (vertex_number)
- </em></dt>
-
- <dd>
- Return the global index of one of the vertices of this object.
- </dd>
-
-
- <dt><em>
- vertex (vertex_number)
- </em></dt>
-
- <dd>
- Return the position of the respective vertex in space.
- </dd>
-
-
- <dt><em>
- used ()
- </em></dt>
-
- <dd>
- Return whether the object is used. The return value is
- <code>true</code> for all iterators that are either normal iterators
- or active iterators, only raw iterators can return
- <code>false</code>. Since raw iterators are only used in the
- interiors of the library, you will not usually need this function.
- </dd>
-
-
- <dt><em>
- set_used () / clear_used ()
- </em></dt>
-
- <dd>
- Set or clear the flag that describes whether the object is used by
- the triangulation. Only for internal use.
- </dd>
-
-
- <dt><em>
- user_flag_set ()
- </em></dt>
-
- <dd>
- Return whether the user flag is set.
- </dd>
-
-
- <dt><em>
- set_user_flag () / clear_user_flag ()
- </em></dt>
-
- <dd>
- Set or clear the flag that might be used by a user to indicate that
- something should happen with this object.
- </dd>
-
-
- <dt><em>
- recursively_set_user_flag () / recursively_clear_user_flag ()
- </em></dt>
-
- <dd>
- Set or clear the user flag for this cell and all its descendants.
- </dd>
-
-
- <dt><em>
- user_pointer ()
- </em></dt>
-
- <dd>
- Query the pointer belonging to this object which may be used by
- the user to store additional information with this object.
- </dd>
-
-
- <dt><em>
- set_user_pointer () / clear_user_pointer ()
- </em></dt>
-
- <dd>
- Set or clear a pointer belonging to this object which may be used by
- the user to store additional information with this object.
- </dd>
-
-
- <dt><em>
- child (child_number)
- </em></dt>
-
- <dd>
- Return an iterator to one of the children of this object.
- </dd>
-
-
- <dt><em>
- child_index (child_number)
- </em></dt>
-
- <dd>
- Return the index of the child within the next finer level of the
- triangulation.
- </dd>
-
-
- <dt><em>
- set_children (index), clear_children ()
- </em></dt>
-
- <dd>
- Only for internal use.
- </dd>
-
-
- <dt><em>
- has_children ()
- </em></dt>
-
- <dd>
- Return whether an object has children, i.e. whether it is further
- refined. If it has children, then it is not active.
- </dd>
-
-
- <dt><em>
- max_refinement_depth ()
- </em></dt>
-
- <dd>
- Return how often this cell or one of its children is refined.
- </dd>
-
-
- <dt><em>
- boundary_indicator
- </em></dt>
-
- <dd>
- Return the number of the boundary at which this object lies, if the
- object has a dimension less than the space dimension.
- </dd>
-
-
- <dt><em>
- set_boundary_indicator (boundary_id)
- </em></dt>
-
- <dd>
- Set the number of the boundary to which this object belongs.
- </dd>
-
-
- <dt><em>
- at_boundary ()
- </em></dt>
-
- <dd>
- Return whether this object is at the boundary (if the dimension of
- the object is less than the space dimension), or one of its faces is
- at the boundary for cells.
- </dd>
-
-
- <dt><em>
- has_boundary_lines ()
- </em></dt>
-
- <dd>
- Return whether one of the lines bounding this cell is at the
- boundary. For 1d and 2d this is equivalent to <em>at_boundary</em>,
- in 3d, there are cases where bounding lines of a hex are at the
- boundary, while the faces are in the interior. (Only for cell
- iterators.)
- </dd>
-
-
- <dt><em>
- diameter ()
- </em></dt>
-
- <dd>
- Return the diameter of the object.
- </dd>
-
-
- <dt><em>
- center ()
- </em></dt>
-
- <dd>
- Return the coordinates of the center of the object.
- </dd>
-
-
- <dt><em>
- barycenter ()
- </em></dt>
-
- <dd>
- Return the coordinates of the barycenter of the object.
- </dd>
-
-
- <dt><em>
- measure ()
- </em></dt>
-
- <dd>
- Return the length, area, or volume of an object, depending on the
- dimension of the object.
- </dd>
-
-
- <dt><em>
- point_inside (point)
- </em></dt>
-
- <dd>
- Return whether the given point is inside this cell, or rather the
- (bi-, tri-)linearly mapped image of the unit cell with the vertices
- of this cell. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- number_of_children ()
- </em></dt>
-
- <dd>
- Accumulated number of children and their children.
- </dd>
-
-
- <dt><em>
- line (line_number)
- </em></dt>
-
- <dd>
- Return an iterator to one of the bounding lines of this object. (Only
- for iterators to quadrilaterals and hexahedra.)
- </dd>
-
-
- <dt><em>
- line_index (line_number)
- </em></dt>
-
- <dd>
- Return the index of one of the bounding lines of this object. The
- level index is the same as that of the present object. (Only
- for iterators to quadrilaterals and hexahedra.)
- </dd>
-
-
- <dt><em>
- quad (quad_number)
- </em></dt>
-
- <dd>
- Return an iterator to one of the bounding quadrilaterals of this
- object. (Only for iterators to hexahedra.)
- </dd>
-
-
- <dt><em>
- line_index (line_number)
- </em></dt>
-
- <dd>
- Return the index of one of the bounding quadrilaterals of this
- object. The level index is the same as that of the present
- object. (Only for iterators to hexahedra.)
- </dd>
-
-
- <dt><em>
- neighbor (neighbor_number)
- </em></dt>
-
- <dd>
- Return iterator to one of the neighbors. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- neighbor_index (neighbor_number) / neighbor_level (neighbor_number)
- </em></dt>
-
- <dd>
- Return number and level of one of the neighbors. (Only for cell
- iterators.)
- </dd>
-
-
- <dt><em>
- set_neighbor ()
- </em></dt>
-
- <dd>
- Set a neighbor. Only for internal use. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- neighbor_of_neighbor (neighbor_number)
- </em></dt>
-
- <dd>
- Return the how-manyth neighbor the present cell is of the neighbor
- specified by the argument. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- at_boundary (face_number)
- </em></dt>
-
- <dd>
- Return whether this cell's given face is at the boundary. (Only for
- cell iterators.)
- </dd>
-
-
- <dt><em>
- refine_flag_set ()
- </em></dt>
-
- <dd>
- Return whether the refinement flag is set or not for the present
- cell. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- set_refine_flag () / clear_refine_flag ()
- </em></dt>
-
- <dd>
- Set/clear the flag indicating refinement. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- coarsen_flag_set ()
- </em></dt>
-
- <dd>
- Query whether the flag indicating coarsening is set for this
- object. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- set_coarsen_flag () / claer_coarsen_flag ()
- </em></dt>
-
- <dd>
- Set/clear the flag indicating coarsening. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- face (face_number)
- </em></dt>
-
- <dd>
- Return an iterator to one of the faces of this cell, if dimension is
- greater than one. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- material_id ()
- </em></dt>
-
- <dd>
- Return the material number of this cell. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- set_material_id (id)
- </em></dt>
-
- <dd>
- Set the material number of this cell. (Only for cell iterators.)
- </dd>
-
-
- <dt><em>
- active ()
- </em></dt>
-
- <dd>
- Return whether this cell is active, i.e. has no children. (Only for
- cell iterators.)
- </dd>
-</dl>
-
-
-
-<a name="dof-accessors"></a>
-<H3>
-The degree of freedom accessor hierarchy
-</H3>
-
-<p>
-The DoFAccessor classes provide access to the degree of freedom
-information associated with cells, lines, etc. The inheritance
-relationship is much the same as for the triangulation accessor
-classes, as can be seen from the following pictures.
-
-<hr>
-
-<CENTER>
-<IMG SRC="1d-dof.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-
-<hr>
-
-<CENTER>
-<IMG SRC="2d-dof.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-
-<hr>
-
-<CENTER>
-<IMG SRC="3d-dof.jpg" ALIGN="CENTER" WIDTH="80%">
-</CENTER>
-<p>
-
-<hr>
-
-<p>
-The main difference to the triangulation accessor hierarchy is that we
-want the DoF accessors to provide the information about the degrees of
-freedom, but for convenience also that of the triangulation. This way,
-we can get all the information from one object rather than needing two
-which work in parallel, and the class hierarchy shown above does
-exactly this.
-</p>
-
-<p>
-For the named reason, it is necessary to derive the
-<code>DoFObjectAccessor<1,dim></code> from the
-<code>TriaObjectAccessor<1,dim></code> class of the
-triangulation accessor hierarchy, as well as the
-<code>DoFObjectAccessor<2,dim></code> from the
-<code>TriaObjectAccessor<2,dim></code>. However, we would also
-like to include the functionality added by the CellAccessor class;
-this is done through some template magic: when in one space dimension,
-the <code>DoFObjectAccessor<1,1></code> is derived from
-CellAccessor<1>, while when in higher dimensions, it is derived
-from <code>DoFObjectAccessor<1,dim></code>; the same applies for
-the <code>DoFObjectAccessor<2,dim></code> class. Note that this
-way, CellAccessor is always a base class to DoFCellAccessor and the
-inheritance lattice is dimension dependant; the exact way of achieving
-this is complicated but not of interest here.
-</p>
-
-
-<a name="dof-typedefs"></a>
-<H4>
-Typedefs of the DoFHandler class to iterators and accessors
-</H4>
-
-<p>
-The typedefs done by the DoFHandler class are much alike those done by
-the Triangulation class. They could be summarized as follows:
-</p>
-
-<p>
-For one space dimension:
-<PRE>
- typedef TriaRawIterator <1,DoFCellAccessor<1> > raw_line_iterator;
- typedef TriaIterator <1,DoFCellAccessor<1> > line_iterator;
- typedef TriaActiveIterator<1,DoFCellAccessor<1> > active_line_iterator;
-
- typedef raw_line_iterator raw_cell_iterator;
- typedef line_iterator cell_iterator;
- typedef active_line_iterator active_cell_iterator;
-</PRE>
-Since lines are cells in one space dimension, all line iterators are
-cell iterators as well.
-</p>
-
-<p>
-For two space dimensions:
-<PRE>
- typedef TriaRawIterator <2,DoFObjectAccessor<1, 2> > raw_line_iterator;
- typedef TriaIterator <2,DoFObjectAccessor<1, 2> > line_iterator;
- typedef TriaActiveIterator<2,DoFObjectAccessor<1, 2> > active_line_iterator;
-
- typedef TriaRawIterator <2,DoFCellAccessor<2> > raw_quad_iterator;
- typedef TriaIterator <2,DoFCellAccessor<2> > quad_iterator;
- typedef TriaActiveIterator<2,DoFCellAccessor<2> > active_quad_iterator;
-
- typedef raw_quad_iterator raw_cell_iterator;
- typedef quad_iterator cell_iterator;
- typedef active_quad_iterator active_cell_iterator;
-
- typedef raw_line_iterator raw_face_iterator;
- typedef line_iterator face_iterator;
- typedef active_line_iterator active_face_iterator;
-</PRE>
-</p>
-
-<p>
-For three space dimensions:
-<PRE>
- typedef TriaRawIterator <3,DoFObjectAccessor<1, 3> > raw_line_iterator;
- typedef TriaIterator <3,DoFObjectAccessor<1, 3> > line_iterator;
- typedef TriaActiveIterator<3,DoFObjectAccessor<1, 3> > active_line_iterator;
-
- typedef TriaRawIterator <3,DoFObjectAccessor<2, 3> > raw_quad_iterator;
- typedef TriaIterator <3,DoFObjectAccessor<2, 3> > quad_iterator;
- typedef TriaActiveIterator<3,DoFObjectAccessor<2, 3> > active_quad_iterator;
-
- typedef TriaRawIterator <3,DoFCellAccessor<3> > raw_hex_iterator;
- typedef TriaIterator <3,DoFCellAccessor<3> > hex_iterator;
- typedef TriaActiveIterator<3,DoFCellAccessor<3> > active_hex_iterator;
-
- typedef raw_hex_iterator raw_cell_iterator;
- typedef hex_iterator cell_iterator;
- typedef active_hex_iterator active_cell_iterator;
-
- typedef raw_quad_iterator raw_face_iterator;
- typedef quad_iterator face_iterator;
- typedef active_quad_iterator active_face_iterator;
-</PRE>
-</p>
-
-
-
-<a name="dof-functions"></a>
-<h4>Functions offered by degree of freedom accessors</h4>
-
-<p>
-Since degree of freedom accessors are derived from triangulation
-accessors, they inherit the functionality of these accessors, but add
-some of their own. We only list the additional functionality
-below. For a full reference, including data types of parameters and
-return values, please refer to the general
-<a href="../../documentation.html" target="body">API
-documentation of the `DoF' classes</a>.
-</p>
-
-
-<dl>
- <dt><em>
- dof_index (dof_number)
- </em></dt>
-
- <dd>
- Return the global index of one of the DoFs on this object.
- </dd>
-
-
- <dt><em>
- set_dof_index (dof_number, index)
- </em></dt>
-
- <dd>
- Set the index of a DoF. Only for internal use.
- </dd>
-
-
- <dt><em>
- vertex_dof_index (vertex_number, dof_number)
- </em></dt>
-
- <dd>
- Return the index of one of the DoFs on one of the vertices of this
- object.
- </dd>
-
-
- <dt><em>
- set_vertex_dof_index (...)
- </em></dt>
-
- <dd>
- Set the vertex DoF index. Only for internal use.
- </dd>
-
-
- <dt><em>
- get_dof_indices (vector_of_indices)
- </em></dt>
-
- <dd>
- Return a vector of the indices of the DoFs on this object.
- </dd>
-
-
- <dt><em>
- get_dof_values (global_values, local_values)
- </em></dt>
-
- <dd>
- Extract and return the values of the DoFs on this object from a data
- vector defined on all DoFs.
- </dd>
-
-
- <dt><em>
- set_dof_values (local_values, global_values)
- </em></dt>
-
- <dd>
- Reverse operation: take values of DoFs on this object, and set them
- into a global data vector.
- </dd>
-
-
- <dt><em>
- distribute_local_to_global (local_source, global_destination)
- </em></dt>
-
- <dd>
- Add the elements of local_source, defining values of the degrees of
- freedom on this object, to the elements of the global data
- vector. The two parameters may be either vectors or matrices.
- </dd>
-
-
- <dt><em>
- get_interpolated_dof_values (global_values, local_interpolation)
- </em></dt>
-
- <dd>
- Interpolate the global field to this cell. If this cell is active,
- then this is the restriction of the global field to this cell,
- but when this cell is not active then it is the interpolation of the
- restriction of the field to the child cells and the interpolation to
- the present one. (For cell iterators only.)
- </dd>
-
-
- <dt><em>
- set_dof_values_by_interpolation (local_values, global_interpolation)
- </em></dt>
-
- <dd>
- Inverse operation: interpolate the local values to the children (if
- this cell is not active) and set the respective values in the global
- vector. (For cell iterators only.)
- </dd>
-</dl>
-
-
-<HR>
-
-<div ALIGN="RIGHT">
-Wolfgang Bangerth, 1998, 1999, 2000
-</div>
-<p> </P></BODY>
-</HTML>
-
-
-
-</BODY>
-</HTML>
-
<ul>
<li>
A brief report about the classes involved in the
- <a href="class-hierarchies/index.html"
+ <a href="http://www.dealii.org/reports/class-hierarchies/index.html"
target="body">iterators and accessors</a>
used to access cells in the triangulations and the data
thereon, such as their geometry, the number of the
</li>
<li>
- A brief report on <a href="mapping_q/index.html"
+ A brief report on <a href="http://www.dealii.org/reports/mapping_q/index.html"
target="body">mapping</a> functions of higher polynomial
degrees (by Ralf Hartmann). These allow the realisation
of higher order boundary approximations. This report
<li>
A report on
- <a href="assemble/assemble.pdf"
+ <a href="http://www.dealii.org/reports/assemble/assemble.pdf"
target="body">assembling matrices</a> (by Wolfgang
Bangerth). This report looks in particular at how
matrices are assembled for vector-valued problems, and
<li>
A very detailed report on
- <a href="nedelec/nedelec.pdf"
+ <a href="http://www.dealii.org/reports/nedelec/nedelec.pdf"
target="body">Nedelec elements</a> (by Anna
Schneebeli, University of Basel, Switzerland). It
explains the construction and application of Nedelec
<li>
A report on the
- <a href="codimension-one/desimone-heltai-manigrasso.pdf"
+ <a href="http://www.dealii.org/reports/codimension-one/desimone-heltai-manigrasso.pdf"
target="body">codimension one</a> capabilities of the library
(by Antonio DeSimone, Luca Heltai and Cataldo Manigrasso,
SISSA, Trieste, Italy). It explains in detail how to use the
+++ /dev/null
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
-<!--Converted with LaTeX2HTML 98.1p1 release (March 2nd, 1998)
-originally by Nikos Drakos (nikos@cbl.leeds.ac.uk), CBLU, University of Leeds
-* revised and updated by: Marcus Hennecke, Ross Moore, Herb Swan
-* with significant contributions from:
- Jens Lippmann, Marek Rouchal, Martin Wilck and others -->
-<HTML>
-<HEAD>
-<TITLE>No Title</TITLE>
-<META NAME="description" CONTENT="No Title">
-<META NAME="keywords" CONTENT="mapping">
-<META NAME="resource-type" CONTENT="document">
-<META NAME="distribution" CONTENT="global">
-<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
-<LINK REL="STYLESHEET" HREF="../../screen.css">
-<LINK REL="next" HREF="node1.html">
-</HEAD>
-<BODY >
-<p>
-In modified form taken from
-<br>
-<br>
-<a href="http://ganymed.iwr.uni-heidelberg.de/~hartmann/" target="_top">Ralf Hartmann</a>
-<br>
-Adaptive Finite Element Methods for the Compressible Euler Equations
-<br>
-PhD thesis, University of Heidelberg, 2002.
-</p>
-
-
-<P>
-<DIV ALIGN="CENTER">
-<FONT SIZE="+4"><B>Higher order Boundary approximation</B></FONT>
-
-</DIV>
-<P>
-<B>Introduction:</B> In many numerical applications the domain
-
-<!-- MATH: $\Omega\subset\mathbb R^d$ -->
-<IMG
- WIDTH="61" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img6.gif"
- ALT="$\Omega\subset\mathbb R^d$">,
-<IMG
- WIDTH="46" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img7.gif"
- ALT="$d\geq 2$">
-is not a polygonal domain but includes
-curved boundaries. For these cases the boundary cannot be represented
-exactly by the discretised boundary. Approximating the boundary by a
-piecewise linear boundary interpolation, i.e. by a polygonal boundary,
-may in some applications not be sufficient. In these cases a higher
-order boundary approximation, for example by piecewise quadratic or
-cubic boundary interpolation, must be employed. In the finite element
-framework this higher order boundary approximation is realized by
-mapping the reference element <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-to the element
-
-<!-- MATH: $K=\sigma_K(\hat K)$ -->
-<IMG
- WIDTH="96" HEIGHT="41" ALIGN="MIDDLE" BORDER="0"
- SRC="img9.gif"
- ALT="$K=\sigma_K(\hat K)$">
-in real space, whereas on cells <I>K</I> at the
-boundary, i.e.
-<!-- MATH: $\partial K\cap\Gamma=\emptyset$ -->
-<IMG
- WIDTH="93" HEIGHT="34" ALIGN="MIDDLE" BORDER="0"
- SRC="img10.gif"
- ALT="$\partial K\cap\Gamma=\emptyset$">,
-the mappings
-<IMG
- WIDTH="28" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img11.gif"
- ALT="$\sigma_K$">
-are given by polynomial functions of higher degree.
-
-<P>
-<B>Elements with general mapping functions <IMG
- WIDTH="28" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img11.gif"
- ALT="$\sigma_K$">.</B> We begin
-by first introducing some notation. Let <IMG
- WIDTH="61" HEIGHT="31" ALIGN="MIDDLE" BORDER="0"
- SRC="img12.gif"
- ALT="$K\in T_h$">
-be a cell of the
-triangulation <I>T</I><SUB><I>h</I></SUB> with
-<!-- MATH: $K=\sigma_K(\hat K)$ -->
-<IMG
- WIDTH="96" HEIGHT="41" ALIGN="MIDDLE" BORDER="0"
- SRC="img9.gif"
- ALT="$K=\sigma_K(\hat K)$">,
-where <IMG
- WIDTH="28" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img11.gif"
- ALT="$\sigma_K$">is a smooth bijective mapping of the reference element (unit square)
-<IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-to the element <I>K</I> in real space, see Figure
-<A HREF="index.html#fig:mapping">1</A>.
-<BR>
-<DIV ALIGN="CENTER"><A NAME="fig:mapping"> </A><A NAME="183"> </A>
-<TABLE WIDTH="50%">
-<CAPTION><STRONG>Figure:</STRONG>
-Mapping <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">
-of reference element <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-to the element <I>K</I> in real space.</CAPTION>
-<TR><TD>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: $\includegraphics[scale=0.3]{figures/m1.ps}$ -->
-<IMG
- WIDTH="660" ALIGN="BOTTOM" BORDER="0"
- SRC="img13.gif"
- ALT="\includegraphics[scale=0.3]{figures/m1.ps}"></DIV></TD></TR>
-</TABLE>
-</DIV>
-<BR>
-<P>
-In the following and for the sake of simplicity we suppress the letter
-<I>K</I> in the subscript and write <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">
-instead of <IMG
- WIDTH="28" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img11.gif"
- ALT="$\sigma_K$">.
-
-<P>
-<B>Mapping functions of higher polynomial degree.</B> A mapping
-function <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">,
-that maps the reference element <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-to an
-arbitrary quadrilateral cell <I>K</I> with straight boundaries, can in
-general be represented by a bilinear function, i.e. by a
-<I>Q</I><SUB>1</SUB>-mapping. For the case that the cell <I>K</I> includes curved
-boundaries it might be necessary to employ polynomial mapping
-functions of higher degree.
-
-<P>
-Given a degree <I>p</I>>0, a cell <IMG
- WIDTH="61" HEIGHT="31" ALIGN="MIDDLE" BORDER="0"
- SRC="img12.gif"
- ALT="$K\in T_h$">,
-and (<I>p</I>+1)<SUP><I>d</I></SUP> mapping
-support points <IMG
- WIDTH="56" HEIGHT="31" ALIGN="MIDDLE" BORDER="0"
- SRC="img14.gif"
- ALT="$p_i\in K$">,
-
-<!-- MATH: $i=0,\ldots,(p+1)^d-1$ -->
-<IMG
- WIDTH="174" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img15.gif"
- ALT="$i=0,\ldots,(p+1)^d-1$">,
-we define a
-<I>Q</I><SUB><I>p</I></SUB>-mapping
-<!-- MATH: $\sigma\in [Q_p]^d$ -->
-<IMG
- WIDTH="75" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img16.gif"
- ALT="$\sigma\in [Q_p]^d$">
-as follows
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\sigma(\hat x)=\sum_{i=0}^{(p+1)^d-1}p_i\phi_i(\hat x).
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:def-mapping-q"> </A><IMG
- WIDTH="176" HEIGHT="66"
- SRC="img17.gif"
- ALT="\begin{displaymath}
-\sigma(\hat x)=\sum_{i=0}^{(p+1)^d-1}p_i\phi_i(\hat x).
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(1)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-Here, <IMG
- WIDTH="20" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img18.gif"
- ALT="$\phi_i$">,
-
-<!-- MATH: $i=0,\ldots,(p+1)^d-1$ -->
-<IMG
- WIDTH="174" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img15.gif"
- ALT="$i=0,\ldots,(p+1)^d-1$">
-denote the Lagrange interpolation
-basis functions, that satisfy
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-\phi_i(\hat p_j)=\delta_{ij}, \quad i,j=0,\ldots,(p+1)^d-1,
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="302" HEIGHT="32"
- SRC="img19.gif"
- ALT="\begin{displaymath}\phi_i(\hat p_j)=\delta_{ij}, \quad i,j=0,\ldots,(p+1)^d-1,
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-where <IMG
- WIDTH="19" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img20.gif"
- ALT="$\hat p_i$">,
-
-<!-- MATH: $i=0,\ldots,(p+1)^d-1$ -->
-<IMG
- WIDTH="174" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img15.gif"
- ALT="$i=0,\ldots,(p+1)^d-1$">
-denote the Lagrange support
-points on the unit cell <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">.
-The definition of <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">(<A HREF="index.html#eq:def-mapping-q">1</A>) ensures that each of the unit support points
-<IMG
- WIDTH="19" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img20.gif"
- ALT="$\hat p_i$">
-is mapped onto the corresponding mapping support points
-<I>p</I><SUB><I>i</I></SUB>, i.e.
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\sigma(\hat p_i)=p_i, \quad i=0,\ldots,(p+1)^d-1
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:point-mappings"> </A><IMG
- WIDTH="270" HEIGHT="31"
- SRC="img21.gif"
- ALT="\begin{displaymath}
-\sigma(\hat p_i)=p_i, \quad i=0,\ldots,(p+1)^d-1
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(2)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-Analogous to Lagrange finite elements the unit Lagrange support points
-<IMG
- WIDTH="19" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img20.gif"
- ALT="$\hat p_i$">
-are equidistantly distributed on <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-based on a tensor
-product mesh. In the following we only consider the two-dimensional
-case, <I>d</I>=2. For that case, Figure <A HREF="index.html#fig:unit-mapping-points">2</A>
-shows the distributions of the unit support points <IMG
- WIDTH="19" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img20.gif"
- ALT="$\hat p_i$">,
-
-<!-- MATH: $i=0,\ldots,(p+1)^2-1$ -->
-<IMG
- WIDTH="174" HEIGHT="37" ALIGN="MIDDLE" BORDER="0"
- SRC="img22.gif"
- ALT="$i=0,\ldots,(p+1)^2-1$">
-for degrees
-<!-- MATH: $p=1,\ldots,4$ -->
-<IMG
- WIDTH="96" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img5.gif"
- ALT="$p=1,\ldots ,4$">.
-<BR>
-<DIV ALIGN="CENTER"><A NAME="fig:unit-mapping-points"> </A><A NAME="184"> </A>
-<TABLE WIDTH="50%">
-<CAPTION><STRONG>Figure:</STRONG>
-Unit support points <IMG
- WIDTH="19" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img20.gif"
- ALT="$\hat p_i$">,
-
-<!-- MATH: $0\leq i<(p+1)^2$ -->
-<IMG
- WIDTH="126" HEIGHT="37" ALIGN="MIDDLE" BORDER="0"
- SRC="img4.gif"
- ALT="$0\leq i<(p+1)^2$">,
-for degrees
-<!-- MATH: $p=1,\ldots,4$ -->
-<IMG
- WIDTH="96" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img5.gif"
- ALT="$p=1,\ldots ,4$">.</CAPTION>
-<TR><TD>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: $\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q1_n.eps}$ -->
-<IMG
- WIDTH="180" ALIGN="BOTTOM" BORDER="0"
- SRC="img23.gif"
- ALT="\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q1_n.eps}">
-
-<!-- MATH: $\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q2_n.eps}$ -->
-<IMG
- WIDTH="180" ALIGN="BOTTOM" BORDER="0"
- SRC="img24.gif"
- ALT="\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q2_n.eps}">
-
-<!-- MATH: $\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q3_n.eps}$ -->
-<IMG
- WIDTH="180" ALIGN="BOTTOM" BORDER="0"
- SRC="img25.gif"
- ALT="\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q3_n.eps}">
-
-<!-- MATH: $\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q4_n.eps}$ -->
-<IMG
- WIDTH="180" ALIGN="BOTTOM" BORDER="0"
- SRC="img26.gif"
- ALT="\includegraphics*[width=2.750cm]{../../../phd/figures/boundary_approximation/mapping/unit_points_q4_n.eps}"></DIV></TD></TR>
-</TABLE>
-</DIV>
-<BR>
-Let the ordering and numbering of the unit support points be as
-follows: first the corners, then the points on the edges and finally
-the inner support points, see also Figure
-<A HREF="index.html#fig:unit-mapping-points">2</A>. Thus the first 4<I>p</I> points are placed
-on the boundary
-<!-- MATH: $\partial\hat K$ -->
-<IMG
- WIDTH="31" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img27.gif"
- ALT="$\partial\hat K$">
-of the reference cell, i.e.
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-\hat p_k\in\partial\hat K, \quad k=0,\ldots,4p-1.
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="225" HEIGHT="30"
- SRC="img28.gif"
- ALT="\begin{displaymath}\hat p_k\in\partial\hat K, \quad k=0,\ldots,4p-1.
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-According to (<A HREF="index.html#eq:point-mappings">2</A>) these points are mapped to the
-mapping support points <I>p</I><SUB><I>k</I></SUB>,
-<!-- MATH: $k=0,\ldots,4p-1$ -->
-<IMG
- WIDTH="135" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img29.gif"
- ALT="$k=0,\ldots,4p-1$">
-that are chosen to be
-placed on the boundary of the real cell in approximatively equal
-distances, i.e.
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-p_k\in\partial K, \quad k=0,\ldots,4p-1.
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="224" HEIGHT="30"
- SRC="img30.gif"
- ALT="\begin{displaymath}p_k\in\partial K, \quad k=0,\ldots,4p-1.
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-While the support points <I>p</I><SUB><I>k</I></SUB>,
-<!-- MATH: $k=0,\ldots,4p-1$ -->
-<IMG
- WIDTH="135" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img29.gif"
- ALT="$k=0,\ldots,4p-1$">
-on the boundary are
-given by the boundary description of the real cell <I>K</I>, the <EM>inner
- mapping support points</EM>
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-p_i\in K\setminus\partial K, \quad i=4p,\ldots,(p+1)^2-1
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="297" HEIGHT="31"
- SRC="img31.gif"
- ALT="\begin{displaymath}p_i\in K\setminus\partial K, \quad i=4p,\ldots,(p+1)^2-1
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-are not uniquely determined. Numerical tests show that it is not a
-trivial task to define the positions of the inner mapping support
-points appropriately. If they are not chosen appropriately the
-resulting mapping <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">
-for a cell <I>K</I> may degenerate, i.e. the
-mapping <IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">
-for some cell <I>K</I> may not be bijective.
-
-<P>
-<B>Computation of inner support points by smooth transformation.</B>
-In the following we will define the positions of the inner mapping
-support points so that the mapping does - in all practical cases - <I>not</I>
-degenerate. To this end, we employ an approach for the mapping of the
-support points, that is in the style of the smooth transformations
-that is used to transform structured triangulations to match complex
-boundary discriptions. In the following, again for notational
-convenience, we consider only the two-dimensional case.
-
-<P>
-The smooth transformation mentioned above is based on solutions to the
-Laplace equation that is solved on the reference cell <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">.
-Discrete boundary conditions are imposed that are given by the
-coordinates of the mapping support points <I>p</I><SUB><I>k</I></SUB>,
-<!-- MATH: $k=0,\ldots,4p-1$ -->
-<IMG
- WIDTH="135" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img29.gif"
- ALT="$k=0,\ldots,4p-1$">,
-on
-the boundary of the cell <I>K</I> in real space.
-
-<P>
-To be more explicite we define a Laplace problem on the unit
-cell <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\begin{array}{rcll}
--\hat\Delta \sigma_l(\hat x)&=&0, \quad &\hat x\in \hat K,\\
- \sigma_l(\hat x)&=&{g_l}|_{\partial \hat K}(\hat x), \quad &\hat x\in \partial\hat K,
-\end{array}
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:local-laplace-problem"> </A><IMG
- WIDTH="273" HEIGHT="53"
- SRC="img32.gif"
- ALT="\begin{displaymath}
-\begin{array}{rcll}
--\hat\Delta \sigma_l(\hat x)&=&0, \quad...
-...l \hat K}(\hat x), \quad &\hat x\in \partial\hat K,
-\end{array}\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(3)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-for each component <IMG
- WIDTH="20" HEIGHT="30" ALIGN="MIDDLE" BORDER="0"
- SRC="img33.gif"
- ALT="$\sigma_l$">,
-<I>l</I>=1,2, of the <I>Q</I><SUB><I>p</I></SUB> mapping
-<IMG
- WIDTH="15" HEIGHT="16" ALIGN="BOTTOM" BORDER="0"
- SRC="img1.gif"
- ALT="$\sigma $">.
-Here, the discrete boundary function
-<!-- MATH: $g\in [Q_p]^2$ -->
-<IMG
- WIDTH="73" HEIGHT="37" ALIGN="MIDDLE" BORDER="0"
- SRC="img34.gif"
- ALT="$g\in [Q_p]^2$">
-is
-given by
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-g_l(\hat x)=\sum_{i=0}^{4p-1}(p_i)_l\phi_i(\hat x), \quad l=1,\ldots,d
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:discrete-boundary-function"> </A><IMG
- WIDTH="277" HEIGHT="62"
- SRC="img35.gif"
- ALT="\begin{displaymath}
-g_l(\hat x)=\sum_{i=0}^{4p-1}(p_i)_l\phi_i(\hat x), \quad l=1,\ldots,d
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(4)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-where (<I>p</I><SUB><I>i</I></SUB>)<SUB><I>l</I></SUB> denotes the <I>l</I>th component of the support point <I>p</I><SUB><I>i</I></SUB>,
-and <IMG
- WIDTH="20" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img18.gif"
- ALT="$\phi_i$">
-the corresponding Lagrangian interpolation basis
-function. We recall that the numbering of the mapping support points
-involves
-<!-- MATH: $p_k\in\partial K$ -->
-<IMG
- WIDTH="69" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img36.gif"
- ALT="$p_k\in\partial K$">
-for
-<!-- MATH: $k=0,\ldots, 4p-1$ -->
-<IMG
- WIDTH="135" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img29.gif"
- ALT="$k=0,\ldots,4p-1$">.
-Substituting
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\tilde \sigma_l:=\sigma_l-g_l, \quad l=1,2,
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:def-tilde-sigma"> </A><IMG
- WIDTH="176" HEIGHT="30"
- SRC="img37.gif"
- ALT="\begin{displaymath}
-\tilde \sigma_l:=\sigma_l-g_l, \quad l=1,2,
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(5)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-into the Laplace problem (<A HREF="index.html#eq:local-laplace-problem">3</A>) yields the
-zero boundary value problem,
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\begin{array}{rcll}
--\hat\Delta \tilde\sigma_l(\hat x)&=&\hat\Delta g_l(\hat x), \quad &\hat x\in \hat K,\\
- \tilde\sigma_l(\hat x)&=&0, \quad &\hat x\in \partial\hat K,
-\end{array}
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:transformed-local-laplace-problem"> </A><IMG
- WIDTH="262" HEIGHT="53"
- SRC="img38.gif"
- ALT="\begin{displaymath}
-\begin{array}{rcll}
--\hat\Delta \tilde\sigma_l(\hat x)&=&\h...
-...gma_l(\hat x)&=&0, \quad &\hat x\in \partial\hat K,
-\end{array}\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(6)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-that is equivalent to the following variational formulation
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-\tilde\sigma_l\in H^1_0(\hat K):\qquad
-(\hat\nabla \tilde\sigma_l, \hat\nabla \phi)_{\hat K}
- = -(\hat\nabla g_l, \hat\nabla \phi)_{\hat K} \quad \forall \phi\in H^1_0(\hat K).
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="467" HEIGHT="33"
- SRC="img39.gif"
- ALT="\begin{displaymath}\tilde\sigma_l\in H^1_0(\hat K):\qquad
-(\hat\nabla \tilde\si...
-...\hat\nabla \phi)_{\hat K} \quad \forall \phi\in H^1_0(\hat K). \end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-Discretisation of this problem
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-\tilde\sigma_l\in Q_p(\hat K):\qquad
-(\hat\nabla \tilde\sigma_l, \hat\nabla \phi_{4p+i})_{\hat K}
- = -(\hat\nabla g_l, \hat\nabla \phi_{4p+i})_{\hat K} \quad \forall i=0,\ldots, (p-1)^2-1,
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="609" HEIGHT="33"
- SRC="img40.gif"
- ALT="\begin{displaymath}\tilde\sigma_l\in Q_p(\hat K):\qquad
-(\hat\nabla \tilde\sigm...
-...bla \phi_{4p+i})_{\hat K} \quad \forall i=0,\ldots, (p-1)^2-1, \end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-and recalling definitions (<A HREF="index.html#eq:def-mapping-q">1</A>), (<A HREF="index.html#eq:def-tilde-sigma">5</A>) and (<A HREF="index.html#eq:discrete-boundary-function">4</A>) gives
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-\sum_{j=1}^{(p-1)^2}S_{ij}(p_{4p+j})_l=-\sum_{k=0}^{4p-1}T_{ik}(p_k)_l, \quad i=0, \ldots, (p-1)^2-1,
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:discrete-local-laplace"> </A><IMG
- WIDTH="455" HEIGHT="68"
- SRC="img41.gif"
- ALT="\begin{displaymath}
-\sum_{j=1}^{(p-1)^2}S_{ij}(p_{4p+j})_l=-\sum_{k=0}^{4p-1}T_{ik}(p_k)_l, \quad i=0, \ldots, (p-1)^2-1,
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(7)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-with the matrices
-<!-- MATH: $S_{ij}\in\mathbb R^{(p-1)^2\times(p-1)^2}$ -->
-<IMG
- WIDTH="155" HEIGHT="42" ALIGN="MIDDLE" BORDER="0"
- SRC="img42.gif"
- ALT="$S_{ij}\in\mathbb R^{(p-1)^2\times(p-1)^2}$">
-and
-<!-- MATH: $T_{ik}\in\mathbb R^{(p-1)^2\times 4p}$ -->
-<IMG
- WIDTH="128" HEIGHT="42" ALIGN="MIDDLE" BORDER="0"
- SRC="img43.gif"
- ALT="$T_{ik}\in\mathbb R^{(p-1)^2\times 4p}$">
-given by
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-S_{ij}=(\hat\nabla \phi_{4p+i}, \hat\nabla \phi_{4p+j})_{\hat K}, \quad i,j=0,\ldots,(p-1)^2-1,
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="404" HEIGHT="33"
- SRC="img44.gif"
- ALT="\begin{displaymath}S_{ij}=(\hat\nabla \phi_{4p+i}, \hat\nabla \phi_{4p+j})_{\hat K}, \quad i,j=0,\ldots,(p-1)^2-1,
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-and
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-T_{ik}=(\hat\nabla \phi_{4p+i}, \hat\nabla \phi_k)_{\hat K}, \quad i=0,\ldots,(p-1)^2-1,\quad k=0,\ldots,4p-1.
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="522" HEIGHT="33"
- SRC="img45.gif"
- ALT="\begin{displaymath}T_{ik}=(\hat\nabla \phi_{4p+i}, \hat\nabla \phi_k)_{\hat K}, \quad i=0,\ldots,(p-1)^2-1,\quad k=0,\ldots,4p-1.
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-The solutions to problem (<A HREF="index.html#eq:discrete-local-laplace">7</A>) for <I>l</I>=1,2 are
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-(p_{4p+j})_l=-\sum_{i=0}^{(p-1)^2-1}\sum_{k=0}^{4p-1}S^{-1}_{ji}T_{ik}(p_k)_l, \quad j=0,\ldots,(p-1)^2-1,
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="481" HEIGHT="66"
- SRC="img46.gif"
- ALT="\begin{displaymath}(p_{4p+j})_l=-\sum_{i=0}^{(p-1)^2-1}\sum_{k=0}^{4p-1}S^{-1}_{ji}T_{ik}(p_k)_l, \quad j=0,\ldots,(p-1)^2-1,
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-that may be written in compact form:
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-p_{4p+j}=\sum_{k=0}^{4p-1}c_{jk}p_k, \quad j=0,\ldots,(p-1)^2-1,
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:linear-combination-laplace"> </A><IMG
- WIDTH="337" HEIGHT="62"
- SRC="img47.gif"
- ALT="\begin{displaymath}
-p_{4p+j}=\sum_{k=0}^{4p-1}c_{jk}p_k, \quad j=0,\ldots,(p-1)^2-1,
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(8)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-where <I>c</I><SUB><I>jk</I></SUB> represents the coefficient
-<BR><P></P>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: \begin{equation}
-c_{jk}=-\sum_{i=0}^{(p-1)^2-1}S^{-1}_{ji}T_{ik}.
-\end{equation} -->
-
-<TABLE WIDTH="100%" ALIGN="CENTER">
-<TR VALIGN="MIDDLE"><TD ALIGN="CENTER" NOWRAP><A NAME="eq:coefficients"> </A><IMG
- WIDTH="180" HEIGHT="65"
- SRC="img48.gif"
- ALT="\begin{displaymath}
-c_{jk}=-\sum_{i=0}^{(p-1)^2-1}S^{-1}_{ji}T_{ik}.
-\end{displaymath}"></TD>
-<TD WIDTH=10 ALIGN="RIGHT">
-(9)</TD></TR>
-</TABLE>
-</DIV>
-<BR CLEAR="ALL"><P></P>
-of the linear combination (<A HREF="index.html#eq:linear-combination-laplace">8</A>), that
-represents the dependency of the <I>j</I>th inner mapping support point
-<I>p</I><SUB>4<I>p</I>+<I>j</I></SUB> on the support points <I>p</I><SUB><I>k</I></SUB>,
-<!-- MATH: $k=0,\ldots,4p-1$ -->
-<IMG
- WIDTH="135" HEIGHT="32" ALIGN="MIDDLE" BORDER="0"
- SRC="img29.gif"
- ALT="$k=0,\ldots,4p-1$">,
-that are
-placed on the boundary of the cell <I>K</I>. For a fixed degree <I>p</I>, these
-coefficients <I>c</I><SUB><I>jk</I></SUB> are the same for the mapping of <EM>all</EM> cells
-<I>K</I> in real space because the <I>c</I><SUB><I>jk</I></SUB> depend only on the reference
-element <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">.
-Therefore the coefficients <I>c</I><SUB><I>jk</I></SUB> can be
-precomputed and result in following linear combinations:
-
-<P>
-For <I>p</I>=2 the linear combination turns out to be
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-p_8=\tfrac{1}{16}\sum_{k=0}^3p_k+\tfrac{3}{16}\sum_{k=4}^7p_k,
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="196" HEIGHT="61"
- SRC="img49.gif"
- ALT="\begin{displaymath}p_8=\tfrac{1}{16}\sum_{k=0}^3p_k+\tfrac{3}{16}\sum_{k=4}^7p_k,
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-see also Figure <A HREF="index.html#fig:coefficients-q2-q3">3</A>, left.
-<BR>
-<DIV ALIGN="CENTER"><A NAME="fig:coefficients-q2-q3"> </A><A NAME="185"> </A>
-<TABLE WIDTH="50%">
-<CAPTION><STRONG>Figure 3:</STRONG>
-Left: Coefficients <I>c</I><SUB>8,<I>k</I></SUB> for <I>Q</I><SUB>2</SUB> mapping. Right: Coefficients <I>c</I><SUB>12,<I>k</I></SUB> for <I>Q</I><SUB>3</SUB> mapping.</CAPTION>
-<TR><TD>
-<DIV ALIGN="CENTER">
-
-<!-- MATH: $\includegraphics*[scale=0.4]{figures/m2.ps}$ -->
-<IMG
- WIDTH="700" ALIGN="BOTTOM" BORDER="0"
- SRC="img50.gif"
- ALT="\includegraphics*[scale=0.4]{figures/m2.ps}"></DIV></TD></TR>
-</TABLE>
-</DIV>
-<BR>
-For the case that <I>p</I>=3, Figure <A HREF="index.html#fig:coefficients-q2-q3">3</A>, right, shows the coefficients <I>c</I><SUB>12,<I>k</I></SUB> of the linear combination for the inner mapping support point <I>p</I><SUB>12</SUB>. The coefficents for the points <I>p</I><SUB>13</SUB>, <I>p</I><SUB>14</SUB> and <I>p</I><SUB>15</SUB> can be obtain by rotation of the coefficients.
-
-<P>
-<B>Implementation in deal.II.</B> The coefficients <I>c</I><SUB><I>jk</I></SUB>, see
-(<A HREF="index.html#eq:coefficients">9</A>), are represented in the <I>MappingQ</I>
-class by the <I>laplace_on_quad_vector</I> as follows
-<BR><P></P>
-<DIV ALIGN="CENTER">
-<!-- MATH: \begin{displaymath}
-\mbox{\textit{laplace\_on\_quad\_vector}[j][k]}=c_{jk}
-\end{displaymath} -->
-
-
-<IMG
- WIDTH="247" HEIGHT="32"
- SRC="img51.gif"
- ALT="\begin{displaymath}\mbox{\textit{laplace\_on\_quad\_vector}[j][k]}=c_{jk}
-\end{displaymath}">
-</DIV>
-<BR CLEAR="ALL">
-<P></P>
-These coefficients are the same for the mapping of <EM>all</EM> cells
-<I>K</I> in real space because the <I>c</I><SUB><I>jk</I></SUB> depend only on the reference
-element <IMG
- WIDTH="21" HEIGHT="21" ALIGN="BOTTOM" BORDER="0"
- SRC="img8.gif"
- ALT="$\hat K$">.
-Hence for a given degree <I>p</I> the
-<I>laplace_on_quad_vector</I> can be filled by the constructor of
-the <I>MappingQ</I> class. This is done by calling the
-<I>MappingQ::set_laplace_on_quad_vector</I> function that
-includes the coefficients hardcoded for <I>p</I>=2 and <I>p</I>=3 in <I>d</I>=2 dimensions, and a routine for computing the coefficients according to
-(<A HREF="index.html#eq:coefficients">9</A>) for all other cases. The mapping support
-points <IMG
- WIDTH="56" HEIGHT="31" ALIGN="MIDDLE" BORDER="0"
- SRC="img14.gif"
- ALT="$p_i\in K$">,
-
-<!-- MATH: $i=0,\ldots,(p+1)^d-1$ -->
-<IMG
- WIDTH="174" HEIGHT="38" ALIGN="MIDDLE" BORDER="0"
- SRC="img15.gif"
- ALT="$i=0,\ldots,(p+1)^d-1$">
-are computed once for each
-MappingQ object by the
-<I>MappingQ::compute_support_points_laplace</I> that is invoked
-by the virtual <I>compute_mapping_support_points</I> function of
-the base <I>Mapping</I> class. In
-<I>MappingQ::compute_support_points_laplace</I>, first the 4<I>p</I> points on the boundary of the cell are computed (by calling
-<I>MappingQ::add_line_support_points</I>), then by calling
-<I>MappingQ::apply_laplace_vector</I> the remaining (<I>p</I>-1)<SUP>2</SUP> inner mapping supports points are computed, where
-<I>MappingQ::apply_laplace_vector</I> just performs the linear
-combination given in (<A HREF="index.html#eq:linear-combination-laplace">8</A>).
-<BR><HR>
-</FONT>
-<ADDRESS>
-<I>Ralf Hartmann</I>
-<BR><I>2001-09-03</I>
-</ADDRESS>
-</BODY>
-</HTML>
+++ /dev/null
-
-<H1 ALIGN="CENTER">
-A short description of the new threading scheme
-</H1>
-
-
-<p ALIGN="CENTER">
- <strong> Wolfgang Bangerth, May 2003</strong>
-</p>
-
-
-<p>
-Since the first deal.II report on
-multithreading was written in 2000 (see the list of deal.II
-publications),
-we have put in place a new
-implementation of the threading scheme (the first release to contain it is
-4.0). The new scheme can do all that you could do before, so the report is in a
-sense still valid, but it describes a syntax that is no more used. We will here
-briefly describe this syntax as well as some considerations that guided us
-while implementing it. For general questions on multithreading, how programs
-that use it must look like, and for pitfalls to watch out for, please still
-refer to the report mentioned above.
-</p>
-
-<p>
-We note that since this report was written, there has been another
-incarnation of support for multicore machines, namely by using the
-Threading Building Blocks and tasks. The documentation module on
-parallel computing, available through the modules page of the deal.II
-manual, explains this new direction in more detail.
-</p>
-
-
-<h3>1. Rationale and Introduction</h3>
-
-
-<p>
-POSIX and other thread libraries only allow functions as thread entry
-points that satisfy the signature
-<code><pre>
- void * (*) (void *)
-</pre></code>
-and starting threads involves a clumsy syntax. Thread entry points
-with another signature need to be "wrapped", i.e. their arguments need
-to be stored in a structure, and we need a function with above
-signature that can be used to "unpack" the arguments and call the
-desired function. This basically forces us to have one such structure
-and entry function for each function signature that we want to start a
-thread with.
-</p>
-
-<p>
-The first incarnations of the threading scheme in deal.II already got a long
-way towards making this simpler, by hiding the thread entry points, the packing
-and unpacking behind a layer of carefully crafted templates. It allowed you to
-call (almost) any function with arbitrary argument lists on a new thread,
-except that functions that returned values were not allowed. Implementing such
-a template scheme is not simple, since, besides simplicity to use, it has to
-take care of the lifetimes of objects that need to be synchronised across
-threads, and in particular since templates do not allow for functions with
-arbitrary numbers of arguments - they need to be repeated for every number of
-arguments, which makes implementation tedious. Nevertheless, the old scheme was
-very much usable.
-</p>
-
-<p>
-However, the old scheme had a number of shortcomings:
-<ul>
-<li>The implementation did not allow for functions returning
- anything but <code>void</code>. We want to be able to call everything
- on a new thread that can also be called on the present one.</li>
-<li>Thread objects could not be copied. Rather, thread ids were put into a
-thread manager object that took care of it, but handling single, or even
-detached threads was not too convenient.</li>
-<li>The general syntax for calling a function on a new thread was a
- little clumsy and not intuitive.</li>
-</ul>
-</p>
-
-<p>
-Regarding the last point, note that any other function is called by
-<code><pre>
- f(arg1, arg2);
- obj.f(arg1, arg2);
-</pre></code>
-Ideally, the following syntax for starting any function on a new
-thread would be nice:
-<code><pre>
- spawn f(arg1, arg2);
- spawn obj.f(arg1,arg2);
-</pre></code>
-This syntax is not possible in C++, but the following syntax is,
-making it relatively clear what the intent of the statement is:
-<code><pre>
- spawn (f)(arg1, arg2);
- spawn (obj, &Class::f)(arg1,arg2);
-</pre></code>
-This is the syntax we will want to achieve (except for the fact that the
-<code>spawn</code> function is in a namespace <code>Threads</code>, just like
-all other entities described here).
-</p>
-
-<p>
-This text will discuss the details that are needed to implement
-this syntax, as well as the following points:
-<ul>
-<li>Overloading <code>spawn(</code>) so as to take unbound functions and member
-functions, whether virtual or static. Of course, every call needs to be type
-safe, i.e. the exact
- same conversions of arguments need to be performed as in a usual call (except
- for two additional copies that are necessary).</li>
-<li><code>spawn()</code> needs to return a value that allows us to identify,
-and join a thread. The syntax for this will be
-<code><pre>
- Thread<> t = spawn(f)(arg1, arg2);
- t.join ();
-</pre></code>
- If we don't save the return value of <code>spawn()</code>, as in the examples
- above, then we have just created a detached thread.</li>
-<li>Return values: if <code>f()</code> returns a value, say, an integer, then
-we want to be able to retrieve it once the thread has finished:
-<code><pre>
- Thread<int> t = spawn (f)(1., 1.);
- t.join ();
- int i = t.return_value ();
-</pre></code>
- This requires some care when functions return references, but some
- template magic will save us. Another special case are functions that
- return <code>void</code>.</li>
-<li>Thread groups: if threads are created inside a loop, we will want to
- put all of them into a <code>ThreadGroup</code> object, and wait for them
- collectively, rather than one-by-one.</li>
-</ul>
-</p>
-
-<p>
-Basically, the syntax above is all you need to know. It is as simple as
-that. The rest of this text, in comparison is very much of technical nature. I
-took most of it from a technical discussion I had with the author of the
-threading scheme in boost, William Kempf. It describes the way the threading
-scheme is implemented, the meaning of the various classes, etc. It probably
-doesn't give you much insight how to <em>use</em> it, but should explain in
-reasonable detail how it <em>works</em>. For more examples of use, take a look
-at a number of the example programs in deal.II, or at some places in the
-library itself.
-</p>
-
-
-<p>
-This paper is divided into the following parts:
-<ol>
-<li>This introduction</li>
-<li>Entities (functions, classes) that are used by both and that
- describe the newly created thread</li>
-<li>Entities that are used on the calling thread</li>
-<li>Entities that are used to create a thread</li>
-<li>Tool classes</li>
-<li>Open problems</li>
-<li>Further suggestions</li>
-</ol>
-We will present the main parts of the code in the text. The implementation is
-in the library; all entities that
-are not to be used by the user are placed into a namespace
-<code>internal</code>, those to be used are in a namespace
-<code>Threads</code>. The implementation uses Boost's shared_ptr. Some parts of
-the implementation parallel the
-boost::function library, but they are small and taylored to the
-particular purpose at hand; in particular, they make heavy use of the
-boost::tuple library. We note that the code has in some places already evolved
-a little bit beyond the state of this paper, but the main ideas are all to be
-found still.
-</p>
-
-
-
-<h3>2. Entities that describe threads</h3>
-
-
-<p>
-Each thread that has been created is described by exactly one object
-of type <code>thread_description<RT></code>, where <code>RT</code> here and in the
-sequel will always denote the return type of the function being called
-on a new thread. The <code>thread_description</code> class is split into an
-operating system dependent base class, and an independent derived
-class. The base class is responsible for abstracting the OS
-interface to the functions creating, joining, killing, and signalling
-threads. For POSIX threads, this class looks as follows:
-</p>
-
-<code><pre>
- struct thread_description_base {
- private:
- pthread_t pt;
- mutable volatile bool was_joined;
- mutable boost::mutex join_mutex;
- mutable boost::condition join_condition;
-
- public:
- thread_description_base () : was_joined (false) {};
- virtual ~thread_description_base () { /* ... */ };
-
- void create (void * (*p) (void *), void *d) {
- pthread_create (&pt, 0, p, d);
- };
-
- void join () const {
- if (was_joined)
- return;
- boost::mutex::scoped_lock lock(join_mutex);
- if (!was_joined)
- pthread_join (pt, 0);
- was_joined = true;
- };
- };
-</pre></code>
-
-<p>
-<code>join()</code> can be called more than once and uses Schmidt's thread-safe
-double-checking pattern for speed. There could be additional functions
-<code>kill()</code> or <code>send_signal()</code>, but these are not presently
-implemented.
-</p>
-
-<p>
-In the destructor, we need to make sure that a thread is joined at
-least once in its lifetime, or if not that it is being detached
-(otherwise, we create the thread equivalent of a zombie process, which
-will lead to a resource leak in the operating system). This is a
-little tricky, since the destructor might be called while the thread
-is still running; comments in the code explain how we work around
-this.
-</p>
-
-<p>
-The <code>thread_description<RT></code> class is derived from this base
-class:
-<code><pre>
- template <typename RT>
- struct thread_description : public thread_description_base
- {
- return_value<RT> ret_val;
- };
-</pre></code>
-</p>
-
-<p>
-Its only purpose is to provide a place of storage for the return
-value of the function being called on the new thread. Since functions
-might return references or just nothing at all, the <code>return_value</code>
-template is used. It is described below in the section on Tool
-Classes. The return value will be set on exit of the function being
-called.
-</p>
-
-<p>
-As mentioned, there is exactly one <code>thread_description<RT></code>
-object per created thread. It is accessed using <code>boost::shared_ptr</code>
-objects, and references are held from each <code>Thread<RT></code> object
-for this thread as
-well as from a wrapper function on the new thread. The object is thus
-deleted, when all <code>Thread<RT></code> objects for this thread have gone out of
-scope (or point to different threads) and the thread itself has
-finished; this is the appropriate time.
-</p>
-
-
-
-<h3>3. Entities that are used on the calling thread</h3>
-
-
-<p>
-On the calling thread, we basically use the <code>Thread<RT></code>
-class, <code>ThreadGroup<RT></code> class, and <code>spawn</code>
-function. The <code>Thread<RT></code> class has the following
-implementation:
-</p>
-
-<code><pre>
- template <typename RT = void>
- class Thread {
- public:
- Thread () {};
- Thread (const boost::shared_ptr<thread_description<RT> > &td)
- : thread_description (td) {};
-
- void join () const { thread_description->join (); };
-
- RT return_value () {
- join ();
- return thread_description->ret_val.get();
- };
-
- bool operator == (const thread &t) {
- return thread_description == t.thread_description;
- };
-
- private:
- boost::shared_ptr<thread_description<RT> > thread_description;
- };
-</pre></code>
-
-<p>
-Copy constructor and <code>operator=</code> are generated automatically by the
-compiler. Note that asking for the <code>return_value</code> automatically waits
-for the thread to finish, and that for this it is helpful that we can
-call <code>join()</code> more than once on the thread description object. The
-<code>return_value()</code> function also makes use of the fact that if <code>RT=void</code>,
-then the return construct is still valid. Furthermore, since this is
-the most common case, the template argument of the thread class has a
-default of <code>void</code>.
-</p>
-
-<p>
-The <code>ThreadGroup</code> class is a container distributing calls to its
-member functions to all its elements. Elements are added using
-<code>operator+=</code>, and they are stored using a
-<code>std::vector</code>. (A <code>std::set</code> would be more appropriate,
-but then we would have to have <code>operator<</code> for
-<code>Thread<RT></code> objects.) It has the same default value for the
-template argument:
-</p>
-
-<code><pre>
- template <typename RT = void>
- class ThreadGroup
- {
- public:
- ThreadGroup & operator += (const Thread<RT> &t) {
- threads.push_back (t);
- return *this;
- };
-
- void join_all () const {
- for (typename std::vector<Thread<RT> >::const_iterator
- t=threads.begin(); t!=threads.end(); ++t)
- t->join ();
- };
-
- private:
- std::vector<Thread<RT> > threads;
- };
-</pre></code>
-
-<p>
-Since objects of type <code>Thread<RT></code> are freely copyable, there
-is no need
-to provide an index operator for <code>ThreadGroup</code>; if you need to index
-its elements (for example to get at the return value), use
-<code>std::vector<Thread<RT> ></code>.
-</p>
-
-<p>
-Finally, there are overloads of the <code>spawn</code> template, for unbound
-functions, as well as <code>const</code> and non-<code>const</code> member
-functions. We only show them for unary member functions:
-<code><pre>
- template <typename RT, typename C, typename Arg1>
- mem_fun_encapsulator<RT,C,boost::tuple<Arg1> >
- spawn (C &c, RT (C::*fun_ptr)(Arg1)) {
- return mem_fun_encapsulator<RT, C, boost::tuple<Arg1> > (c,fun_ptr);
- }
-
- template <typename RT, typename C, typename Arg1>
- mem_fun_encapsulator<RT,const C,boost::tuple<Arg1> >
- spawn (const C &c, RT (C::*fun_ptr)(Arg1) const) {
- return mem_fun_encapsulator<RT, const C, boost::tuple<Arg1> > (c,fun_ptr);
- }
-</pre></code>
-</p>
-
-<p>
-Note that we need two overloaded versions, for <code>const</code> and
-non-<code>const</code>
-member functions. Both create an intermediate object (in the
-<code>internal</code>
-namespace) that will accept arguments in place of the function being
-called on the new thread, make sure a new thread is created, copy the
-arguments to the new thread's stack, and only then return. The exact
-mechanism is described in the next section.
-</p>
-
-<p>
-In the implementation, we have to repeat the functions above for
-binary, ternary, ... member functions, and also for unbound member
-functions. One would really like to have something also for objects other than
-pointers to (member-)functions that provide an
-<code>operator()</code>. However, this doesn't seem to be possible if
-<code>operator()</code> returns something other than <code>void</code> or takes
-arguments. This
-would need some kind of typeof-operator which is not standard C++. See the
-discussion in the Open Problems section.
-</p>
-
-
-<h3>4. Entities that are used to create a thread</h3>
-
-
-<p>
-In this section, we describe the gory details of copying arguments
-from the stack of the old thread to the stack of the new one. These
-details are not necessary to <em>use</em> the <code>spawn()</code> functions,
-so are probably boring and may be skipped.
-</p>
-
-<p>
-The basic idea is the following: <code>spawn()</code> returns an object and provides
-it with the address of the function to be called, and in the case of a
-member function with the address of an object. <code>mem_fun_encapsulator</code>
-looks like this:
-</p>
-
-<code><pre>
- template <typename RT, typename C, typename ArgList,
- int length = boost::tuples::length<ArgList>::value>
- class mem_fun_encapsulator;
-
- template <typename RT, typename C, typename ArgList>
- class mem_fun_encapsulator<RT,C,ArgList,1> {
- typedef typename mem_fun_ptr<RT,C,ArgList>::type MemFunPtr;
-
- public:
- mem_fun_encapsulator (C &c, MemFunPtr mem_fun_ptr)
- : c (c), mem_fun_ptr(mem_fun_ptr) {};
-
- Thread<RT>
- operator() (typename boost::tuples::element<0,ArgList>::type arg1) {
- return mem_fun_wrapper<RT,C,ArgList> (mem_fun_ptr, c,
- boost::tie(arg1)).fire_up ();
- };
-
- private:
- C &c;
- MemFunPtr mem_fun_ptr;
- };
-</pre></code>
-
-<p>
-(Note how the default value specification of the last template
-argument automatically redirects uses with three template parameters
-to the correct four-parameter specialization, even though the general
-template is never used.)
-</p>
-
-<p>
-The constructor stores the two addresses. If one calls
-<code><pre>
- spawn(obj, &C::f) (42);
-</pre></code>
-the next thing that is invoked is the <code>operator()</code> of this class. It
-takes the argument(s), creates a temporary with the two addresses and
-a reference to the argument (that's what <code>boost::tie</code>) does, and calls
-<code>fire_up()</code> on this temporary. <code>fire_up</code> has all the information, and does
-the work. Note that we will not pass references to the individual
-arguments, but bind them all together with <code>boost::tie</code>, so that we need
-not have different versions of the <code>mem_fun_wrapper</code> class for different
-numbers of arguments. (However, we need a separate partial
-specialization of the <code>mem_fun_encapsulator</code> class for each number of
-function arguments.) The <code>tie_args</code> template is used to make a version
-of the <code>ArgList</code> type with all reference types; it is described below.
-</p>
-
-<p>
-The next question, of course, is how <code>mem_fun_wrapper</code> looks like. Let
-us first consider the base class that it has in common with
-<code>fun_wrapper</code>, the wrapping class for non-member function objects:
-<code><pre>
- template <typename RT, typename EntryPointClass>
- struct wrapper_base {
- Thread<RT> fire_up () {
- thread_descriptor
- = DescriptionPointer(new typename thread_description<RT>());
-
- boost::mutex::scoped_lock lock (mutex);
- thread_descriptor->create (&EntryPointClass::entry_point,
- (void *)this);
- condition.wait (lock);
-
- return thread_descriptor;
- }
-
- protected:
- typedef boost::shared_ptr<thread_description<RT> >
- DescriptionPointer;
-
- DescriptionPointer thread_descriptor;
-
- mutable boost::mutex mutex;
- mutable boost::condition condition;
- };
-</pre></code>
-<p>
-<code>fire_up</code> is the only real function; it creates a thread descriptor
-object, and calls it with a pointer to the present object, and the address of
-the starting point is <code>EntryPointClass::entry_point</code>, where
-<code>EntryPoint</code> is the name of a class that implements this thread
-starting function and is passed as a template argument to
-<code>wrapper_base</code>.
-Before it starts the new thread, it acquires a mutex and
-afterwards wait until a condition is signalled before it finishes by
-using the thread descriptor object to generate a <code>Thread<RT></code>
-object.
-</p>
-
-<p>
-The magic happens in the derived class:
-<code><pre>
- template <typename RT, class C, typename ArgList>
- struct mem_fun_wrapper
- : public wrapper_base<RT, mem_fun_wrapper<RT,C,ArgList> >
- {
- typedef typename mem_fun_ptr<RT,C,ArgList>::type MemFunPtr;
- typedef typename tie_args<ArgList>::type ArgReferences;
- mem_fun_wrapper (MemFunPtr mem_fun_ptr,
- C &c,
- const ArgReferences &args)
- : c (c),
- mem_fun_ptr (mem_fun_ptr),
- args (args) {};
- private:
- mem_fun_wrapper ();
- mem_fun_wrapper (const mem_fun_wrapper &);
-
- C &c;
- MemFunPtr mem_fun_ptr;
- ArgReferences args;
-
- static void * entry_point (void *arg)
- {
- const wrapper_base<RT> *w
- = reinterpret_cast<const wrapper_base<RT>*> (arg);
- const mem_fun_wrapper *wrapper
- = static_cast<const mem_fun_wrapper*> (w);
- MemFunPtr mem_fun_ptr = wrapper->mem_fun_ptr;
- C &c = wrapper->c;
- ArgList args = wrapper->args;
-
- boost::shared_ptr<thread_description<RT> >
- thread_descriptor = wrapper->thread_descriptor;
-
- {
- boost::mutex::scoped_lock lock (wrapper->mutex);
- wrapper->condition.notify_one ();
- }
-
- call (mem_fun_ptr, c, args, thread_descriptor->ret_val);
-
- return 0;
- };
- };
-</pre></code>
-</p>
-
-<p>
-Note in particular, how this class passes itself as second template parameter
-to the base class, enabling the latter to call the
-<code>mem_fun_wrapper::entry_point</code> function as entry point to the new
-thread. When the fire_up function in the base
-class is called, it creates a new thread that starts inside this
-function, and the argument given to it is the address of the
-<code>wrapper_base</code> object. The first thing the <code>entry_point</code> function does, is
-to cast back this address to the real object's type (it knows the real
-type of the object, since the address of this function has been handed
-down through the template magic), then copies the address of
-the object to work with and the address of the member function to be
-called from the stack of the old thread to the stack of this new
-thread. It then also copies the arguments, which so far have been held
-only as references, but copies them by value. Next, it gets the
-address of the return thread descriptor, and with it the address of
-the return value (the <code>shared_ptr</code> will also make sure that the object
-lives long enough). The part in braces signals the condition to the
-old thread, which hangs in the <code>fire_up</code> function: the arguments have
-been copied, and the old thread can go on, eventually also destroying
-objects that have been copied by value. Finally, it calls the
-requested function with the proper arguments through a generic
-interface (described in the section on tools) and sets the return
-value of the thread.
-</p>
-
-
-<h3>5. Tool classes</h3>
-
-
-<p>
-In the implementation above, some tool classes have been used. These
-are briefly described here.
-</p>
-
-<h4>a) The <code>return_value<T></code> class template</h4>
-
-<p>
-This class stores a value of type <code>T</code> if <code>T</code> is not a
-reference or <code>void</code>. It offers <code>get()</code> and
-<code>set()</code> functions that get and set the value. If <code>T</code> is a
-reference type, then <code>set()</code> is obviously not possible since
-references cannot be rebound after construction time. The class therefore
-stores a pointer, and <code>set()</code> sets the pointer to the object the
-reference references. <code>get()</code> then returns the reference again. If
-<code>T</code> is <code>void</code>, then the class is empty and there is only
-a <code>get()<code> function that returns <code>void</code>.
-</p>
-
-<code><pre>
- template <typename RT> struct return_value
- {
- private:
- RT value;
- public:
- RT get () const { return value; }
- void set (RT v) { value = v; }
- };
-
- template <typename RT> struct return_value<RT &>
- {
- private:
- RT * value;
- public:
- RT & get () const { return *value; }
- void set (RT & v) { value = &v; }
- };
-
- template <> struct return_value<void> {
- static void get () {};
- };
-</pre></code>
-
-
-<h4>b) The <code>call</code> function templates</h4>
-
-<p>
-The <code>call</code> function templates take a function pointer, an argument list
-tuple, and the address of the return value object, and call the
-function with these arguments. Since we have to unpack the argument
-list, we have to dispatch to different functions, depending on the
-number of arguments, in the usual way:
-</p>
-
-<code><pre>
- template <int> struct int2type;
-
- template <typename RT, typename PFun, typename ArgList>
- static void call (PFun fun_ptr,
- ArgList &arg_list,
- return_value<RT> &ret_val)
- {
- Caller<RT>::do_call (fun_ptr, arg_list, ret_val,
- int2type<boost::tuples::length<ArgList>::value>());
- };
-</pre></code>
-
-<p>
-The <code>Caller</code> class has the following member functions:
-
-<code><pre>
- template <typename RT> struct Caller
- {
- template <typename PFun, typename ArgList>
- static void do_call (PFun fun_ptr,
- ArgList &arg_list,
- return_value<RT> &ret_val,
- const int2type<1> &)
- { ret_val.set ((*fun_ptr) (arg_list.template get<0>())); };
-
- // likewise for int2type<0>, int2type<2>, ...
- };
-</pre></code>
-</p>
-
-
-<p>
-There is a specialization <code>Caller<void></code> that does not set a return
-value, and for each call and <code>do_call</code> function there is a second
-function for member function pointers that takes an object as
-additional argument.
-</p>
-
-
-<h4>c) <code>mem_fun_ptr</code></h4>
-
-<p>
-In order to form a pointer to member function for both cases of <code>const</code>
-and non-<code>const</code> member functions, we need a simple tool:
-<code><pre>
- template <typename RT, class C, typename ArgList,
- int length = boost::tuples::length<ArgList>::value>
- struct mem_fun_ptr_helper;
-
- template <typename RT, class C, typename ArgList>
- struct mem_fun_ptr_helper<RT, C, ArgList, 1>
- {
- typedef RT (C::*type) (typename boost::tuples::element<0,ArgList>::type);
- };
-
- template <typename RT, class C, typename ArgList>
- struct mem_fun_ptr_helper<RT, const C, ArgList, 1>
- {
- typedef RT (C::*type) (typename boost::tuples::element<0,ArgList>::type) const;
- };
-
- template <typename RT, class C, typename ArgList>
- struct mem_fun_ptr
- {
- typedef typename mem_fun_ptr_helper<RT,C,ArgList>::type type;
- };
-</pre></code>
-</p>
-
-<p>
-Note that if the second template argument is a <code>const C</code>, then we mark
-the member function <code>const</code>. The two templates for <code>mem_fun_ptr_helper</code>
-have to be repeated for every number of arguments that we have in
-mind. Note also that the specification of the default argument in the
-declaration of the general template of <code>mem_fun_ptr_helper</code> saves us
-from recomputing it in <code>mem_fun_ptr</code>.
-</p>
-
-
-
-<h4>d) <code>add_reference</code> for tuples</h4>
-
-<p>
-The following classes add references to the elements of a tuple, thus
-providing the type equivalent of the return value of the <code>boost::tie</code>
-functions. There are probably ways inside boost's tuples library to do
-this, but I couldn't locate this.
-<code><pre>
- template <int N, typename Tuple>
- struct add_reference_to_Nth
- {
- typedef typename boost::tuples::element<N,Tuple>::type ArgType;
- typedef typename boost::add_reference<ArgType>::type type;
- };
-
- template <typename Tuple, int = boost::tuples::length<Tuple>::value>
- struct tie_args_helper;
-
- template <typename Tuple>
- struct tie_args_helper<Tuple,1>
- {
- typedef
- boost::tuple<typename add_reference_to_Nth<0,Tuple>::type>
- type;
- };
-
- template <typename Tuple>
- struct tie_args
- {
- typedef typename tie_args_helper<Tuple>::type type;
- };
-</pre></code>
-</p>
-<p>
-The <code>tie_args_helper</code> class is repeated for every number of elements we
-want to use.
-</p>
-
-
-
-<h3>6. Open Problems</h3>
-
-
-<h4>a) A variable lifetime problem</h4>
-<p>
-The only unsolved semantic problem I am aware of at present is the
-following: if we have a function
-<code><pre>
- void f(const int &i);
-</pre></code>
-then this function can be called as
-<code><pre>
- f(1);
-</pre></code>
-i.e. the compiler creates a temporary and passes its address to
-<code>f()</code>. When invoking <code>f()</code> on a new thread, however, as in
-<code><pre>
- spawn (f)(1);
-</pre></code>
-then it is only guaranteed that the call to <code>spawn()</code> does not return
-before the new thread is started and has copied the arguments to
-<code>f()</code>. However, the argument is only the reference to the temporary, not
-its value. <code>f()</code> will thus likely observe corrupted values for its
-argument. On the other hand, copying the value is no option either, of
-course. Since to the author's best knowledge the language does not
-provide means to avoid taking the address of a temporary, there is
-presently no way to avoid this problem. Suggestions for healing it are
-very welcome.
-</p>
-
-
-<h4>b) Forwarding of <code>operator()</code></h4>
-<p>
-Above, we have not defined an overload of <code>spawn</code> for functor-like
-objects, even though that would be desirable. One way to do so would be
-<code><pre>
- template <typename C>
- mem_fun_encapsulator<void,C,boost::tuple<> >
- spawn (C &c) {
- return spawn (c, &C::operator());
- }
-</pre></code>
-This only works if <code>operator()</code> satisfies the signature
-<code><pre>
- struct C { void operator() (); };
-</pre></code>
-</p>
-<p>
-We could add another overload if <code>operator()</code> is
-<code>const</code>. However, what one
-would like is an overload for more general signatures. Unfortunately,
-this requires that we can infer type and number of arguments and
-return type of <code>operator()</code> at the time we declare the return type of
-above overload of <code>spawn()</code>. I have not found a way to infer this
-information just by using the template parameter <code>C</code> -- it just seems
-not possible. What would work if it were supported by compilers is a
-kind of <code>typeof</code>-operator:
-<code><pre>
- template <typename C>
- typeof(spawn(c,&C::operator())) // **
- spawn (C &c) {
- return spawn (c, &C::operator());
- }
-</pre></code>
-</p>
-<p>
-When seeing the declaration, the compiler would automatically check
-which version of the overloaded <code>spawn()</code> function it would call, and
-correspondingly take the return type. gcc does support the <code>typeof</code>
-keyword, but even present CVS snapshots generate an internal compiler
-error on this construct.
-</p>
-
-<h4>c) Using a memory based scheme rather than condition variables</h4>
-<p>
-The scheme using mutices and condition variables to synchronise
-calling and called thread seems expensive. A simpler approach would be
-to replace it by letting the creating thread generate an object on the
-heap that holds copies of the arguments (instead of references as
-presently), spawn the new thread and just go on without any
-synchronisation.
-</p>
-
-<p>
-The calling thread would then not have to copy the arguments onto its
-local stack and signal to the calling thread. It would only have to
-delete the memory after the call to the user-supplied function
-returns. Apart from replacing <code>ArgReferences</code> by
-<code>ArgList</code> in some places,
-the scheme would basically just replace <code>*_encapsulator::operator()</code>,
-<code>fire_up</code>, and <code>thread_entry_point</code>:
-</p>
-
-<code><pre>
- thread<RT>
- operator() (typename boost::tuples::element<0,ArgList>::type arg1) {
- return (new mem_fun_wrapper<RT,C,ArgList> (mem_fun_ptr, c,
- boost::tie(arg1)))->fire_up ();
- };
-
- thread<RT> fire_up () {
- thread_descriptor
- = DescriptionPointer(new typename detail::thread_description<RT>());
-
- thread_descriptor->create (entry_point, (void *)this);
- // no synchronisation here
- return thread_descriptor;
- }
-
- static void * entry_point (void *arg) {
- wrapper_base<RT> *w = reinterpret_cast<wrapper_base<RT>*> (arg);
- fun_wrapper *wrapper = static_cast<fun_wrapper*> (w);
- // no copying here; no synchronisation necessary
- detail::call (wrapper->fun_ptr, wrapper->args,
- wrapper->thread_descriptor->ret_val);
- // delete memory
- delete wrapper;
- return 0;
- }
-</pre></code>
-
-<p>
-The perceived simplicity without using mutices and condition variable
-might be deceptive, however, since memory allocation and deallocation
-requires locking and unlocking mutices as well, and is generally not a
-cheap operation.
-</p>
-
-<p>
-However, the main problem is that I get spurious segmentation faults
-with this on my Linux box. These always happen inside the memory
-allocation and deallocation functions in the C++ and C language
-support libraries. I believe that these are not bugs in the
-application, but in the language runtime. However, my motivation to
-debug multithreading problems in the libc is very limited; for
-reference, valgrind 1.94 does not show accesses to uninitialized or
-already freed memory portions, even for runs that eventually crash
-later on.
-</p>
-
-
-<h3>7. Alternative Suggestions</h3>
-
-
-<p>
-Here are some additional suggestions for discussion:
-</p>
-
-<h4>a) Conversions between return values</h4>
-
-<p>
-If <code>f()</code> is a function returning an integer, then the following is
-legal:
-<code><pre>
- double d = f(arg1, arg2);
-</pre></code>
-The question, then, would be: do we want to allow conversions between
-<code>Thread<double></code> and <code>Thread<int></code> objects?
-And do we want to allow a
-conversion from <code>Thread<T></code> to <code>Thread<void></code>
-(i.e.: casting away the return value)?
-</p>
-
-<p>
-Since one can still assign the return value of the thread to a double,
-<code><pre>
- double d = thread.return_value();
-</pre></code>
-the only real merit in allowing conversions is in putting threads with
-different return value types into a <code>ThreadGroup</code>:
-<code><pre>
- double f1 ();
- int f2 ();
-
- ThreadTroup<double> tg;
- tg += spawn(f1)();
- tg += spawn(f2)(); // convert Thread<int> to Thread<double>
- tg.join_all ();
-</pre></code>
-</p>
-<p>
-Being able to do this is probably only syntactic sugar, except for the
-case where we are not interested in the return values of all threads,
-i.e. the conversion <code>Thread<T> -> Thread<void></code> seems
-like the only one that is really worth it.
-</p>
-
-<p>
-I have made some initial experiments with implementing general
-conversions. The main problem is that we need to allow conversion
-chains:
-<code><pre>
- thread<double> t1 = spawn (f)(arg1, arg2);
- thread<int> t2 = t1;
- thread<double> t3 = t2;
-</pre></code>
-</p>
-<p>
-If <code>f()</code> returns 1.5, then <code>t3.return_value()</code> needs to
-return 1.0. I believe that such conversions could be implemented, by adding the
-types in the chain into a <code>boost::tuple</code> of growing length, and writing
-a function that converts a value of the first type of this tuple to
-the second, to the third, ..., to the last type in the tuple. However,
-a plethora of internal compiler errors has scared me off doing more
-experiments in this direction.
-</p>
-
-
-<h4>b) Conversions between class types I</h4>
-
-<p>
-When you have a class hierarchy like
-<code><pre>
- struct B { void f(); };
- struct D : public B {};
-</pre></code>
-then calling
-<code><pre>
- spawn (D(), &B::f);
-</pre></code>
-fails for gcc (but succeeds with Intel's icc). Presumably, gcc is
-right: template arguments must match exactly, and <code>D()</code> is of type
-<code>D</code>, while <code>&B::f</code> leads to a class type of
-<code>B</code>. There is no function template for spawn for which this call can
-match without a derived-to-base conversion. We could now change the template
-<code><pre>
- template <typename RT, typename C, typename Arg1>
- mem_fun_encapsulator<RT,C,boost::tuple<Arg1> >
- spawn (C &c, RT (C::*fun_ptr)(Arg1)) {
- return mem_fun_encapsulator<RT, C, boost::tuple<Arg1> > (c,fun_ptr);
- }
-</pre></code>
-into
-<code><pre>
- template <typename RT, typename A, typename C, typename Arg1>
- mem_fun_encapsulator<RT,C,boost::tuple<Arg1> >
- spawn (A &a, RT (C::*fun_ptr)(Arg1)) {
- return mem_fun_encapsulator<RT, C, boost::tuple<Arg1> > (a,fun_ptr);
- }
-</pre></code>
-i.e. introduce another class template <code>A</code> for the type of the
-object. Since the arguments of the constructor to the
-<code>mem_fun_encapsulator</code> object are known, the compiler would perform a
-derived-to-base conversion for object <code>a</code> if necessary. I don't know
-whether this is desirable, in particular since also other conversions
-could happen here that one would not want (in the extreme case
-generating a temporary)..
-</p>
-
-
-<h4>c) Conversions between class types II</h4>
-
-<p>
-When one writes
-<code><pre>
- spawn (this, &X::f)
-</pre></code>
-one gets an error that "'this' is not convertible to type X&". One has
-to write <code>*this<code> instead. It would be simple to have another set of
-overloads of <code>spawn()</code> that accepts a pointer instead of a reference,
-and simply forwards to the existing function. This is just for the
-lazy people, probably, but it is a common case.
-</p>
-
-
-<h4>d) Catching exceptions</h4>
-
-<p>
-When a function on a new thread throws an exception, it only
-propagates up to one of the two <code>entry_point()</code> functions, then vanishes
-into the run-time system and kills the program. Ideally, we would have
-a way to pass it over to the main thread. This, however, would need
-some support from the language. Basically, we would need two
-operations:
-<ul>
-<li>clone an exception without knowing its type; we could then in the
- <code>entry_point</code> function catch it and stack it somewhere, just like we
- do for the return value</li>
-<li>back on the main thread, the <code>Thread::join()</code> function must raise this
- stored exception if there was one, again without knowing its type.</li>
-</ul>
-Given how exceptions are implemented usually, the machinery for these
-operations is probably there, but is not exported to the user through
-the run-time environment. Thus, an implementation of such ideas has to
-wait for changes in the language specification.
-</p>
-
-
-<HR>
-
-<div ALIGN="RIGHT">
-Wolfgang Bangerth, 2003
-</div>
-<p> </P></BODY>
-</HTML>
-
-
-
-</BODY>
-</HTML>
-