-
Notifications
You must be signed in to change notification settings - Fork 184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Alter CCE interface managers for new changes to interpolation #3422
Alter CCE interface managers for new changes to interpolation #3422
Conversation
8c79776
to
105b9b8
Compare
105b9b8
to
dfaae3d
Compare
Rebased on develop, no longer dependent. |
template <typename VarsToInterpolate> | ||
auto create_span_for_time_value( | ||
double time, size_t interpolator_length, | ||
const std::map<double, VarsToInterpolate>& gh_data) noexcept { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about something like this. (Probably +1 in some places.)
const auto now = gh_data.upper_bound(time);
if (std::distance(gh_data.begin(), now) < interpolator_length)) {
return gh_data.begin();
} else if (std::distance(now, gh_data.end()) < interpolator_length) {
return std::prev(gh_data.end(), 2 * interpolator_length);
} else {
return std::prev(now, interpolator_length);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice, I like this -- I didn't know std::prev
for incrementing/decrementing iterators by arbitrary amounts.
while (lower_span_size < interpolator_length) { | ||
++upper_iterator; | ||
++lower_span_size; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this form of this function survives, this loop should be removed because none of the variables modified here are read afterwards.
2 * interpolator->required_number_of_points_before_and_after()}; | ||
DataVector tensor_component_values{ | ||
2 * interpolator->required_number_of_points_before_and_after()}; | ||
for (auto [i, map_it] = std::make_tuple(0_st, iterator_start); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Not a request) Neat! I haven't seen this structured-binding application before.
for (auto gh_data_it = gh_data_.begin(); | ||
gh_data_it != gh_data_.end() and | ||
gh_data_it->first < requests_.front().substep_time().value(); | ||
++gh_data_it, ++number_of_points_before_first_request) { | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be written in terms of upper_bound
or something?
* sufficient to perform interpolation to arbitrary times required by CCE. From | ||
* the Generalized Harmonic system, it receives the spacetime metric \f$g_{a | ||
* b}\f$ and Generalized Harmonic \f$\Phi_{i a b}\f$ and \f$\Pi_{ab}\f$ and the | ||
* current `TimeStepId` via `GhLocalTimeStepping::insert_gh_data()`. The CCE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not TimeStepId anymore.
/// system should wait for additional data from the GH system. | ||
void insert_gh_data(TimeStepId time_id, | ||
/// \brief Store the provided data set to prepare for interpolation. | ||
void insert_gh_data(double time, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't remember how the code driving this class works, but is there something sequencing the calls to insert_gh_data
and retrieve_and_remove_first_ready_gh_data
so that you get consistent results when running in parallel?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I have it working is that there is an action that inserts requests for the next CCE time, and an action that inserts new data from GH interpolation. Each time there is either a new request or new gh data it checks the retrieve_and_remove_first_ready_gh_data
, and sends it to the CCE evolution component if its ready, so I don't think there's any trouble with sequencing between the components.
The GH data is stored in a map, so I think there shouldn't be any trouble with misordered arrival of the GH data.
The CCE requests are stored in a std::deque
, so there is an assumption here that the CCE requests are ordered, but I think that is guaranteed by the communication pattern in CCE -- it always consumes a time before requesting the next. For flexibility, though, I'll to change it to a std::set
, then there aren't any ordering constraints for these structures.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that answers my question, but I'm going to ask another clarifying one to be sure.
The thing I'm worried about is that the create_span_for_time_value
function makes decisions based on what GH data is available. Is the set of available data deterministic when that function is called?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right, that's a good point. That does make ordering assumptions -- In particular, one could imagine that if the data was inserted such that most of the data in a part of the evolution arrives in sequence, but one intermediate value arrives far later, then this interpolation would activate using more distant points, and presumably have degraded accuracy because of the missing point.
I think I can solve this if I can send along with each set of data from a dense trigger, the previous time the dense trigger activated -- then the interpolation step in this class could check that the set of data it is using to perform the interpolation is contiguous.
Is there an easy way to get access to the previous trigger time so that I could include that information?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can change DenseTrigger::is_triggered
to non-const and use a member variable. I was planning to do that anyway because the control system trigger has some similar needs.
@@ -28,7 +28,9 @@ | |||
#include "Framework/TestCreation.hpp" | |||
#include "Helpers/DataStructures/DataBox/TestHelpers.hpp" | |||
#include "Helpers/Evolution/Systems/Cce/BoundaryTestHelpers.hpp" | |||
#include "NumericalAlgorithms/Interpolation/BarycentricRationalSpanInterpolator.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are these needed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll drop these from this commit directly -- looks like they're removed again in a later commit anyway.
dfaae3d
to
8d144c2
Compare
fixup posted. |
@@ -110,7 +110,7 @@ class GhLocalTimeStepping : public GhInterfaceManager { | |||
void clean_up_gh_data() noexcept; | |||
|
|||
std::map<double, gh_variables> gh_data_; | |||
std::deque<TimeStepId> requests_; | |||
std::set<TimeStepId> requests_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think std::priority_queue
is that data structure you're looking for, unless you need to ignore duplicates for some reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, the std::priority_queue
turns out to be troublesome for serialization, because as far as I can tell, it's a non-iterable container. The only way I can see to serialize it is to either make a full copy and serialize as elements are popped off the top, or to pop elements, save them off to a different container, then push them back on again (so, again, requires something like a copy).
If it's acceptable for the time being, I think I'd prefer to leave it as a set to make the serialization more graceful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, yeah, that's a good reason. I expect this container should always be small anyway.
@@ -85,7 +85,7 @@ class GhLockstep : public GhInterfaceManager { | |||
|
|||
private: | |||
std::map<TimeStepId, gh_variables> provided_data_; | |||
std::deque<TimeStepId> requests_; | |||
std::set<TimeStepId> requests_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
priority_queue
again.
/// system should wait for additional data from the GH system. | ||
void insert_gh_data(TimeStepId time_id, | ||
/// \brief Store the provided data set to prepare for interpolation. | ||
void insert_gh_data(double time, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that answers my question, but I'm going to ask another clarifying one to be sure.
The thing I'm worried about is that the create_span_for_time_value
function makes decisions based on what GH data is available. Is the set of available data deterministic when that function is called?
You can squash and rebase. |
8d144c2
to
0616dd7
Compare
I've squashed the previous fixup and rebased. I've added two new commits and a fixup that make the remaining changes to the interface managers necessary to guarantee strict ordering using the previous times from the triggers. |
std::map<std::pair<int, double>, double, PairComparator> map_to_serialize; | ||
map_to_serialize.insert({std::make_pair(1, 2.0), 3.0}); | ||
map_to_serialize.insert({std::make_pair(3, 1.0), 1.5}); | ||
map_to_serialize.insert({std::make_pair(2, 6.0), 10.2}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure what this commit is about (maybe give a brief description somewhere?), but this test is definitely not doing what you intend. The statement on this line doesn't do anything because it is a "duplicate" of the first key that was inserted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, yeah, I see the mistake; I guess I shouldn't have gotten cute with the comparison operator -- I'll fix the comparator.
The commit is just adding a pup function that a) doesn't interfere with existing pup functions for STL containers -- because we'll want to use the charm built-in one once it works, and b) doesn't cause a compiler error for a std::map with a custom comparator. There is currently a charm bug (actually just fixed, but not yet in a version) that causes reserve
to be called when the map has a custom comparator, and therefore doesn't compile, I'll add that information to the commit message as well
edit: if you think it would be better to just make this the actual pup function for nevermind, that's redefinition problem, needs to be left as a separate functionstd::map
with a comparator and then remove it later when the charm fix is available, I'm fine with doing that too
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I see. I think you could add an overload of PUP::reserve_if_applicable
, but I like the separate function better.
(It was a valid comparator, just probably not one you'd want for a general map. I can even assign it almost-reasonable meaning as the timelike (i.e., non-null) comparator for events in null coordinates in SR with one axis reversed. :))
#include "Time/TimeStepId.hpp" | ||
#include "Time/TimeSteppers/AdamsBashforthN.hpp" | ||
#include "Utilities/MakeString.hpp" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not used.
0616dd7
to
87e0264
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Squash.
std::map<std::pair<int, double>, double, PairComparator> map_to_serialize; | ||
map_to_serialize.insert({std::make_pair(1, 2.0), 3.0}); | ||
map_to_serialize.insert({std::make_pair(3, 1.0), 1.5}); | ||
map_to_serialize.insert({std::make_pair(2, 6.0), 10.2}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, I see. I think you could add an overload of PUP::reserve_if_applicable
, but I like the separate function better.
(It was a valid comparator, just probably not one you'd want for a general map. I can even assign it almost-reasonable meaning as the timelike (i.e., non-null) comparator for events in null coordinates in SR with one axis reversed. :))
87e0264
to
c86cb80
Compare
fixups squashed in. |
c86cb80
to
b7b4a65
Compare
Needed to squash again to remove a |
(Not a request.) We've encountered a similar requirement for keeping track of message order in the control systems, which I'll probably try to deal with something like how it was done here. If I end up with a sufficiently general solution it might be possible to share some classes between the two, but I don't know if that will happen, yet. Not something that should hold this PR up. |
They will not be needed anymore, as CCE will not support any method of data transfer apart from dense interpolation.
Adds a function `pup_override` to use for `std::map`s with custom comparators, because currently a charm bug causes an invalid `reserve` call for such containers. The function is intentionally chosen to not directly interfere with the charm pup override so that the charm version of the function can be easily used or tested once the bug is fixed.
- dense interpolation sends `double`s for times rather than TimeStepIds - dense interpolation will not send time derivatives of the evolved quantities, so we must perform the CCE interpolation without them.
Both versions of interface manager will still be needed, and need to maintain a common interface, but they should not be selectable at runtime -- one will be used only during self-start, and one only during the main evolution.
b7b4a65
to
7205109
Compare
Interpolation for self start cannot follow the standard events and dense triggers control flow, so needs a specialized action to provide CCE with boundary data during self start.
This is needed to provide the interpolator source tags for CCE
Self start with GH-CCE requires the communication via the interpolator, which requires registration. It should be fine to perform registration before self-start, as no current registration process assumes anything about the state of the `TimeStepId`.
This allows evaluating dense triggers at a step value shortly after self-start.
7205109
to
894fe69
Compare
@wthrowe I rebased this |
I need to think for a bit about whether there is any interaction with #3510. |
I think "Use evolution_less_equal for receive_local_time_stepping" is redundant with #3510 and can be dropped. Unfortunately, I can't remember exactly what problem that commit was supposed to fix. (I was consulted on the matter, but I don't remember what the problem was anymore.) |
I took over this PR in #3963 |
Proposed changes
This makes a number of changes to the interface for the GH system sending data to CCE based on the newer design considerations from the availability of dense interpolation:
GhLockstep
interface manager is the only available method during self-start, and theGhLocalTimeStepping
interface manager is the only available method during the evolutionTimeStepId
as the relevant temporal id for those utilities intended for self start, anddouble
for all other cases.Upgrade instructions
Any usage of the
GhInterfaceManagers
will likely need to be reworked to account for the new interfaces.Code review checklist
make doc
to generate the documentation locally intoBUILD_DIR/docs/html
.Then open
index.html
.code review guide.
bugfix
ornew feature
if appropriate.Dependencies
temporal_id
for interpolation in interpolation target tags #3421