Skip to content

Commit

Permalink
Add host device annotations and device unit tests for Polygon
Browse files Browse the repository at this point in the history
  • Loading branch information
bmhan12 committed Apr 24, 2024
1 parent 951fb44 commit 96d5777
Show file tree
Hide file tree
Showing 2 changed files with 154 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/axom/primal/geometry/Polygon.hpp
Expand Up @@ -55,6 +55,7 @@ class Polygon

public:
/// Default constructor for an empty polygon
AXOM_HOST_DEVICE
Polygon() { }

/// \brief Constructor for a polygon with the given vertices
Expand All @@ -70,6 +71,7 @@ class Polygon
}

// \brief Constructor for a polygon with an initializer list of Points
AXOM_HOST_DEVICE
explicit Polygon(std::initializer_list<PointType> vertices)
{
SLIC_ASSERT(static_cast<int>(vertices.size()) <= MAX_VERTS);
Expand All @@ -84,9 +86,11 @@ class Polygon
}

/// Return the number of vertices in the polygon
AXOM_HOST_DEVICE
int numVertices() const { return m_num_vertices; }

/// Appends a vertex to the list of vertices
AXOM_HOST_DEVICE
void addVertex(const PointType& pt)
{
SLIC_ASSERT(m_num_vertices + 1 < MAX_VERTS);
Expand All @@ -95,6 +99,7 @@ class Polygon
}

/// Clears the list of vertices
AXOM_HOST_DEVICE
void clear()
{
for(int i = 0; i < MAX_VERTS; i++)
Expand All @@ -105,8 +110,11 @@ class Polygon
}

/// Retrieves the vertex at index idx
AXOM_HOST_DEVICE
PointType& operator[](int idx) { return m_vertices[idx]; }

/// Retrieves the vertex at index idx
AXOM_HOST_DEVICE
const PointType& operator[](int idx) const { return m_vertices[idx]; }

/*!
Expand All @@ -115,6 +123,7 @@ class Polygon
* \return normal polygon normal vector
*/
template <int TDIM = NDIMS>
AXOM_HOST_DEVICE
typename std::enable_if<TDIM == 3, VectorType>::type normal() const
{
SLIC_ASSERT(isValid());
Expand All @@ -141,6 +150,7 @@ class Polygon
* \return A point at the mean of the polygon's vertices
* \pre polygon.isValid() is true
*/
AXOM_HOST_DEVICE
PointType vertexMean() const
{
SLIC_ASSERT(isValid());
Expand Down Expand Up @@ -168,6 +178,7 @@ class Polygon
* The area is always non-negative since 3D polygons do not have a unique orientation.
*/
template <int TDIM = NDIMS>
AXOM_HOST_DEVICE
typename std::enable_if<TDIM == 3, double>::type area() const
{
const int nVerts = numVertices();
Expand Down Expand Up @@ -197,6 +208,7 @@ class Polygon
* \sa signedArea()
*/
template <int TDIM = NDIMS>
AXOM_HOST_DEVICE
typename std::enable_if<TDIM == 2, double>::type area() const
{
return axom::utilities::abs(signedArea());
Expand All @@ -212,6 +224,7 @@ class Polygon
* \sa area()
*/
template <int TDIM = NDIMS>
AXOM_HOST_DEVICE
typename std::enable_if<TDIM == 2, double>::type signedArea() const
{
const int nVerts = numVertices();
Expand Down Expand Up @@ -263,6 +276,7 @@ class Polygon
* Initial check is that the polygon has three or more vertices
* \return True, if the polygon is valid, False otherwise
*/
AXOM_HOST_DEVICE
bool isValid() const { return m_num_vertices >= 3; }

private:
Expand Down
140 changes: 140 additions & 0 deletions src/axom/primal/tests/primal_polygon.cpp
Expand Up @@ -7,6 +7,8 @@
#include "axom/primal.hpp"
#include "axom/slic.hpp"

#include "axom/core/execution/execution_space.hpp"

#include <math.h>
#include "gtest/gtest.h"

Expand Down Expand Up @@ -718,6 +720,144 @@ TEST(primal_polygon, normal)
}
}

#if defined(AXOM_USE_RAJA) && defined(AXOM_USE_UMPIRE)
template <typename ExecPolicy>
void check_polygon_policy()
{
using Polygon3D = axom::primal::Polygon<double, 3>;
using Point3D = axom::primal::Point<double, 3>;
using Polygon2D = axom::primal::Polygon<double, 2>;
using Point2D = axom::primal::Point<double, 2>;
using Vector3D = axom::primal::Vector<double, 3>;

const int NUM_VERTS_SQUARE = 4;

Polygon3D* poly_3d_device =
axom::allocate<Polygon3D>(1,
axom::execution_space<ExecPolicy>::allocatorID());
Polygon2D* poly_2d_device =
axom::allocate<Polygon2D>(1,
axom::execution_space<ExecPolicy>::allocatorID());

Point3D* vertex_mean_3d_device =
axom::allocate<Point3D>(1, axom::execution_space<ExecPolicy>::allocatorID());
Point2D* vertex_mean_2d_device =
axom::allocate<Point2D>(1, axom::execution_space<ExecPolicy>::allocatorID());

double* area_3d_device =
axom::allocate<double>(1, axom::execution_space<ExecPolicy>::allocatorID());
double* area_2d_device =
axom::allocate<double>(1, axom::execution_space<ExecPolicy>::allocatorID());

// 3d only
Vector3D* normal_3d_device =
axom::allocate<Vector3D>(1, axom::execution_space<ExecPolicy>::allocatorID());

axom::for_all<ExecPolicy>(
1,
AXOM_LAMBDA(int i) {
// Initialize to empty polygons
poly_3d_device[i] = Polygon3D();
poly_2d_device[i] = Polygon2D();
poly_3d_device[i].clear();
poly_2d_device[i].clear();

// Initialize to triangles
poly_3d_device[i] = Polygon3D({Point3D({0.0, 0.0, 0.0}),
Point3D({1.0, 0.0, 0.0}),
Point3D({1.0, 1.0, 0.0})});
poly_2d_device[i] = Polygon2D(
{Point2D({0.0, 0.0}), Point2D({1.0, 0.0}), Point2D({1.0, 1.0})});

// Add a vertex to make squares
(poly_3d_device[i]).addVertex(Point3D({0.0, 1.0, 0.0}));
(poly_2d_device[i]).addVertex(Point2D({0.0, 1.0}));

// Collect info about squares
vertex_mean_3d_device[i] = poly_3d_device[i].vertexMean();
vertex_mean_2d_device[i] = poly_2d_device[i].vertexMean();
area_3d_device[i] = poly_3d_device[i].area();
area_2d_device[i] = poly_2d_device[i].area();
normal_3d_device[i] = poly_3d_device[i].normal();

//Sanity check - functions are callable on device
poly_3d_device[i].numVertices();
poly_3d_device[i].isValid();
poly_2d_device[i].numVertices();
poly_2d_device[i].isValid();
});

// Copy polygons and data back to host
Polygon3D poly_3d_host;
Polygon2D poly_2d_host;
Point3D vertex_mean_3d_host;
Point3D vertex_mean_2d_host;
double area_3d_host;
double area_2d_host;
Vector3D normal_3d_host;

axom::copy(&poly_3d_host, poly_3d_device, sizeof(Polygon3D));
axom::copy(&poly_2d_host, poly_2d_device, sizeof(Polygon2D));
axom::copy(&vertex_mean_3d_host, vertex_mean_3d_device, sizeof(Point3D));
axom::copy(&vertex_mean_2d_host, vertex_mean_2d_device, sizeof(Point2D));
axom::copy(&area_3d_host, area_3d_device, sizeof(double));
axom::copy(&area_2d_host, area_2d_device, sizeof(double));
axom::copy(&normal_3d_host, normal_3d_device, sizeof(Vector3D));

// Verify values
EXPECT_EQ(poly_3d_host.numVertices(), NUM_VERTS_SQUARE);
EXPECT_EQ(poly_2d_host.numVertices(), NUM_VERTS_SQUARE);

EXPECT_EQ(vertex_mean_3d_host, Point3D({0.5, 0.5, 0}));
EXPECT_EQ(vertex_mean_2d_host, Point3D({0.5, 0.5}));

EXPECT_DOUBLE_EQ(area_3d_host, 1.0);
EXPECT_DOUBLE_EQ(area_2d_host, 1.0);

EXPECT_EQ(normal_3d_host, Vector3D(Point3D({0.0, 0.0, 2.0})));

EXPECT_TRUE(poly_3d_host.isValid());
EXPECT_TRUE(poly_2d_host.isValid());

// Cleanup allocations
axom::deallocate(poly_3d_device);
axom::deallocate(poly_2d_device);
axom::deallocate(vertex_mean_3d_device);
axom::deallocate(vertex_mean_2d_device);
axom::deallocate(area_3d_device);
axom::deallocate(area_2d_device);
axom::deallocate(normal_3d_device);
}

//------------------------------------------------------------------------------
TEST(primal_polygon, polygon_check_seq)
{
check_polygon_policy<axom::SEQ_EXEC>();
}

#ifdef AXOM_USE_OPENMP
TEST(primal_polygon, polygon_check_omp)
{
check_polygon_policy<axom::OMP_EXEC>();
}
#endif /* AXOM_USE_OPENMP */

#ifdef AXOM_USE_CUDA
TEST(primal_polygon, polygon_check_cuda)
{
check_polygon_policy<axom::CUDA_EXEC<256>>();
}
#endif /* AXOM_USE_CUDA */

#ifdef AXOM_USE_HIP
TEST(primal_clip, polygon_check_hip)
{
check_polygon_policy<axom::HIP_EXEC<256>>();
}
#endif /* AXOM_USE_HIP */

#endif /* AXOM_USE_RAJA && AXOM_USE_UMPIRE */

//------------------------------------------------------------------------------
int main(int argc, char* argv[])
{
Expand Down

0 comments on commit 96d5777

Please sign in to comment.