From 0d2dad97471f0a03c0face4c2a4e5f17e09cc496 Mon Sep 17 00:00:00 2001 From: "Brian T.N. Gunney" Date: Mon, 22 Sep 2025 16:50:45 -0700 Subject: [PATCH 1/3] Add Cone and type-free geometry info to klee Geometry. Cone provides interface for specify a cone geometry. Type-free geometry is work-in-progress toward allowing klee::Geometry to support arbitrary geometry types without requiring a primal representation of that geometry. Also add asterisks to comment blocks. --- src/axom/klee/Geometry.cpp | 125 +++++++++++++++++++++++++++---- src/axom/klee/Geometry.hpp | 104 ++++++++++++++++++++----- src/axom/quest/DiscreteShape.cpp | 2 +- 3 files changed, 197 insertions(+), 34 deletions(-) diff --git a/src/axom/klee/Geometry.cpp b/src/axom/klee/Geometry.cpp index 6f55148b97..91a2902656 100644 --- a/src/axom/klee/Geometry.cpp +++ b/src/axom/klee/Geometry.cpp @@ -27,7 +27,9 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_format(std::move(format)) , m_path(std::move(path)) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, const axom::sidre::Group* simplexMeshGroup, @@ -38,7 +40,9 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_meshGroup(simplexMeshGroup) , m_topology(topology) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, const axom::primal::Tetrahedron& tet, @@ -47,7 +51,9 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_format("tet3D") , m_tet(tet) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, const axom::primal::Hexahedron& hex, @@ -56,7 +62,9 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_format("hex3D") , m_hex(hex) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, const Sphere3D& sphere, @@ -67,22 +75,42 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_sphere(sphere) , m_levelOfRefinement(levelOfRefinement) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} + +Geometry::Geometry(const TransformableGeometryProperties& startProperties, + const axom::primal::Cone& cone, + axom::IndexType levelOfRefinement, + std::shared_ptr operator_) + : m_startProperties(startProperties) + , m_format("cone3D") + , m_path() + , m_meshGroup(nullptr) + , m_topology() + , m_cone(cone) + , m_levelOfRefinement(levelOfRefinement) + , m_operator(std::move(operator_)) +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, - const axom::Array& discreteFunction, - const Point3D& sorBase, // surface of revolution. + axom::ArrayView discreteFunction, + const Point3D& sorOrigin, // surface of revolution. const Vector3D& sorDirection, axom::IndexType levelOfRefinement, std::shared_ptr operator_) : m_startProperties(startProperties) , m_format("sor3D") , m_discreteFunction(discreteFunction) - , m_sorBase(sorBase) + , m_sorOrigin(sorOrigin) , m_sorDirection(sorDirection) , m_levelOfRefinement(levelOfRefinement) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} Geometry::Geometry(const TransformableGeometryProperties& startProperties, const axom::primal::Plane& plane, @@ -91,13 +119,84 @@ Geometry::Geometry(const TransformableGeometryProperties& startProperties, , m_format("plane3D") , m_plane(plane) , m_operator(std::move(operator_)) -{ } +{ + populateGeomInfo(); +} + +void Geometry::populateGeomInfo() +{ + if(m_format == "blueprint-tets") + { + m_meshGroup->deepCopyToConduit(m_geomInfo["klee::Geometry:tetMesh"]); + m_geomInfo["topologyName"].set(getBlueprintTopology()); + } + + else if(m_format == "tet3D") + { + const auto& tet = getTet(); + m_geomInfo["v0"].set(tet[0].data(), 3); + m_geomInfo["v1"].set(tet[1].data(), 3); + m_geomInfo["v2"].set(tet[2].data(), 3); + m_geomInfo["v3"].set(tet[3].data(), 3); + } + + else if(m_format == "sphere3D") + { + const Sphere3D& sphere = getSphere(); + m_geomInfo["center"].set(sphere.getCenter().data(), 3); + m_geomInfo["radius"].set(sphere.getRadius()); + m_geomInfo["levelOfRefinement"].set(m_levelOfRefinement); + } + + else if(m_format == "cone3D") + { + const Cone3D& cone = getCone(); + m_discreteFunction = axom::Array(2, 2); + m_discreteFunction(0, 0) = cone.getBaseZ(); + m_discreteFunction(0, 1) = cone.getBaseRadius(); + m_discreteFunction(1, 1) = cone.getTopZ(); + m_discreteFunction(1, 1) = cone.getTopRadius(); + m_geomInfo["discreteFunction"].set(m_discreteFunction.data(), m_discreteFunction.size()); + m_geomInfo["sorOrigin"].set(cone.getOrigin().data(), 3); + m_geomInfo["sorDirection"].set(cone.getDirection().data(), 3); + m_geomInfo["levelOfRefinement"].set(m_levelOfRefinement); + } + + else if(m_format == "sor3D") + { + m_geomInfo["sorOrigin"].set(m_sorOrigin.data(), 3); + m_geomInfo["sorDirection"].set(m_sorDirection.data(), 3); + m_geomInfo["discreteFunction"].set(m_discreteFunction.data(), m_discreteFunction.size()); + m_geomInfo["levelOfRefinement"].set(m_levelOfRefinement); + } + + else if(m_format == "hex3D") + { + const auto& hex = getHex(); + m_geomInfo["v0"].set(hex[0].data(), 3); + m_geomInfo["v1"].set(hex[1].data(), 3); + m_geomInfo["v2"].set(hex[2].data(), 3); + m_geomInfo["v3"].set(hex[3].data(), 3); + m_geomInfo["v4"].set(hex[4].data(), 3); + m_geomInfo["v5"].set(hex[5].data(), 3); + m_geomInfo["v6"].set(hex[6].data(), 3); + m_geomInfo["v7"].set(hex[7].data(), 3); + } + + else if(m_format == "plane3D") + { + const auto& plane = getPlane(); + m_geomInfo["normal"].set(plane.getNormal().data(), 3); + m_geomInfo["offset"].set(plane.getOffset()); + } + + // TODO: other formats. +} bool Geometry::hasGeometry() const { - bool isInMemory = (m_format == "blueprint-tets" || m_format == "sphere3D" || - m_format == "tet3D" || m_format == "hex3D" || m_format == "plane3D" || - m_format == "cone3D" || m_format == "cylinder3D"); + bool isInMemory = (m_format == "blueprint-tets" || m_format == "sphere3D" || m_format == "tet3D" || + m_format == "hex3D" || m_format == "plane3D" || m_format == "cone3D"); if(isInMemory) { return true; diff --git a/src/axom/klee/Geometry.hpp b/src/axom/klee/Geometry.hpp index 61546b6637..26ced43306 100644 --- a/src/axom/klee/Geometry.hpp +++ b/src/axom/klee/Geometry.hpp @@ -10,7 +10,7 @@ #include "axom/klee/Units.hpp" #include "axom/primal.hpp" -#include "axom/sidre.hpp" +#include "axom/sidre/core/Group.hpp" #include #include @@ -56,6 +56,7 @@ class Geometry using Point3D = axom::primal::Point; using Vector3D = axom::primal::Vector; using Sphere3D = axom::primal::Sphere; + using Cone3D = axom::primal::Cone; using Tet3D = axom::primal::Tetrahedron; using Hex3D = axom::primal::Hexahedron; using Plane3D = axom::primal::Plane; @@ -127,23 +128,38 @@ class Geometry * * \param startProperties the transformable properties before any operators are applied * \param discreteFunction Discrete function describing the surface of revolution. - * \param sorBase Coordinates of the base of the SOR. + * \param sorOrigin 3D coordinates of the point (z=0, r=0). * \param sorDirection SOR axis, in the direction of increasing z. * \param levelOfRefinement Number of refinement levels to use for discretizing the SOR. * \param operator_ a possibly null operator to apply to the geometry. * * The \c discreteFunction should be an Nx2 array, interpreted as * (z,r) pairs, where z is the axial distance and r is the radius. - * The \c sorBase coordinates corresponds to z=0. + * * \c sorAxis should point in the direction of increasing z. */ Geometry(const TransformableGeometryProperties &startProperties, - const axom::Array &discreteFunction, - const Point3D &sorBase, + axom::ArrayView discreteFunction, + const Point3D &sorOrigin, const Vector3D &sorDirection, axom::IndexType levelOfRefinement, std::shared_ptr operator_); + /** + * Create a cone Geometry object. + * + * \param startProperties the transformable properties before any + * operators are applied + * \param sphere Analytical sphere specifications + * \param levelOfRefinement Number of refinement levels to use for + * discretizing the sphere. + * \param operator_ a possibly null operator to apply to the geometry. + */ + Geometry(const TransformableGeometryProperties &startProperties, + const axom::primal::Cone &cone, + axom::IndexType levelOfRefinement, + std::shared_ptr operator_); + /** * Create a planar Geometry object. * @@ -157,6 +173,17 @@ class Geometry const axom::primal::Plane &plane, std::shared_ptr operator_); + /*! + @brief Geometry definition in hierarchical format. + + This hierarchy should be reproducible from its Geometry object, + and an identical Geometry should be reconstructible from this + hierarchy. + */ + const conduit::Node &asHierarchy() const { return m_geomInfo; } + + conduit::Node &asHierarchy() { return m_geomInfo; } + /** * \brief Get the format in which the geometry was specified. * @@ -170,14 +197,14 @@ class Geometry * - "sphere3D" = 3D sphere, as \c primal::Sphere * - "sor3D" = 3D surface of revolution. * - "cone3D" = 3D cone, as \c primal::Cone - * - "cylinder3D" = 3D cylinder, as \c primal::Cylinder * - "hex3D" = 3D hexahedron (8 points) * - "plane3D" = 3D plane * * \return the format of the shape * - * TODO: Depending on the specified geometry, some members are not - * used. It may clarify if we make each supported geometry a subclass. + * TODO: Put all geometry-specific parameters in m_geomInfo, and + * deprecate geometry-specific interfaces, so new shapes can be added + * without modifying this code. */ const std::string &getFormat() const { return m_format; } @@ -214,10 +241,10 @@ class Geometry /// \brief Return the SOR axis direction. const Vector3D getSorDirection() const { return m_sorDirection; } - /// \brief Return the 3D coordinates of the SOR base. - const Point3D getSorBaseCoords() const { return m_sorBase; } + /// \brief Return the 3D coordinates of the point (z=0, r=0) + const Point3D getSorOriginCoords() const { return m_sorOrigin; } - /** + /* * \brief Predicate that returns true when the shape has an associated geometry * * A false means that this is set up to determine volume fractions without @@ -251,30 +278,55 @@ class Geometry TransformableGeometryProperties getEndProperties() const; /** - * \brief Return the number of levels of refinement for discretization of analytical curves. - * - * This number is unused for geometries that are specified in discrete form. + * @brief Return the number of levels of refinement for discretization + * of analytical curves. + * + * This number is unused for geometries that are specified in discrete + * form. */ axom::IndexType getLevelOfRefinement() const { return m_levelOfRefinement; } - /// \brief Return the tet geometry, when the Geometry represents a tetrahedron. + /** + * @brief Return the tet geometry, when the Geometry + * represents a tetrahedron. + */ const axom::primal::Tetrahedron &getTet() const { return m_tet; } - /// \brief Return the hex geometry, when the Geometry represents a hexahedron + /** + * @brief Return the hex geometry, when the Geometry + * represents a hexahedron. + */ const axom::primal::Hexahedron &getHex() const { return m_hex; } - /// \brief Return the sphere geometry, when the Geometry represents an analytical sphere. + /** + * @brief Return the sphere geometry, when the Geometry + * represents an alalytical sphere. + */ const axom::primal::Sphere &getSphere() const { return m_sphere; } - /// \brief Return the plane geometry, when the Geometry represents a plane. + /** + * @brief Return the cone geometry, when the Geometry + * represents an alalytical cone. + */ + const axom::primal::Cone &getCone() const { return m_cone; } + + /** + * @brief Return the plane geometry, when the Geometry + * represents a plane. + */ const axom::primal::Plane &getPlane() const { return m_plane; } - /// \brief Get the discrete function used in surfaces of revolution. + /** + * @brief Get the discrete function used in surfaces of revolution. + */ axom::ArrayView getDiscreteFunction() const { return m_discreteFunction.view(); } private: TransformableGeometryProperties m_startProperties; + /// \brief Geometry info in hierarchical format. + conduit::Node m_geomInfo; + /// \brief Geometry format. std::string m_format; @@ -299,11 +351,14 @@ class Geometry /// \brief The analytical sphere, if used. Sphere3D m_sphere; + /// @brief The analytical cone (or cylinder), if used. + Cone3D m_cone; + /// \brief The discrete 2D function, as an Nx2 array, if used. axom::Array m_discreteFunction; /// \brief The point corresponding to z=0 on the SOR axis. - Point3D m_sorBase; + Point3D m_sorOrigin; /// \brief SOR axis in the direction of increasing z. Vector3D m_sorDirection; @@ -312,6 +367,15 @@ class Geometry axom::IndexType m_levelOfRefinement {0}; std::shared_ptr m_operator; + + /*! + * @brief Populate m_geomInfo with the geometry definition. + * + * This helps transition away from geometry-specific constructors and + * methods like @c getTet(), @c getHex() and @c getSphere() and + * toward a uniform interface for providing geometry info. + */ + void populateGeomInfo(); }; } // namespace klee diff --git a/src/axom/quest/DiscreteShape.cpp b/src/axom/quest/DiscreteShape.cpp index 379f7750b6..32dae02327 100644 --- a/src/axom/quest/DiscreteShape.cpp +++ b/src/axom/quest/DiscreteShape.cpp @@ -563,7 +563,7 @@ void DiscreteShape::createRepresentationOfSOR() // Rotate to the SOR axis direction and translate to the base location. numerics::Matrix rotate = sorAxisRotMatrix(sorGeom.getSorDirection()); - const auto& translate = sorGeom.getSorBaseCoords(); + const auto& translate = sorGeom.getSorOriginCoords(); auto octsView = octs.view(); axom::for_all( octCount, From a67dbdc503c1f68805847e6738a11cf9e8f50174 Mon Sep 17 00:00:00 2001 From: "Brian T.N. Gunney" Date: Mon, 22 Sep 2025 18:23:37 -0700 Subject: [PATCH 2/3] Touch up some internal comments. --- src/axom/klee/Geometry.hpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/axom/klee/Geometry.hpp b/src/axom/klee/Geometry.hpp index 26ced43306..8e1a7e402e 100644 --- a/src/axom/klee/Geometry.hpp +++ b/src/axom/klee/Geometry.hpp @@ -174,12 +174,8 @@ class Geometry std::shared_ptr operator_); /*! - @brief Geometry definition in hierarchical format. - - This hierarchy should be reproducible from its Geometry object, - and an identical Geometry should be reconstructible from this - hierarchy. - */ + * @brief Geometry definition in hierarchical format. + */ const conduit::Node &asHierarchy() const { return m_geomInfo; } conduit::Node &asHierarchy() { return m_geomInfo; } @@ -202,7 +198,7 @@ class Geometry * * \return the format of the shape * - * TODO: Put all geometry-specific parameters in m_geomInfo, and + * \internal TODO: Put all geometry-specific parameters in m_geomInfo, and * deprecate geometry-specific interfaces, so new shapes can be added * without modifying this code. */ @@ -371,9 +367,10 @@ class Geometry /*! * @brief Populate m_geomInfo with the geometry definition. * - * This helps transition away from geometry-specific constructors and - * methods like @c getTet(), @c getHex() and @c getSphere() and - * toward a uniform interface for providing geometry info. + * Representing geometries in m_geomInfo is a step away from + * geometry-specific constructors and methods like @c getTet(), @c + * getHex() and @c getSphere() and toward a uniform interface for + * providing geometry info. */ void populateGeomInfo(); }; From 476f7e722765a1a7e984f466aeae38afe0be5a07 Mon Sep 17 00:00:00 2001 From: "Brian T.N. Gunney" Date: Fri, 26 Sep 2025 10:30:24 -0700 Subject: [PATCH 3/3] Adjust to changed Cone interface. --- src/axom/klee/Geometry.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/axom/klee/Geometry.cpp b/src/axom/klee/Geometry.cpp index 91a2902656..09c8b03e6e 100644 --- a/src/axom/klee/Geometry.cpp +++ b/src/axom/klee/Geometry.cpp @@ -152,12 +152,12 @@ void Geometry::populateGeomInfo() { const Cone3D& cone = getCone(); m_discreteFunction = axom::Array(2, 2); - m_discreteFunction(0, 0) = cone.getBaseZ(); + m_discreteFunction(0, 0) = 0.0; m_discreteFunction(0, 1) = cone.getBaseRadius(); - m_discreteFunction(1, 1) = cone.getTopZ(); + m_discreteFunction(1, 1) = cone.getLength(); m_discreteFunction(1, 1) = cone.getTopRadius(); m_geomInfo["discreteFunction"].set(m_discreteFunction.data(), m_discreteFunction.size()); - m_geomInfo["sorOrigin"].set(cone.getOrigin().data(), 3); + m_geomInfo["sorOrigin"].set(cone.getBaseCenter().data(), 3); m_geomInfo["sorDirection"].set(cone.getDirection().data(), 3); m_geomInfo["levelOfRefinement"].set(m_levelOfRefinement); }