Enabling Adaptive Mesh Refinement development

Plan, as developed by Dave, Luke, Steve and Louis - 20070614

  1. Phase 1
    1. Static-decomposition input refined grid, FEM only
      1. Test FEM-space: velocity and pressure.
      2. Use Mirko's smooth pressure lid driven analytical solution.
    2. Static-decomposition Dynamic-refinement, FEM only
      1. Test synchronisation of refinement.
    3. Dynamic-decomposition input refined grid, FEM only
      1. Test that repartition algorithm and parallel transfers are working
    4. Dynamic-decomposition Dynamic-refinement, FEM only
      1. Test that ghost values, etc are working too.
  2. Phase 2
    1. Make PIC work
    2. Make REP, etc work.
    3. ...

Breakdown

At present there are two major options for implementing the hierarchical mesh representation needed for AMR. These are:

  1. Provide abstract meshing interfaces that allow general, on-the-fly modification of a mesh's topology; thus storing the refinements as a single mesh.
  2. Store each refinement level as a separate mesh, conglomerating them in a mesh wrapper class.

These two options are not mutually exclusive; both can exist in the same mesh implementation. However, at present the second option, I feel, is the easiest to implement in the short-term and has the advantage of explicitly storing refined meshes for use with multigrid.

Preparatory modifications

Before jumping in to the actual refinement process, we need to make the following mofications to the code:

  1. Improve the mesh's interface and create an abstract mesh class to represent this interface.
  2. Create a hierarchical mesh, inherited from the abstract interface, capable of storing several meshes and returing incidence information conglomerated from all meshes in the hierarchy.

The biggest change as a result of the first point is probably going to be the separation of the mesh class into a spatial component and the abstract mesh interface. I feel we need to extract the spatial component so as to allow implicit spatial storage along with implicit topological storage (there is already a separate 'MeshTopology?' class). This will involve a bit of a wander throughout the rest of the code levels, replacing direct references to mesh geometry. All-in-all this isn't a large job; it would probably only take a day or two.

Once the abstract interface is there, the second point shouldn't be too difficult. I have already written most of the hierarchical mesh code in the last effort to begin implementing AMR, so this should primarily be an updating, not too much new code writing. I expect, along with the necessary testing, this would probably take a week or so.

Abstract Topology Interface

The abstract topology interface should be general enough to allow for arbitrary modifications to the mesh's topology while being convienient and useful. I'm basing the following interface on that described (briefly) in the paper "Representing Geometric Structures in d Dimensions: Topology and Order" (page 31); Erik Brisson. Brisson describes a set of constructors useful for creating, modifying and destroying mesh topologies. I've made very minor modifications to these constructors to allow for construction of reduced topology meshes.

Constructors

Brisson's set of topological constructors are based on the use of a complete topological representation, i.e. storing sufficient incidence to be able to calculate implicit incidence relations (those not explicitly stored). StGermain tries to force as little as possible regarding incidence relations, as such I've modified the constructors a little to allow for reduced incidence representations.

Brisson described the basic cell constructors as make_vertex, lift and unlift. Brisson uses the implicit uniqueness from a cell's downward incidence to identify cells of dimension greater than zero, but still requires an explicit identifier to make vertices unique. As such, two different constructors are required to create vertices and cells of dimensions greater than zero, make_vertex and lift, resepectively. In StGermain each stored cell always has an explicit identifier, thus we are able to merge the two constructors, making lift capable of generating vertices.

void lift( int toDim, 
           int fromDim, int nSubCells, int* subCells, 
           int *newID );

unlift, being the inverse of lift, takes a cell and removes it's incidence and removes the cell's ID from the existing set.

void unlift( int id );

We can merge two existing cells that are known to be topologically identical with the join constructor.

void join( int dim, int leftID, int rightID, 
           int *newID );

The inverse of join, being unjoin, takes a cell's ID and creates two new cell's, each posessing identical incidence (therefore being topologically identical).

void unjoin( int dim, int *id, 
             int *leftID, int *rightID );

For AMR we will be constantly splitting and merging regions. If we were to use only the existing constructors there would be a lot of redundant destructions and creation of incidence. For this reason we need two more constructors for decomposing existing regions into non-overlapping sub-regions, and for merging regions into one.

void split( );

and

void unsplit( );