next up previous contents
Next: 3.2 Saving the whole Up: 3 A more complex Previous: 3 A more complex   Contents

Subsections

3.1 Domain geometry and boundary conditions

What we want is a narrow channel (4 x 1 mathend000# for example). From the previous example, we know that we can build it like this:

4 3 GfsSimulation GfsBox GfsGEdge {} {
  GfsTime { end = 0 }
}
GfsBox {}
GfsBox {}
GfsBox {}
GfsBox {}
1 2 right
2 3 right
3 4 right
i.e. four boxes, box 1 connected to box 2 horizontally (to the right), box 2 connected to box 3 horizontally and box 3 connected to box 4 horizontally. Box 1 is centered on the origin and is of size one. All the other boxes are positioned accordingly. We now have our 4 x 1 mathend000# rectangular domain.

3.1.1 Boundary conditions

What about boundary conditions? By default Gerris assumes that boundaries are solid walls with slip conditions for the velocity (i.e. the tangential stress on the wall is zero). For the moment we then have defined a rectangular box closed on all sides by solid walls.

What we really want is to specify an input velocity on the left side of the box and some sort of output condition on the right side. We can do that like this:

4 3 GfsSimulation GfsBox GfsGEdge {} {
  GfsTime { end = 0 }
}
GfsBox { left = GfsBoundaryInflowConstant 1 }
GfsBox {}
GfsBox {}
GfsBox { right = GfsBoundaryOutflow }
1 2 right
2 3 right
3 4 right
The whole left side of the first (leftmost) box is now defined to be a GfsBoundaryInflowConstant object and the whole right side of the last (rightmost) box a GfsBoundaryOutflow object. Again, boundary conditions objects are all derived from the GfsBoundary object and, as initial conditions, new objects can be easily written by the user (see also section 4.1).

We see that GfsBoundaryInflowConstant takes one argument which is the value of the (constant) normal velocity applied to this boundary. All the other variables (pressure, tracer concentration etc...) follow a zero gradient condition.

GfsBoundaryOutflow implements a simple outflow boundary condition where the pressure is set to zero as well as the gradient of all other quantities.

3.1.2 Solid boundaries

We now have an empty ``wind tunnel'' with a constant inlet velocity of norm unity. Gerris can deal with arbitrarily complex solid boundaries embedded in the quad/octree mesh. The geometry of the solid boundaries is described using GTS triangulated surfaces. In 2D, using 3D triangulated surfaces seems overkill, as 2D curves would be enough. However, Gerris being both a 2D and 3D code it deals with 2D solid boundaries exactly as with 3D ones, even if the simulation is done only on a 2D cross-section.

Creating 3D polygonal surfaces is not an easy job and is clearly outside the scope of this tutorial. There are a number of utilities you can use to do that, including big commercial CAD packages. In general, once you have created a polygonal surface with one of these tools it should be relatively easy to convert it to the file format used by GTS. In particular, most CAD packages can export to the STL (stereolithography) format which is easily converted to the GTS file format using the stl2gts utility which comes with the library.

This tutorial comes (handily) with one such file: half-cylinder.gts. You can visualise the surface it describes using a program called Geomview. To do this, you first need to convert the GTS file to a format Geomview understands. This can be done using the gts2oogl utility like this:

% gts2oogl < half-cylinder.gts > half-cylinder.oogl
(OOGL is the file format used by Geomview). gts2oogl has a number of options. You can have a short explanation of what they do by typing:
% gts2oogl -h
If you now start geomview like this:
% geomview half-cylinder.oogl
and play around with the pan/rotate/zoom functions of Geomview (read the manual for details), you should see something like the image on figure 3.
Figure 3: Geomview representation of half-cylinder.gts
\includegraphics[width=0.3\hsize]{half-cylinder.eps}
You can notice that this is a proper 3D object, even if we are only going to simulate the flow in a 2D cross-section. It is also important that the object is ``tall'' enough so that it spans the entire ``height'' of the 2D domain, as if we were going to simulate the flow around it in a proper 3D channel with a square cross-section. The orientation of the surface is also important to define what is inside (the solid) and what is outside (the fluid).

We can now insert this object in the simulation domain like this:

4 3 GfsSimulation GfsBox GfsGEdge {} {
  GfsTime { end = 0 }
  GtsSurfaceFile half-cylinder.gts
}
GfsBox { left = GfsBoundaryInflowConstant 1 }
GfsBox {}
GfsBox {}
GfsBox { right = GfsBoundaryOutflow }
1 2 right
2 3 right
3 4 right
add what mesh refinement we want and a few things to output:
4 3 GfsSimulation GfsBox GfsGEdge {} {
  GfsTime { end = 9 }
  GfsRefine 6
  GtsSurfaceFile half-cylinder.gts
  GfsInit {} { U = 1 }
  GfsOutputBoundaries {} boundaries
  GfsOutputTime { step = 0.02 } stdout
  GfsOutputProjectionStats { step = 0.02 } stdout
  GfsOutputPPM { step = 0.02 } vorticity.ppm { 
    min = -100 max = 100 v = Vorticity 
  }
  GfsOutputTiming { start = end } stdout
}
GfsBox { left = GfsBoundaryInflowConstant 1 }
GfsBox {}
GfsBox {}
GfsBox { right = GfsBoundaryOutflow }
1 2 right
2 3 right
3 4 right
I have added a new GfsOutput object we haven't seen yet: GfsOutputTiming. This object writes a summary of the time taken by various parts of the solver. You might also have noticed the unusual start = end bit ; this just specifies that this event will only happen once at the end of the simulation.

Another new output object is GfsOutputBoundaries. This object writes a geometrical summary (in OOGL/Geomview format) of the mesh used, including boundary conditions, solid boundaries and so on.

We also initialise the velocity field on the whole domain to a constant value (1,0,0). We could have left the velocity field to its default value of (0,0,0) but, given that we impose inflow boundary conditions, it would have meant that the initial velocity would have been strongly divergent. Gerris always starts a simulation by a projection step (to fix problems like this) but it is always a good idea to start with the best possible velocity field.

We can now run the code:

% gerris2D half-cylinder.gfs
It is going to take a while to complete, but remember that you can look at files while they are being generated. The first file which will be generated is boundaries. If you load it in Geomview, you should get something like figure 4 (you probably want to disable automatic normalization in Geomview by selecting Inspect $ \rightarrow$ mathend000#Appearance $ \rightarrow$ mathend000#Normalize $ \rightarrow$ mathend000#None).
Figure 4: Representation of boundary conditions and solid boundaries
\includegraphics[angle=90,width=0.8\hsize]{boundaries.eps}
The black lines represent the boundaries between solid cells and fluid cells. If you zoom in on the half-cylinder, you will see that it is represented by lines following the grid (it is ``lego-looking''). This does not mean that the ``real'' (i.e. computational) solid boundary is also lego-looking because fluid cells can be cut by the solid boundaries, in which case the algorithm properly takes into account the corresponding cell geometry.

Each GfsBoundary object is colour-coded. From the colours in the picture we see that we have indeed an inflow boundary condition on the left side (blue) and an outflow boundary condition on the right side (green).

You can also load in the full half-cylinder geometry we created before: half-cylinder.oogl or visualise the PPM files using animate and display as in the previous example. By the way, a useful feature of display is that you can zoom in by clicking on the middle button in the image being displayed.


next up previous contents
Next: 3.2 Saving the whole Up: 3 A more complex Previous: 3 A more complex   Contents