algorithm 817 p2mesh: generic object-oriented interface between 2-d unstructured meshes and...

31
Algorithm 817 P2MESH: Generic Object-Oriented Interface Between 2-D Unstructured Meshes and FEM/FVM-based PDE Solvers ENRICO BERTOLAZZI University of Trento and GIANMARCO MANZINI Institute of Numerical Analysis—CNR The software interface P2MESH is a collection of C++ class templates suitable for developing pro- totypes of high-performance PDE solvers on unstructured 2-D meshes. P2MESH supports several discretization methods on triangles and quadrilaterals, such as finite volume or finite element. The design philosophy of P2MESH does not consider specific model problems or built-in approximation al- gorithms. The software package is general purpose and it may also be used as a building block in the implementation of numerical codes both for engineering applications and mathematical problems. Categories and Subject Descriptors: D.1.5 [Programming Techniques]: Object-oriented Pro- gramming; D.3.3 [Programming Languages]: Language Constructs and Features—Classes and objects, Data types and structures; G.1.8 [Numerical Analysis]: Partial Differential Equations— Finite element methods, finite volume methods General Terms: Algorithms, Languages Additional Key Words and Phrases: Finite Element, Finite Volume, Object-Oriented programming, PDE solvers, unstructured mesh 1. INTRODUCTION Unstructured grids in PDE calculations allow some families of numerical methods—such as finite element methods (FEM) and finite volume methods (FVM)—to be adopted in problems involving general geometries. As pointed out by Berzins et al. [1998], this is one of the most important trends in the Authors’ addresses: E. Bertolazzi, via Mesiano 77, I-38050 Trento, Italy; email: enrico.bertolazzi@ ing.unitn.it; G. Manzini, via Abbiategrasso 209, I-27100 Pavia, Italy; email: gianmarco.manzini@ ian.pv.cnr.it. Permission to make digital or hard copies of part or all of this work for personal or classroom use is granted without fee provided that copies are not made or distributed for profit or direct commercial advantage and that copies show this notice on the first page or initial screen of a display along with the full citation. Copyrights for components of this work owned by others than ACM must be honored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers, to redistribute to lists, or to use any component of this work in other works requires prior specific permission and/or a fee. Permissions may be requested from Publications Dept., ACM, Inc., 1515 Broadway, New York, NY 10036 USA, fax +1 (212) 869-0481, or [email protected]. C 2002 ACM 0098-3500/02/0300–0101 $5.00 ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002, Pages 101–131.

Upload: gianmarco

Post on 03-Feb-2017

213 views

Category:

Documents


1 download

TRANSCRIPT

Algorithm 817P2MESH: Generic Object-Oriented InterfaceBetween 2-D Unstructured Meshes andFEM/FVM-based PDE Solvers

ENRICO BERTOLAZZIUniversity of TrentoandGIANMARCO MANZINIInstitute of Numerical Analysis—CNR

The software interface P2MESH is a collection of C++ class templates suitable for developing pro-totypes of high-performance PDE solvers on unstructured 2-D meshes. P2MESH supports severaldiscretization methods on triangles and quadrilaterals, such as finite volume or finite element. Thedesign philosophy of P2MESH does not consider specific model problems or built-in approximation al-gorithms. The software package is general purpose and it may also be used as a building block in theimplementation of numerical codes both for engineering applications and mathematical problems.

Categories and Subject Descriptors: D.1.5 [Programming Techniques]: Object-oriented Pro-gramming; D.3.3 [Programming Languages]: Language Constructs and Features—Classes andobjects, Data types and structures; G.1.8 [Numerical Analysis]: Partial Differential Equations—Finite element methods, finite volume methods

General Terms: Algorithms, Languages

Additional Key Words and Phrases: Finite Element, Finite Volume, Object-Oriented programming,PDE solvers, unstructured mesh

1. INTRODUCTION

Unstructured grids in PDE calculations allow some families of numericalmethods—such as finite element methods (FEM) and finite volume methods(FVM)—to be adopted in problems involving general geometries. As pointedout by Berzins et al. [1998], this is one of the most important trends in the

Authors’ addresses: E. Bertolazzi, via Mesiano 77, I-38050 Trento, Italy; email: [email protected]; G. Manzini, via Abbiategrasso 209, I-27100 Pavia, Italy; email: [email protected] to make digital or hard copies of part or all of this work for personal or classroom use isgranted without fee provided that copies are not made or distributed for profit or direct commercialadvantage and that copies show this notice on the first page or initial screen of a display alongwith the full citation. Copyrights for components of this work owned by others than ACM must behonored. Abstracting with credit is permitted. To copy otherwise, to republish, to post on servers,to redistribute to lists, or to use any component of this work in other works requires prior specificpermission and/or a fee. Permissions may be requested from Publications Dept., ACM, Inc., 1515Broadway, New York, NY 10036 USA, fax +1 (212) 869-0481, or [email protected]© 2002 ACM 0098-3500/02/0300–0101 $5.00

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002, Pages 101–131.

102 • E. Bertolazzi and G. Manzini

development of numerical software packages for PDEs. For example, we canmention a (largely incomplete) list of remarkable software products such asDIFFPACK [Bruaset and Langtangen 1996], ELLPACK [Rice and Boisvert1984], KASKADE [Beck et al. 1995], SPRINT2D–SPRINT3D [Berzins et al.1998], and UG [Bastian et al. 1997].

In this work we present P2MESH, an object-oriented interface between 2-Dunstructured meshes and the assembly process of FEM/FVM.

The numerical approximation process to the solution of a PDE problem in-volves steps that are briefly summarized in the following list:

(i) mesh generation;(ii) formation of discrete algebraic equations;

(iii) equation resolution;(iv) post-processing (visualization) of the numerical solution.

P2MESH is an object-oriented interface between item (i) and (ii) and the meshdata set output by (i) is its most important input.

The name P2MESH is not an acronym, but stands for “mesh of polygons in 2-D”because it processes both triangular and quadrilateral meshes. The implemen-tation of P2MESH uses the C++ programming language and strongly exploitsthe basic OO mechanisms of encapsulation and polymorphism, see Stroustroup[1998].

The format of the software is generic, meaning that it is not affected by aspecific model problem nor by a built-in approximation technique. Thus, it canbe used as a building block in developing numerical software for applicationsboth in engineering and applied mathematics.

The idea of interfacing the mesh data set output by a mesh generator soft-ware and the PDE solver is not new. For instance ELLPACK implements asimilar idea in a procedural way, see Rice and Boisvert [1984]. However, P2MESHsupports an innovative object-oriented approach.

Basically all of the relevant information to be manipulated by a numericalPDE solver, such as geometrical quantities, physical unknowns, and auxiliarydependent variables, may be logically associated to elementary mesh entities,namely vertices, edges and polygons (triangles or quadrilaterals).

P2MESH supports the above software definitions by inheritance from a suit-able set of corresponding template base classes. The public methods of theseclasses return topological—mesh connectivity—and geometrical informationabout the mesh. A special recursive template mechanism allows the extensionof the base types to include attributes and methods specific to the model problemand the approximation algorithm under consideration [Barton and Nackman1994].

For example, we can define a finite element which may behave as a meshtriangle for all that pertains to connectivity and geometric quantities, but alsoencapsulates discrete approximation variables and the functions to manipulatethem. That is, this finite element is able to return information about its vertices,its edges and the neighboring triangles, and this capability is transparentlyprovided by P2MESH. Then, one can extend this triangle by introducing into its

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 103

definition a public method to compute the element contribution to the stiffnessmatrix and to the load vector, according to an FEM assembly process.

The mesh itself, as derived from the corresponding base class in P2MESH, hascontainers for these extended vertex, edge, and polygon objects. We emphasizethat the initialization process on the mesh data set output by a mesh generatoris automatically and transparently carried out by P2MESH.

The equation assembly process for both FEM and FVM usually involves loopson mesh vertices, edges and polygons—whether these latter ones are inter-preted as cells, elements, part of dual control volumes or something else. Tothis purpose, P2MESH supports two sets of iterator types. The first one followsthe Standard Template Library (STL) fashion [Musser and Saini 1996] whilethe second one is given in a form that we feel more suitable to PDE applications.

From a technical viewpoint, genericity is expressed by static polymorphismvia the C++ mechanism of instantiating template classes from class tem-plates [Barton and Nackman 1994]. The recursive template technique en-sures efficiency in our algorithm-oriented software design [Furnish 1997, 1998;Veldhuizen 1999].

As for iterators, the implementation of P2MESH uses the STL containers. Weremark that this is not a constraint on portability, as the STL is part of thestandard ANSI definition of C++ and must be available in any ANSI compliantcompiler.

The software is given in an STL-like programming format, so that it does notrequire any installation procedure; that is no library files with the usual Unixextension “.a” must be pre-compiled and linked. The whole interface consists ofthe single header file p2mesh.hh which has to be included at the beginning ofeach software application header file using P2MESH facilities.

The present article illustrates the non-procedural programming paradigmsupported by P2MESH and also aims at giving the reader a fairly high-level ac-quaintance with the library capabilities.

The outline of the paper is as follows. In Section 2 we overview the maininterface design issues and implementation details. This section illustratesthe generic classes defined in P2MESH and the way they can be used to buildmore complex data structures. The main features of the interface are pre-sented in some details, but for a complete description—namely, function proto-types and application examples—we refer the interested reader to the pro-grammer’s manual [Bertolazzi and Manzini 1999c] and the short referenceguide [Bertolazzi and Manzini 1999e], available in the package distribution[Bertolazzi and Manzini 1999b]. In Section 3 we analyze some simple applica-tion examples that illustrate how P2MESH works practically in implementing anFEM/FVM; the conclusion follows in Section 4.

2. INTERFACE DESIGN ISSUES

P2MESH assumes that the minimum mesh data set available from a mesh gen-erator consists of

(i) the list of the mesh vertex coordinates and(ii) the connectivity table “element→ constitutive vertices.”

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

104 • E. Bertolazzi and G. Manzini

The mesh connectivity of a 2-D unstructured grid is usually given by specialconnectivity lists. As pointed out in references [George 1991, 1996], there is nounique way of representing a mesh in a software implementation; that is, ofspecifying which connectivity lists should be available from a mesh generatoror eventually built and maintained within an application program. This is be-cause the way the mesh information is used may change significantly dependingon the problem and the solution approach. However, it is important to realizethat all of the topological relationships among mesh geometrical entities, suchas vertices, edges, and polygons, can be reconstructed from data set (ii). Anal-ogously, all of the values of geometrical quantities such as distances betweenvertices, components of normal vectors, edge lengths, and element areas can becomputed using (ii) and the values of the vertex coordinates in (i).

In a typical procedural implementation, these lists of connectivity and vertexcoordinates are available as an ordered collection (array) of real values andtables of integer identifiers. Instead, the approach of P2MESH is based on a non-procedural abstraction.

The core of the P2MESH software comprises five generic base classes, whichare templates for the definition of specific derived classes.

In this section, the P2MESH base classes are also referred to as interface classes,and the derived classes as project classes, the project being the application basedon P2MESH. The following table indicates the names of the P2MESH classes, theconventional names adopted for the project classes in the documentation, andthe nature (geometrical or not) of the type.

Base Class Name Derived Class Name Parameterized Typep2_common Common shared informationp2_vertex Vertex vertex instancep2_edge Edge edge instancep2_poly Poly (Triangle, Quad) polygon instancep2_mesh Mesh mesh instance

For example, the project class Vertex whose instances are the applicationvertices is publicly derived from the interface class p2_vertex.

It should be noted that the project class names are simply a conventionalchoice: no name is forced to the types defined by the P2MESH user. The prefix p2_in the base class names has been adopted in the interface implementation toavoid name conflicts with other project names defined either by the user or byother software packages.

Notice that from the base class p2_poly, at least two different types of poly-gons may be derived, either triangles or quadrilaterals. The class name Polythus refers to a generic polygon type, and any information concerning an in-stance of such a type will hold for both triangle and quadrilateral objects.

The interface classes are designed to be used as base classes in public deriva-tions; no objects of this types should be instantiated. The instances of the projectclasses Vertex, Edge, Poly—Triangle, Quad— and Mesh will be simply calledvertices, edges, polygons—triangles, quadrilaterals—and meshes. No objects oftype Common must be instantiated.

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 105

The keyword const is omitted in the prototype declarations reported hereinfor the sake of compactness. However, the complete form of the declarations canbe found in the kernel description given in Bertolazzi and Manzini [1999e] orin the source code.

2.1 The Class p2 common

The class p2 common is the base class for the public derivation of the classCommon. The class Common contains the static data and the typedef aliasesshared by the project classes and inherits the statically stored information spec-ified in the template argument list of p2 common. Since this latter one does nothave any public methods, Common contains only the method defined in its scopeby the user.

The template header declaration of the class p2 common is:

template <typename P2V_type, // vertex project nametypename P2E_type, // edge project nametypename P2P_type, // polygon project nametypename P2M_types, // mesh project nameunsigned SIZE_value = 3, // polygon sizebool LIST_value = false, // vertex connectivitytypename REAL_type = double, // floating point typetypename INTEGER_type = int, // integer typetypename UNSIGNED_type = unsigned, // unsigned integer typetypename VMARK_type = unsigned, // vertex markertypename EMARK_type = unsigned, // edge markertypename PMARK_type = unsigned> // polygon marker

class p2_common ;

The default values assume a triangular mesh, no vertex topology lists, standardbuilt-in arithmetic types and unsigned integer markers:

class Common : public p2_common<Vertex, Edge, Triangle, Mesh> { } ;

A quadrilateral-based mesh requires that the entry SIZE be explicitly set to 4in the template argument list of the base class p2 common:

class Common : public p2_common<Vertex, Edge, Quad, Mesh, 4> { } ;

Whenever set to true the entry LIST makes available the vertex connectivityin the mesh representation. The double mechanism of template parameteriza-tion of the base classes with the project class Common and inheritance fromthem allows the redefinition of the arithmetic types in all of the classes built onP2MESH, by changing simply the entries REAL, INTEGER and UNSIGNED in the tem-plate argument list of p2 common. The arithmetic types in the interface classesare parameterized in the template argument list of p2 common and are visi-ble as Integer, Unsigned and Real, with default values the built-in types int,unsigned and double.

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

106 • E. Bertolazzi and G. Manzini

The three last arguments in the template header list of the class p2 commonare dummies for the marker type names used in a P2MESH-based project. In-stances of vertices, edges, and polygons can be assigned different markers bythe user in the input mesh data set to drive specific processes, such as the treat-ment of the boundary conditions. By default, markers are unsigned integers,but P2MESH allows the user to introduce more complex definitions. An exampleof the use of markers on edges is given in Section 3.2.

2.2 The Classes p2 vertex, p2 edge, and p2 poly

The project types Vertex, Edge, and Poly for extended vertices, edges and poly-gons are publicly derived from the interface classes p2 vertex, p2 edge, andp2 poly by using the syntax

class Vertex : public p2_vertex<Common> { ... } ;class Edge : public p2_edge <Common> { ... } ;class Poly : public p2_poly <Common> { ... } ;

The project class Common parameterizes the template argument list of all theinterface classes. The double mechanism of public inheritance and templateparameterization allows the interface generic classes to be specialized by theproject classes [Furnish 1997, 1998; Veldhuizen 1999].

The class p2 vertex basically contains an ordered pair of real numbers thatare the vertex coordinates (x, y). It may also contain the connectivity lists ofpointers to connected vertices, to incident edges, and to incident polygons. Tolimit the occupation of memory, this information is not stored by default butmust be explicitly required by the application using P2MESH.

The class p2 edge basically contains the ordered pair of pointers to the edgevertices and to the edge polygons. When an edge is a boundary edge there isonly one adjacent polygon and the pointer to the missing polygon is set to NULL.

The class p2 poly basically contains the counterclockwise ordered lists ofpointers to both mesh vertices and edges. The cardinality of these two listsdefines the size of the polygon.

The public interface of p2 vertex, p2 edge, and p2 poly is inherited by thecorresponding project classes. The public interface is designed by following someregular and systematic rules with very few exceptions. It provides a small set ofsimple member functions which can combine in more complicated expressions.The public methods are logically grouped and listed in three subsets:

—topological methods: they return information about the first neighbor con-nectivity of a vertex, an edge or a polygon to instances of type Vertex, Edge,and Poly;

—geometrical methods: they return “non-topological” information, such as forexample the coordinates of a vertex, the length of an edge, the area of apolygon and so forth;

—mapping methods: they return the coordinates and the Jacobian matri-ces for the coordinate transformation from and onto the reference polygon;P2MESH implements the simplest linear coordinate mappings for triangles and

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 107

quadrilaterals and the methods are available only in the public interface ofthe class p2 poly.

Topological Methods. The public interfaces of the P2MESH classes contain es-sentially the same procedure names for their topological methods. These meth-ods are:1

1. unsigned n_vertex(): number of vertices;2. unsigned n_edge (): number of edges;3. unsigned n_poly (): number of polygons;4. Vertex & vertex(unsigned i): reference to the i-th vertex;5. Edge & edge (unsigned i): reference to the i-th edge;6. Poly & poly (unsigned i): reference to the i-th polygon;7. unsigned local_number(Vertex & v): local identifier of vertex v ;8. unsigned local_number(Edge & e): local identifier of edge e;9. unsigned local_number(Poly & p): local identifier of polygon p;

10. bool ok_poly (unsigned i): returns true if the i-th polygon exists;11. bool ok_oriented(unsigned i): check the edge orientation.

For each instance of type vertex, edge and polygon the methods of the publicinterfaces give the following information:

—methods 1–3: how many vertices, edges, and polygons are in the instancedefinition;

—methods 4–6: their reference in the mesh representation;—methods 7–9: their local identifier in the instance definition.

Any geometric entity of the mesh is naturally associated to many integeridentifiers which depend on the context. For example, the same vertex can bethe first vertex of an edge, the third vertex of a polygon, and the 42-th vertexin the vertex list of the mesh. For the sake of presentation, in the topologi-cal methods 4–6, we refer to all these different identifiers by using in inputthe same unsigned integer index i. P2MESH also provides the inverse function-alities that return the integer identifiers corresponding to a given input ver-tex/edge/polygon reference. These functionalities are implemented by the meth-ods 7–9 and are all named local_number by exploiting the C++ polymorphism.Clearly, the following relations hold

X::vertex(X::local_number(v)) = v // v is a reference to a vertexX::edge (X::local_number(e)) = e // e is a reference to an edgeX::poly (X::local_number(p)) = p // p is a reference to a polygon

where X can be any of the P2MESH classes p2 vertex, p2 edge, and p2 poly.

1For the sake of presentation, the enumeration of the public methods adopted here differs from theone used in the programmer’s manual.

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

108 • E. Bertolazzi and G. Manzini

Fig. 1. (a) Vertex-Vertex, (b) Vertex-Edge and (c) Vertex-Polygon connections in the definition of ap2 vertex instance (pointers are optionally stored in memory).

Fig. 2. (a) Edge-Edge connections for a p2 edge instance, (b) Polygon-Edge and Polygon-Vertexconnections for a triangular p2 poly instance, (c) Polygon-Polygon connections for a triangularp2 poly instance.

Methods 1, 4, 7 in the public interface of the class p2 edge return informationabout the vertices in the current instance of that class. The other methods inp2 edge refer to adjacent edges and polygons.

Similarly, methods 1, 4, 7, and 2, 5, 8, in the class p2 poly are respectivelyrelated to the vertices and edges in the current polygon, while the other onesrefer to the adjacent polygon.

Some of the member functions in the public interface return the same infor-mation; for example there holds:

Poly::n_vertex() == Poly::n_edge() == Poly::n_poly()

In spite of redundancy, P2MESH provides all of the mentioned methods in orderto have the same public interface for all the interface classes.

In order to save memory storage, the topological methods of a vertex: methods1–9, are not available by default, but must be required by introducing LIST=truein the template argument list of the class p2 common.

Figure 1 depicts the pointers to vertices, edges, and polygons adjacent toa given vertex. Figure 2 illustrates on the left the local numbering of edgesadjacent to a given edge in the mesh, and on the right the local numbering ofvertices and edges forming a given polygon and its adjacent polygons. In both

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 109

pictures a triangle-based mesh is assumed. Remark that all the local identifiersare numbered starting from 0, as it is usual in the C and C++ programminglanguage.

Method 10 checks whether a polygon adjacent a given edge exists. Themethod is in the public interface of both p2 edge and p2 poly.

Finally, method 11, which is only in the public interface of the class p2 poly,checks the orientation of an edge in a polygon by comparing it with the orien-tation of an edge as an independent instance of class Edge.

Geometrical Methods. We list here the geometrical methods that returnnon-topological information on vertices, edges, and polygons. These methodsare inherited from the classes p2 vertex, p2 edge, and p2 poly.

Methods of vertices

12. double x(): first coordinate of the vertex;13. double y(): second coordinate of the vertex;

Methods of edges

14. double xm(): first coordinate of the midpoint15. double ym(): second coordinate of the midpoint;16. double xt(double & t): linearly interpolated first coordinate;17. double yt(double & t): linearly interpolated second coordinate;18. double nx(): first component of the vector normal to the edge;19. double ny(): second component of the vector normal to the edge;20. double length(): length of the edge;

Methods of polygons

21. double xc(): first coordinate of the centroid;22. double yc(): second coordinate of the centroid;23. double area(): polygon area.

The sequence p2 vertex, p2 edge and p2 poly lists the interface classes inincreasing order of complexity. In fact, a vertex is the simplest entity existingin a mesh, an edge may be defined by “a couple of vertices” and a polygon by“a set of vertices and edges.” It is clearly to be expected that the quantitiesrelated to a vertex, for example its coordinates, must also be available for theedges and the polygon that vertex belongs to. Thus, the methods returningthis kind of information should appear not only in the public interface of theclass p2 vertex, but also in the classes p2 edge and p2 poly. However, since anedge contains two vertices, and a polygon three or four, a sorting rule amongthe vertices must be conceived. For this reason, the prototype of any vertexmethod in the public interface of p2 edge and p2 poly is modified by adding anunsigned integer entry at the beginning of its argument list. This entry labelsvertices ranging through 0...n_vertex()-1 according to the local numbering.For example, the vertex method Vertex::x() becomes Edge::x(unsigned i),or Poly::x(unsigned i).

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

110 • E. Bertolazzi and G. Manzini

In a similar way, the methods of edges are in the public interface of theclass p2 poly and take an additional unsigned entry at the beginning of theirargument lists.

2.3 Mapping Methods

In the class p2 poly there is also a minimal set of methods which map theactual polygon—no matter if it is a triangle or a quadrilateral—onto a referencepolygon and vice versa. Their prototypes are

24. st_to_xy(double & s, double & t double & x, double & y)affine mapping from reference to actual element;

25. void xy_to_st(double & x, double & y, double & s, double & t)affine mapping from actual to reference element;

26. void jacobian(double & s, double & t, double J[2][2])Jacobian of the mapping;

27. void inverse_jacobian(double & s, double & t, double InvJ[2][2])inverse Jacobian of the mapping.

2.4 The Class p2 mesh

p2 mesh is the class for the public derivation of the project class Mesh. As is thecase of the other data structures examined herein, the double mechanism ofinheritance and template parameterization by p2 mesh applies in the definitionof Mesh.

class Mesh : public p2_mesh <Common> { ... } ;

Mesh is thus the most complex data structure that can be built by using P2MESHand without any further project specification. Within its private attributes thereare the lists of vertices, edges, and polygons inherited from p2 mesh.

Topological Methods. The main topological information is accessible by thefollowing methods:

1. unsigned n_vertex (): number of vertices;2. unsigned n_bvertex(): number of boundary vertices;3. unsigned n_ivertex(): number of internal vertices;4. unsigned n_edge (): number of edges;5. unsigned n_bedge(): number of boundary edges;6. unsigned n_iedge(): number of internal edges;7. unsigned n_poly (): number of polygons;8. unsigned n_bpoly(): number of boundary polygons;9. unsigned n_ipoly(): number of internal polygons;

10. Vertex & vertex(unsigned i): reference to the i-th vertex;11. Edge & edge (unsigned i): reference to the i-th edge;12. Poly & poly (unsigned i): reference to i-th polygon;13. unsigned local_number(Vertex & v): local identifier of vertex v;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 111

14. unsigned local_number(Edge & e): local identifier of edge e;15. unsigned local_number(Poly & p): local identifier of polygon p.

Methods 1–3, 4–6, and 7–9 return the total number of instances of type Vertex,Edge, and Poly and the number of internal and boundary instances in the meshdata set.

Methods 10–12 return the reference to the i-th vertex/edge/polygon instancein the corresponding vertex/edge/polygon list of the mesh and methods 13–15implement the inverse functionalities, that is they accept a reference to aninstance of a given type and return its integer identifier.

Finally the method

void bbox(double & xmin, double & ymin, double & xmax, double & ymax)

returns the coordinates of the bottom-left and the top-right extrema definingthe bounding box of the mesh.

Mesh Builders. When the application program is being executed, the meshdata set must be initialized by invoking one of the available mesh builder meth-ods that are provided by P2MESH either to be called as independent methods orto implement application constructors of the project class Mesh:

—tensor_mesh: builds a regular mesh of triangles or quadrilaterals inside aboxed frame;

—std_tensor_mesh: builds a regular mesh of triangles or quadrilaterals insidea unit boxed frame;

—map_mesh: builds a regular mesh of triangles or quadrilaterals inside a boxedframe re-mapped onto a four-side domain of general shape;

—read_map_mesh: initializes a mesh from an input file description of a regularmesh of triangles or quadrilaterals inside a boxed frame re-mapped onto afour-side domain of general shape;

—build_mesh: initializes a mesh from an input description of an unstructuredmesh by using a list of vertex coordinates, a polygon-vertex connectivity andoptionally a list of edge-vertex connectivity;

—read_mesh: performs the same action as the previous method, but the inputmesh is read from external files in the output format coming from the meshgenerator TRIANGLE, see for example Shewchuk [1996].

The first four methods build a regular mesh of triangles—three different orien-tations are possible—or quadrilaterals starting from a structured descriptionof the domain triangulation. This description is internally generated for thefirst three methods and given as an input data file for the fourth one. Themethod map_mesh remaps the computational domain onto a four-side domain ofgeneral shape by a project coordinate transformation function.

The method build_mesh initializes the mesh data set starting from anunstructured description of the initial triangulation, provided by the projectapplication as lists of coordinates and connectivity. The method read_mesh per-forms the mesh data set initialization starting from input data files in the

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

112 • E. Bertolazzi and G. Manzini

output format of the mesh generator TRIANGLE. For both methods, the list ofvertex coordinates and the list of polygon–vertex connectivity are mandatory;a list of edges can be optionally given in input. The data set of edges is ini-tialized by using such a list whenever edge–vertex connectivity is available. Itis worth noticing that the external inputs are absolutely not restricted to theoutput file format of TRIANGLE. Any file format can be used by programming asimple reader function and combining it with the method build_mesh.

The nature of the polygons to be generated by the mesh builders, namelytriangles or quadrilaterals, is not explicitly indicated as an entry argument ofthe mesh builder methods. This information is already specified as an argumentin the template argument list of the class p2 common.

Should an external mesh be given by input files, the object markers are sim-ply read, whereas if the mesh is generated internally, a set of markers follow-ing an internal convention—see the documentation of P2MESH—is automaticallycreated. These internal markers indicate the location on the mesh of the enti-ties that have been internally generated. At run-time mesh instantiation, themesh builder method called by the application program performs an internalloop over all the vertices, edges, and triangles of the mesh data set, and for anyentity, invokes the specific marker processing function if required. No actionoccurs if the marker processing function pointer is set to NULL.

2.5 The Internal Ordering of the Mesh Data Sets

Special mathematical treatment is normally provided to the boundary of thecomputational domain. For this reason, it is useful to distinguish between an“internal” and a “boundary” instance of a basic geometric type. A procedu-ral implementation of separate access to internal and boundary mesh enti-ties might consist, for example, of enumerating their identifiers in differentlist structures. A rather classical C++ strategy might rely on using inheri-tance to specialize a class in a higher position of the class hierarchy—usuallyan abstract class—and then applying virtual functions and dynamic polymor-phism [Vankeirsbilck and Nelissen 1994; McKenna 1997]. P2MESH proposes adifferent solution which consists of giving the mesh itself the capability of de-tecting whether an instance is an internal or a boundary item. We believe thatthis design issue does not force any particular implementation choice on thefinal application using P2MESH.

By means of a particular reordering strategy during the mesh initializationphase, all the vertex-, edge- and polygon-type instances are consecutively storedin memory starting by a zero offset address, and the boundary ones are forcedbefore the internal ones. Each entity is thus mapped onto a subset of the naturalnumbers, and this mapping will be called the rank, and identified in the sequelby the symbolR. Also, vertices in edges and polygons, and edges in polygons arelocally numbered in a consecutive way starting from zero—this number beingtheir local rank. Thus, the classes p2 vertex, p2 edge, and p2 poly as well asthe class p2 mesh are equipped with the public method local_number whichreturns the rank of a given entity. This strategy makes it possible to easilyassociate local identifiers to any mesh object, within the mesh object it belongs,

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 113

to without storing them as class attributes. In fact, the rank numbering systemof all the data structures in the mesh implies that the mesh objects have a veryprecise location in memory and can be quickly accessed in a random way. Thislocation in memory, defined with respect to an offset address, is returned as the“local identifier.”

It is worth noticing that this very simple strategy works effectively in 2-D,but it is not easily generalizable to the 3-D case.

In the sequel, the symbol e = (va, vb) will denote the instance of the classEdge whose ordered pair of vertices are respectively va and vb. The constraintswhich are satisfied by the P2MESH order are:

(a) vertex reordering: boundary vertices are reordered in such a way that whene = (va, vb) is a boundary edge, then

R(e) ≥ R(va);

(b) edge reordering: boundary edges are reordered in such a way that when forthe two consecutive edges

ea = (va, v) and eb = (v, vb)

the vertex v is not contained in any other boundary edge, only one of thetwo following conditions must hold:1. R(ea)+ 1 = R(eb),2. R(ea) > R(eb);

(c) polygon reordering: boundary polygons are reordered in such a way thatwhen p0 and p1 are boundary polygons and e0 ∈ p0, e1 ∈ p1 are boundaryedges, then

R(e0) < R(e1)⇒ R(p0) ≤ R(p1);

(we use “≤” instead of “<” because p0 and p1 can be the same polygon).

Furthermore, the boundary edges are ordered in such a way that if e = (v0, v1)is a boundary edge, the external region is on the right. As a consequence ofthese constraints, if for example v1 is a boundary vertex and v2 is an internalone, their ranks will satisfy the conditionR(v1) < R(v2). Similar relations holdtrue also for the other mesh data sets.

Whenever a mesh is run-time instantiated by means of a P2MESH meshbuilder, the reordering algorithm is automatically and transparently invoked.The algorithm is detailed in Bertolazzi and Manzini [1999a]. As it is basedon the quick-sort and the binary search—available in the STL—its computa-tional cost has a growth proportional to n log n, where n is the total number ofboundary items [Knuth 1998; Hoare 1962].

2.6 Iterators

An iterator in P2MESH is a particular object which allows iteration over the ver-tices, edges, and polygons of the mesh data set in a very effective and transpar-ent way. The use of iterators hides the actual processing of the items iterated by

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

114 • E. Bertolazzi and G. Manzini

the program. Two different kinds of iterators are provided by P2MESH. The firstone is based on the STL containers that are used in the P2MESH implementationwhile the second one consists of an iterator template to be used with the specialmacro foreach.

STL-like iterator types. Since P2MESH has been designed and implementedusing, as much as possible, the technology of the STL, two families of STL-like iterator types—for respectively objects and constant objects—are naturallyderived.

—Mesh::vertex_iterator, iterator type for vertices;—Mesh::edge_iterator, iterator type for edges;—Mesh::poly_iterator, iterator type for polygons;—Mesh::vertex_const_iterator, constant iterator type for vertices;—Mesh::edge_const_iterator, constant iterator type for edges;—Mesh::poly_const_iterator, constant iterator type for polygons.

Iterators are defined as public types in the scope of the class Mesh, thatis the scope operator must be used, for example Mesh::vertex_iterator. Somemethods are provided in the scope of the interface class P2 MESH to return “smartpointers” to particular items in the set of vertices, edges, and polygons. Forexample, in the case of vertices we have

—Mesh::vertex_iterator vertex_begin(): returns a smart pointer to the firstitem in the set of mesh vertices;

—Mesh::vertex_iterator vertex_end(): returns a smart pointer to the onepast-the-end item in the set of vertices.

Similar action is performed on the subset of internal vertices by the methods

—Mesh::vertex_iterator ivertex_begin();—Mesh::vertex_iterator ivertex_end();

and the subset of boundary vertices by

—Mesh::vertex_iterator bvertex_begin();—Mesh::vertex_iterator bvertex_end().

The following code fragment illustrates how STL-like iterators can be instanti-ated and used in an application program.

Mesh mesh ; // creates a mesh objectMesh::vertex_iterator iv ; // creates the vertex iterator

named ivfor ( iv = mesh.vertex_begin() ; // points to the first mesh vertex

iv != mesh.vertex_end() ; // is it the last vertex?++iv ) { // advances the vertex pointer

Vertex & v = *iv ; // reference to the current vertexVertex * pv = &*iv ; // pointer to the current

}

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 115

For edges and polygons, P2MESH makes available analogous member methods;it is simply sufficient to substitute the word vertex for edge or poly.

The P2MESH iterator class template. P2MESH contains also an iterator classtemplate, named Iterator<T>. (CIterator<T> for the constant iterator type).The dummy label T indicates one of the three project classes Vertex, Edge, Poly.

The iterator template is an interface for the STL-like iterator types describedin the previous section. Its class constructor prototype is

Iterator<T> (Mesh & M, unsigned f=0) ;

The reference M stands for the mesh data set and the flag f=0,1,2 specifiesthe iteration range—respectively all, boundary and internal items. The publicmethod

void set_loop(Mesh & M, unsigned f) ;

can be used to change the loop sequence. An iteration loop is specified asfollows:

—void begin(): sets the iterator to the first item;—bool end_of_loop(): returns true if all the items have already been visited

by the iterator;—Iterator<T> const & operator ++ (): advances the iterator to the next

item;—T const * operator () () const and T * operator () (): return the cur-

rent item pointed by the iterator.

The following code fragment illustrates how the iterators can be instantiatedand used in an application program.

Mesh mesh ; // creates a mesh objectIterator<Edge> ie ; // creates the edge iterator named ieie . set_loop( mesh, 2 ) ; // sets loop range on internal edgesfor ( ie . begin() ; // points to the internal edge

! ie . end_of_loop() ; // is it the last edge?++ie ) { // advances the edge pointer

Edge & e = *ie ; // reference to the current edgeEdge * pe = &*ie ; // pointer to the current edge

}

A special macro, named foreach, is also available by default and can be setundefined on request. It is defined by the following pre-processor statement

# define foreach(X) for ( X . begin() ; ! X . end_of_loop() ; ++X )

which allows a very short and effective syntax for the definition of loops

Mesh mesh ; // creates a mesh objectIterator<Edge> ie ; // creates the edge iterator named ieie . set_loop( mesh, 2 ) ; // sets loop range on internal edgesforeach( ie ) { // for each items

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

116 • E. Bertolazzi and G. Manzini

Edge & e = *ie ; // reference to the current edgeEdge * pe = &*ie ; // pointer to the current edge

}

2.7 Memory Requirements and Computational Costs

A performance criterion has been taken into account in the design phase ofthe P2MESH development process, meaning that a P2MESH-based software shouldshow a “convenient” behavior from the viewpoint of computational costs andmemory storage requirements.

In order to achieve this goal, P2MESH guarantees that the first-neighbor topol-ogy of the mesh is generally available at the cost of a single pointer dereferen-tiation plus at most one comparison. The latter additional cost is needed onlyfor retrieving the edges which are adjacent to an edge and the polygons whichare adjacent to a polygon. P2MESH always stores four pointers for each edge and2 × size pointers for each polygon, where size=3 for triangular meshes andsize=4 for quadrilateral meshes. Lists of pointers for the vertex topology arenot provided by default and are stored only upon explicit request by the P2MESHuser.

The total memory requirement for a general unstructured mesh of Nv ver-tices, Ne edges, and Np polygons, either triangles or quadrilaterals, can thusbe easily estimated. Since the relation Ne = Nv + Np − 1 holds, a mesh ofNv vertices and Np polygons is represented in the P2MESH abstraction withoutexplicit vertex topology by 4 (Nv − 1) + 2 (size + 2) Np pointers. In addition,P2MESH stores 2 Nv double precision floating point numbers (default built-inarithmetic type) for the vertex coordinates.

Should vertex topology be requested, the previous memory requirement mustbe increased by the number of pointers of each vertex to the connected verticesand to the adjacent edges and polygons. In a mesh with no connectivity con-straints, as is the case of a general unstructured grid, this additional cost isdifficult to be estimated, but it is likely to have a great impact on the storagerequirements.

Memory requirements could have been halved by storing only pointers toedges (or, alternatively, to vertices) in each edge and size pointers to vertices(or, alternatively, to edges) in each polygon. Further, when no edge topology isneeded by a numerical algorithm, no pointers at all might be stored in edges.Notice that these ones are just different design choices. To this purpose webelieve that, when developing a general purpose tool, it is better to pay someredundancy in simpler cases and gain nearly constant-in-time access in a widerrange of situations. Moreover, we outline that the minimum memory require-ment is normally amortized when an application is developed in the spirit ofP2MESH, since each geometric structure is extended to store a larger numericaldata set.

All the geometrical and mapping methods require a run-time calculation.Thus, if these methods are repeatedly invoked to compute some expensive quan-tity such as the area of a polygon, a performance penalty may occur. In sucha case, we suggest a very simple but indeed effective strategy to tune the code

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 117

and to get better performances: expensive geometric quantities have to be cal-culated at the beginning of the run and stored in their natural place—for ex-ample, the area of a polygon should be stored as an attribute of polygon objects.Then, instantiate appropriate methods to return the value of the previouslyestimated quantities, which override the homonymous P2MESH methods. Suchan explicit storage may be convenient when a linear FEM is implemented. Infact, the Jacobian of the mapping onto the reference element is proportionalto the area of the current element. Thus, the storage of the Jacobian and itsinverse is redundant.

2.8 Technical Details

P2MESH-based numerical codes have been successfully run on the following com-pilers and platforms:

Compiler Version Operating Systemegcs 1.1 Linux 2.2.12, Solaris SunOS 5.7gcc 2.95 Linux 2.2.12, Solaris SunOS 5.7KAY 4.3 Solaris SunOS 5.7Metrowerks Codewarrior 4.0, 7.0 MacOS 8.5, MacOSXDigital C++ 6.1 Digital UNIX V4.0DMIPSpro 7.3 IRIX64

3. APPLICATION EXAMPLES

The examples presented in this section are small source fragments of possi-ble applications of P2MESH in implementing FEM/FVM solvers of elliptic andhyperbolic problems. Part of the following examples are given in the P2MESHdistribution package and are completely explained in Bertolazzi and Manzini[1999d]. We emphasize that the class design solutions that we propose here areneither unique nor possibly the best ones in terms of computational efficiency.

3.1 FEM Implementation of a Poisson Solver

3.1.0.1 Conforming linear and quadratic elements on triangles. As in theconforming linear FEM every triangle coincides with an approximation element,it is natural to define the methods to estimate the local contribution to thestiffness matrix and to the load vector within the scope of the project classTriangle. The other project classes Vertex, Edge and Mesh are instead defined ina very simple way by public inheritance from the corresponding P2MESH classes.

The statement size=3 specifies to P2MESH that we are dealing with atriangle-based mesh. The definition of the project class Common introducesinto the P2MESH context all the project class names and the polygon size.

unsigned const size = 3 ;

class Common : public p2_common<Vertex,Edge,Triangle,Mesh,size> { } ;

class Vertex : public p2_vertex<Common> {} ;

class Edge : public p2_edge <Common> {} ;

class Triangle : public p2_poly <Common> {

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

118 • E. Bertolazzi and G. Manzini

public:

double local_load_vector( unsigned i, double (*)(double,double) ) ;

double local_stiffness_matrix( unsigned i, unsigned j ) ;

} ;

class Mesh : public p2_mesh<Common> {} ;

We emphasize that instances of these types are really mesh vertices, edges,and triangles, and behave like them for all that pertains to the mesh manip-ulation. Since in this case a triangle is also an approximation element, thetwo public methods local stiffness matrix and local load vector are de-fined within their class scope to evaluate respectively the stiffness matrix andthe load vector. The implementation of the methods follows. Notice the usageof the P2MESH functions n vertex, area, nx, ny, xm and ym.

double Triangle::local_stiffness_matrix( unsigned iv, unsigned jv ) {

unsigned ie = (iv+1)%n_vertex() ; // edge opposed to vertex iv

unsigned je = (jv+1)%n_vertex() ; // edge opposed to vertex jv

return 0.25 * ( nx(ie) * nx(je) + ny(ie) * ny(je) ) / area() ;

}

double Triangle::local_load_vector(unsigned iv,

double (*f)(double,double) ) {

unsigned ne = iv ; // edge coming out from vertex iv

unsigned pe = (iv+n_vertex()-1)%n_vertex() ; // edge going into vertex iv

return ( f( xm(ne), ym(ne) ) + f( xm(pe), ym(pe) ) ) * area() / 6.0 ;

}

Finally, we sketch the design of the class Elliptic Solver. This class con-tains an instance of the project class Mesh. Its constructor invokes the meshbuilder method read mesh, which takes in input

—the name of the mesh file output by the mesh generator;—three NULL arguments which signal to P2MESH that no special boundary

marker methods are provided by this application.

When the main program instantiates an elliptic solver, that is an object of typeElliptic Solver, the mesh is initialized by using the input file "my mesh file".The public method Solve implements the resolution algorithm and can be in-voked by the main program.

class Elliptic_Solver : public Common {private:

Mesh mesh ;public:

Elliptic_Solver() { mesh . read_mesh("my_mesh_file",NULL,NULL, NULL); }void Solve() ;// other stuff ...

} ;

The following code fragment illustrates the usage of P2MESH iterators to loopsequentially on the triangles/elements of the mesh. During the traversal, the

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 119

methods local stiffness matrix and local load vector are invoked and eachelement contribution is accumulated. Notice how references to mesh verticesand their indices in the mesh are easily recovered by using P2MESH topologicalfacilities.

void Elliptic_Solver::Solve() {

// arrays for LAPACKint const ndim = 10 ;double mat[ ndim ][ ndim ], rhs[ ndim ] ;

// other stuff ...

// build global stiffness matrix and rhsIterator<Triangle> triangle(mesh) ;foreach( triangle ) {

for ( unsigned iv=0; iv<triangle->n_vertex(); ++iv ) {unsigned i = mesh.local_number( triangle->vertex(iv) ) ;rhs[i] += triangle -> local_load_vector( iv, f ) ;for ( unsigned jv=0; jv<ndof; ++jv ) {

unsigned j = mesh.local_number( triangle->vertex(jv) ) ;mat[i][j] += triangle -> local_stiffness_matrix( iv, jv ) ;

}}

}// other stuff ...

}

As far as conforming quadratic elements are concerned, we suggest the follow-ing design, but again we remind the reader that many other different solutionsare possible. The project class Common contains the number of degrees of free-dom memorized by the static constant degree of freedom, and the quadraticshape functions shape and shape grad defined on the reference triangle.

unsigned const size=3 ;class Common : public p2_common<Vertex,Edge,Triangle,Mesh,size> {protected:

static unsigned const degree_of_freedom = 6 ;

static void shape( unsigned nb,double const & s,double const & t,double & val ) ;

static void shape_grad( unsigned nb,double const & s,double const & t,double g[2] ) ;

} ;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

120 • E. Bertolazzi and G. Manzini

void Common::shape( unsigned nb,double const & s,double const & t,double & val ) {

switch ( nb ) {case 0: val = (1-2*(s+t))*(1-(s+t)) ; break ;case 1: val = 4*s*(1-(s+t)) ; break ;case 2: val = s*(2*s-1) ; break ;case 3: val = 4*s*t ; break ;case 4: val = (2*t-1)*t ; break ;case 5: val = 4*(1-(s+t))*t ; break ;}

}

void Common::shape_grad(unsigned nb,double const & s,double const & t,double g[2] ) {

switch ( nb ) {case 0: g[0] = 4*(s+t)-3 ; g[1] = 4*(s+t)-3 ; break ;case 1: g[0] = 4 - 8*s - 4*t ; g[1] = -4*s ; break ;case 2: g[0] = 4*s-1 ; g[1] = 0 ; break ;case 3: g[0] = 4*t ; g[1] = 4*s ; break ;case 4: g[0] = 0 ; g[1] = 4*t-1 ; break ;case 5: g[0] = -4*t ; g[1] = 4 - 4*s - 8*t ; break ;}

}

The definitions of the project classes are as follows:

class Vertex : public p2_vertex<Common> {public:

unsigned EqNumber (Mesh const &) const ;bool IsOnBoundary(Mesh const &) const ;

} ;

class Edge : public p2_edge<Common> {public:

unsigned EqNumber (Mesh const &) const ;bool IsOnBoundary(Mesh const &) const ;

} ;

class Triangle : public p2_poly<Common> {public:

void eval_JJT(double[2][2], double &) const ;double eval_int_f(unsigned, pFun, double const &) const ;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 121

double eval_int_grad(unsigned, unsigned,double const [2][2], double const &) const ;

bool IsOnBoundary(Mesh const &, unsigned) const ;} ;

class Mesh : public p2_mesh<Common> {} ;

In conforming quadratic finite element on triangles, a finite element nodecan be identified by either a mesh vertex or the mid point of a mesh edge. Thus,both Vertex and Edge have the public method EqNumber, which returns the nodeinteger identifier in the global numbering system where the stiffness matrixand load vector assembly takes place.

As for the linear elements, a mesh triangle can be identified with an approx-imation element of the method, and the scope of Triangle contains the methodeval JJT, eval int f, eval int grad, which respectively evaluates the 2 × 2Jacobian of the mapping from this triangular element onto the reference trian-gle, the source term integral— f denoting the right hand side source functionin the Poisson equation—and the left hand side bilinear form of the discretevariational formulation of the approximate problem.

Vertex, Edge, and Triangle also have the public method IsOnBoundary whichreturns the boolean value true whenever their instances are boundary ones.For the sake of brevity, we do not report the P2MESH-based implementation ofthe foregoing mentioned methods. We just remark that it can be greatly simpli-fied, as shown in Bertolazzi and Manzini [1999d] by using the P2MESH mappingmethods from and onto either a triangle or a quadrilateral mesh element andthe reference one.

The design of the Elliptic Solver class in this case is very similar to the oneof the linear case, and thus, for brevity it is not shown.

3.1.0.2 Linear and quadratic elements on quadrilaterals. Analogous classdefinitions can be developed in the case of (bi)linear and quadratic elements onquadrilaterals. For the former ones, we may define the following set of projectclasses:

unsigned const size = 4 ;class Common : public p2_common<Vertex,Edge,Quad,Mesh,size> {} ;class Vertex : public p2_vertex<Common> {} ;class Edge : public p2_edge <Common> {} ;class Quad : public p2_poly <Common> {public:

double local_load_vector( unsigned i, double (*)(double,double)) ;double local_stiffness_matrix( unsigned i, unsigned j ) ;

} ;class Mesh : public p2_mesh<Common> {} ;

while for the latter ones, as in the case of linear elements on triangles, we canproceed by introducing the shape function definition within the common project

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

122 • E. Bertolazzi and G. Manzini

class Common; that is,

class Common : public p2_common<Vertex,Edge,Quad,Mesh,size> {protected:

static unsigned const degree_of_freedom = 9 ;

static void shape( unsigned nb,double const & s,double const & t,double & val ) ;

static void shape_grad( unsigned nb,double const & s,double const & t,double [2] ) ;

} ;

The implementation of the methods shape and shape grad is straightforward,see for the algorithm details Ciarlet [1987].

3.2 FVM Implementation for Conservation Laws

In this section we present a high-level abstraction with some implementa-tion details about a simple FVM scheme applied to a linear advection prob-lem. The FVM is based on an upwind numerical flux evaluation which is basi-cally first-order accurate in space; space accuracy can be increased by suitablenon-oscillatory techniques. The derivative in time is discretized by using aniterative multi-stage explicit Runge-Kutta scheme. The accuracy of the timestepping scheme depends on the number of stages and the Runge-Kutta coef-ficients. Generally, second and third-order accuracy can be easily reached. Adetailed description of these issues is beyond the scope of the present paper;hence, we refer the reader to the available literature, for instance, the textbookin reference Hirsch [1990].

As we are not interested in the algorithm, but rather in the way it may beimplemented by using P2MESH, we do not report the complete solver, but we ex-tract some pieces of the software to illustrate some programming issues. As forthe examples discussed in the previous section, we emphasize that the exam-ple we report here is not the unique way of using P2MESH to solve this problem,and perhaps neither the best nor the more effective one. It is just an exam-ple of how the P2MESH interface can be used in solving practical programmingproblems.

In order to show how the arithmetic type parameterization works in P2MESH,we introduce at the very beginning of the program the following type definitionto alias the built-in arithmetic type double by the dummy name Real.

typedef double Real ;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 123

The initial solution is linearly advected by a velocity field whose prototypesare

Real vx(Real x, Real y) ;Real vy(Real x, Real y) ;

We shall restrict to two different types of boundary conditions: Dirichlet andhomogeneous Neumann type. The former one consists of imposing the exter-nal solution by a suitable boundary value function bc value, whose prototypereads as

Real bc_value(Real x, Real y) ;

while the latter one of imposing a null flux through the boundary edge. Wewill suppose that the implementation of the previous three methods is givensomewhere in the program.

The boundary conditions may be specified as entries in an enum definitionwithin the project class Common. Again, the statement size=3 implies thatwe are considering a mesh of triangles. Also notice the input argument Realspecified in the template header declaration.

unsigned const size = 3 ;class Common : public p2_common<Vertex,Edge,Triangle,Mesh,

size,false,Real> {typedef enum {

BC_INTERNAL=0,BC_DIRICHLET,BC_HOMOGENEUOUS_NEUMANN

} BC ;} ;

The project class definitions for vertices, edges, and triangles, and for themesh follow.

class Vertex : public p2_vertex<Common> {} ;class Edge : public p2_edge<Common> {

friend class Triangle ;private:

BC bc_flag ;Real num_flux ;

public:void InternalNumFlux() ;void BoundaryNumFlux() ;

} ;class Triangle : public p2_poly<Common> {

friend class Edge ;private:

Real sol, sol0 ;public:

Real RK_Init() ;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

124 • E. Bertolazzi and G. Manzini

Real RK_Update(Real dt, unsigned RK_step) ;} ;class Mesh : public p2_mesh<Common> {} ;

Edge is provided with the methods InternalNumFlux and BoundaryNumFluxto compute the numerical flux across, respectively, an internal and a boundaryedge instance. The current value of the numerical flux is stored in the privateattribute num flux. The private attribute bc flag in the scope of Edge memo-rizes whether the edge is an internal one or, otherwise, its boundary type, andis set during the run initialization phase. The class Triangle has two solutionstate variables, sol0 and sol, which respectively store the cell-average solutionat the beginning of each Runge-Kutta time step and the current update at eachintermediate Runge-Kutta stage. The two methods perform the initialization ofa Runge-Kutta step, and update the solution by estimating the cell residual in-tegral. Finally, the class Mesh is simply the P2MESH mesh class whose definitionis inherited by public derivation.

For brevity we do not report the implementation of the Runge-Kutta meth-ods declared in the scope of Triangle, but we show a possible implementation ofthe internal and numerical flux methods declared with the class Edge. Noticethe usage of the topological method poly to recover the left and the rightsolution state, and the usage of the geometrical methods nx, ny, length, xm,and ym.

void Edge::InternalNumFlux() {Real vn = (vx(xm())*nx()+vy(ym())*ny())/length(); // normal velocityReal uL = poly(0) . sol ; // left state solutionReal uR = poly(1) . sol ; // right state solution// upwind fluxnum_flux = uL*( vn + abs(vn) ) / 2.0 + uR*( vn - abs(vn) ) / 2.0 ;}void Edge::BoundaryNumFlux() {switch ( bc_flag ) {case BC_DIRICHLET :

Real vn = vx(xm())*nx() + vy(ym())*ny() ;Real uL = poly(0) . sol ;Real uR = bc_value(xm(),ym()) ;num_flux = uL*( vn + abs(vn) ) / 2.0 + uR*( vn - abs(vn) ) / 2.0;break ;

case BC_HOMOGENEUOUS_NEUMANN :num_flux = 0.0 ;break ;

}}

Finally, we sketch the design of the class Solver.

class Solver : public Common {

private:

static void mark_edge(Edge & E, unsigned const & marker) ;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 125

Mesh mesh ; // the mesh object

Iterator<Edge> iedge, bedge ; // iterators on edges

Iterator<Triangle> triangle ; // iterator on triangles

Real max_CFL, final_time, current_time, dt ; // parameters of the run

unsigned RK_nstep ;

// ... other RK coefficients

public:

Solver() { // Solver constructor

// external mesh input and set up of the Mesh object mesh

mesh . read_mesh("my_input_mesh",NULL,mark_edge,NULL) ;

triangle . set_loop(mesh) ; // set up the triangle iterator

bedge . set_loop(mesh,1) ; // set up the boundary edge iterator

iedge . set_loop(mesh,2) ; // set up the internal edge iterator

// ... set up the other parameters of the run

// ... set the initial solution state

}

void RungeKuttaScheme() ;

// ... other stuff

} ;

The P2MESH mesh builder read mesh takes the project-defined static methodmark edge in input to process the markers assigned to the edges. In this case,edge markers are used to distinguish internal from boundary edges, and tospecify the boundary conditions of the latter.

void Solver::mark_edge(Edge & E, Unsigned const & marker) {switch ( marker ) {case 0 : E.ibc = BC_INTERNAL ; break ;case 1 : E.ibc = BC_SUPERSONIC_INLET ; break ;case 2 : E.ibc = BC_SOLID ; break ;case 3 : E.ibc = BC_FREE ; break ;default: cerr << "mark_edge( E, " << marker

<< ") bad boundary condition" << endl ;exit(0) ;

}}

Some private attributes, like max CFL, final time, current time and dt, arerun parameters to be set at the beginning of the calculation and to be updatedduring the run. The names are self explantory.

The instance mesh of the project class Mesh, which refers to the mesh dataset currently in use during the run of the program is, again, a private at-tribute of Solver. Among the other private attributes, we mention the threeiterators triangle, bedge and iedge (see also the comments within the source).These iterators are set up in the Solver constructor and used in the methodRungeKuttaScheme() to loop on mesh triangles and on internal and boundaryedges.

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

126 • E. Bertolazzi and G. Manzini

void Solver::RungeKuttaScheme() {// first stage of the Runge-Kutta time stepping schemeforeach ( triangle ) { triangle -> RK_Init() ; }

for ( k=0; k<RK_nstep; ++k ) { // loop on the multiple stagesforeach ( bedge ) bedge -> BoundaryNumFlux() ;foreach ( iedge ) iedge -> InternalNumFlux() ;foreach ( triangle ) triangle -> RK_Update( dt, k ) ;

}}

3.3 A Domain-Decomposition Example

The example that we discuss in this section concerns the implementation of adomain-decomposition method for elliptic problems. The computational domainis divided into a set of sub-domains. Within each sub-domain an elliptic prob-lem is defined and solved by using, for example, one of the elliptic solvers whoseimplementation has been discussed above. Then, the internal sub-domain so-lutions restricted at the interface edges are compared and matched by solv-ing an appropriate interface problem whose discrete formulation depends onthe domain decomposition technique adopted. The current interface solution isthen used to set up new boundary conditions for the elliptic problem of eachsub-domain. The method iterates this way until convergence of the interfacesolution is reached. The possibility of managing (handling) more than one meshat a time in the same code, as supported by P2MESH, can be easily exploited todefine a higher level mesh whose “cells” are in fact the “sub-domains” of theactual computational domain.

We shall call this higher level mesh HyperMesh. The computational domainis covered by a HyperMesh instance, which is formed by ndx × ndy rectangularsub-domains. Its edges are objects of type InterfaceEdge and its vertices of typeCrossPoints.

In this section we present the main issues regarding the design of theseproject classes, without giving in-depth details about the final program imple-mentation and its performances. We refer the reader interested in this topic toBertoluzza and Manzini [2001].

unsigned const hsize=4 ; // HyperMesh is formed by quadrilaterals

class HyperMeshCommon :

public p2_common<CrossPoint,InterfaceEdge,SubDomain,HyperMesh,hsize> {} ;

class CrossPoint : public p2_vertex<HyperMeshCommon> {

public:

// ... methods to treat the cross point solution

} ;

class InterfaceEdge : public p2_edge <HyperMeshCommon> {

// ... methods to solve the interface problem

// ... between domains by matching the adjacent

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 127

// ... domain solutions on a set of interface nodes

} ;

class SubDomain : public p2_poly <HyperMeshCommon> {

public:

Elliptic_Solver * psolver ;

void set_up( Elliptic_Solver * _psolver ) { psolver = _psolver ; }

// ... other stuff

} ;

class HyperMesh : public p2_mesh<HyperMeshCommon> {

private:

unsigned ndx ; // number of sub-domain partitionings in x

unsigned ndy ; // number of sub-domain partitionings in y

unsigned ni ; // number of nodes along each interface edge

Iterators<SubDomain> subdomain ;

public:

HyperMesh( int _ndx, int _ndy, int _ni, Elliptic_Solver * _psolver ) :

ndx(_ndx), ndy(_ndy), ni(_ni) {

// init hypermesh by using the P2MESH mesh builder

std_tensor_mesh(ndx,ndy,NULL,NULL,NULL,0) ;

// set up the subdomain iterator

subdomain . set_loop(*this) ;

// initialize the sub domain Elliptic solver

foreach ( subdomain ) { subdomain -> set_up( _psolver ) ;

// other initialization stuff

} ;

// ...

} ;

An object of the class SubDomain contains the pointer to an instance of theclass Elliptic Solver. The object of type HyperMesh is then responsible forinitializing itself and each subdomain solver.

We then have to define a class Interface Solver—that we do not present—which can rely on P2MESH facilities to manipulate objects of the previously de-fined project classes.

We remark that in the same program P2MESH is able to manage boththe quadrilateral domain-decomposition grid of type HyperMesh, namelyhyper mesh, and the triangle-based Mesh instance mesh, which is the compu-tational mesh used within each subdomain.

# include "p2mesh.hh" // p2mesh interface file# include "mesh.hh" // mesh def.s for the sub-domain

elliptic solver

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

128 • E. Bertolazzi and G. Manzini

Fig. 3. Wall impact: sketch of the problem.

# include "hyper_mesh.hh" // hyper mesh def.smain() {

// instantiate an elliptic solverElliptic_Solver solver ;

unsigned ndx = ndy = 10 ; // a 10x10 domain partitioningunsigned ni = 100 ; // 100 interface nodes for the

interface pblm

// instantiate the mesh partitioningsHyperMesh hyper_mesh( ndx, ndy, ni, &solver ) ;

// ... rest of implementation ...}

3.4 An Evolutive Problem with Remeshing of the Computational Domain

As the last example, we illustrate the numerical modeling of the water impacton a wall. We will not show details about the source implementation of thesimulation code, but only the effect of using P2MESH on the total CPU costs of asimulation run. We feel that this example is particularly significant because thetime advancing strategy of the unsteady solution requires a full remeshing ofthe computational domain at every time step. The impact phenomenon is mod-elled in two dimensions by a fully non-linear potential approach, which involvesthe resolution of the coupling interaction among the potential flow equation,the Bernoulli’s equation and the free surface equation. Figure 3 depicts thetypical situation. The computational domain is the 2-D region enclosed by theunsteady free surface boundary, the impermeable bed and the impact wall. Atevery time-step, the solution algorithm requires:

(i) a complete re-meshing of the computational domain by using the meshgenerator Triangle;

(ii) the approximate solution of the potential flow equation by a conformingquadratic FEM;

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 129

Fig. 4. Wall impact: grid history.

Table I. Wall Impact: Average CostDistribution per Time Step

Code Module %mesh generation 3mesh initialization 2stiffness matrix evaluation 13linear algebra solver (PCG) 82

(iii) the updating of the domain shape by evolving in time the free surfaceboundary;

(iv) the updating of the free surface potential solution by solving the Bernoulli’sequation.

The approximation strategy proposed in Trivellato and Bertolazzi [2001] tracesthe pathlines of the mesh nodes on the free surface. The updated potential so-lution generated at step (iv) is then used as the boundary condition to solve thepotential problem in step (ii) at the new time-step within the computationaldomain updated in step (iii). In Figure 4 a typical grid history for a simulationrun is sketched. The percentage CPU costs of the more expensive computationsperformed at each time step by the code in a typical case study are reported inTable I. The costs not mentioned are negligible. The use of P2MESH has a verylow impact on the total cost of the computation, whose greatest contributionsare due to the evaluation of the stiffness matrix of the potential equation. Thematrix is considered in unlumped form and the related linear problem solvedby the conjugate gradient method preconditioned by an incomplete LU factor-ization [Barrett et al. 1994].

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

130 • E. Bertolazzi and G. Manzini

4. CONCLUSION

In this paper we presented P2MESH, a generic object-oriented interface softwareespecially designed as a building block in the development and implementationof PDE solvers on 2-D unstructured meshes. One of the most important featuresof P2MESH regards the non-procedural nature of this programming model. In thisrespect, OO programming techniques turn out to be quite effective; in fact, theyare versatile in the description of data abstractions and helpful in isolating thedata structure design from the implementation. All relevant information tobe represented and manipulated by a PDE solver implemented using P2MESH,such as geometrical quantities, physical unknowns, and auxiliary dependentvariables, are logically associated to an elementary mesh entity, namely a vertex,an edge, or a polygon (triangular or quadrilateral). The mesh data set originatedby a mesh generator is referred to by an object of a user-defined mesh classthat contains the references to suitable mesh vertices, edges, and elements (orcells). The latter ones are defined by extending the base definitions provided inthe corresponding P2MESH classes with attributes and methods specific to thecurrent model problem and application.

An enhanced version featuring both the dynamic memory management andthe mesh refinement primitives is in progress. We are also planning a 3-Dextension.

ACKNOWLEDGMENTS

We thank (in alphabetical order) Dr. Mario Arioli, Dr. Antonio Cazzani,Dr. Loula Fezoui, Prof. Bruno Firmani, Dr. Luca Formaggia, Dr. AlessandroRusso, Prof. Gianni Sacchi, Prof. Filippo Trivellato and Dr. Gianluigi Zanettifor their interest on P2MESH. We would like to address special thanks to Prof.Bruce Simpson, Dr. J.-Daniel Boissonat and all the team of the project Prismeat INRIA, Sophia-Antipolis, France, for the opportunity they gave us to presentthe work for the first time. Finally, we would like to thank the anonymous re-viewers for their comments and suggestions that greatly helped us in improvingthe layout and the readability of the paper.

REFERENCES

BARRETT, R., BERRY, M., CHAN, T. F., DEMMEL, J., DONATO, J., DONGARRA, J., EIJKHOUT, V., POZO, R.,ROMINE, C., AND DER VORST, H. V. 1994. Templates for the Solution of Linear Systems: BuildingBlocks for Iterative Methods, 2nd Edition. SIAM, Philadelphia, PA.

BARTON, J. J. AND NACKMAN, L. R. 1994. Scientific and Engineering C++. Addison-Wesley.BASTIAN, P., BIRKEN, K., JOHANNSEN, K., LANG, S., NEUSS, N., RENTZ-REICHERT, H., AND WIENERS, C.

1997. UG—A flexible software toolbox for solving partial differential equations. Computingand Visualization in Science 1, 27–40. http://cox.iwr.uni-heidelberg.de/∼ug/

BECK, R., ERDMANN, B., AND ROITZSCH, R. 1995. KASKADE 3.0 an object-oriented adaptivefinite element code. Tech. Rep. TR–95–4, Konrad–Zuse–Zentrum fur Informationstecknik,Berlin. http://www.zib.de/SciSoft/kaskade/

BERTOLAZZI, E. AND MANZINI, G. 1999a. The kernel of P2MESH. Tech. Rep. IAN–1166, IAN–CNR.BERTOLAZZI, E. AND MANZINI, G. 1999b. The P2MESH Home Page. http://www.ing.unitn.

it/∼bertolaz/p2mesh/index.htmlBERTOLAZZI, E. AND MANZINI, G. 1999c. P2MESH: Programmer’s manual. Tech. Rep. IAN–1164,

IAN–CNR.

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.

Generic OO Interface Between Unstructured Meshes and PDE Solvers • 131

BERTOLAZZI, E. AND MANZINI, G. 1999d. P2MESH: programming finite element and finite volumemethods. Tech. Rep. IAN–1165, IAN–CNR.

BERTOLAZZI, E. AND MANZINI, G. 1999e. P2MESH: Short reference guide. Tech. Rep. IAN–1167,IAN–CNR.

BERTOLUZZA, S. AND MANZINI, G. 2001. The wavelet stabilization of the three fields method: imple-mentation and numerical test. SIAM, Scientific Computing (SISC).

BERZINS, M., FAIRLIE, R., PENNINGTON, S. V., WARE, J. M., AND SCALES, L. E. 1998. SPRINT2D:adaptive software for PDEs. ACM Trans. Math. Soft. 24, 4, 475–499. http://www.scs.leeds.ac.uk/cpde/software.html

BRUASET, A. M. AND LANGTANGEN, H. P. 1996. A comprehensive set of tools for solving partial differ-ential equations; Diffpack. In Numerical Methods and Software Tools in Industrial Mathematics,M. Daehlen and A. Tveito, Eds. Birkauser. http://www.nobjects.com/Diffpack

CIARLET, P. 1987. The Finite Element Methods for Elliptic Problems. North-Holland.FURNISH, G. 1997. Disambiguate glommable expression templates. Comput. Phys. 11, 3, 263–269.FURNISH, G. 1998. Container-free numerical algorithms in C++. Comput. Phys. 12, 3, 258–265.GEORGE, P. L. 1991. Automatic Mesh Generation. Application to Finite Element Methods. John

Wiley & Sons.GEORGE, P. L. 1996. Automatic mesh generation and finite element computation. In Handbook

of Numerical Analysis, P. Ciarlet and J. Lions, Eds. Vol. IV. North-Holland.HIRSCH, C. 1990. Numerical Computation of Internal and External Flows. J. Wiley & Sons Ltd.,

Baffins Lane, Chichester, West Sussex PO19 1UD, England.HOARE, C. A. R. 1962. Quicksort. Comput. J. 5, 10–15.KNUTH, D. E. 1998. The Art of Computer Programming—Sorting and Searching, second ed. Vol. 3.

Addison-Wesley.MCKENNA, F. T. 1997. Object-oriented finite element programming: frameworks for analysis,

algorithms and parallel computing. Ph.D. dissertation, University of California, Berkeley.MUSSER, D. AND SAINI, A. 1996. STL Tutorial & Reference Guide: C++ Programming with the

Standard Template Library. Addison-Wesley.RICE, J. R. AND BOISVERT, R. F. 1984. Solving Elliptic Problems Using ELLPACK. Springer Verlag.SHEWCHUK, J. R. 1996. A two-dimensional quality mesh generator and delaunay triangulator.http://www.cs.cmu.edu/afs/cs.cmu.edu/project/quake/public/www/triangle.html

STROUSTRUP, B. 1998. The C++ Programming Language (third edition). Addison-Wesley.TRIVELLATO, F. AND BERTOLAZZI, E. 2001. Potential flow modeling of bore impact. Advances in Water

Resources.VANKEIRSBILCK, P. AND NELISSEN, G. 1994. ELEMD: An object-oriented software system for grid

elements with multiple discretizations for solving PDEs. In Second Annual Object-OrientedNumerics Conference, S. editor, Ed. SIAM, Sunriver, Oregon.

VELDHUIZEN, T. L. 1999. The Blitz++ Home Page. http://oonumerics.org/blitz/

Received January 2000; revised May 2001; accepted March 2002

ACM Transactions on Mathematical Software, Vol. 28, No. 1, March 2002.