|
| 1 | +#include "specfem/attenuation.hpp" |
| 2 | +#include <cmath> |
| 3 | +#include <gtest/gtest.h> |
| 4 | + |
| 5 | +using specfem::attenuation::compute_tau_sigma; |
| 6 | + |
| 7 | +// Test that the function returns the correct number of elements |
| 8 | +TEST(Attenuation_ComputeTauSigma, ReturnsCorrectSize) { |
| 9 | + constexpr type_real min_period = 0.01; |
| 10 | + constexpr type_real max_period = 10.0; |
| 11 | + |
| 12 | + auto tau_s_3 = compute_tau_sigma<3>(min_period, max_period); |
| 13 | + EXPECT_EQ(tau_s_3.extent(0), 3); |
| 14 | + |
| 15 | + auto tau_s_5 = compute_tau_sigma<5>(min_period, max_period); |
| 16 | + EXPECT_EQ(tau_s_5.extent(0), 5); |
| 17 | +} |
| 18 | + |
| 19 | +// Test that tau_sigma values are positive |
| 20 | +TEST(Attenuation_ComputeTauSigma, ValuesArePositive) { |
| 21 | + constexpr type_real min_period = 0.01; |
| 22 | + constexpr type_real max_period = 10.0; |
| 23 | + |
| 24 | + auto tau_s = compute_tau_sigma<3>(min_period, max_period); |
| 25 | + |
| 26 | + for (int i = 0; i < 3; ++i) { |
| 27 | + EXPECT_GT(tau_s(i), 0.0) << "tau_s(" << i << ") should be positive"; |
| 28 | + } |
| 29 | +} |
| 30 | + |
| 31 | +// Test that tau_sigma values are monotonically decreasing |
| 32 | +// (higher frequency = smaller tau) |
| 33 | +TEST(Attenuation_ComputeTauSigma, ValuesAreMonotonicallyDecreasing) { |
| 34 | + constexpr type_real min_period = 0.01; |
| 35 | + constexpr type_real max_period = 10.0; |
| 36 | + |
| 37 | + auto tau_s = compute_tau_sigma<5>(min_period, max_period); |
| 38 | + |
| 39 | + for (int i = 1; i < 5; ++i) { |
| 40 | + EXPECT_LT(tau_s(i), tau_s(i - 1)) |
| 41 | + << "tau_s(" << i << ") should be less than tau_s(" << i - 1 << ")"; |
| 42 | + } |
| 43 | +} |
| 44 | + |
| 45 | +// Test that tau_sigma values are equally spaced in log10 frequency |
| 46 | +TEST(Attenuation_ComputeTauSigma, EquallySpacedInLog10Frequency) { |
| 47 | + constexpr type_real min_period = 0.01; |
| 48 | + constexpr type_real max_period = 10.0; |
| 49 | + constexpr int N_SLS = 5; |
| 50 | + |
| 51 | + auto tau_s = compute_tau_sigma<N_SLS>(min_period, max_period); |
| 52 | + |
| 53 | + // Convert tau_s to frequencies: f = 1 / (2 * pi * tau_s) |
| 54 | + // Then check that log10(f) values are equally spaced |
| 55 | + std::array<type_real, N_SLS> log_freq; |
| 56 | + for (int i = 0; i < N_SLS; ++i) { |
| 57 | + type_real freq = 1.0 / (2.0 * pi * tau_s(i)); |
| 58 | + log_freq[i] = std::log10(freq); |
| 59 | + } |
| 60 | + |
| 61 | + // Check that differences between consecutive log10(freq) are equal |
| 62 | + type_real expected_spacing = log_freq[1] - log_freq[0]; |
| 63 | + for (int i = 2; i < N_SLS; ++i) { |
| 64 | + type_real actual_spacing = log_freq[i] - log_freq[i - 1]; |
| 65 | + EXPECT_NEAR(actual_spacing, expected_spacing, 1e-10) |
| 66 | + << "Log10 frequency spacing should be constant"; |
| 67 | + } |
| 68 | +} |
| 69 | + |
| 70 | +// Test boundary values match expected frequencies |
| 71 | +TEST(Attenuation_ComputeTauSigma, BoundaryFrequenciesMatch) { |
| 72 | + constexpr type_real min_period = 0.01; |
| 73 | + constexpr type_real max_period = 10.0; |
| 74 | + constexpr int N_SLS = 3; |
| 75 | + |
| 76 | + auto tau_s = compute_tau_sigma<N_SLS>(min_period, max_period); |
| 77 | + |
| 78 | + // Expected frequencies at boundaries |
| 79 | + type_real f_min = 1.0 / max_period; // 0.1 Hz |
| 80 | + type_real f_max = 1.0 / min_period; // 100 Hz |
| 81 | + |
| 82 | + // Convert tau_s to frequency: f = 1 / (2 * pi * tau_s) |
| 83 | + type_real freq_first = 1.0 / (2.0 * pi * tau_s(0)); |
| 84 | + type_real freq_last = 1.0 / (2.0 * pi * tau_s(N_SLS - 1)); |
| 85 | + |
| 86 | + // First tau_s corresponds to f_min, last to f_max |
| 87 | + EXPECT_NEAR(freq_first, f_min, f_min * 1e-10) |
| 88 | + << "First frequency should match f_min"; |
| 89 | + EXPECT_NEAR(freq_last, f_max, f_max * 1e-10) |
| 90 | + << "Last frequency should match f_max"; |
| 91 | +} |
| 92 | + |
| 93 | +// Test with different period ranges |
| 94 | +TEST(Attenuation_ComputeTauSigma, DifferentPeriodRanges) { |
| 95 | + // Narrow range |
| 96 | + { |
| 97 | + auto tau_s = compute_tau_sigma<3>(1.0, 10.0); |
| 98 | + EXPECT_GT(tau_s(0), 0.0); |
| 99 | + EXPECT_GT(tau_s(1), 0.0); |
| 100 | + EXPECT_GT(tau_s(2), 0.0); |
| 101 | + } |
| 102 | + |
| 103 | + // Wide range |
| 104 | + { |
| 105 | + auto tau_s = compute_tau_sigma<3>(0.001, 100.0); |
| 106 | + EXPECT_GT(tau_s(0), 0.0); |
| 107 | + EXPECT_GT(tau_s(1), 0.0); |
| 108 | + EXPECT_GT(tau_s(2), 0.0); |
| 109 | + } |
| 110 | +} |
| 111 | + |
| 112 | +// Test N_SLS = 2 edge case (minimum valid value) |
| 113 | +// Note: N_SLS=1 causes division by zero in dexpval calculation |
| 114 | +TEST(Attenuation_ComputeTauSigma, TwoSLS) { |
| 115 | + constexpr type_real min_period = 0.01; |
| 116 | + constexpr type_real max_period = 10.0; |
| 117 | + |
| 118 | + auto tau_s = compute_tau_sigma<2>(min_period, max_period); |
| 119 | + |
| 120 | + EXPECT_EQ(tau_s.extent(0), 2); |
| 121 | + EXPECT_GT(tau_s(0), 0.0); |
| 122 | + EXPECT_GT(tau_s(1), 0.0); |
| 123 | + |
| 124 | + // First should correspond to f_min, second to f_max |
| 125 | + type_real f_min = 1.0 / max_period; |
| 126 | + type_real f_max = 1.0 / min_period; |
| 127 | + type_real freq_first = 1.0 / (2.0 * pi * tau_s(0)); |
| 128 | + type_real freq_last = 1.0 / (2.0 * pi * tau_s(1)); |
| 129 | + |
| 130 | + EXPECT_NEAR(freq_first, f_min, f_min * 1e-10); |
| 131 | + EXPECT_NEAR(freq_last, f_max, f_max * 1e-10); |
| 132 | +} |
0 commit comments