Object oriented refactoring of fcType#577
Conversation
…e and construction
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #577 +/- ##
==========================================
+ Coverage 69.44% 69.47% +0.02%
==========================================
Files 181 183 +2
Lines 34072 34208 +136
Branches 5930 5932 +2
==========================================
+ Hits 23662 23765 +103
- Misses 10273 10306 +33
Partials 137 137 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
| // SPDX-FileCopyrightText: Copyright (c) Stanford University, The Regents of the University of California, and others. | ||
| // SPDX-License-Identifier: BSD-3-Clause |
There was a problem hiding this comment.
In this PR, the functions fft and ifft have been moved from this file to fourier_interpolation.cpp, inside the new FourierInterpolation class. I think this makes sense, since those functions were tightly coupled to fcType.
However, this file also contains another function, igbc, which is now the only function left. The function is not related to Fourier transform, so it seems odd to keep the name of this file as it is.
I propose renaming it to igbc.cpp (and the header to igbc.h).
| // @todo[michelebucelli] This is consistent with the old code, but is | ||
| // incorrect when use_ramp = true. In that case, the derivative should be | ||
| // zero outside the interpolation interval [initial_time, initial_time + | ||
| // period]. | ||
| if (evaluate_derivative) | ||
| derivative[i] = linear_trend_slopes[i]; |
There was a problem hiding this comment.
This was probably an unintended behavior of the old code.
When using the "ramp" option, the following function is computed (the implementation is formulated slightly different):
For times outside of the inerpolation interval
| // @todo[michelebucelli] This is consistent with the old code, but is | |
| // incorrect when use_ramp = true. In that case, the derivative should be | |
| // zero outside the interpolation interval [initial_time, initial_time + | |
| // period]. | |
| if (evaluate_derivative) | |
| derivative[i] = linear_trend_slopes[i]; | |
| if (evaluate_derivative) { | |
| if (use_ramp && (time < initial_time || time > initial_time + period)) { | |
| derivative[i] = 0.0; | |
| } else { | |
| derivative[i] = linear_trend_slopes[i]; | |
| } | |
| } |
I tried this out and all the tests still pass, so I propose changing this behavior.
| // @todo[michelebucelli] This seems pretty fragile! It happens in a few | ||
| // other places in this file as well, where using an increment | ||
| // operator (*= or +=) changes the order of operations resulting in | ||
| // changes in the test values. This should be investigated and the | ||
| // best (i.e. most accurate) operation order should be chosen. | ||
| value[j] = value[j] + fourier_coefficients_real(j, i) * std::cos(K) - | ||
| fourier_coefficients_imaginary(j, i) * std::sin(K); |
There was a problem hiding this comment.
This took me a while to figure out 😅 There's at least another place where the same thing happens. I'm honestly not sure which is the most correct option, but the fact that the order of operations makes a measurable difference probably means that this needs to be carefully evaluated.
| std::tie(value, derivative) = gt.value_and_derivative(x_start - 1.0); | ||
| ASSERT_NEAR(value[0], temporal_values[0][1], 1e-6) | ||
| << "Expected value before initial time to be equal to initial value of " | ||
| "linear trend"; | ||
|
|
||
| // Check that after the final time the value is equal to the final value of | ||
| // the linear trend. | ||
| std::tie(value, derivative) = gt.value_and_derivative(x_end + 1.0); | ||
| ASSERT_NEAR(value[0], temporal_values.back()[1], 1e-6) | ||
| << "Expected value after final time to be equal to final value of linear " | ||
| "trend"; | ||
|
|
||
| // Check that the value in the interpolation interval is a linear | ||
| // interpolation of the initial and final value. | ||
| for (double t = x_start; t <= x_end; t += 0.5) { | ||
| std::tie(value, derivative) = gt.value_and_derivative(t); | ||
|
|
||
| const double expected_y = | ||
| temporal_values[0][1] + | ||
| (temporal_values.back()[1] - temporal_values[0][1]) * (t - x_start) / | ||
| (x_end - x_start); | ||
| const double expected_z = | ||
| temporal_values[0][2] + | ||
| (temporal_values.back()[2] - temporal_values[0][2]) * (t - x_start) / | ||
| (x_end - x_start); | ||
|
|
||
| ASSERT_NEAR(value[0], expected_y, 1e-6) | ||
| << "Expected value in interpolation interval to be linear " | ||
| "interpolation of initial and final value"; | ||
| ASSERT_NEAR(value[1], expected_z, 1e-6) | ||
| << "Expected value in interpolation interval to be linear " | ||
| "interpolation of initial and final value"; |
There was a problem hiding this comment.
These assertions should be extended to include checks on the evaluated derivative, once we agree whether to change or keep the current behavior as per my previous comment.
Fixes #575.
Current situation
The class
fcTypeis currently defined inComMod.h, and its interface and that of related function make its use slightly more cumbersome and less seamless than it needs to be (see discussion in #575 for more details).Release Notes
fcTyperenamed toFourierInterpolation, and its data members (now private) renamed with more explicit names.FourierInterpolationimplementation moved to dedicated filesfourier_interpolation.{h,cpp}.FourierInterpolationobject is now done through static methodsFourierInterpolation::from_time_seriesandFourierInterpolation::from_fourier_coefficients(while before it was done "manually" everywhere this was needed).FourierInterpolation::from_time_series_fileandFourierInterpolation::from_fourier_coefficients_filemanage reading data from file (while before it was done "manually" everywhere this was needed).FourierInterpolation::distribute.FourierInterpolation::valueandFourierInterpolation::value_and_derivative.fftandifftwere tightly related tofcType(they worked on anfcTypeinstance), and they have been merged into the methodsFourierInterpolationclass (for construction and evaluation, respectively).All this should make it a bit easier to add support for reading time-dependent data from file in new classes (which is part of the aims of #519).
Documentation
The class and its methods have been given detailed Doxygen documentation.
Testing
The unit test and the integration tests all pass with the new interface.
TODO before marking as ready
Code of Conduct & Contributing Guidelines