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 }}