There are two categories of geometric objects in Sundance: those relating to discrete geometry (see Discrete geometry) and those relating to symbolic geometry (see Grouping Cells into subdomains (CellSets)).
You will need to work with the discrete geometry objects when you read meshes (see Reading meshes from files), and when you tag certain cells on which boundary conditions might be applied (see Labeling cells).
Weak equations and boundary conditions will be associated with symbolic geometry objects called CellSets. A CellSet might refer to all cells given a certain label, for instance.
The user-level discrete geometry objects are Point, Cell, and Mesh.
Cells store topological information (connectivity with their neighbors) and geometric information (positions of nodes) independently. You can reposition a node point, and all cells that contain it will automatically refer to the new nodal position.
A Cell has accessors that let you look up its facet and cofacet Cells, and look up its vertex and node points. You will often use these in writing conditional functions to identify cells on a particular subdomain (see Labeling cells).
The data underlying a Cell object is stored by reference, so a change to a Cell also changes all copies of that Cell.
// never, ever do this Cell myCell; { Mesh myMesh = someMeshReader.getMesh(); myCell = myMesh.cell(0, 0); } // at end of scope, myMesh was destroyed and myCell is left // with a reference to a nonexistent mesh. The next statement // will segfault. Point x = myCell.point(0);
In most problems you will read a mesh from an input file. There are many mesh file formats out there, so Sundance has an extensible inteface for reading meshes: the MeshReader system.
To create a MeshReader, allocate one of the mesh reader subclasses and capture into a MeshReader handle. For example, if your mesh was created with Jonathan Shewchuk's triangle mesher and stored in Shewchuk's file format in files "myMesh.node" and "myMesh.ele", you would create a ShewchukMeshReader object.
MeshReader reader = new ShewchukMeshReader("myMesh");
Mesh myMesh = reader.getMesh();
Sundance lets you define subdomains, called CellSets, on which you can apply an equation; for example, you can define a boundary region on which a boundary condition is going to hold.
There are several ways to create CellSets
Setting a label on a given Cell is simple enough: just call the setLabel() method on that Cell with the String label as an argument. However, usually your task won't be labeling Cells, it will be identifying the group of Cells that you want to label. For example, you might want to find all Cells that are positioned on the top of a wing, and give each of them the label "top".
Mesh has a method called labelCells() for identifying and labeling Cells that satisfy a user-defined condition. The condition is specified through a user-defined C++ function of type CellConditional. CellConditional takes a Cell as its sole argument, and returns a bool. For example, suppose you want to give the label "A" to all 1-cells that are on the line segment y=0.1 x + 0.5 with the additional stipulation that x be in the interval [0, 3]. You can write a CellConditional function that returns true if both of the cell's vertices are on that line, otherwise false:
bool onLineA(const Cell& cell) { // identify cells for which all vertices are on y = 0.1*x + 0.5 for (int i=0; i<cell.numFacets(); i++) { const Point& pt = cell.facet(0,i).point(0); bool ptIsOnLine = fabs(0.1*pt[0] + 0.5 - pt[1]) < 1.0e-10; if (!ptIsOnLine) return false; } return true; }
Having written such a conditional function, you can then label all cells for which the condition is true by making a call to labelCells().
/* read mesh from a file in Shewchuk format */ MeshReader reader = new ShewchukMeshReader("myMesh"); Mesh mesh = reader.getMesh(); /* give label "A" to all cells on line y=0.1*x + 0.5 */ mesh.labelCells(1, "A", onLineA);
The present version of Sundance does mesh partitioning in serial, and then scatters the processor submeshes to files for use in a later parallel run. Currently, all partitioning is done with Chaco.
To partition a mesh, do the following:
Normally, you will read a mesh from a file. However, in some cases you may want to assemble a mesh by hand (perhaps in order to write a new MeshReader subclass to handle your favorite mesh file format).