Archive for March, 2008

Equation Tee Shirts

Wednesday, March 26th, 2008

Last summer, my daughter got a job at CafePress, a company that enables you to make custom tee shirts and other items, and sell them online. There are literally thousands and thousands of designs people have come up with. It is fascinating to scroll through all of the offerings. Whatever your political, religious or philosophical bend, there is a tee shirt for you. Need a humorous saying? They have them, by the truck load. Need a pithy commentary on the cruelty of life? It’s there. Just about anything you can imagine is there.

With this huge assortment, I figured there would be tons of interesting equation tee shirts available. There are, if you are a fan of Maxwell’s equations. You can find many variations of this classic:

Maxwell’s Equations

but there wasn’t much else. I didn’t see any fluid dynamics or CFD offerings, so I decided to create my own. So far I have made five of them. Here are the images:

White pink Blue

Green Yellow

I have created an “online store” to house these offerings. You can reach it at www.cafepress.com/basicnumerics. Once you upload an image, you can put it on a wide variety of products. I can chose several styles of shirt (both men and women), a coffee mug and a couple of bags.

Making Equations

When I decided to make the shirts, I figured it would take 30 minutes. I would fire up Microsoft Word, create an equation with Equation Editor, put a cute saying under it, color it, save it as an image and upload it. It didn’t work out that way. I hit snags at every step. First, I couldn’t resize the equations to the appropriate size without Word running out of memory. I am still puzzled by this, but I was able to repeat it several times. The continuity equation would display fine with a 12 point font, but when I scaled it up to 72 point, Word would start displaying out of memory errors and lock up. Additionally, I couldn’t color the equations using Word’s Equation Editor.

It is possible that the more feature rich MathType would work better, but I didn’t have access to that. Instead, I downloaded OpenOffice v2.3 and used the Math module to create my equations. There were no memory problems, but I still couldn’t colorize the equations. Instead, I used Paintshop Pro for this. CafePress recommends that tee shirt images be 2000 by 2000 pixels, with a resolution of 200 dpi. The math module has no way to export a graphic image, so I made the equations quite large on the screen and did a “PrintScreen” to copy the image to the clipboard. On a large monitor, you can get a 1900 pixel wide image this way. I then used Paintshop Pro for the rest.

Recipe

Here is the recipe I used to prepare the images:

  • Make the equation in Open Office Math using 24 pt font.
  • Open equation on a monitor with at least 1900 pixels of width. Use the magnifier in Open Office to blow it up to full screen. Hit PrintScreen
  • Open Paintshop Pro and create a 2000×2000 image at 200 dpi, with transparent background.
  • Paste the equation in as a New Image, crop it, copy it and paste as a Layer into the 2000×2000 image
  • Use the Background Eraser tool to remove the white background around the equation
  • Use the Color Replacer tool to replace the black in the equations with blue at an RBG value of (32, 72, 254)
  • Create a vector layer and use Text tool to create a saying to accompany the equations. Set it to a font of 72, 108 or more (whatever fits). Use the font Freestyle Script. (This is set while the text is selected in the text window.)
  • Set text to the same color. (Set background color to the same RGB of 32, 72, 254).
  • Place the phrase about halfway in window and the equation about ¼ of the way down.
  • Save file as a pspimage file (native Paintshop format) and as a png file.
  • Upload the png file to CafePress.

The recipe is a bit convoluted, and I am sure there are more efficient ways, but it does work.

Creating the Shirts

Once the images are uploaded to CafePress, its easy to put them on products. You simply click on the items you want and add them to your “store”. I chose a variety of shirts, a mug and a couple of bags. Check them out at www.cafepress.com/basicnumerics.

Algebraic Mesher

Thursday, March 13th, 2008

In looking for an alternative to the half edge meshing scheme, I hit upon the idea of using algebraic relations between cells, faces and vertices in order to build a mesh. Those relationships were described in the previous post. Here I want to describe how I implemented this in C.

Data Structures

Like my Half Edge mesher, the MESH_TYPE data structure consists of lists of all the vertices, faces and cells in the mesh.

struct mesh_type { //contains all mesh info ALIST cells; //cell list ALIST faces; //face list ALIST verts; //vert list };

ALIST is the generic array I had defined earlier. It consists of a small data structure that includes a pointer to an array on the heap containing the actual data. In this way, the array can be resized and bounds checking can be done. The figure shows the mesh data structure.

Mesh Data Structure

Up to this point, the structures are the same as in the Half Mesh program. Where things change is in the data structures for the cells, faces and vertices. For instance a face structure looks like

struct face_type { ALIST verts; //list of ptrs to face verts ALIST cells; //list of ptrs to faces 1 or 2 cells };

Each face in the list of faces contains lists of pointers to elements in these three master lists. Trying to draw all the relationships can get confusing. This pictures gives an idea for the faces of a cell

Cell Data Structure

Each cell in the master list contains a list of four face pointers. These pointers point to the four faces in the master list where this cell’s faces reside. Imagine how confusing that picture would be if I were to try and draw all the connections between cells, vertices and faces?

Accessing the Data

Suppose you want to average the x and y coordinates all the vertices of a cell, to make sure it matches the cell center. (This is one of the tests I used to check the meshing code.) This can be done easily using the new improved FOR_EACH macro from the generic list include file:

double totX, totY,dx,dy; VERT_TYPE **ppVert; FOR_EACH(pCell, pMesh->cells) { totX = 0; totY = 0; FOR_EACH(ppVert, pCell->verts) { pVert = *ppVert; totX += pVert->x[0]; totY += pVert->x[1]; } //Find diff betw cell center and vert ave dx = pCell->x[0] - totX/4; dy = pCell->x[1] - totY/4;

The outer loop is over the cells in the master list of cells for the mesh. The way the FOR_EACH works, is it puts a pointer to the current cell into pCell on each pass through the loop. This allows us to dereference the fields of the cell. It is the inner loop, over the cell vertices, where confusion can set in. The vertex list in a cell structure holds pointers to the actual vertices residing in the master vertex list. Since FOR_EACH returns a pointer to whatever is in the list, it returns a pointer to a pointer. That is why I defined the variable ppVert. In order to gain access to the x and y position of the vertex, we dereference ppVert, to get a pointer to the vertex. From their we can get the position. These dereferencing subtleties were not at all clear to me as I wrote this. In addition, I hadn’t always allocated memory for my lists. The result was the memory debugging nightmare I mentioned previously.

Assessment

The entire motivation for this project was to generate a meshing program that had some of the elegance of the half edge mesh, while being better suited for CFD applications. Was it successful? It is hard for me to say at this point. In terms of code length, the two implementations are nearly identical. Thus one is not a lot clumsier than the other. One thing I find troubling about the algebraic meshing approach is you can’t look at the code and tell if its right. When you see a line like

pVert = getItem(verts,CID+i+1); //SE vert

how do you know that pVert is really the south east vertex of cell CID? You need to sketch out the grid and work out the relationships. Also, I am still reeling a bit from all the memory problems I had. The half edge mesh routine came together a lot more easily.

All in all, I would say the jury is still out on this one. But now that I have created it, I hope to use it to do some work with Immersed Boundaries.

Download

If you want to play with the code to generate meshes, you can download it here. Put the files ArrayType.inc and AlgMesher.c in the same folder and compile and run:

gcc -Wall AlgMesher.c ./a.exe

When main runs, it will call a test function that tests five different aspects of a simple 100×100 mesh. It writes out the results to a text file. In this way, I tried to make the code relatively bug free. Enjoy.

Meshing by the Numbers

Saturday, March 8th, 2008

We saw earlier that the half edge data structure is a very elegant way to create a mesh. However, as I pointed out recently, this approach does have a couple of drawbacks for general CFD applications. Are there other elegant approaches worth considering? One interesting possibility is to use the algebraic relationships between vertices, faces and cells to generate the connections between them. If the mesh is rectangular, and you number the components systematically, you can work out these relationships.

Cell and Vertex Numbering

Cells & Vertices

Lets say we number our cells from left to right, starting with the bottom row, as in the figure. Any given cell can be expressed in terms of its column number and row number:

CID = N_cols*i + j

The Cell ID (CID) is found by multiplying the number of columns in the grid (N_cols) by the current row number i, and adding the current column number j. We are following the C convention of starting our numbering from zero. We can number the vertices in the same way, starting in the lower left corner. Without too much trouble, we can see that if you know the ID of the cell, you can work out the ID of the south west vertex of that cell:

VID_SW = CID + i

where VID_SW is the ID number of the southwest vertex. The equation works out this way because any row of N cells has N+1 vertices.

The ID for the southeast vertex is just one more bigger than the southwest:

VID_SE = CID + i + 1

To get the index for the northern vertices, we need to add a row of vertices to the index of the corresponding southern vertex:

VID_NW = CID + i + (N_Cols + 1) VID_NE = CID + i + 1 + (N_Cols + 1)

Face Numbering

Faces

The numbering scheme for the faces is a bit trickier. You can just name them sequentially starting from the south west corner, but I think its a bit easier if you create two lists: a list of horizontal faces (i.e., the north and south faces) and a list of vertical faces (i.e., the east and west faces). The figure shows the idea, with the horizontal faces numbered in black and the verticals in blue. With this approach, the southern faces have the same numbering as the cells, thus

FID_S = CID

The northern face ID numbers can be found by taking the southern face ID and adding the number of columns in the grid:

FID_N = CID + N_cols

For the east and west faces, each row has one more face than there are cells. This is the same as the vertex numbering, thus

FID_W = CID + i FID_E = CID + i + 1

In practice, we don’t really want to have two lists of faces. It is more convenient if we can loop through a single list. This can be achieved by appending the east-west list onto the north-south list. Once that is done, the indices for the east and west faces will need to be increased by the number of horizontal faces:

FID_W = N_HFaces + CID + i FID_E = N_HFaces + CID + i + 1

where

N_HFaces = N_Cells + N_cols

.

Implementation

I have written a C program to implement these ideas, but it was a torture. I made heavy use of my generic list structure and in the process hit a bunch snags. C is notorious for giving you the power to shoot yourself in the foot, and I dare say that I don’t have many toes left. I made a ton of memory mistakes and it took me more than 10 hours of debugging to find and correct them all. In the process, I made a number of improvements to the generic list routines (including writing a bunch of documentation), so hopefully this won’t happen again. I’ll discuss the implementation more in the next post.

Rethinking the Half Edge Mesh

Saturday, March 1st, 2008

In earlier discussions (here and here), I extolled the benefits of the half edge mesh. It is an elegant way of compactly storing 2d mesh information. Moreover, it allows you to easily do adjacency tests (e.g., what are all the edges touching this vertex?). However, upon further reflection, two weaknesses have occurred to me:

  1. It is lacking for the finite volume method.
  2. Its not extendable to 3d

I don’t know that these are show stopper considerations, but they do give one pause. Lets look at them in more detail.

Finite Volume

The key tenet of the finite volume method is the balance of fluxes leaving and entering each cell face. This is what makes this approach intrinsically conservative, unlike the finite element method.

At some point in the execution of a finite volume code, we loop over the faces in the domain and calculate the fluxes crossing those faces. Because each pair of cells share one face, we know that the material leaving cell A must flow into cell B. But the half edge data structure doesn’t have faces; it has half faces. There is no single entity that connects both cells. So how do we achieve this conservation? The simplest way is probably to create a full face data structure that each half face points to. We can then calculate the fluxes on this face as normal. While this adds additional complexity to the scheme and reduces its elegance, it should be perfectly doable.

3d

What really makes me doubt the viability of the half edge approach is in generalizing it to 3d. In 2d, the vertices, edges and cells are connected together in a simple fashion. For instance, the edges around a cell are connected, one to the next, in a chain. This makes it easy to create a linked list of edges to go around the cell.

Face linkage in 2d, 3d

In 3d, each cell is surrounded by six faces. There are many ways to connect these faces together in a linked list. The figure shows one of them. That is workable, but how do you get an adjacency test out of it? For instance, lets say you want to know all the faces that surround a vertex. I can’t figure out any clever way of looping through the half faces to achieve this.

Next Steps

I am working on another mesh generator that uses algebraic relationships between cells, faces and vertices to establish the connections between these entities. It has a certain elegance to it as well. Unfortunately, in implementing it, I hit all kinds of memory and pointer problems that took awhile to work out.