Skip to content
3 changes: 3 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ The Axom project release numbers follow [Semantic Versioning](http://semver.org/
- Updates to [MFEM version 4.8.0][https://github.com/mfem/mfem/releases/tag/v4.8]
- Readers in Quest were moved from a `quest/readers` directory to `quest/io`.
- Sina: Renames a Fortran module to `sina_hdf5_config` (from `hdf5_config`)
- Spin: Uses `axom::FlatMap` in `SparseOctreeLevel` implementation. We have observed a performance regression
of about 20% during InOutOctree construction and queries over STL surface meshes relative to the previous sparsehash
implementation. Please reach out to Axom developers if this affects you while we work on fixes for these.

### Fixed
- Core: prevent incorrect instantiations of `axom::Array` from a host-only compile, when Axom is compiled
Expand Down
54 changes: 24 additions & 30 deletions src/axom/core/Macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,35 +301,29 @@
* \note Can be used in test files after including `gtest/gtest.h`
*/
// Specifically, we expose the `TestBody()` method as public instead of private
#define AXOM_TYPED_TEST(CaseName, TestName) \
static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, \
"test-name must not be empty"); \
template <typename gtest_TypeParam_> \
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \
: public CaseName<gtest_TypeParam_> { \
public: \
typedef CaseName<gtest_TypeParam_> TestFixture; \
typedef gtest_TypeParam_ TypeParam; \
void TestBody() override; \
}; \
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool \
gtest_##CaseName##_##TestName##_registered_ = \
::testing::internal::TypeParameterizedTest< \
CaseName, \
::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_( \
CaseName, TestName)>, \
GTEST_TYPE_PARAMS_( \
CaseName)>::Register("", \
::testing::internal::CodeLocation( \
__FILE__, __LINE__), \
GTEST_STRINGIFY_(CaseName), \
GTEST_STRINGIFY_(TestName), 0, \
::testing::internal::GenerateNames< \
GTEST_NAME_GENERATOR_(CaseName), \
GTEST_TYPE_PARAMS_(CaseName)>()); \
template <typename gtest_TypeParam_> \
void GTEST_TEST_CLASS_NAME_(CaseName, \
TestName)<gtest_TypeParam_>::TestBody()

#define AXOM_TYPED_TEST(CaseName, TestName) \
static_assert(sizeof(GTEST_STRINGIFY_(TestName)) > 1, "test-name must not be empty"); \
template <typename gtest_TypeParam_> \
class GTEST_TEST_CLASS_NAME_(CaseName, TestName) : public CaseName<gtest_TypeParam_> \
{ \
public: \
typedef CaseName<gtest_TypeParam_> TestFixture; \
typedef gtest_TypeParam_ TypeParam; \
void TestBody() override; \
}; \
GTEST_INTERNAL_ATTRIBUTE_MAYBE_UNUSED static bool gtest_##CaseName##_##TestName##_registered_ = \
::testing::internal::TypeParameterizedTest< \
CaseName, \
::testing::internal::TemplateSel<GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \
GTEST_TYPE_PARAMS_( \
CaseName)>::Register("", \
::testing::internal::CodeLocation(__FILE__, __LINE__), \
GTEST_STRINGIFY_(CaseName), \
GTEST_STRINGIFY_(TestName), \
0, \
::testing::internal::GenerateNames<GTEST_NAME_GENERATOR_(CaseName), \
GTEST_TYPE_PARAMS_(CaseName)>()); \
template <typename gtest_TypeParam_> \
void GTEST_TEST_CLASS_NAME_(CaseName, TestName)<gtest_TypeParam_>::TestBody()

#endif // AXOM_MACROS_HPP_
17 changes: 9 additions & 8 deletions src/axom/quest/InOutOctree.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
#include <vector>
#include <iterator>
#include <sstream>
#include <unordered_map>

#ifndef DUMP_VTK_MESH
// #define DUMP_VTK_MESH
Expand Down Expand Up @@ -177,9 +176,7 @@ class InOutOctree : public spin::SpatialOctree<DIM, InOutBlockData>
setVertexWeldThreshold(DEFAULT_VERTEX_WELD_THRESHOLD);
}

/**
* \brief Generate the spatial index over the surface mesh
*/
/// \brief Generate the spatial index over the surface mesh
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for all the noise in this PR -- I used it as an opportunity to clean up documentation in the files related to the InOutOctree

void generateIndex();

/**
Expand Down Expand Up @@ -229,9 +226,7 @@ class InOutOctree : public spin::SpatialOctree<DIM, InOutBlockData>
*/
void insertVertex(VertexIndex idx, int startingLevel = 0);

/**
* \brief Insert all mesh cells into the octree, generating a PM octree
*/
/// \brief Insert all mesh cells into the octree, generating a PM octree
void insertMeshCells();

/**
Expand Down Expand Up @@ -448,6 +443,7 @@ void InOutOctree<DIM>::generateIndex()
// STEP 1 -- Add mesh vertices to octree
{
AXOM_ANNOTATE_SCOPE("insert vertices");
timer.reset();
timer.start();
int numMeshVerts = m_meshWrapper.numMeshVertices();
for(int idx = 0; idx < numMeshVerts; ++idx)
Expand All @@ -464,6 +460,7 @@ void InOutOctree<DIM>::generateIndex()
// STEP 1(b) -- Update the mesh vertices and cells with after vertex welding from octree
{
AXOM_ANNOTATE_SCOPE("update surface mesh vertices");
timer.reset();
timer.start();
updateSurfaceMeshVertices();
timer.stop();
Expand Down Expand Up @@ -496,6 +493,7 @@ void InOutOctree<DIM>::generateIndex()
// STEP 2 -- Add mesh cells (segments in 2D; triangles in 3D) to octree
{
AXOM_ANNOTATE_SCOPE("insert mesh cells");
timer.reset();
timer.start();
insertMeshCells();
timer.stop();
Expand All @@ -509,6 +507,7 @@ void InOutOctree<DIM>::generateIndex()
// -- Black (in), White(out), Gray(Intersects surface)
{
AXOM_ANNOTATE_SCOPE("color octree leaves");
timer.reset();
timer.start();
colorOctreeLeaves();

Expand All @@ -519,8 +518,8 @@ void InOutOctree<DIM>::generateIndex()
"\t--Coloring octree leaves took {:.3Lf} seconds.",
timer.elapsed()));

// -- Print some stats about the octree
#ifdef DUMP_OCTREE_INFO
// -- Print some stats about the octree
SLIC_INFO_ROOT("** Octree stats after inserting cells");
{
AXOM_ANNOTATE_SCOPE("dump stats after inserting cells");
Expand All @@ -533,9 +532,11 @@ void InOutOctree<DIM>::generateIndex()
AXOM_ANNOTATE_SCOPE("validate after inserting cells");
checkValid();
}

// CLEANUP -- Finally, fix up the surface mesh after octree operations
{
AXOM_ANNOTATE_SCOPE("regenerate surface mesh");
timer.reset();
timer.start();
m_meshWrapper.regenerateSurfaceMesh();
timer.stop();
Expand Down
78 changes: 32 additions & 46 deletions src/axom/quest/detail/inout/BlockData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,13 @@ class InOutBlockData
*/
InOutBlockData() : m_idx(LEAF_BLOCK_UNCOLORED) { }

/** \brief Constructor from a given index */
/// \brief Constructor from a given index
explicit InOutBlockData(int dataIdx) : m_idx(dataIdx) { }

/** \brief Copy constructor for an InOutBlockData instance */
/// \brief Copy constructor for an InOutBlockData instance
InOutBlockData(const InOutBlockData& other) : m_idx(other.m_idx) { }

/** \brief Assignment operator for an InOutBlockData instance */
/// \brief Assignment operator for an InOutBlockData instance
InOutBlockData& operator=(const InOutBlockData& other)
{
this->m_idx = other.m_idx;
Expand All @@ -81,17 +81,16 @@ class InOutBlockData
*/
bool isLeaf() const { return m_idx > INTERNAL_BLOCK; }

/** \brief Marks the associated block as internal */
/// \brief Marks the associated block as internal
void setInternal() { m_idx = INTERNAL_BLOCK; }

/** \brief Marks the associated block as a non-block (i.e. not in the tree) */
/// \brief Marks the associated block as a non-block (i.e. not in the tree)
void setNonBlock() { m_idx = NON_BLOCK; }

/**
* \brief Predicate to determine if the associated block is in the tree
*
* \return True, if the block is in the tree (internal or leaf), False
* otherwise
* \return True, if the block is in the tree (internal or leaf), False otherwise
*/
bool isBlock() const { return m_idx != NON_BLOCK; }

Expand All @@ -111,9 +110,7 @@ class InOutBlockData
* */
bool hasData() const { return m_idx >= 0; }

/**
* Returns the index of the data associated with the block
*/
/// Returns the index of the data associated with the block
const int& dataIndex() const
{
//SLIC_ASSERT(hasData());
Expand All @@ -134,24 +131,24 @@ class InOutBlockData
m_idx = idx;
}

/** Marks the block as Black (the entire domain is inside the surface) */
/// Marks the block as Black (the entire domain is inside the surface)
void setBlack()
{
SLIC_ASSERT(isLeaf());
m_idx = LEAF_BLOCK_BLACK;
}

/** Marks the block as Black (the entire domain is outside the surface) */
/// Marks the block as Black (the entire domain is outside the surface)
void setWhite()
{
SLIC_ASSERT(isLeaf());
m_idx = LEAF_BLOCK_WHITE;
}

/** Sets the data associated with the block to the given index idx */
/// Sets the data associated with the block to the given index idx
void setData(int idx) { m_idx = idx; }

/** Marks the block as uncolored */
/// Marks the block as uncolored
void setUncoloredLeaf()
{
SLIC_ASSERT(isLeaf());
Expand Down Expand Up @@ -187,13 +184,14 @@ class InOutBlockData
return Undetermined;
}

/** Predicate to determine if the associated block has a color
/**
* \brief Predicate to determine if the associated block has a color
* \return True if the block has a color, false otherwise
* \sa color()
*/
bool isColored() const { return color() != Undetermined; }

/** Friend function to compare equality of two InOutBlockData instances */
/// Friend function to compare equality of two InOutBlockData instances
friend bool operator==(const InOutBlockData& lhs, const InOutBlockData& rhs)
{
return lhs.m_idx == rhs.m_idx;
Expand All @@ -204,7 +202,7 @@ class InOutBlockData
};

/**
* Free function to print an InOutBlockData to an output stream
* \brief Free function to print an InOutBlockData to an output stream
* \param os The output stream to write to
* \param iob The InOUtBlockData instance that we are writing
*/
Expand Down Expand Up @@ -274,9 +272,7 @@ class DynamicGrayBlockData
using CellList = std::vector<CellIndex>;

public:
/**
* \brief Default constructor for an InOutLeafData
*/
/// \brief Default constructor for an InOutLeafData
DynamicGrayBlockData() : m_vertIndex(NO_VERTEX), m_isLeaf(true) { }

/**
Expand All @@ -287,18 +283,14 @@ class DynamicGrayBlockData
*/
DynamicGrayBlockData(VertexIndex vInd, bool isLeaf) : m_vertIndex(vInd), m_isLeaf(isLeaf) { }

/**
* \brief Copy constructor for an DynamicGrayBlockData instance
*/
/// \brief Copy constructor for an DynamicGrayBlockData instance
DynamicGrayBlockData(const DynamicGrayBlockData& other)
: m_vertIndex(other.m_vertIndex)
, m_cells(other.m_cells)
, m_isLeaf(other.m_isLeaf)
{ }

/**
* \brief Assignment operator for an InOutLeafData instance
*/
/// \brief Assignment operator for an InOutLeafData instance
DynamicGrayBlockData& operator=(const DynamicGrayBlockData& other)
{
this->m_vertIndex = other.m_vertIndex;
Expand Down Expand Up @@ -334,52 +326,48 @@ class DynamicGrayBlockData
}

public: // Functions related to whether this is a leaf
/** Predicate to determine if the associated block is a leaf in the octree */
/// Predicate to determine if the associated block is a leaf in the octree
bool isLeaf() const { return m_isLeaf; }

/** Sets a flag to determine whether the associated block is a leaf or internal */
/// Sets a flag to determine whether the associated block is a leaf or internal
void setLeafFlag(bool isLeaf) { m_isLeaf = isLeaf; }

public: // Functions related to the associated vertex
/**
* \brief Checks whether there is a vertex associated with this leaf
*/
/// \brief Checks whether there is a vertex associated with this leaf
bool hasVertex() const { return m_vertIndex >= 0; }

/** Sets the vertex associated with this leaf */
/// Sets the vertex associated with this leaf
void setVertex(VertexIndex vInd) { m_vertIndex = vInd; }

/** Clears the associated vertex index */
/// Clears the associated vertex index
void clearVertex() { m_vertIndex = NO_VERTEX; }

/** Accessor for the index of the vertex associated with this leaf */
/// Accessor for the index of the vertex associated with this leaf
VertexIndex& vertexIndex() { return m_vertIndex; }

/** Constant accessor for the index of the vertex associated with this leaf */
/// Constant accessor for the index of the vertex associated with this leaf
const VertexIndex& vertexIndex() const { return m_vertIndex; }

public: // Functions related to the associated triangles
/** Check whether this Leaf has any associated triangles */
/// Check whether this Leaf has any associated triangles
bool hasCells() const { return !m_cells.empty(); }

/**
* Reserves space for a given number of triangles
* \brief Reserves space for a given number of triangles
* \param count The number of triangles for which to reserve space
*/
void reserveCells(int count) { m_cells.reserve(count); }

/** Find the number of triangles associated with this leaf */
/// Find the number of triangles associated with this leaf
int numCells() const { return static_cast<int>(m_cells.size()); }

/** Associates the surface triangle with the given index with this block */
/// Associates the surface triangle with the given index with this block
void addCell(CellIndex tInd) { m_cells.push_back(tInd); }

/** Returns a const reference to the list of triangle indexes associated with
the block */
/// Returns a const reference to the list of triangle indexes associated with the block
const CellList& cells() const { return m_cells; }

/** Returns a reference to the list of triangle indexes associated with the
block */
/// Returns a reference to the list of triangle indexes associated with the block
CellList& cells() { return m_cells; }

private:
Expand All @@ -388,9 +376,7 @@ class DynamicGrayBlockData
bool m_isLeaf;
};

/**
* Free function to print a DynamicGrayBlockData instance to an output stream
*/
/// Free function to print a DynamicGrayBlockData instance to an output stream
inline std::ostream& operator<<(std::ostream& os, const DynamicGrayBlockData& bData)
{
os << "DynamicGrayBlockData{";
Expand Down
2 changes: 2 additions & 0 deletions src/axom/quest/detail/inout/InOutOctreeMeshDumper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

#include "axom/fmt.hpp"

#include <unordered_map>

namespace axom
{
namespace quest
Expand Down
7 changes: 2 additions & 5 deletions src/axom/quest/examples/containment_driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

/*!
* \file containment_driver.cpp
* \brief Basic demo of point containment acceleration structure over surfaces.
* \brief Demo of InOutOctree point containment acceleration structure over surfaces.
*/

// Axom includes
Expand Down Expand Up @@ -401,10 +401,7 @@ class ContainmentDriver
nVerts,
nCells));

if(dimension() == 3)
{
SLIC_INFO("Edge length range: " << meshEdgeLenRange);
}
SLIC_INFO_IF(dimension() == 3, "Edge length range: " << meshEdgeLenRange);
SLIC_INFO("Cell area range is: " << meshCellAreaRange);

if(dimension() == 3)
Expand Down
Loading
Loading