There are a lot of different technical realizations of the dual concept. So, a
simple dualization leads to a function which returns for a given simplex and a
segment of the related codimension their intersection index. Such a realization
may be easier to use in theoretical considerations, but not for implementation.
We try to find here a variant which allows easy implementation and usage.
Now we want to introduce the definition of a cogeometry for exact real
arithmetics. But, at first, let's consider shortly how we use some
notions like in general and natural. They look very
informal, but have a well-defined formal sense.
The notion in general may be formalized using the concept of
transversality. In this concept we distinguish between the "generic
situation" of "transverse intersection" and "degenerated situations".
They may be characterized by two properties:
- A small modification allows to obtain a generic, transverse
situation.
- On the other hand, a small modification of a generic situation
does not lead to a degenerate situation.
That means the generic situation defines an open, dense subset in the
set of all possible situations. Usually it is very easy to find in a
concrete situation what is the generic situation and what is
degenerated. In the generic situation, a sub-manifold of dimension k
has an intersection with a sub-manifold of codimension l if k >=l. It is a smooth sub-manifold of dimension (k-l), and the intersection
is transverse. That means, the tangential space in the intersection
point will be generated by the tangential subspaces of the two
sub-manifolds. Pre-images of sub-manifolds will be sub-manifolds.
To obtain formal results it is necessary to fix the related spaces
of manifolds. It is always possible to use smooth manifolds and
functions. To obtain the correct number of derivatives which has to
be defined is more complicate, especially it depends on the dimensions
of the involved manifolds. The basic result is the theorem of Sard [Sard1942] . Related results and techniques
which allow to establish such results you can find in [Hirsch1976] .
There will be different possibilities to handle the degenerate
cases. In a degenerate situation we have different possible results
which may be obtained as the limit from different directions. There
are different strategies:
- To leave the result undefined.
- To allow every of the possible results.
- To use the complete set of the possible results.
- To fix some order and to use the lowest possible result.
The strategy used here is not relevant for the problems of
implementation, because the problem of degenerate cases will be
covered by another serious problem --- the rounding errors. That's why
we simply use the first strategy and define the cogeometry only for
the generic case. Compared with the other strategies, we sometimes
have to add "in general" even if the other strategies may allow to
omit this.
The notion natural will be used to describe an important
property of a construction related with mappings. Assume we have a
construction which allows to create some object on Y for a given
object on X and a mapping f: X --> Y. This construction is
natural if a composition property will be fulfilled: If we consider
the composition of f with g: Y --> Z, the construction for the
composition of the mappings leads to the same object on Z as the
composition of the constructions for the two mappings.
In the following, we use the short, informal notions "in general"
and "natural" having in mind that they may be transformed into exact
results. We do not give these exact formulations because they will be
straightforward from point of view of theoretical mathematics, and the
main interest of the "theoretical part" is to show that the concept of
cogeometry is very natural from theoretical point of view.
Let's now introduce the basic object. The required properties of these
objects we define later.
- A k-segment S_k
- is a closed submanifold with
boundary of codimension k.
- A k-simplex
- is a continuous mapping from the standard
k-dimensional reference simplex into X. In the case of a smooth
manifold, it makes sense to consider only smooth mappings.
- A side of a k-simplex
- is a (k-1)-simplex defined by the
mapping of the related side of the reference simplex. To avoid
exceptions we define the side of a 0-simplex as the empty object.
- A k-flag
- consists of a point p (called position), a sequence
of (k+1) segments (S_0,...,S_k) and k orthogonal directions
(d(1),...,d(k)). To avoid exceptions we define the flag also for
k = -1 as the empty object.
- An intersection of a k-simplex
- may be a k-flag with position
in the simplex --- an inner intersection --- or a (k-1)-flag on
a side of the simplex --- a boundary intersection.
- The intersection function f(k)
- allows to find intersections
of k-simplices. Input is a k-simplex and an inititial intersection of
the simplex. The result is another intersection of the same simplex
which we call the continuation of the first intersection through the
simplex.
- A cogeometry G(X)
- is a sequence of functions f(k) for k
>= 0.
Before we define the properties required for these objects, let's
define them for the case of a n-dimensional geometry described by a
smooth cell complex. We consider only smooth simplices.
In this case, the position of a k-flag is inside the segmentS_k and is a boundary point for all S_i with i < k, S_i
is part of the boundary of S_j for i > j, the direction d(i)
is in p tangential to S_j for j < i, orthogonal to S_j . It
points into S_i-1.
For an inner intersection, we require not only that the position
of the flag is inside the simplex, but also that the projections of
the flag directions into the plane of the simplex define a
non-degenerate volume. This allows to define an orientation of the
intersection.
Now let's define the intersection function f(k). The input flag
defines a point on some (k-1)-segment S_k-1. Consider the
intersection of the k-simplex with this segment, especially the
component containing the initial point. In the generic situation we
obtain a smooth 1-dimensional manifold, and the initial intersection
is one of the two ends of this curve. The position of the return value
is the second end of this curve. The related flag we obtain using the
continuation of the flag along the curve. For degenerate cases we do
not define the function.
This description may fail, if it is not possible to continue the
flag because of a change of the neighbourhood relations in some
intermediate point of the curve. To avoid this effect we have to
require that such intermediate points must be part of some boundary of
codimension k. For an arbitrary geometry, this may be obtained by
further subdivision of the related boundaries into parts with
identical neighbourhood relations.
Let's define now the properties of a cogeometry. The strategy we
use to fix these properties is to find properties which are fulfilled
for our example. Let's list at first the most obvious properties:
- At first, we have a list of "transversality and orthogonality
conditions" --- the directions of a flag have to be orthogonal, their
projection on the tangential plane of the simplex not degenerated.
- We have a symmetry in the definition of f(k). The output of
a first call may be used as the input with the same simplex. Then the
result has to be the input of the first call.
- The (k-1)-part of the list of segments of the two flags is
identical.
- Usually the positions of the two flags are different. Only in the
case of inner intersections, the position may be the same. But in this
case the directions must be different.
- The result for a simplex may be derived from the results for
smaller simplices obtained by subdivision of the initial simplex.
Obviously these properties make sense for every geometry.
Especially the last allows to localize the problem: The geometry will
be completely defined by the results of f(k) for arbitrary small
simplices.
To complete the definition, we have to add a condition which
describes the local behaviour of the geometry. This may be a condition
of the following type:
- For every point there is a small neighbourhood so that there is a
homeomorphism which is smooth enough and allows to transfer the local
situation into the linear reference situation.
or another set of local regularity conditions which allows to build
such a homeomorphism. Different variants of this condition allow to
define different classes of smoothness of a cogeometry.
The codimension of a cogeometry is the highest codimension of a
segment of the cogeometry. For a cogeometry of codimension k it is not
possible to define input values for f(l) with l > k+1. So, such
a cogeometry will be completely defined by the sequence of the f(l)
between 0 and k+1. Because of this simplification it is useful to have
information about the codimension. We have the following obvious
properties of the codimension:
- The codimension of a cogeometry in a n-dimensional space is <= n.
- The codimension of the induced cogeometry is the same as of the original.
- The codimension of the intersection of two cogeometries is the sum of the
codimensions of these cogeometries.
Thus, for the most interesting operations we can compute the
codimension explicitly.
There is a natural connection between the cogeometry and Morse functions (see
[Morse1934] ,
[Milnor1963] ):
A Morse function on a space X defines a cogeometry.
Each segment of this cogeometry will be related to a
singularity of the Morse function. The segment may be defined as the
set of points so that the limit of the gradient flow is the related
singularity. The codimension of the segment is obviously the index of
the singularity.
This connection shows that a cogeometry is a very natural object
from mathematical point of view. It also shows that a cogeometry may
be defined also for spaces of infinite dimension. A space which allow
to define a Morse function on it, allows also to define a cogeometry.
This shows that the class of spaces which allow a cogeometry is
greater than the class of spaces which allow a standard geometry
description.
Now let's consider some modifications of the concept for the
continuous case which will be necessary or useful for an
implementation of the concept.
At first, for simplices we consider instead of arbitrary smooth
mappings only affine mappings. At a first look, this seems to be a
restriction, because this requires an affine structure on the basic
space X we consider. But because the geometry will be defined by the
results for arbitrary small simplices, and for such small simplices we
have some transformation into some standard situation, the affine
structure will not have any influence. For a manifold without affine
structure we can simply use the affine structure of some local
coordinates. The usage of other coordinates does not influence the
limit of arbitrary small simplices.
Usually in applications we consider only the n-dimensional
Euclidean space, so we have some well-defined global affine structure.
That's why, to use only affine simplices makes the interface much more
simpler to use. Instead of the definition of a mapping we have to define
only the coordinates of the corners of the simplex.
To define a flag, we have to define a sequence of segments and
infinitesimal directions. In finite precision arithmetics, we use
instead a sequence of points (k, k-1,...,0) so that:
- Each point i is inside the segment S_i of the flag.
- The direction d(i) is defined by the vector from i to i-1.
- The distance between the points is small: |d(i)| < epsilon
- The position of the flag is the position of k.
There are some advantages of this method:
- We need only one data type for the description of all flags.
- If we need only the intersection point instead of the complete
flag, we can simply ignore the information which is not necessary.
- Sometimes it is useful to have a point inside a segment in the
immediate neighbourhood of the boundary. But even a small shift from
the basic point into the related direction can lead to a point of
another segment. So, to obtain such a neighbour point becomes easier.
- The point data type may be used to transfer function values
through the geometry description. If the function we have to consider
has different boundary limits for different segments, a point inside a
given segment but in the neighbourhood of the boundary point may be
used to transfer the boundary limit.
In an implementation of the interface we have to manage two problems:
- degenerate cases and
- rounding errors.
The main problem is that the result of a call may be used for
later input. So, the result must have properties which allow the
continuation of the computation if it will be used later as input.
The typical situation is that we have some expression f which in the
continuous situation leads to one answer if f > 0 and to another if
f < 0, in the case f = 0 the answer is not defined. In the case of
finite precision, not only the case f = 0 is a problem, but also very
small values of f, because different rounding errors for f may lead to
a different classification of the situation in different parts of the
algorithm. This usually leads to a fatal error in the program.
The strategy to avoid such situations is to make a small
modification of the result if the exact result is in such a dangerous
neighbourhood of a degeneration. The modification must be small enough
compared with the required accuracy of boundary computation, but it
must be large enough to avoid an incorrect classification if it will be
used later as input.
Thus, if the required accuracy is large enough compared with the
possible rounding errors, this technique allows to avoid fatal
errors. It also does not require a special handling for the
degenerated situations where the result is not defined in the exact,
continuous case.
Remark that the case of a degenerated simplex is not dangerous, if
the side containing the input flag itself is not degenerated. There
will be simply a smaller set of possible output --- there may be no
k-flag inside the simplex and no (k-1)-flag on degenerated sides.
For a theoretical consideration it looks very nice if we have only one
function for every dimension. But in the real implementation it
becomes easier two distinguish two functions:
- The first variant of f(k) for the case of a (k-1)-flag as input.
- The other variant of f(k) for the case of a k-flag as input.
The idea of the simplification is that for the first variant we
implement only one special case --- the flag on the first side of the
simplex. This makes the implementation simpler, but for the calling
function it is not difficult to use a point order for the simplex
corner so that the flag lies on the first side. For the other variant,
we can use a default implementation:
Subdivide the simplex into smaller simplices so that the flag
lies on the border between the sub-simplices. Use the first variant of
f(k) to find the continuation. While the continuation was found on
the inner border between the two sub-simplices, we have to continue the
search in the other sub-simplex.
The orthogonality condition for the flag directions require a special
consideration.
- The orthogonality may not be exactly fulfilled in finite
precision arithmetics caused by rounding errors. Thus, in reality we
will not have exactly orthogonal flag directions.
- There are algorithms which do not include the computation of
the related orthogonal directions. Usually they allow to create only some
set of directions with non-degenerated projection on the simplex plane.
- For a non-smooth boundary, it will not be possible to define the
tangential and orthogonal directions required for the definition of a
flag.
These problems may be solved using the convention that the directions
must not be orthogonal, but only their projections have to be not
degenerated. But in this case we obtain a new problem --- the
projection of the directions on the simplex plane may lead to an
incorrect result for the orientation of the intersection. This problem
may be solved by the following convention:
- The flag directions of the result must define a set of
non-degenerated projection on the simplex plane so that it's
orientation coincides with the projections of the orthogonal flag
directions.
- For every flag, a plane containing this flag is defined by the
following rules:
- If the flag is immediate output of some function call,
the plane is defined by the simplex or it's side containing the flag.
- If the flag l is a part of another flag k with k
> l, the plane is the part of the plane of the initial flag which
is orthogonal to the flag directions d(k),...,d(l+1) which will be
omitted.
If the flag will be used as input, the plane of the simplex
containing this flag must coincide with this plane containing the
flag.
Very often the flag will be used only in combination with the same
simplex. The previous rules allow to use also other simplices if these
simplices are in the same plane. Our general strategy to handle
rounding errors guarantees that the orientation of the projection will
be the same also for a slightly different plane caused by rounding
errors.
We see that the orthogonal variant is easier to use because it
allows to use any plane which contains the given flag and leads to a
non-degenerated projection of the flag direction. It is not necessary
to hold information about the plane containing the given flag.
The contravariant geometry description is very natural from
object-oriented point of view:
- The cogeometry is a class.
- The intersection functions f(k) are the methods of this class.
This leads to a natural C++ implementation. The cogeometry will be
defined as an abstract class, the functions f(k) will be virtual
methods. A concrete geometry description will be a derived class
which contains all necessary data of the geometry. In principle, for
all functions f(k) there is some default implementation which may be
used if no better implementation is available. This default
implementation describes a boundary which is not further subdivided
into parts.
The case f(0) may be in principle considered as the degenerated case
of the general intersection function f(k) for k = 0, but this is not
very useful because there is no (-1)-flag and there are no sides for
the 0-simplex. So, let's define f(0) separately:
- For a given point (a 0-simplex) f(0) returns a 0-flag on this point.
That means, it returns a pair which consists of the initial point and
the region containing this point. The nontrivial part of this operation is
to find the region containing the given point.
The function f(1) in principle may be used as defined, but we
use here also some modification. Every smooth boundary face lies
between two regions. Thus, if for every higher codimension the number
of flags containing a given boundary point is not bounded, it is
well-defined for codimension 1. That's why it seems natural to return
above flags in a single call of f(1) instead of calling f(1)
always two times from above sides of the edge. We simply have to add one
new output point --- the point 0 of the "other side" of the flag.
Necessary part of the description of a physical situation is the
attribute description. An attribute may be an arbitrary
application-dependent information. An attribute has a result type
(scalar, vector, integer) and can depend on geometrical data (points,
segments). The physical sense of the attribute is defined by the
application and hidden from the geometry description. That's why it is
a good idea to separate the geometry description and the attribute
description whenever possible. For many types of attributes this is
possible.
Consider, for example, attributes which depend on the segment but
are constant on this segment like material data of a region or
boundary conditions on a boundary face. In this case, the geometry
description returns a pointer (or a small positive integer) as the
identifier of the segment, and the related attributes may be described
by components of the related object (or by arrays over the possible
integer values). In this case, we have a clear modular subdivision
between geometry description and application data.
Another interesting class of attributes are space-dependent
attributes. In principle, they may be described independently of the
geometry description. But often this leads to problems. The reason is
that they have to be evaluated once for every point which will be
considered in the application. If this may be done later, this does
not cause problems. But often the values may be used in the process
itself. For example, the refinement criterion used for grid generation
may depend on such an attribute. That's why the attribute must be
evaluated in the process of grid generation. Or the attribute value of
an initial geometry may be used to define another geometry (for
example the induced geometry of a mapping defined by this attribute).
In this case, the attribute must be evaluated in the process of
geometry description itself. Thus, a separate description may lead to
problems.
This situation is a special case of another class of attributes
where it is not so easy to separate the geometry description and the
attribute description. These are attributes which depend not only on
the segment, but also on the point of the segment. This class of
application also often occurs in applications. For example, many
functions are defined only on some regions. Boundary concentrations
and other functions defined only on a boundary also often have to be
considered. Another example are functions which are continuous only
inside a given region, but with different boundary limits for
different regions (for example concentrations with segregation
boundary conditions).
Because of this deep interaction with the geometry description it
is necessary to have a general scheme to manage such attributes.
Let's consider now this interaction. At first, remark that we have
also a natural functional behaviour for the attributes. Indeed, for
the geometry induced by a mapping f:X --> Y on X and for given
attributes of the original geometry on Y related induced attributes
may be defined in a natural way: The attribute value of a point in X
is simply the attribute value of it's image in Y.
For the standard geometry description, such attribute data may be
described by functions over the cells of the cell complex. The
resulting attribute description is not very modular --- a small
modification of the mapping (another parametrization) requires a
modification of the related attribute description on the cell. We also
obtain the same incorrect functional behaviour as for the cell complex
itself. Indeed, a mapping f: X --> Y and an attribute description
on a cell complex in X defines a natural attribute description on the
image of the cell complex in Y. So, not only the construction of the
cell complex which describes the induced geometry, but also the
transfer of the attribute description becomes a complicate problem.
In the case of the contravariant geometry description, we can manage
attributes using the following simple technique:
We use a data type for the point which contains also the
attribute values of the point. The function f(k) has to compute also
these attribute values for the output points.
In principle, this technique may be considered as a special case
of an induced geometry: We have to consider the embedding of a
lower-dimensional space into a higher-dimensional space defined by the
graph of the attribute functions. This interpretation shows that it
is possible to combine this technique with other operations using the
composition of mappings. For example, the attribute values of some
geometry may be used to define a mapping which may be used to define
an induced geometry.
Our scheme leads to a natural implementation for the
interpolation of function values for a given grid. The functionsf(k) have to find the intersections of a simplex with the related
boundary. Using our technique, this function also has to evaluate the
function values. But this is a very natural place to interpolate the
function values, because the majority of data we need for the
interpolation of the function values in the grid (especially the
element which contains the point) we need also if we have to find only
the intersection point in the grid.