From 88321527c28d65831448887c9e6ade3611307ee2 Mon Sep 17 00:00:00 2001
From: Christophe Geuzaine <cgeuzaine@ulg.ac.be>
Date: Sun, 7 Dec 2003 05:37:00 +0000
Subject: [PATCH] New MSH file format, version 2.0.

********************************************************
************ Please send me your comments **************
********************************************************
---
 Common/Context.h        |   1 +
 Common/DefaultOptions.h |   2 +
 Common/Options.cpp      |   9 ++-
 Common/Options.h        |   1 +
 Fltk/Callbacks.cpp      |  22 ++++++-
 Mesh/Print_Mesh.cpp     |  73 +++++++++++----------
 Mesh/Read_Mesh.cpp      |  48 ++++++++++++--
 doc/VERSIONS            |   3 +-
 doc/texinfo/gmsh.texi   | 141 +++++++++++++++++++++++++++++++++++++---
 9 files changed, 244 insertions(+), 56 deletions(-)

diff --git a/Common/Context.h b/Common/Context.h
index a4f2afafde..3fb143eb4d 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -150,6 +150,7 @@ public :
 
   // mesh options 
   struct {
+    double msh_file_version;
     int vis_type, changed, display_lists;
     int draw;
     int points, lines, surfaces, volumes;
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 891a6d366a..b40e9a9fc1 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -746,6 +746,8 @@ StringXNumber MeshOptions_Number[] = {
 
   { F|O, "MinimumCirclePoints" , opt_mesh_min_circ_points, 7. ,
     "Minimum number of points used to mesh a circle" },
+  { F|O, "MshFileVersion" , opt_mesh_msh_file_version , 1.0 , 
+    "MSH mesh file version to generate" },
 
   { F, "NbHexahedra" , opt_mesh_nb_hexahedra , 0. , 
     "Number of hexahedra in the current mesh" },
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 3095d2e9bb..c9927ccc09 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.127 2003-12-07 00:23:06 geuzaine Exp $
+// $Id: Options.cpp,v 1.128 2003-12-07 05:37:00 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -3243,6 +3243,13 @@ double opt_mesh_format(OPT_ARGS_NUM)
   return CTX.mesh.format;
 }
 
+double opt_mesh_msh_file_version(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX.mesh.msh_file_version = val;
+  return CTX.mesh.msh_file_version;
+}
+
 double opt_mesh_nb_smoothing(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index c7e6c56317..a6344fff1d 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -354,6 +354,7 @@ double opt_mesh_line_width(OPT_ARGS_NUM);
 double opt_mesh_line_type(OPT_ARGS_NUM);
 double opt_mesh_aspect(OPT_ARGS_NUM);
 double opt_mesh_format(OPT_ARGS_NUM);
+double opt_mesh_msh_file_version(OPT_ARGS_NUM);
 double opt_mesh_nb_smoothing(OPT_ARGS_NUM);
 double opt_mesh_algo(OPT_ARGS_NUM);
 double opt_mesh_point_insertion(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 1422f978f9..c715f14ac7 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.196 2003-12-07 00:23:07 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.197 2003-12-07 05:37:00 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -439,6 +439,20 @@ void _save_msh_all(char *name)
   CreateOutputFile(name, CTX.mesh.format = FORMAT_MSH);
   CTX.mesh.save_all = all;
 }
+void _save_msh_v2(char *name)
+{
+  double ver = CTX.mesh.msh_file_version;
+  CTX.mesh.msh_file_version = 2.0;
+  _save_msh(name);
+  CTX.mesh.msh_file_version = ver;
+}
+void _save_msh_all_v2(char *name)
+{
+  double ver = CTX.mesh.msh_file_version;
+  CTX.mesh.msh_file_version = 2.0;
+  _save_msh_all(name);
+  CTX.mesh.msh_file_version = ver;
+}
 void _save_gref(char *name)
 {
   CreateOutputFile(name, CTX.mesh.format = FORMAT_GREF);
@@ -608,8 +622,10 @@ void file_save_as_cb(CALLBACK_ARGS)
     {"By extension (*)", _save_auto},
     {"Gmsh options (*.opt)", _save_geo_options},
     {"Gmsh unrolled geometry (*.geo)", _save_geo},
-    {"Gmsh mesh (*.msh)", _save_msh},
-    {"Gmsh mesh without physicals (*.msh)", _save_msh_all},
+    {"Gmsh mesh v1.0 (*.msh)", _save_msh},
+    {"Gmsh mesh v1.0 without physicals (*.msh)", _save_msh_all},
+    {"Gmsh mesh v2.0 (*.msh)", _save_msh_v2},
+    {"Gmsh mesh v2.0 without physicals (*.msh)", _save_msh_all_v2},
     {"GREF mesh (*.gref)", _save_gref},
     {"I-DEAS universal mesh format (*.unv)", _save_unv},
     {"VRML surface mesh (*.wrl)", _save_vrml},
diff --git a/Mesh/Print_Mesh.cpp b/Mesh/Print_Mesh.cpp
index 511770ca99..44e9af5b81 100644
--- a/Mesh/Print_Mesh.cpp
+++ b/Mesh/Print_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Print_Mesh.cpp,v 1.45 2003-12-07 02:56:34 geuzaine Exp $
+// $Id: Print_Mesh.cpp,v 1.46 2003-12-07 05:37:00 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -49,7 +49,6 @@ static FILE *meshfile;
 #define PYRAMID_2      14
 #define POINT          15
 
-static double MSH_VERSION = 1.0;
 static int MSH_VOL_NUM, MSH_SUR_NUM, MSH_LIN_NUM;
 static int MSH_NODE_NUM, MSH_ELEMENT_NUM, MSH_3D, MSH_ADD;
 static int MSH_PHYSICAL_NUM, MSH_PHYSICAL_ORI;
@@ -90,16 +89,16 @@ void process_msh_nodes(Mesh * M)
 
   MSH_NODE_NUM = Tree_Nbr(M->Vertices);
 
-  if(MSH_VERSION > 1.0)
+  if(CTX.mesh.msh_file_version == 2.0)
     fprintf(meshfile, "$Nodes\n");
   else
     fprintf(meshfile, "$NOD\n");
   fprintf(meshfile, "%d\n", MSH_NODE_NUM);
   Tree_Action(M->Vertices, print_msh_node);
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "$ENDNOD\n");
-  else
+  if(CTX.mesh.msh_file_version == 2.0)
     fprintf(meshfile, "$EndNodes\n");
+  else
+    fprintf(meshfile, "$ENDNOD\n");
 }
 
 void print_msh_simplex(void *a, void *b)
@@ -168,11 +167,10 @@ void print_msh_simplex(void *a, void *b)
     }
   }
 
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "%d %d %d %d 0 %d",
-	    MSH_ELEMENT_NUM++, type,
-	    MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*S)->iEnt, (*S)->iEnt,
-	    nbn + nbs);
+  if(CTX.mesh.msh_file_version == 2.0)
+    fprintf(meshfile, "%d %d 2 %d %d",
+	    MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*S)->iEnt, 
+	    (*S)->iEnt);
   else
     fprintf(meshfile, "%d %d %d %d %d",
 	    MSH_ELEMENT_NUM++, type,
@@ -218,11 +216,10 @@ void print_msh_hexahedron(void *a, void *b)
   else
     type = HEXAHEDRON;
 
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "%d %d %d %d 0 %d",
-	    MSH_ELEMENT_NUM++, type,
-	    MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*H)->iEnt, (*H)->iEnt,
-	    nbn + nbs);
+  if(CTX.mesh.msh_file_version == 2.0)
+    fprintf(meshfile, "%d %d 2 %d %d",
+	    MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*H)->iEnt,
+	    (*H)->iEnt);
   else
     fprintf(meshfile, "%d %d %d %d %d",
 	    MSH_ELEMENT_NUM++, type,
@@ -261,11 +258,10 @@ void print_msh_prism(void *a, void *b)
     type = PRISM;
   }
 
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "%d %d %d %d 0 %d",
-	    MSH_ELEMENT_NUM++, type,
-	    MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*P)->iEnt, (*P)->iEnt,
-	    nbn + nbs);
+  if(CTX.mesh.msh_file_version == 2.0)
+    fprintf(meshfile, "%d %d 2 %d %d",
+	    MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*P)->iEnt,
+	    (*P)->iEnt);
   else
     fprintf(meshfile, "%d %d %d %d %d",
 	    MSH_ELEMENT_NUM++, type,
@@ -304,11 +300,10 @@ void print_msh_pyramid(void *a, void *b)
     type = PYRAMID;
   }
 
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "%d %d %d %d 0 %d",
-	    MSH_ELEMENT_NUM++, type,
-	    MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*P)->iEnt, (*P)->iEnt,
-	    nbn + nbs);
+  if(CTX.mesh.msh_file_version == 2.0)
+    fprintf(meshfile, "%d %d 2 %d %d",
+	    MSH_ELEMENT_NUM++, type, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : (*P)->iEnt,
+	    (*P)->iEnt);
   else
     fprintf(meshfile, "%d %d %d %d %d",
 	    MSH_ELEMENT_NUM++, type,
@@ -330,10 +325,10 @@ void print_msh_point(Vertex * V)
     return;
   }
 
-  if(MSH_VERSION > 1.0)
-    fprintf(meshfile, "%d %d %d %d 0 1 %d\n",
-	    MSH_ELEMENT_NUM++, POINT,
-	    MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : V->Num, V->Num, V->Num);
+  if(CTX.mesh.msh_file_version == 2.0)
+    fprintf(meshfile, "%d %d 2 %d %d %d\n",
+	    MSH_ELEMENT_NUM++, POINT, MSH_PHYSICAL_NUM ? MSH_PHYSICAL_NUM : V->Num, V->Num,
+	    V->Num);
   else
     fprintf(meshfile, "%d %d %d %d 1 %d\n",
 	    MSH_ELEMENT_NUM++, POINT,
@@ -502,7 +497,7 @@ void process_msh_elements(Mesh * M)
   else
     print_msh_elements(M);
 
-  if(MSH_VERSION > 1.0)
+  if(CTX.mesh.msh_file_version == 2.0)
     fprintf(meshfile, "$Elements\n");
   else
     fprintf(meshfile, "$ELM\n");
@@ -519,7 +514,7 @@ void process_msh_elements(Mesh * M)
   else
     print_msh_elements(M);
 
-  if(MSH_VERSION > 1.0)
+  if(CTX.mesh.msh_file_version == 2.0)
     fprintf(meshfile, "$EndElements\n");
   else
     fprintf(meshfile, "$ENDELM\n");
@@ -1399,12 +1394,20 @@ void Print_Mesh(Mesh * M, char *c, int Type)
 
   switch(Type){
   case FORMAT_MSH:
-    MSH_VERSION = 0.0;
-    if(MSH_VERSION > 1.0){
+    if(CTX.mesh.msh_file_version == 1.0){
+      // OK, no header
+    }
+    else if(CTX.mesh.msh_file_version == 2.0){
       fprintf(meshfile, "$MeshFormat\n");
-      fprintf(meshfile, "%g %d %d\n", MSH_VERSION, LIST_FORMAT_ASCII, sizeof(double));
+      fprintf(meshfile, "%g %d %d\n", CTX.mesh.msh_file_version,
+	      LIST_FORMAT_ASCII, sizeof(double));
       fprintf(meshfile, "$EndMeshFormat\n");
     }
+    else{
+      Msg(GERROR, "Unknown MSH file version to generate (%g)", 
+	  CTX.mesh.msh_file_version);
+      return;
+    }
     process_msh_nodes(M);
     process_msh_elements(M);
     Msg(INFO, "%d nodes", MSH_NODE_NUM);
diff --git a/Mesh/Read_Mesh.cpp b/Mesh/Read_Mesh.cpp
index 002cde66aa..6dcdd86787 100644
--- a/Mesh/Read_Mesh.cpp
+++ b/Mesh/Read_Mesh.cpp
@@ -1,4 +1,4 @@
-// $Id: Read_Mesh.cpp,v 1.61 2003-12-07 02:56:34 geuzaine Exp $
+// $Id: Read_Mesh.cpp,v 1.62 2003-12-07 05:37:00 geuzaine Exp $
 //
 // Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 //
@@ -93,6 +93,7 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
   int format = LIST_FORMAT_ASCII, size = sizeof(double);
   int Nbr_Nodes, Nbr_Elements, i_Node, i_Element;
   int Num, Type, Physical, Elementary, Partition, i, j;
+  int NbTags, Tag;
   double x, y, z, lc1, lc2;
   Vertex *vert, verts[NB_NOD_MAX_ELM], *vertsp[NB_NOD_MAX_ELM], **vertspp;
   Simplex *simp;
@@ -118,7 +119,15 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
 
     if(!strncmp(&String[1], "MeshFormat", 10)) {
       fscanf(fp, "%lf %d %d\n", &version, &format, &size);
-      Msg(INFO, "Detected mesh file format %g", version);
+
+      if(version == 2.0){
+	Msg(INFO, "Detected mesh file format %g", version);
+      }
+      else{
+	Msg(GERROR, "Unknown MSH file version to read (%g)", version);
+	return;
+      }
+
       if(format == 0)
         format = LIST_FORMAT_ASCII;
       else if(format == 1)
@@ -129,7 +138,7 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
       }
     }
 
-    /*  P T S  */
+    /*  POINTS -- this field is deprecated, and will eventually disappear */
 
     if(!strncmp(&String[1], "PTS", 3) ||
        !strncmp(&String[1], "Points", 6)) {
@@ -148,7 +157,7 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
       }
     }
 
-    /*  N O E  */
+    /*  NODES  */
 
     if(!strncmp(&String[1], "NOD", 3) ||
        !strncmp(&String[1], "NOE", 3) ||
@@ -197,8 +206,35 @@ void Read_Mesh_MSH(Mesh * M, FILE * fp)
 	  Partition = Physical;
 	}
 	else{
-	  fscanf(fp, "%d %d %d %d %d %d",
-		 &Num, &Type, &Physical, &Elementary, &Partition, &Nbr_Nodes);
+	  fscanf(fp, "%d %d %d", &Num, &Type, &NbTags);
+	  Elementary = Physical = Partition = 1;
+	  for(j = 0; j < NbTags; j++){
+	    fscanf(fp, "%d", &Tag);	    
+	    if(j == 0)
+	      Physical = Tag;
+	    else if(j == 1)
+	      Elementary = Tag;
+	    else if(j == 2)
+	      Partition = Tag;
+	    // ignore any other tags for now
+	  }
+	  switch (Type) {
+	  case PNT : Nbr_Nodes = 1; break;
+	  case LGN1: Nbr_Nodes = 2; break;
+	  case LGN2: Nbr_Nodes = 3; break;
+	  case TRI1: Nbr_Nodes = 3; break;
+	  case TRI2: Nbr_Nodes = 6; break;
+	  case QUA1: Nbr_Nodes = 4; break;
+	  case QUA2: Nbr_Nodes = 8; break;
+	  case TET1: Nbr_Nodes = 4; break;
+	  case TET2: Nbr_Nodes = 10; break;
+	  case HEX1: Nbr_Nodes = 8; break;
+	  case HEX2: Nbr_Nodes = 20; break;
+	  case PRI1: Nbr_Nodes = 6; break;
+	  case PRI2: Nbr_Nodes = 15; break;
+	  case PYR1: Nbr_Nodes = 5; break;
+	  case PYR2: Nbr_Nodes = 13; break;
+	  }
 	}
 
         for(j = 0; j < Nbr_Nodes; j++)
diff --git a/doc/VERSIONS b/doc/VERSIONS
index b5bb0c9ad0..6247816d16 100644
--- a/doc/VERSIONS
+++ b/doc/VERSIONS
@@ -1,6 +1,7 @@
-$Id: VERSIONS,v 1.176 2003-12-07 00:29:47 geuzaine Exp $
+$Id: VERSIONS,v 1.177 2003-12-07 05:37:00 geuzaine Exp $
 
 New in 1.51: initial support for visualizing mesh partitions;
+integrated version 2.0 of the MSH mesh file format;
 
 New in 1.50: small changes to the visibility browser + made visibility
 scriptable (new Show/Hide commands); fixed (rare) crash when deleting
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index 395027a640..8d5c443129 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -1,5 +1,5 @@
 \input texinfo.tex @c -*-texinfo-*-
-@c $Id: gmsh.texi,v 1.91 2003-12-04 18:24:50 geuzaine Exp $
+@c $Id: gmsh.texi,v 1.92 2003-12-07 05:37:00 geuzaine Exp $
 @c
 @c Copyright (C) 1997-2003 C. Geuzaine, J.-F. Remacle
 @c
@@ -235,6 +235,11 @@ File formats
 * Gmsh parsed post-processing file format::  
 * Gmsh node ordering::          
 
+Gmsh mesh file format
+
+* Version 1.0::                 
+* Version 2.0::                 
+
 Bugs, versions and credits
 
 * Bugs::                        
@@ -2605,9 +2610,24 @@ All non-parsed file formats have sections enclosed between @code{$KEY} and
 @cindex File format, mesh
 @cindex @file{.msh} file
 
-The @file{.msh} file format is Gmsh's native mesh file format. The file is
-divided in two sections, defining the nodes (@code{$NOD}-@code{$ENDNOD}) and
-the elements (@code{$ELM}-@code{$ENDELM}) in the mesh:
+@menu
+* Version 1.0::                 
+* Version 2.0::                 
+@end menu
+
+@c .........................................................................
+@c Version 1.0
+@c .........................................................................
+
+@node Version 1.0, Version 2.0, Gmsh mesh file format, Gmsh mesh file format
+@subsection Version 1.0
+
+The @file{.msh} file format, version 1.0, is Gmsh's old native mesh file
+format, now superseeded by the format described in @ref{Version 2.0}.
+
+In the @file{.msh} file format, version 1.0, the file is divided in two
+sections, defining the nodes (@code{$NOD}-@code{$ENDNOD}) and the elements
+(@code{$ELM}-@code{$ENDELM}) in the mesh:
 
 @example
 $NOD
@@ -2626,7 +2646,7 @@ $ENDELM
 where
 @table @code
 @item @var{number-of-nodes}
-is the number of nodes in the mesh
+is the number of nodes in the mesh.
 
 @item @var{node-number}
 is the number (index) of the @var{n}-th node in the mesh. Note that the
@@ -2638,7 +2658,7 @@ are the floating point values giving the X, Y and Z coordinates of the
 @var{n}-th node.
 
 @item @var{number-of-elements}
-is the number of elements in the mesh
+is the number of elements in the mesh.
 
 @item @var{elm-number}
 is the number (index) of the @var{n}-th element in the mesh. Note that the
@@ -2674,15 +2694,116 @@ is the number of the elementary entity to which the element belongs.
 
 @item @var{number-of-nodes}
 is the number of nodes for the @var{n}-th element. This is redundant, but
-kept for backward compatibility. The redundancy may disappear in the future
-if higher order elements are implemented using the same @w{@var{elm-type}s}
-as the current ones.
+kept for backward compatibility.
 
 @item @var{node-number-list}
 is the list of the @var{number-of-nodes} node numbers of the @var{n}-th
 element (separated by white space, without commas).
 @end table
 
+@c .........................................................................
+@c Version 2.0
+@c .........................................................................
+
+@node Version 2.0,  , Version 1.0, Gmsh mesh file format
+@subsection Version 2.0
+
+The version 2.0 of the @file{.msh} file format is the Gmsh's new native mesh
+file format. It will eventually become the new default mesh format generated
+by Gmsh. This new format is very similar to the old one, but is more
+general: it contains information about itself and allows to attach an
+arbitrary number of tags to each element.
+
+The @file{.msh} file format, version 2.0, is divided in three sections,
+defining the file format (@code{$MeshFormat}-@code{$EndMeshFormat}), the
+nodes (@code{$Nodes}-@code{$EndNodes}) and the elements
+(@code{$Elements}-@code{$EndElements}) in the mesh:
+
+@example
+$MeshFormat
+2.0 @var{file-type} @var{data-size}
+$EndMeshFormat
+$Nodes
+@var{number-of-nodes}
+@var{node-number} @var{x-coord} @var{y-coord} @var{z-coord}
+@dots{}
+$EndNodes
+$Elements
+@var{number-of-elements}
+@var{elm-number} @var{elm-type} @var{number-of-tags} < @var{tag} > @dots{} @var{node-number-list}
+@dots{}
+$EndElements
+@end example
+
+@noindent
+where
+@table @code
+@item @var{file-type}
+is an integer equal to 0 in the ASCII file format.
+
+@item @var{data-size}
+is an integer equal to the size of the floating point numbers used in the
+file (usually, @var{data-size} = sizeof(double)).
+
+@item @var{number-of-nodes}
+is the number of nodes in the mesh.
+
+@item @var{node-number}
+is the number (index) of the @var{n}-th node in the mesh. Note that the
+@w{@var{node-number}s} do not have to be given in a consecutive (or even an
+ordered) way.
+
+@item @var{x-coord} @var{y-coord} @var{z-coord}
+are the floating point values giving the X, Y and Z coordinates of the
+@var{n}-th node.
+
+@item @var{number-of-elements}
+is the number of elements in the mesh.
+
+@item @var{elm-number}
+is the number (index) of the @var{n}-th element in the mesh. Note that the
+@w{@var{elm-number}s} do not have to be given in a consecutive (or even an
+ordered) way.
+
+@item @var{elm-type}
+defines the geometrical type of the @var{n}-th element:
+@table @code
+@item 1
+Line (2 nodes, 1 edge).
+@item 2
+Triangle (3 nodes, 3 edges).
+@item 3
+Quadrangle (4 nodes, 4 edges).
+@item 4
+Tetrahedron (4 nodes, 6 edges, 4 faces).
+@item 5
+Hexahedron (8 nodes, 12 edges, 6 faces).
+@item 6
+Prism (6 nodes, 9 edges, 5 faces).
+@item 7
+Pyramid (5 nodes, 8 edges, 5 faces).
+@item 15
+Point (1 node).
+@end table
+
+@item @var{number-of-tags}
+gives the number of (integer) tags for the @var{n}-th element. By default,
+Gmsh generates meshes with two tags, but can read files with an arbitrary
+number of tags (and currently only interprets the three first ones: see
+below).
+
+@item @var{tag}
+is an integer tag associated with the @var{n}-th element. By default, the
+first tag is the number of the physical entity to which the element belongs;
+the second tag is the number of the elementary geometrical entity to which
+the element belongs; the third tag is the number of a mesh partition to
+which the element belongs.
+
+@item @var{node-number-list}
+is the list of the node numbers of the @var{n}-th element (separated by
+white space, without commas).
+@end table
+
 @c -------------------------------------------------------------------------
 @c Gmsh ASCII post-processing file format
 @c -------------------------------------------------------------------------
@@ -2752,7 +2873,7 @@ is an integer equal to 0 in the ASCII file format.
 
 @item @var{data-size}
 is an integer equal to the size of the floating point numbers used in the
-file (usually, data-size = sizeof(double)).
+file (usually, @var{data-size} = sizeof(double)).
 
 @item @var{view-name}
 is a string containing the name of the view (max. 256 characters).
-- 
GitLab