diff --git a/arcane/tools/GeometricGenerationScriban/GeomShapeInfos.cs b/arcane/tools/GeometricGenerationScriban/GeomShapeInfos.cs
new file mode 100644
index 000000000..d15a6be30
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/GeomShapeInfos.cs
@@ -0,0 +1,128 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace GeometricGenerationScriban
+{
+ ///
+ /// Type of a geometric element (copy of Arcane::geometric::GeomType).
+ /// NOTE: the identifiers must correspond to those of the enumeration
+ /// GeomType of 'arcane/src/arcane/geometry/GeomType.h' and to the
+ /// descriptors of 'GeometricGenerationCpp/GeomShapeInfos.h'; this is
+ /// checked at startup by GeomShapeInfos.Check().
+ ///
+ public enum GeomType
+ {
+ Vertex,
+ Line2,
+ Triangle3,
+ Quad4,
+ Pentagon5,
+ Hexagon6,
+ Tetraedron4,
+ Pyramid5,
+ Pentaedron6,
+ Hexaedron8,
+ Heptaedron10,
+ Octaedron12
+ }
+
+ ///
+ /// Description of one geometric shape type.
+ ///
+ public sealed class GeomShapeInfo
+ {
+ public string Name { get; }
+ public GeomType Type { get; }
+ public int NbNode { get; }
+ public int NbEdge { get; }
+ public int NbFace { get; }
+ public int Dimension { get; }
+ public string BasicName { get; }
+ //! Name of the element holding a control sub-volume ("Quad4" or "Hexaedron8")
+ public string SvcName { get; }
+ //! Arguments "const Real3& a0, const Real3& a1, ..." (NbNode arguments)
+ public string CoordsArgs { get; }
+
+ internal GeomShapeInfo(GeomType type, int nb_node, int nb_edge, int nb_face,
+ int dimension, string basic_name)
+ {
+ Name = type.ToString();
+ Type = type;
+ NbNode = nb_node;
+ NbEdge = nb_edge;
+ NbFace = nb_face;
+ Dimension = dimension;
+ BasicName = basic_name;
+ SvcName = (dimension == 2) ? "Quad4" : "Hexaedron8";
+ var args = new StringBuilder();
+ for (int i = 0; i < nb_node; ++i) {
+ if (i != 0)
+ args.Append(", ");
+ args.Append("const Real3& a").Append(i);
+ }
+ CoordsArgs = args.ToString();
+ }
+ }
+
+ ///
+ /// Static description of the geometric shape types.
+ /// This is the data model of the generator.
+ ///
+ public static class GeomShapeInfos
+ {
+ static readonly GeomShapeInfo[] _items = new GeomShapeInfo[]{
+ new GeomShapeInfo(GeomType.Vertex, 1, 0, 0, 1, "Vertex"),
+ new GeomShapeInfo(GeomType.Line2, 2, 0, 0, 1, "Line"),
+ new GeomShapeInfo(GeomType.Triangle3, 3, 3, 3, 2, "Triangle"),
+ new GeomShapeInfo(GeomType.Quad4, 4, 4, 4, 2, "Quad"),
+ new GeomShapeInfo(GeomType.Pentagon5, 5, 5, 5, 2, "Pentagon"),
+ new GeomShapeInfo(GeomType.Hexagon6, 6, 6, 6, 2, "Hexagon"),
+ new GeomShapeInfo(GeomType.Tetraedron4, 4, 6, 4, 3, "Tetra"),
+ new GeomShapeInfo(GeomType.Pyramid5, 5, 12, 5, 3, "Pyramid"),
+ new GeomShapeInfo(GeomType.Pentaedron6, 6, 9, 5, 3, "Penta"),
+ new GeomShapeInfo(GeomType.Hexaedron8, 8, 12, 6, 3, "Hexa"),
+ new GeomShapeInfo(GeomType.Heptaedron10, 10, 15, 6, 3, "Wedge7"),
+ new GeomShapeInfo(GeomType.Octaedron12, 12, 18, 8, 3, "Wedge8")
+ };
+
+ public static IReadOnlyList Items {
+ get { return _items; }
+ }
+
+ public static IReadOnlyList Items2DAnd3D {
+ get {
+ var result = new List();
+ foreach (var item in _items)
+ if (item.Dimension == 2 || item.Dimension == 3)
+ result.Add(item);
+ return result;
+ }
+ }
+
+ ///
+ /// Checks that each GeomType enumerator has exactly one descriptor
+ /// with the same identifier and the same value, and vice versa.
+ ///
+ public static void Check()
+ {
+ string[] names = Enum.GetNames(typeof(GeomType));
+ if (names.Length != _items.Length)
+ throw new InvalidOperationException("The number of GeomType enumerators does not match the number of descriptors");
+ foreach (var name in names) {
+ GeomShapeInfo found = null;
+ foreach (var item in _items) {
+ if (item.Name == name) {
+ if (found != null)
+ throw new InvalidOperationException("Duplicate descriptor for GeomType::" + name);
+ found = item;
+ }
+ }
+ if (found == null)
+ throw new InvalidOperationException("Missing descriptor for GeomType::" + name);
+ if (found.Type != (GeomType)Enum.Parse(typeof(GeomType), name))
+ throw new InvalidOperationException("Mismatched value for descriptor GeomType::" + name);
+ }
+ }
+ }
+}
diff --git a/arcane/tools/GeometricGenerationScriban/GeometricGenerationScriban.csproj b/arcane/tools/GeometricGenerationScriban/GeometricGenerationScriban.csproj
new file mode 100644
index 000000000..9ef390734
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/GeometricGenerationScriban.csproj
@@ -0,0 +1,20 @@
+
+
+ net8.0
+ .dll
+ Exe
+ false
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
diff --git a/arcane/tools/GeometricGenerationScriban/Main.cs b/arcane/tools/GeometricGenerationScriban/Main.cs
new file mode 100644
index 000000000..a69f6090b
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Main.cs
@@ -0,0 +1,84 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using Scriban;
+using Scriban.Runtime;
+
+namespace GeometricGenerationScriban
+{
+ ///
+ /// Generation of the 'Generated*.h' files of arcane/src/arcane/geometry
+ /// from the Scriban templates of the 'Templates' directory.
+ /// This generator produces the same files as the C++26 reflection
+ /// generator 'GeometricGenerationCpp'. The generated headers are plain
+ /// C++ and can be used by any C++20 compiler.
+ ///
+ public static class MainClass
+ {
+ public static int Main(string[] args)
+ {
+ GeomShapeInfos.Check();
+
+ string base_path = (args.Length > 0) ? args[0] : "../../src/arcane/geometry";
+ string template_dir = Path.Combine(AppContext.BaseDirectory, "Templates");
+
+ _Generate(template_dir, "GeneratedConnectivity.h.scriban", base_path, "GeneratedConnectivity.h");
+ _Generate(template_dir, "GeneratedGeomShapeView.h.scriban", base_path, "GeneratedGeomShapeView.h");
+ _Generate(template_dir, "GeneratedGeomElement.h.scriban", base_path, "GeneratedGeomElement.h");
+ _Generate(template_dir, "GeneratedGeomElementView.h.scriban", base_path, "GeneratedGeomElementView.h");
+ _Generate(template_dir, "GeneratedGeomShapeViewDeclarations.h.scriban", base_path, "GeneratedGeomShapeViewDeclarations.h");
+ return 0;
+ }
+
+ static void _Generate(string template_dir, string template_name, string base_path, string output_name)
+ {
+ string template_path = Path.Combine(template_dir, template_name);
+ var template = Template.Parse(File.ReadAllText(template_path, Encoding.UTF8), template_path);
+ if (template.HasErrors) {
+ foreach (var error in template.Messages)
+ Console.Error.WriteLine("Template error: {0}", error);
+ throw new InvalidOperationException("Failed to parse template '" + template_path + "'");
+ }
+
+ var context = new TemplateContext();
+ context.PushGlobal(_BuildModel());
+ string text = template.Render(context);
+
+ string full_path = Path.Combine(base_path, output_name);
+ Console.WriteLine("Generating file '{0}'", full_path);
+ File.WriteAllText(full_path, text, new UTF8Encoding(true));
+ }
+
+ ///
+ /// Builds the model exposed to the templates: the objects are ScriptObject
+ /// with explicit keys (name, nb_node, ...) so that the rendering does not
+ /// depend on the .NET member renaming rules.
+ ///
+ static ScriptObject _BuildModel()
+ {
+ var root = new ScriptObject();
+ root["items"] = _ToList(GeomShapeInfos.Items);
+ root["items_2d_3d"] = _ToList(GeomShapeInfos.Items2DAnd3D);
+ return root;
+ }
+
+ static List _ToList(IReadOnlyList descriptors)
+ {
+ var result = new List();
+ foreach (var info in descriptors) {
+ var obj = new ScriptObject();
+ obj["name"] = info.Name;
+ obj["nb_node"] = info.NbNode;
+ obj["nb_edge"] = info.NbEdge;
+ obj["nb_face"] = info.NbFace;
+ obj["dimension"] = info.Dimension;
+ obj["basic_name"] = info.BasicName;
+ obj["svc_name"] = info.SvcName;
+ obj["coords_args"] = info.CoordsArgs;
+ result.Add(obj);
+ }
+ return result;
+ }
+ }
+}
diff --git a/arcane/tools/GeometricGenerationScriban/Templates/GeneratedConnectivity.h.scriban b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedConnectivity.h.scriban
new file mode 100644
index 000000000..833e79c29
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedConnectivity.h.scriban
@@ -0,0 +1,36 @@
+// WARNING: This file is generated by a tool. DO NOT EDIT.
+/*
+ * Generation of classes allowing retrieval of connectivity information
+ * for each type of geometric element.
+ */
+{{ for item in items }}/*!
+ * \ingroup ArcaneGeometric
+ * \brief Connectivity information for geometric elements of type GeomType::{{ item.name }}.
+{{ if item.name == 'Pyramid5' }} *
+ * \note the pyramid has 8 edges but it is considered a degenerate hexahedron
+ * at the pyramid's apex. To account for this, we indicate
+ * that it has 12 edges.
+{{ end }} */
+class ARCANE_GEOMETRY_EXPORT {{ item.name }}Connectivity
+: public CellConnectivity
+{
+ public:
+
+ {{ item.name }}Connectivity()
+ : CellConnectivity({{ item.nb_node }},{{ item.nb_edge }},{{ item.nb_face }},GeomType::{{ item.name }})
+ {
+ _init();
+ }
+
+ public:
+
+ constexpr Int32 nbNode() const { return {{ item.nb_node }}; }
+ constexpr Int32 nbEdge() const { return {{ item.nb_edge }}; }
+ constexpr Int32 nbFace() const { return {{ item.nb_face }}; }
+
+ private:
+
+ void _init();
+};
+{{ end }}
+
diff --git a/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElement.h.scriban b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElement.h.scriban
new file mode 100644
index 000000000..04ded9243
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElement.h.scriban
@@ -0,0 +1,49 @@
+// WARNING: This file is generated by a tool. DO NOT EDIT.
+/*
+ * Generation of classes managing geometric elements (GeomElement).
+ */
+
+{{ for item in items_2d_3d }}{{ if !for.first }}
+{{ end }}/*!
+ * \ingroup ArcaneGeometric
+ * \brief Geometric elements of type GeomType::{{ item.name }}.
+ */
+class ARCANE_GEOMETRY_EXPORT {{ item.name }}Element
+: public GeomElementBase< {{ item.nb_node }} >
+{
+ public:
+
+ using ConstViewType = {{ item.name }}ElementConstView;
+ using ViewType = {{ item.name }}ElementView;
+
+ public:
+
+ using GeomElementBase< {{ item.nb_node }} >::init;
+
+ {{ item.name }}Element() = default;
+ {{ item.name }}Element(const VariableNodeReal3& coords,ItemWithNodes item) : GeomElementBase(coords,item){}
+ constexpr {{ item.name }}Element(ConstArrayView coords) : GeomElementBase(coords){}
+ {{ item.name }}Element({{ item.coords_args }})
+ {
+{{ for i in 0..(item.nb_node - 1) }} m_s[{{ i }}] = a{{ i }};
+{{ end }} }
+
+ //! Initializes the instance with the coordinates passed as arguments
+ constexpr void init({{ item.coords_args }})
+ {
+{{ for i in 0..(item.nb_node - 1) }} m_s[{{ i }}] = a{{ i }};
+{{ end }} }
+ //! Conversion operator to a constant view
+ constexpr operator ConstViewType() const { return ConstViewType(m_s); }
+ //! Conversion operator to a mutable view
+ constexpr operator ViewType() { return ViewType(m_s); }
+ //! Constant view of the element
+ constexpr ConstViewType constView() const { return ConstViewType(m_s); }
+ //! Mutable view of the element
+ constexpr ViewType view() { return ViewType(m_s); }
+};
+
+//! Geometric element of type GeomType::{{ item.name }}
+using {{ item.basic_name }}Element = {{ item.name }}Element;
+
+{{ end }}
\ No newline at end of file
diff --git a/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElementView.h.scriban b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElementView.h.scriban
new file mode 100644
index 000000000..adaa444ac
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomElementView.h.scriban
@@ -0,0 +1,66 @@
+// WARNING: This file is generated by a tool. DO NOT EDIT.
+/*
+ * Génération des classes des vues sur les éléments géométriques (GeomElement).
+ */
+
+{{ for item in items_2d_3d }}{{ if !for.first }}
+
+{{ end }}/*!
+ * \ingroup ArcaneGeometric
+ * \brief Constant view on geometric elements of type GeomType::{{ item.name }}.
+ *
+ * It is possible to retrieve a view of this type via:
+ * - directly from an instance of Triangle3ShapeView.
+ * - directly from an instance of Triangle3Element
+ * - an instance of Triangle3ElementView via Triangle3ElementView::constView()
+ * - an instance of GeomShapeView via GeomShapeView::toTriangle3Element()
+ *
+ * For more information on usage, refer to \ref arcanedoc_cea_geometric_viewusage.
+ */
+class ARCANE_GEOMETRY_EXPORT {{ item.name }}ElementConstView
+: public GeomElementConstViewBase
+{
+ public:
+
+ constexpr {{ item.name }}ElementConstView(ARCANE_RESTRICT const Real3POD* ptr)
+ : GeomElementConstViewBase(ptr){}
+};
+
+/*!
+ * \ingroup ArcaneGeometric
+ * \brief Modifiable view on geometric elements of type GeomType::{{ item.name }}.
+ *
+ * It is possible to retrieve a view of this type via:
+ * - directly from an instance of Triangle3Element
+ * - an instance of Triangle3Element via Triangle3ElementView::view()
+ *
+ * For more information on usage, refer to \ref arcanedoc_cea_geometric_viewusage.
+ */
+class ARCANE_GEOMETRY_EXPORT {{ item.name }}ElementView
+: public GeomElementViewBase
+{
+ public:
+
+ using ConstViewType = {{ item.name }}ElementConstView;
+
+ public:
+
+ //! Construct a view from the coordinates passed as arguments
+ constexpr {{ item.name }}ElementView(ARCANE_RESTRICT Real3POD* ptr)
+ : GeomElementViewBase(ptr){}
+ //! Initializes the view with the coordinates passed as arguments
+ constexpr void init({{ item.coords_args }})
+ {
+{{ for i in 0..(item.nb_node - 1) }} m_s[{{ i }}] = a{{ i }};
+{{ end }} }
+ //! Conversion operator to a constant view
+ constexpr operator {{ item.name }}ElementConstView() const { return ConstViewType(m_s); }
+ //! Constant view on the element
+ constexpr {{ item.name }}ElementConstView constView() const { return ConstViewType(m_s); }
+};
+
+//! View on an element of type GeomType::{{ item.name }}
+using {{ item.basic_name }}ElementView = {{ item.name }}ElementView ;
+//! Constant view on an element of type GeomType::{{ item.name }}
+using {{ item.basic_name }}ElementConstView = {{ item.name }}ElementConstView ;
+{{ end }}
diff --git a/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeView.h.scriban b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeView.h.scriban
new file mode 100644
index 000000000..7b893cd2b
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeView.h.scriban
@@ -0,0 +1,80 @@
+// WARNING: This file is generated by a tool. DO NOT EDIT.
+/*
+ * Generation of specific view classes for GeomShapeView.
+ */
+{{ for item in items_2d_3d }}/*!
+ * \ingroup ArcaneGeometric
+ * \brief Specific view on geometric shapes of type GeomType::{{ item.name }}.
+ */
+class ARCANE_GEOMETRY_EXPORT {{ item.name }}ShapeView
+: public GeomShape{{ item.dimension }}DView
+{
+ public:
+
+ typedef {{ item.basic_name }}ElementConstView ElementConstView;
+ typedef {{ item.basic_name }}ElementView ElementView;
+ typedef {{ item.basic_name }}Element ElementType;
+ typedef {{ item.svc_name }}Element SVCElement;
+ typedef {{ item.svc_name }}ElementView SVCElementView;
+
+ public:
+
+ {{ item.name }}ShapeView() {}
+ explicit {{ item.name }}ShapeView(const GeomShapeView& rhs)
+ : GeomShape{{ item.dimension }}DView(rhs)
+ {
+ ARCANE_GEOMETRIC_CHECKTYPE(rhs.geomType(),GeomType::{{ item.name }});
+ }
+
+ //! Number of nodes of the shape (returns \a {{ item.nb_node }})
+ static constexpr Integer nbNode() { return {{ item.nb_node }}; }
+ //! Type of the shape (returns \a GeomType::{{ item.name }} )
+ static constexpr GeomType geomType() { return GeomType::{{ item.name }}; }
+ //! Fills \a svc with the values of the \a i-th control sub-volume.
+ void fillSVC({{ item.svc_name }}ElementView svc, Integer i)
+ {
+ fillSubZone{{ item.basic_name }}(svc,i);
+ }
+
+ //! Conversion operator to a constant view of the geometric element
+ constexpr operator {{ item.name }}ElementConstView () const
+ {
+ return ElementConstView(_nodeView());
+ }
+ //! Constant view of the geometric element
+ constexpr {{ item.name }}ElementConstView elemView() const
+ {
+ return ElementConstView(_nodeView());
+ }
+};
+typedef {{ item.name }}ShapeView {{ item.basic_name }}ShapeView;
+
+{{ end }}
+/*!
+ * \name Conversion to a view on a specific geometric shape.
+ *
+ * These methods allow converting the instance into a specific view for a given type.
+ * The geometric type (geomType()) of the instance must match.
+ */
+//@{
+{{ for item in items_2d_3d }}inline {{ item.name }}ShapeView GeomShapeView::
+to{{ item.name }}Shape() const
+{
+ return {{ item.name }}ShapeView(*this);
+}
+{{ end }}//@}
+
+/*!
+ * \name Conversion to a view on a specific geometric element.
+ *
+ * These methods allow converting the instance into a specific view for a given type.
+ * The geometric type (geomType()) of the instance must match.
+ */
+//@{
+{{ for item in items_2d_3d }}inline {{ item.name }}ElementConstView GeomShapeView::
+to{{ item.name }}Element() const
+{
+ ARCANE_GEOMETRIC_CHECKTYPE(geomType(),GeomType::{{ item.name }});
+ return {{ item.name }}ElementConstView(_nodeView());
+}
+{{ end }}//@}
\ No newline at end of file
diff --git a/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeViewDeclarations.h.scriban b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeViewDeclarations.h.scriban
new file mode 100644
index 000000000..f2411f274
--- /dev/null
+++ b/arcane/tools/GeometricGenerationScriban/Templates/GeneratedGeomShapeViewDeclarations.h.scriban
@@ -0,0 +1,52 @@
+// WARNING: This file is generated by a tool. DO NOT EDIT.
+/*
+ * Generation of declarations for GeomShapeView.
+ * This file must be included directly in the definition of the GeomShapeView class.
+ */
+
+/*!
+ * \name Filling of control sub-volumes for a specific type.
+ *
+ * The geometric type (geomType()) of the instance must match the chosen method.
+ */
+//@{
+{{ for item in items_2d_3d }}/*!
+ * \brief Fills \a svc with the information of the \a i-th control sub-volume.
+ * \pre type()==GeomType::{{ item.name }}
+ */
+void fillSubZone{{ item.name }}({{ item.svc_name }}ElementView svc,Integer i);
+{{ end }}
+//@}
+
+/*!
+ * \name Filling of control sub-volumes (obsolete methods).
+ *
+ * These methods are obsolete and must be replaced by the equivalent method
+ * with the full element name.
+ */
+//@{
+{{ for item in items_2d_3d }}/*!
+ * \brief Fills \a svc with the information of the \a i-th control sub-volume.
+ *
+ * \deprecated Use fillSubZone{{ item.name }}() instead.
+ */
+void fillSubZone{{ item.basic_name }}({{ item.svc_name }}ElementView svc,Integer i)
+{
+ fillSubZone{{ item.name }}(svc,i);
+}
+{{ end }}
+//@}
+
+{{ for item in items_2d_3d }}/*!
+ * \brief Returns a specific view to a geometric element of type GeomType::{{ item.name }}.
+ * \pre type()==GeomType::{{ item.name }}
+ */
+inline {{ item.name }}ElementConstView to{{ item.name }}Element() const;
+{{ end }}
+
+{{ for item in items_2d_3d }}/*!
+ * \brief Returns a specific view for a geometric shape of type GeomType::{{ item.name }}.
+ * \pre type()==GeomType::{{ item.name }}
+ */
+inline {{ item.name }}ShapeView to{{ item.name }}Shape() const;
+{{ end }}