[SCM] Gerris Flow Solver branch, upstream, updated. b3aa46814a06c9cb2912790b23916ffb44f1f203

Stephane Popinet popinet at users.sf.net
Fri May 15 02:55:16 UTC 2009


The following commit has been merged in the upstream branch:
commit 0ed7f419e8ff7867dc31430e98ea198ff1c8183f
Author: Stephane Popinet <popinet at users.sf.net>
Date:   Tue Apr 29 11:14:58 2008 +1000

    Removed "Writing new objects" section of tutorial
    
    This has been superseded by the wiki version in the Gerris programming course.
    
    darcs-hash:20080429011458-d4795-a38d92d943b07a6e10750ba1ad03f91ff5af73ba.gz

diff --git a/doc/tutorial/tutorial.tex b/doc/tutorial/tutorial.tex
index 580c4c5..4f6cc7f 100644
--- a/doc/tutorial/tutorial.tex
+++ b/doc/tutorial/tutorial.tex
@@ -1239,367 +1239,6 @@ and change the inlet boundary condition back to
   ...
 \end{verbatim}
 
-\section{Writing new objects}
-
-If you want to implement your own boundary conditions, initial
-conditions, outputs, criterium for adaptive mesh refinement etc\dots
-you will need to learn how to write new objects within the gerris
-framework. As gerris is written in C, a basic knowledge of C
-programming will help a lot.
-
-Gerris uses the object-oriented framework provided by {\sc GTS}. This is
-essentially a set of structures and functions implementing the
-fundamental concepts of object-oriented programming (essentially data
-and methods inheritance and overloading) using C. Of course, as C is
-not an object-oriented language, it does not provide direct
-(syntaxical) support for this and consequently, as we will see, the
-expression of these concepts is rather more verbose than in, say, C++,
-python, smalltalk or Java.
-
-So, why use C and not an object-oriented language? An exhaustive
-discussion would be too long for this tutorial. In short, the
-strongest case for this approach is that C is the smallest common
-denominator between most of the languages out there: it is possible to
-use the gerris library with any one of C++, Fortran 90, Java, Perl,
-python, ruby etc\dots but it would not be the case if gerris was written
-in any of these other languages.
-
-\subsection{A template for new object classes}
-
-{\sc GTS} comes with a simple script called {\tt gtstemplate} which will
-generate a C code template for the new class you want to create. For a 
-summary of its syntax just type:
-\begin{verbatim}
-% gtstemplate
-Usage: gtstemplate [OPTIONS] Class ParentClass
-Options:
-        [--no-extra-data]
-        [--no-extra-method]
-        [--overload=METHOD]
-\end{verbatim}
-As an example we are going to try and create a template for a new
-initial condition class called {\tt InitPeriodic}. Just type:
-\begin{verbatim}
-% gtstemplate --overload=read --overload=write --overload=event \
-InitPeriodic GfsInit > init_periodic.c
-\end{verbatim}
-We have just created a template for a new class called {\tt
-InitPeriodic} derived from {\tt GfsInit} and where the {\tt read},
-{\tt write} and {\tt event} methods are overloaded. Fire up your
-favourite editor and have a look at the file generated: {\tt
-init}\_{\tt periodic.c}. The first thing you see is that the file is divided
-in two sections starting with
-\begin{verbatim}
-/* InitPeriodic: Header */
-\end{verbatim}
-and
-\begin{verbatim}
-/* InitPeriodic: Object */
-\end{verbatim}
-As their names indicate these sections correspond respectively to the
-declaration of the structures and functions (header part) and to the
-corresponding definitions (object part). If we were to use these
-functions and structures in a library, these two parts would be in
-separate files (a {\tt .h} and a corresponding {\tt .c} file). For
-what we are interested in (a gerris {\em module}) they are fine
-staying in the same file. There is a function we will not need: {\tt
-init}\_{\tt periodic}\_{\tt new}, just remove the lines declaring and
-defining it in the header and object sections. We are left with only
-one function: {\tt init}\_{\tt periodic}\_{\tt class}. This function
-essentially registers our new class and its associated
-attributes. Things like:
-\begin{itemize}
-\item the name of the class: {\tt "InitPeriodic"},
-\item the sizes of the object and class structures: 
-{\tt sizeof (InitPeriodic)} and {\tt sizeof (InitPeriodicClass)},
-\item function to call to initialize the class: {\tt
-init}\_{\tt periodic}\_{\tt class}\_{\tt init},
-\item function to call to initialize a new object: {\tt
-init}\_{\tt periodic}\_{\tt init},
-\item as well as which class is the ancestor of this new class: {\tt
-gfs}\_{\tt init}\_{\tt class ()}.
-\end{itemize}
-If we now look at what the {\tt init}\_{\tt periodic}\_{\tt
-class}\_{\tt init} function does, we see that it indeed overloads the
-{\tt event}, {\tt read} and {\tt write} methods of our class with
-locally defined functions. The {\tt GFS}\_{\tt EVENT}\_{\tt CLASS} and
-{\tt GTS}\_{\tt OBJECT}\_{\tt CLASS} macro calls are casting operators
-which change the type of our new class ({\tt InitPeriodicClass}) to
-the types of one of its parent class. {\tt GtsObjectClass} is the
-ancestor of all object classes and we see that the {\tt read} and {\tt
-write} methods are thus defined for all objects. The {\tt GfsInit}
-class is also a descendant of the {\tt GfsEvent} class (as we have
-seen before it is a special type of event occurring once at the start
-of the simulation) which has and associated {\tt event} method.
-
-\subsection{Initial conditions}
-
-With this preliminary overall understanding of what the template does, 
-we are ready to define our new initialisation class. What we want to
-do is initialise the 2D velocity field using the following functions:
-\begin{eqnarray}
-u(x,y) &=& - \cos(2m\pi x)\sin(2m\pi y)\\
-v(x,y) &=& \sin(2m\pi x)\cos(2m\pi y)
-\end{eqnarray}
-where $m$ is a parameter. This is an exact stationary solution of the
-2D Euler equations with periodic boundary conditions.
-
-We need to store the value of $m$ somewhere. A clean way to do that is 
-to add $m$ as a data associated with our {\tt InitPeriodic}
-object. To do this just modify the definition of the structure in the
-header part of the file, like this:
-\begin{verbatim}
-struct _InitPeriodic {
-  /*< private >*/
-  GfsInit parent;
-
-  /*< public >*/
-  gdouble m;
-};
-\end{verbatim}
-Note that the {\tt GfsInit parent;} data {\em must be the first} data
-in the structure. The whole object-inheritance mechanism in C relies
-on this data alignment.
-
-We now need to specify the value of $m$. The first value we want to
-assign is the default value of $m$ for an object newly created. We can
-do that using the initialisation function {\tt init}\_{\tt periodic}\_{\tt init}
-which is called everytime a new {\tt InitPeriodic} object is created
-(it is the {\em constructor} function of the {\tt
-InitPeriodicClass}). Just add:
-\begin{verbatim}
-static void init_periodic_init (InitPeriodic * object)
-{
-  object->m = 1.;
-}
-\end{verbatim}
-Our default value for $m$ is now one. What we really want is being
-able to specify the value of $m$ in the parameter file used by
-gerris. We can do that by using the {\tt read} and {\tt write}
-methods. We will start with the {\tt write} method: {\tt
-init}\_{\tt periodic}\_{\tt write}. This function first calls the {\tt write} method 
-of the parent class of our object:
-\begin{verbatim}
-  /* call write method of parent */
-  if (GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->write)
-    (* GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->write) 
-      (o, fp);
-\end{verbatim}
-The parent class is given by the
-{\tt parent}\_{\tt class} field of any {\tt GtsObjectClass}. The {\tt write}
-method might not be defined for the parent class, so it is always a
-good (safe) idea to first test that it is indeed defined.
-
-Now that we have written the data associated with the parent class, we 
-can write our own data like this:
-\begin{verbatim}
-static void init_periodic_write (GtsObject * o, FILE * fp)
-{
-  /* call write method of parent */
-  if (GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->write)
-    (* GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->write) 
-      (o, fp);
-
-  fprintf (fp, " %g", INIT_PERIODIC (o)->m);
-}
-\end{verbatim}
-Note that we used a space to separate this new data from the data of
-the parent class and that we didn't add anything after our own data
-(no space or newline). This is so that we can eventually extend
-(through inheritance) this class by adding more data in exactly the
-same way.
-
-We now need to define a ``symmetrical'' {\tt read} method which will
-read the value of $m$ from the parameter file. In the {\tt init}\_{\tt
-periodic}\_{\tt read} method, we first read the parameters associated
-with the parent class. The line:
-\begin{verbatim}
-  if (fp->type == GTS_ERROR)
-    return;
-\end{verbatim}
-just checks if an error occurred while reading parameters for the
-parent class, in which case the method returns prematurely. To read
-our parameter we are going to use functions associated with the {\tt
-GtsFile} data type (have a look at the \htmladdnormallinkfoot{{\sc GTS} reference manual}{http://gts.sf.net/reference/book1.html} for
-details):
-\begin{verbatim}
-static void init_periodic_read (GtsObject ** o, GtsFile * fp)
-{
-  /* call read method of parent */
-  if (GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->read)
-    (* GTS_OBJECT_CLASS (init_periodic_class ())->parent_class->read) 
-      (o, fp);
-  if (fp->type == GTS_ERROR)
-    return;
-
-  if (fp->type != GTS_INT && fp->type != GTS_FLOAT) {
-    gts_file_error (fp, "expecting a number (m)");
-    return;
-  }
-  INIT_PERIODIC (*o)->m = atof (fp->token->str);
-
-  /* do not forget to prepare for next read */
-  gts_file_next_token (fp);
-}
-\end{verbatim}
-We first check that the current token is an integer ({\tt
-GTS}\_{\tt INT}) or a floating point number ({\tt GTS}\_{\tt FLOAT}). If it is not
-we set an error message describing the problem and return
-prematurely. If it is, we convert the string describing the current
-token ({\tt fp->token->str}) into a floating point number (using the
-standard C {\tt atof} function) and assign it to $m$. Note that we
-need to use the type conversion macro {\tt INIT}\_{\tt PERIODIC}
-because the argument passed to {\tt init}\_{\tt periodic}\_{\tt read} is a generic
-{\tt GtsObject}. As we are dealing with a method of our {\tt
-InitPeriodicClass} we know that this {\tt GtsObject} is also a {\tt
-InitPeriodic} object and the type conversion is then legitimate.
-
-We can now create, read and write our new object. However we are not doing
-anything with it yet. Like for any other {\tt GfsEvent}, the action
-performed is controlled by the {\tt event} method. If we look at the
-{\tt init}\_{\tt periodic}\_{\tt event} function, we see that it returns a {\tt
-gboolean}. If {\tt TRUE} this return value means that the event took
-place. We then call the event method of the parent class and check its 
-return value. If {\tt TRUE} we do something and return {\tt TRUE}. We
-know that the parent class is {\tt GfsInit}, an event which takes
-place once at the start of the simulation. What we want to do is
-initialise the velocity field using our formula. We can do that like this:
-\begin{verbatim}
-static void init_velocity (FttCell * cell,
-                           InitPeriodic * init)
-{
-  FttVector pos;
-
-  ftt_cell_pos (cell, &pos);
-  GFS_STATE (cell)->u = 
-    - cos (2.*init->m*M_PI*pos.x)*sin (2.*init->m*M_PI*pos.y);
-  GFS_STATE (cell)->v =   
-    sin (2.*init->m*M_PI*pos.x)*cos (2.*init->m*M_PI*pos.y);
-}
-
-static gboolean init_periodic_event (GfsEvent * event, GfsSimulation * sim)
-{
-  if ((* GFS_EVENT_CLASS (GTS_OBJECT_CLASS (init_periodic_class ())\
-         ->parent_class)->event) (event, sim)) {
-    gfs_domain_cell_traverse (GFS_DOMAIN (sim), 
-                              FTT_PRE_ORDER, FTT_TRAVERSE_LEAFS, -1,
-                              (FttCellTraverseFunc) init_velocity,
-                              event);
-    return TRUE;
-  }
-  return FALSE;
-}
-\end{verbatim}
-The {\tt gfs}\_{\tt domain}\_{\tt cell}\_{\tt traverse} function traverses the cell tree
-and calls the {\tt init}\_{\tt velocity} function for each leaf cell ({\tt
-FTT}\_{\tt TRAVERSE}\_{\tt LEAFS}). A {\tt GfsSimulation} is an object derived from
-{\tt GfsDomain} which justifies the {\tt GFS}\_{\tt DOMAIN (sim)} type
-casting. Have a look in the \htmladdnormallinkfoot{reference manual}{\gfsweb/reference/book1.html} if you want to know more
-about these structures and functions.
-
-We also pass an extra parameter to {\tt init}\_{\tt velocity}: {\tt
-event}. If you now look at {\tt init}\_{\tt velocity} you see that this extra 
-argument is our object: {\tt InitPeriodic * init}. What we have done
-here is an implicit cast of {\tt GfsEvent * event} to {\tt
-InitPeriodic * init}. We know it is valid because {\tt
-init}\_{\tt periodic}\_{\tt event} is a method of our object class.
-
-What happens in {\tt init}\_{\tt velocity} is straightforward. We first get
-the position of the center of the cell using {\tt ftt}\_{\tt cell}\_{\tt pos} and
-then assign the values of the two components of the velocities using
-our formula and the $m$ parameter defined in {\tt init}.
-
-\subsubsection{Creating a module}
-
-We have now almost all that is needed for our new object. How do we
-use this new piece of code with gerris? What we want to do is to
-create a dynamically loadable {\tt module}. First of all we need to
-check that we can compile the code. There are a few missing headers we
-need to add (at the top of the file):
-\begin{verbatim}
-#include <math.h>
-#include <stdlib.h>
-#include <gfs.h>
-
-\end{verbatim}
-The {\tt gfs.h} header contains all the function declarations for the
-gerris library. We can now try to compile using for example:
-\begin{verbatim}
-% cc `gfs-config --2D --cflags` -Wall -g -O2 -c init_periodic.c
-\end{verbatim}
-where {\tt gfs-config --2D --cflags} (quoted using inverted quotes)
-defines the compilation flags needed to use the 2D version of the
-gerris library.
-
-To make a proper module we also need to add the following at the end
-of the file:
-\begin{verbatim}
-/* Initialize module */
-
-const gchar * g_module_check_init (void);
-
-const gchar * g_module_check_init (void)
-{
-  init_periodic_class ();
-  return NULL;
-}
-\end{verbatim}
-This just tells gerris how to initialise the module after it has been
-loaded. The {\tt g}\_{\tt module}\_{\tt check}\_{\tt init} function
-will be called. In our case, it does only one thing which is to {\em
-instantiate} our new class: this is necessary so that gerris registers
-how to handle it.
-
-We are now all set to create our new module. Sadly, dynamically
-loadable module creation is not a standardised process and the
-command-line arguments vary from compiler to compiler and from system
-to system. In the following, I will assume that you use {\tt gcc} on a
-linux box. If you are using another system supporting dynamically
-loadable modules, you will need to read your local manual. On a linux
-box:
-\begin{verbatim}
-% cc `gfs-config --2D --cflags` -Wall -g -O2 -c -fPIC init_periodic.c
-% cc -shared init_periodic.o -lc -o libinit_periodic2D.so
-\end{verbatim}
-should work. Note that we add the {\tt 2D} extension to indicate that
-this module uses the 2D gerris library. We could have built both a 2D
-and a 3D version of the same module. At runtime the gerris executable
-uses this extension to check which version to load.
-
-Our module is now ready to use. We just need to install it in a
-directory where it will be found by gerris. If you installed gerris in 
-{\tt /home/joe/local} just type:
-\begin{verbatim}
-% cp libinit_periodic2D.so /home/joe/local/lib/gerris
-\end{verbatim}
-We can now use it directly in a parameter file, for example:
-\begin{verbatim}
-1 2 GfsSimulation GfsBox GfsGEdge {} {
-  GfsTime { end = 50 }
-  GfsRefine 6
-  GModule init_periodic
-  InitPeriodic {} 2
-  GfsOutputTime            { istep = 10 } stdout
-  GfsOutputProjectionStats { istep = 10 } stdout
-  GfsOutputPPM             { step = 0.1 } vorticity-%4.2f.ppm { v = Vorticity }
-}
-GfsBox {}
-1 1 right
-1 1 top
-\end{verbatim}
-The first part of the object definition: {\tt InitPeriodic \{\}} is the
-generic {\tt GfsEvent} definition, the second part: {\tt 2} is the
-parameter $m$ we added. What if we do not specify the right parameter?
-Just try to replace {\tt InitPeriodic \{\} 2} with {\tt InitPeriodic
-\{\} a}. You should get a message like
-\begin{verbatim}
-gerris: file `periodic.gfs' is not a valid simulation file
-periodic.gfs:5:18: expecting a number (m)
-\end{verbatim}
-which tells you where the error occurred (in file {\tt periodic.gfs},
-line 5, character 18) together with the error message which we
-specified in the {\tt read} method of our class.
-
 \subsection{Outputs}
 
 \subsection{Boundary conditions}

-- 
Gerris Flow Solver



More information about the debian-science-commits mailing list