// Kernel arithmetic checks linked only with the host emulation fixture. #include "../processing/processors/src/sar3d_gpu.hpp" #include #include #include #include #include extern "C" void peak_planes(const float*, int, int, float*, unsigned int*); struct Index { unsigned x; }; extern Index blockIdx; auto probe_ascan_upper_bound() -> float; namespace { void rejects_unsigned_padding() { blockIdx.x = 0x80000000U; peak_planes(nullptr, 1, 1, nullptr, nullptr); } void rejects_rounded_sample_bound() { if (probe_ascan_upper_bound() != 0.0F) { throw std::runtime_error("out-of-range float A-scan position was accepted"); } } void rejects_nan_peak() { blockIdx.x = 0; const float volume[]{std::numeric_limits::quiet_NaN(), 0.0F}; float level = -1.0F; unsigned int index = 0U; peak_planes(volume, 2, 1, &level, &index); if (std::isfinite(level)) { throw std::runtime_error("peak kernel silently ignored NaN"); } } void keeps_first_joint_peak() { blockIdx.x = 0; const float volume[]{0, 1, 0, 1, 0, 0}; float level = 0; unsigned int index = 0U; peak_planes(volume, 6, 1, &level, &index); if (level != 1.0F || index != 1U) { throw std::runtime_error("joint peak tie chose a nonexistent voxel"); } } void rejects_finite_coherent_overflow() { using namespace radar::processing::sar3d; Engine engine(1.5); const std::vector x{-1, 1}, y{-.5, .5}, z{2, 3}; std::vector terms(3); for (auto& term : terms) { term.weight = 1; term.inv_reference_ranges = 1; } std::vector> scans(3 * 64); for (int i = 0; i < 64; ++i) { scans[i] = {1e38F, 0}; scans[64 + i] = {-1e38F, 0}; scans[128 + i] = {1, 0}; } const VolumeRequest request{ .x = x, .y = y, .z = z, .min_depth_m = 1, .max_depth_m = 4, .contributions = terms, .ascans = scans, .samples_per_ascan = 64, .samples_per_metre = 1, .use_compensation = true, .comp_range_power = 1, .comp_weight_max = 5, .norm_edge_margin_m = .3, .oblique = {.u = {1, 0, 0}, .v = {0, 0, 1}, .u0 = -1, .v0 = 2, .pixel_m = 1, .nu = 3, .nv = 2}, }; try { (void)engine.project(request); } catch (const std::runtime_error& error) { if (std::string_view(error.what()).find("non-finite") == std::string_view::npos) { throw; } return; } throw std::runtime_error("finite coherent overflow was silently accepted as no signal"); } } int main() { try { rejects_unsigned_padding(); rejects_rounded_sample_bound(); rejects_nan_peak(); keeps_first_joint_peak(); rejects_finite_coherent_overflow(); std::cout << "SAR CUDA kernel arithmetic regressions passed\n"; } catch (const std::exception& error) { std::cerr << error.what() << '\n'; return 1; } }