Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,19 @@ Follow these code style and documentation rules exactly.
- `This work was performed by GPT-5.3-Codex in response to the prompt: "...".`
- Include the primary user prompt verbatim (or a faithful condensed version if it is extremely long).

12) Unit Test Documentation
- Add a brief Doxygen block immediately before every Catch2 `TEST_CASE` or `SCENARIO`.
- State the behavior being verified and identify the real production API under test.
- Let Doxygen discover real calls in the test body so the test appears in each production API's `Referenced by` list.
- Do not use `\test` or prose-only `\ref` commands to manufacture test-to-API links.

13) Preserve Doxygen Links Through Test Harnesses
- Preserve Doxygen links to the real production APIs when test fixtures, wrappers, namespaces, macros, or private-access techniques prevent automatic symbol linking.
- Add explicit Doxygen-only code references to the production symbols inside the relevant test body when direct calls are otherwise hidden.
- Guard reference-only code with `#ifdef __DOXY_ONLY__` so it need not compile, and use raw calls or member references that Doxygen can add to the production symbol's `Referenced by` list.
- Hide harness-only helpers from generated documentation with `\cond` and `\endcond` when they would dominate or obscure production API links.
- Disable `clang-format` around non-compiling Doxygen-only reference blocks when necessary.

When you finish:
- Summarize what changed.
- List affected files.
Expand Down
237 changes: 155 additions & 82 deletions include/ao/analysis/clAOLinearPredictor.hpp

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions include/ao/analysis/fourierTemporalPSD.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,20 +1139,20 @@ std::cerr << __FILE__ << " " << __LINE__ << "\n";
if( doLP )
{
realT min_sc;
int rv = tflp.regularizeCoefficients( gmax_lp,
gopt_lp,
var_lp,
min_sc,
go_lp,
tPSDpPOL,
tPSDn,
lpNc );

if( rv < 0 )
error_t rv = tflp.regularizeCoefficients( gmax_lp,
gopt_lp,
var_lp,
min_sc,
go_lp,
tPSDpPOL,
tPSDn,
lpNc );

if( rv != error_t::noerror )
{
std::cerr
<< "fourierTemporalPSD::analyzePSDGrid: regularizeCoefficients returned error ";
std::cerr << rv << ' ';
std::cerr << errorName( rv ) << ' ';
std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
}

Expand Down
27 changes: 13 additions & 14 deletions include/improc/imageUtils.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
#ifndef improc_imageUtils_hpp
#define improc_imageUtils_hpp

#include <cstdint>
#include <cmath>

#include "../math/floatUtils.hpp"

#include "imageTransforms.hpp"

namespace mx
Expand Down Expand Up @@ -77,13 +78,14 @@ constexpr T invalidNumber()
return -3e38;
}

/// Check if the number is nan, using several different methods
/**
/// Check whether a value represents an invalid image pixel.
/** Detects the mxlib invalid-number sentinel as well as NaN and positive or negative infinity.
*
* \returns true if value is invalid, otherwise false.
*/
inline bool IsNan( float value )
inline bool isInvalidPixel( float value /**< [in] value to test */ )
{
return ( ( ( ( *(uint32_t *)&value ) & 0x7fffffff ) > 0x7f800000 ) || ( value == invalidNumber<float>() ) ||
!std::isfinite( value ) );
return value == invalidNumber<float>() || !math::isFinite( value );
}

/// Reflect pixel coordinates across the given center pixel.
Expand Down Expand Up @@ -121,7 +123,7 @@ void zeroNaNs( imageT &im, ///< [in.out] image which will have any NaN pixels se
{
for( int r = 0; r < im.rows(); ++r )
{
if( IsNan( im( r, c ) ) )
if( isInvalidPixel( im( r, c ) ) )
{
im( r, c ) = val;
}
Expand Down Expand Up @@ -162,7 +164,7 @@ void zeroNaNCube( cubeT &imc, /**< [in.out] cube which will have any NaN pix
{
for( int r = 0; r < imc.rows(); ++r )
{
if( IsNan( imc.image( p )( r, c ) ) )
if( isInvalidPixel( imc.image( p )( r, c ) ) )
{
imc.image( p )( r, c ) = 0;
if( mask )
Expand Down Expand Up @@ -333,11 +335,11 @@ imageMedian( const imageT &mat, /**< [in] the image
*/
template <typename imageT>
typename imageT::Scalar imageMedian( const imageT &mat, /**< [in] the image to take the median of*/
std::vector<typename imageT::Scalar> *work = 0 /**< [in] [optional] working memory can
be retained and re-passed.*/
std::vector<typename imageT::Scalar> *work = 0 /**< [in] [optional] working memory
can be retained and re-passed.*/
)
{
return imageMedian( mat, static_cast<Eigen::Array<typename imageT::Scalar, -1, -1> *>(nullptr), work );
return imageMedian( mat, static_cast<Eigen::Array<typename imageT::Scalar, -1, -1> *>( nullptr ), work );
}

/// Calculate the center of light of an image
Expand Down Expand Up @@ -528,7 +530,6 @@ void removeCols( eigenT &out, const eigenTin &in, int st, int w )
out.topRightCorner( in.rows(), in.cols() - ( st + w ) ) = in.topRightCorner( in.rows(), in.cols() - ( st + w ) );
}


/** \ingroup image_utils
*@{
*/
Expand Down Expand Up @@ -581,8 +582,6 @@ void *imcpy_flipUDLR( void *dest, ///< [out] the address of the first pixel i
size_t szof ///< [in] the size in bytes of a one pixel
);



} // namespace improc
} // namespace mx

Expand Down
1 change: 1 addition & 0 deletions include/math/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ add_subdirectory(plot)

set(OBJLIB_INCLUDES ${OBJLIB_INCLUDES} include/math/constants.hpp
include/math/eigenLapack.hpp
include/math/floatUtils.hpp
include/math/geo.hpp
include/math/gslInterpolation.hpp
include/math/gslInterpolator.hpp
Expand Down
95 changes: 95 additions & 0 deletions include/math/floatUtils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/** \file floatUtils.hpp
* \author Jared R. Males
* \brief Floating-point classification utilities that remain reliable under fast-math optimization.
* \ingroup gen_math_files
*/

#ifndef math_floatUtils_hpp
#define math_floatUtils_hpp

#include <bit>
#include <cstdint>
#include <limits>
#include <type_traits>

namespace mx
{
namespace math
{

namespace floatUtils_detail
{

/// Convert an extended floating-point value to a classifiable double without overflowing finite values.
template <typename realT>
double normalizedDouble( realT value /**< [in] floating-point value to normalize */ )
{
return static_cast<double>( value / std::numeric_limits<realT>::max() );
}

} // namespace floatUtils_detail

/// Test whether a floating-point value is NaN, including under finite-math-only optimization.
/**
* \returns true if value is a quiet or signaling NaN, otherwise false.
*
* \ingroup gen_math
*/
template <typename realT>
bool isNan( realT value /**< [in] floating-point value to test */ )
{
static_assert( std::is_floating_point_v<realT>, "isNan requires a floating-point type" );

if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint32_t ) )
{
constexpr std::uint32_t exponentMask = 0x7f800000U;
constexpr std::uint32_t mantissaMask = 0x007fffffU;
const std::uint32_t bits = std::bit_cast<std::uint32_t>( value );
return ( bits & exponentMask ) == exponentMask && ( bits & mantissaMask ) != 0;
}
else if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint64_t ) )
{
constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
constexpr std::uint64_t mantissaMask = 0x000fffffffffffffULL;
const std::uint64_t bits = std::bit_cast<std::uint64_t>( value );
return ( bits & exponentMask ) == exponentMask && ( bits & mantissaMask ) != 0;
}
else
{
const double normalized = floatUtils_detail::normalizedDouble( value );
return isNan( normalized );
}
}

/// Test whether a floating-point value is finite, including under finite-math-only optimization.
/**
* \returns true if value is neither infinite nor NaN, otherwise false.
*
* \ingroup gen_math
*/
template <typename realT>
bool isFinite( realT value /**< [in] floating-point value to test */ )
{
static_assert( std::is_floating_point_v<realT>, "isFinite requires a floating-point type" );

if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint32_t ) )
{
constexpr std::uint32_t exponentMask = 0x7f800000U;
return ( std::bit_cast<std::uint32_t>( value ) & exponentMask ) != exponentMask;
}
else if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint64_t ) )
{
constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
return ( std::bit_cast<std::uint64_t>( value ) & exponentMask ) != exponentMask;
}
else
{
const double normalized = floatUtils_detail::normalizedDouble( value );
return isFinite( normalized );
}
}

} // namespace math
} // namespace mx

#endif // math_floatUtils_hpp
1 change: 1 addition & 0 deletions include/math/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "plot/gnuPlot.hpp"
#include "constants.hpp"
#include "eigenLapack.hpp"
#include "floatUtils.hpp"
#include "geo.hpp"
#include "gslInterpolation.hpp"
#include "gslInterpolator.hpp"
Expand Down
2 changes: 2 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ set(MXLIB_TEST_MAIN_SOURCE ${CMAKE_CURRENT_SOURCE_DIR}/testMain.cpp)

set(MXLIB_TEST_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/include/ao/analysis/aoAtmosphere_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ao/analysis/clAOLinearPredictor_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ao/analysis/aoSystem_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ao/analysis/aoPSDs_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/astro/astroDynamics_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ioutils/fileUtils_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ioutils/fits/fitsHeaderCard_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/ioutils/fits/fitsFile_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/math/geo_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/math/floatUtils_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/math/func/moffat_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/math/templateBLAS_test.cpp
${CMAKE_CURRENT_SOURCE_DIR}/include/math/templateLapack_test.cpp
Expand Down
2 changes: 2 additions & 0 deletions tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,15 @@ INCLUDES += -I../include

OBJS = testMain.o \
include/ao/analysis/aoAtmosphere_test.o \
include/ao/analysis/clAOLinearPredictor_test.o \
include/ao/analysis/aoSystem_test.o \
include/ao/analysis/aoPSDs_test.o \
include/astro/astroDynamics_test.o \
include/ioutils/fileUtils_test.o \
include/ioutils/fits/fitsHeaderCard_test.o \
include/ioutils/fits/fitsFile_test.o \
include/math/geo_test.o \
include/math/floatUtils_test.o \
include/math/func/moffat_test.o \
include/math/templateBLAS_test.o \
include/math/templateLapack_test.o \
Expand Down
Loading
Loading