InterpolationTargetDetail.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include <cstddef>
7 #include <memory>
8 #include <unordered_set>
9 #include <utility>
10 #include <vector>
11 
13 #include "DataStructures/IdPair.hpp"
14 #include "DataStructures/VariablesTag.hpp"
15 #include "Domain/BlockLogicalCoordinates.hpp"
16 #include "Domain/Tags.hpp"
17 #include "Domain/TagsTimeDependent.hpp"
18 #include "Parallel/GlobalCache.hpp"
19 #include "Parallel/Invoke.hpp"
20 #include "Parallel/ParallelComponentHelpers.hpp"
21 #include "Utilities/Algorithm.hpp"
22 #include "Utilities/Gsl.hpp"
23 #include "Utilities/Literals.hpp"
24 #include "Utilities/Requires.hpp"
25 #include "Utilities/TMPL.hpp"
26 #include "Utilities/TaggedTuple.hpp"
27 #include "Utilities/TypeTraits.hpp"
28 #include "Utilities/TypeTraits/CreateHasStaticMemberVariable.hpp"
29 
30 /// \cond
31 // IWYU pragma: no_forward_declare db::DataBox
32 namespace intrp {
33 template <class Metavariables>
34 struct Interpolator;
35 template <typename Metavariables, typename InterpolationTargetTag>
36 class InterpolationTarget;
37 namespace Actions {
38 template <typename InterpolationTargetTag>
39 struct CleanUpInterpolator;
40 template <typename InterpolationTargetTag>
41 struct ReceivePoints;
42 } // namespace Actions
43 namespace Tags {
44 template <typename TemporalId>
45 struct IndicesOfFilledInterpPoints;
46 template <typename TemporalId>
47 struct IndicesOfInvalidInterpPoints;
48 template <typename InterpolationTargetTag, typename TemporalId>
49 struct InterpolatedVars;
50 template <typename TemporalId>
51 struct CompletedTemporalIds;
52 template <typename TemporalId>
53 struct PendingTemporalIds;
54 template <typename TemporalId>
55 struct TemporalIds;
56 } // namespace Tags
57 } // namespace intrp
58 template <typename TagsList>
59 struct Variables;
60 /// \endcond
61 
62 namespace intrp {
63 
64 namespace InterpolationTarget_detail {
65 
66 // apply_callback accomplishes the overload for the
67 // two signatures of callback functions.
68 // Uses SFINAE on return type.
69 template <typename T, typename DbTags, typename Metavariables,
70  typename TemporalId>
71 auto apply_callback(
72  const gsl::not_null<db::DataBox<DbTags>*> box,
74  const TemporalId& temporal_id) noexcept
75  -> decltype(T::post_interpolation_callback::apply(box, cache, temporal_id),
76  bool()) {
77  return T::post_interpolation_callback::apply(box, cache, temporal_id);
78 }
79 
80 template <typename T, typename DbTags, typename Metavariables,
81  typename TemporalId>
82 auto apply_callback(
83  const gsl::not_null<db::DataBox<DbTags>*> box,
85  const TemporalId& temporal_id) noexcept
86  -> decltype(T::post_interpolation_callback::apply(*box, *cache,
87  temporal_id),
88  bool()) {
89  T::post_interpolation_callback::apply(*box, *cache, temporal_id);
90  // For the simpler callback function, we will always clean up volume data, so
91  // we return true here.
92  return true;
93 }
94 
95 CREATE_HAS_STATIC_MEMBER_VARIABLE(fill_invalid_points_with)
96 CREATE_HAS_STATIC_MEMBER_VARIABLE_V(fill_invalid_points_with)
97 
98 // Fills invalid points with some constant value.
99 template <typename InterpolationTargetTag, typename TemporalId, typename DbTags,
100  Requires<not has_fill_invalid_points_with_v<
101  typename InterpolationTargetTag::post_interpolation_callback>> =
102  nullptr>
103 void fill_invalid_points(const gsl::not_null<db::DataBox<DbTags>*> /*box*/,
104  const TemporalId& /*temporal_id*/) noexcept {}
105 
106 template <typename InterpolationTargetTag, typename TemporalId, typename DbTags,
107  Requires<has_fill_invalid_points_with_v<
108  typename InterpolationTargetTag::post_interpolation_callback>> =
109  nullptr>
110 void fill_invalid_points(const gsl::not_null<db::DataBox<DbTags>*> box,
111  const TemporalId& temporal_id) noexcept {
112  const auto& invalid_indices =
113  db::get<Tags::IndicesOfInvalidInterpPoints<TemporalId>>(*box);
114  if (invalid_indices.find(temporal_id) != invalid_indices.end() and
115  not invalid_indices.at(temporal_id).empty()) {
116  db::mutate<Tags::IndicesOfInvalidInterpPoints<TemporalId>,
117  Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>(
118  box, [&temporal_id](
120  TemporalId, std::unordered_set<size_t>>*>
121  indices_of_invalid_points,
123  TemporalId, Variables<typename InterpolationTargetTag::
124  vars_to_interpolate_to_target>>*>
125  vars_dest_all_times) noexcept {
126  auto& vars_dest = vars_dest_all_times->at(temporal_id);
127  const size_t npts_dest = vars_dest.number_of_grid_points();
128  const size_t nvars = vars_dest.number_of_independent_components;
129  for (auto index : indices_of_invalid_points->at(temporal_id)) {
130  for (size_t v = 0; v < nvars; ++v) {
131  // clang-tidy: no pointer arithmetic
132  vars_dest.data()[index + v * npts_dest] = // NOLINT
133  InterpolationTargetTag::post_interpolation_callback::
134  fill_invalid_points_with;
135  }
136  }
137  // Further functions may test if there are invalid points.
138  // Clear the invalid points now, since we have filled them.
139  indices_of_invalid_points->erase(temporal_id);
140  });
141  }
142 }
143 
144 /// Wraps calling the callback function on an InterpolationTarget.
145 ///
146 /// First prepares for the callback, then calls the callback,
147 /// and returns true if the callback is done and
148 /// false if the callback is not done (e.g. if the callback is an
149 /// apparent horizon search and it needs another iteration).
150 ///
151 /// call_callback is called by an Action of InterpolationTarget.
152 ///
153 /// Currently two Actions call call_callback:
154 /// - InterpolationTargetReceiveVars (called by Interpolator ParallelComponent)
155 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
156 template <typename InterpolationTargetTag, typename DbTags,
157  typename Metavariables, typename TemporalId>
158 bool call_callback(
159  const gsl::not_null<db::DataBox<DbTags>*> box,
161  const TemporalId& temporal_id) noexcept {
162  // Before doing anything else, deal with the possibility that some
163  // of the points might be outside of the Domain.
164  fill_invalid_points<InterpolationTargetTag>(box, temporal_id);
165 
166  // Fill ::Tags::Variables<typename
167  // InterpolationTargetTag::vars_to_interpolate_to_target>
168  // with variables from correct temporal_id.
170  tmpl::list<::Tags::Variables<
171  typename InterpolationTargetTag::vars_to_interpolate_to_target>>,
172  tmpl::list<Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>>(
173  [&temporal_id](
174  const gsl::not_null<Variables<
175  typename InterpolationTargetTag::vars_to_interpolate_to_target>*>
176  vars,
177  const std::unordered_map<
178  TemporalId, Variables<typename InterpolationTargetTag::
179  vars_to_interpolate_to_target>>&
180  vars_at_all_times) noexcept {
181  *vars = vars_at_all_times.at(temporal_id);
182  },
183  box);
184 
185  // apply_callback should return true if we are done with this
186  // temporal_id. It should return false only if the callback
187  // calls another `intrp::Action` that needs the volume data at this
188  // same temporal_id.
189  return apply_callback<InterpolationTargetTag>(box, cache, temporal_id);
190 }
191 
192 /// Frees InterpolationTarget's memory associated with the supplied
193 /// temporal_id.
194 ///
195 /// clean_up_interpolation_target is called by an Action of InterpolationTarget.
196 ///
197 /// Currently two Actions call clean_up_interpolation_target:
198 /// - InterpolationTargetReceiveVars (called by Interpolator ParallelComponent)
199 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
200 template <typename InterpolationTargetTag, typename DbTags, typename TemporalId>
201 void clean_up_interpolation_target(
202  const gsl::not_null<db::DataBox<DbTags>*> box,
203  const TemporalId& temporal_id) noexcept {
204  // We are now done with this temporal_id, so we can pop it and
205  // clean up data associated with it.
206  db::mutate<Tags::TemporalIds<TemporalId>,
207  Tags::CompletedTemporalIds<TemporalId>,
208  Tags::IndicesOfFilledInterpPoints<TemporalId>,
209  Tags::IndicesOfInvalidInterpPoints<TemporalId>,
210  Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>(
211  box, [&temporal_id](
213  const gsl::not_null<std::deque<TemporalId>*> completed_ids,
214  const gsl::not_null<
216  indices_of_filled,
217  const gsl::not_null<
219  indices_of_invalid,
221  TemporalId, Variables<typename InterpolationTargetTag::
222  vars_to_interpolate_to_target>>*>
223  interpolated_vars) noexcept {
224  completed_ids->push_back(temporal_id);
225  ASSERT(std::find(ids->begin(), ids->end(), temporal_id) != ids->end(),
226  "Temporal id " << temporal_id << " does not exist in ids");
227  ids->erase(std::remove(ids->begin(), ids->end(), temporal_id),
228  ids->end());
229  // We want to keep track of all completed temporal_ids to deal with
230  // the possibility of late calls to
231  // AddTemporalIdsToInterpolationTarget. We could keep all
232  // completed_ids forever, but we probably don't want it to get too
233  // large, so we limit its size. We assume that
234  // asynchronous calls to AddTemporalIdsToInterpolationTarget do not span
235  // more than 1000 temporal_ids.
236  if (completed_ids->size() > 1000) {
237  completed_ids->pop_front();
238  }
239  indices_of_filled->erase(temporal_id);
240  indices_of_invalid->erase(temporal_id);
241  interpolated_vars->erase(temporal_id);
242  });
243 }
244 
245 /// Returns true if this InterpolationTarget has received data
246 /// at all its points.
247 ///
248 /// have_data_at_all_points is called by an Action of InterpolationTarget.
249 ///
250 /// Currently two Actions call have_data_at_all_points:
251 /// - InterpolationTargetReceiveVars (called by Interpolator ParallelComponent)
252 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
253 template <typename InterpolationTargetTag, typename DbTags, typename TemporalId>
254 bool have_data_at_all_points(const db::DataBox<DbTags>& box,
255  const TemporalId& temporal_id) noexcept {
256  const size_t filled_size =
257  db::get<Tags::IndicesOfFilledInterpPoints<TemporalId>>(box)
258  .at(temporal_id)
259  .size();
260  const size_t invalid_size = [&box, &temporal_id ]() noexcept {
261  const auto& invalid_indices =
262  db::get<Tags::IndicesOfInvalidInterpPoints<TemporalId>>(box);
263  if (invalid_indices.count(temporal_id) > 0) {
264  return invalid_indices.at(temporal_id).size();
265  }
266  return 0_st;
267  }
268  ();
269  const size_t interp_size =
270  db::get<Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>(box)
271  .at(temporal_id)
272  .number_of_grid_points();
273  return (invalid_size + filled_size == interp_size);
274 }
275 
276 /// Is domain::Tags::FunctionsOfTime in the mutable global cache?
277 /// Result is either std::true_type or std::false_type.
278 template <typename Metavariables>
279 using cache_contains_functions_of_time =
280  tmpl::found<Parallel::get_mutable_global_cache_tags<Metavariables>,
282 
283 /// Returns true if at least one Block in the Domain has
284 /// time-dependent maps.
285 template <typename InterpolationTargetTag, typename DbTags,
286  typename Metavariables>
287 bool maps_are_time_dependent(
288  const db::DataBox<DbTags>& box,
289  const tmpl::type_<Metavariables>& /*meta*/) noexcept {
290  const auto& domain =
291  db::get<domain::Tags::Domain<Metavariables::volume_dim>>(box);
292  return alg::any_of(domain.blocks(), [](const auto& block) noexcept {
293  return block.is_time_dependent();
294  });
295 }
296 
297 /// Tells an InterpolationTarget that it should interpolate at
298 /// the supplied temporal_ids. Changes the InterpolationTarget's DataBox
299 /// accordingly.
300 ///
301 /// Returns the temporal_ids that have actually been newly flagged
302 /// (since some of them may have been flagged already).
303 ///
304 /// flag_temporal_ids_for_interpolation is called by an Action
305 /// of InterpolationTarget
306 ///
307 /// Currently one Action calls flag_temporal_ids_for_interpolation:
308 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
309 template <typename InterpolationTargetTag, typename DbTags, typename TemporalId>
310 std::vector<TemporalId> flag_temporal_ids_for_interpolation(
311  const gsl::not_null<db::DataBox<DbTags>*> box,
312  const std::vector<TemporalId>& temporal_ids) noexcept {
313  // We allow this function to be called multiple times with the same
314  // temporal_ids (e.g. from each element, or from each node of a
315  // NodeGroup ParallelComponent such as Interpolator). If multiple
316  // calls occur, we care only about the first one, and ignore the
317  // others. The first call will often begin interpolation. So if
318  // multiple calls occur, it is possible that some of them may arrive
319  // late, even after interpolation has been completed on one or more
320  // of the temporal_ids (and after that id has already been removed
321  // from `ids`). If this happens, we don't want to add the
322  // temporal_ids again. For that reason we keep track of the
323  // temporal_ids that we have already completed interpolation on. So
324  // here we do not add any temporal_ids that are already present in
325  // `ids` or `completed_ids`.
326  std::vector<TemporalId> new_temporal_ids{};
327 
328  db::mutate_apply<tmpl::list<Tags::TemporalIds<TemporalId>>,
329  tmpl::list<Tags::CompletedTemporalIds<TemporalId>>>(
330  [&temporal_ids, &new_temporal_ids ](
332  const std::deque<TemporalId>& completed_ids) noexcept {
333  for (auto& id : temporal_ids) {
334  if (std::find(completed_ids.begin(), completed_ids.end(), id) ==
335  completed_ids.end() and
336  std::find(ids->begin(), ids->end(), id) == ids->end()) {
337  ids->push_back(id);
338  new_temporal_ids.push_back(id);
339  }
340  }
341  },
342  box);
343 
344  return new_temporal_ids;
345 }
346 
347 /// Tells an InterpolationTarget that it should interpolate at
348 /// the supplied temporal_ids. Changes the InterpolationTarget's DataBox
349 /// accordingly.
350 ///
351 /// Returns the temporal_ids that have actually been newly flagged
352 /// (since some of them may have been flagged already).
353 ///
354 /// flag_temporal_ids_as_pending is called by an Action
355 /// of InterpolationTarget
356 ///
357 /// Currently one Action calls flag_temporal_ids_as_pending:
358 /// - AddTemporalIdsToInterpolationTarget (called by Events::Interpolate)
359 template <typename InterpolationTargetTag, typename DbTags, typename TemporalId>
360 std::vector<TemporalId> flag_temporal_ids_as_pending(
361  const gsl::not_null<db::DataBox<DbTags>*> box,
362  const std::vector<TemporalId>& temporal_ids) noexcept {
363  // We allow this function to be called multiple times with the same
364  // temporal_ids (e.g. from each element, or from each node of a
365  // NodeGroup ParallelComponent such as Interpolator). If multiple
366  // calls occur, we care only about the first one, and ignore the
367  // others. The first call will often begin interpolation. So if
368  // multiple calls occur, it is possible that some of them may arrive
369  // late, even after interpolation has been completed on one or more
370  // of the temporal_ids (and after that id has already been removed
371  // from `ids`). If this happens, we don't want to add the
372  // temporal_ids again. For that reason we keep track of the
373  // temporal_ids that we have already completed interpolation on. So
374  // here we do not add any temporal_ids that are already present in
375  // `ids` or `completed_ids`.
376  std::vector<TemporalId> new_temporal_ids{};
377 
378  db::mutate_apply<tmpl::list<Tags::PendingTemporalIds<TemporalId>>,
379  tmpl::list<Tags::TemporalIds<TemporalId>,
380  Tags::CompletedTemporalIds<TemporalId>>>(
381  [&temporal_ids, &new_temporal_ids](
382  const gsl::not_null<std::deque<TemporalId>*> pending_ids,
383  const std::deque<TemporalId>& ids,
384  const std::deque<TemporalId>& completed_ids) noexcept {
385  for (auto& id : temporal_ids) {
386  if (std::find(completed_ids.begin(), completed_ids.end(), id) ==
387  completed_ids.end() and
388  std::find(ids.begin(), ids.end(), id) == ids.end() and
389  std::find(pending_ids->begin(), pending_ids->end(), id) ==
390  pending_ids->end()) {
391  pending_ids->push_back(id);
392  new_temporal_ids.push_back(id);
393  }
394  }
395  },
396  box);
397 
398  return new_temporal_ids;
399 }
400 
401 /// Adds the supplied interpolated variables and offsets to the
402 /// InterpolationTarget's internal DataBox.
403 ///
404 /// Note that the template argument to Variables in vars_src is called
405 /// InterpolationTargetTag::vars_to_interpolate_to_target. This is a list
406 /// of tags, and is used for both the interpolated variables (in
407 /// this function add_received_variables) and for the source variables
408 /// (in other functions). The source and interpolated quantities are
409 /// the same set of variables (but at different points).
410 ///
411 /// add_received_variables is called by an Action of InterpolationTarget.
412 ///
413 /// Currently two Actions call add_received_variables:
414 /// - InterpolationTargetReceiveVars (called by Interpolator ParallelComponent)
415 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
416 template <typename InterpolationTargetTag, typename DbTags, typename TemporalId>
417 void add_received_variables(
418  const gsl::not_null<db::DataBox<DbTags>*> box,
419  const std::vector<Variables<
420  typename InterpolationTargetTag::vars_to_interpolate_to_target>>&
421  vars_src,
422  const std::vector<std::vector<size_t>>& global_offsets,
423  const TemporalId& temporal_id) noexcept {
424  db::mutate<Tags::IndicesOfFilledInterpPoints<TemporalId>,
425  Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>(
426  box, [&temporal_id, &vars_src, &global_offsets ](
427  const gsl::not_null<
429  indices_of_filled,
431  TemporalId, Variables<typename InterpolationTargetTag::
432  vars_to_interpolate_to_target>>*>
433  vars_dest_all_times) noexcept {
434  auto& vars_dest = vars_dest_all_times->at(temporal_id);
435  // Here we assume that vars_dest has been allocated to the correct
436  // size (but could contain garbage, since below we are filling it).
437  const size_t npts_dest = vars_dest.number_of_grid_points();
438  const size_t nvars = vars_dest.number_of_independent_components;
439  for (size_t j = 0; j < global_offsets.size(); ++j) {
440  const size_t npts_src = global_offsets[j].size();
441  for (size_t i = 0; i < npts_src; ++i) {
442  // If a point is on the boundary of two (or more)
443  // elements, it is possible that we have received data
444  // for this point from more than one Interpolator.
445  // This will rarely occur, but it does occur, e.g. when
446  // a point is exactly on some symmetry
447  // boundary (such as the x-y plane) and this symmetry
448  // boundary is exactly the boundary between two
449  // elements. If this happens, we accept the first
450  // duplicated point, and we ignore subsequent
451  // duplicated points. The points are easy to keep track
452  // of because global_offsets uniquely identifies them.
453  if ((*indices_of_filled)[temporal_id]
454  .insert(global_offsets[j][i])
455  .second) {
456  for (size_t v = 0; v < nvars; ++v) {
457  // clang-tidy: no pointer arithmetic
458  vars_dest.data()[global_offsets[j][i] + // NOLINT
459  v * npts_dest] = // NOLINT
460  vars_src[j].data()[i + v * npts_src]; // NOLINT
461  }
462  }
463  }
464  }
465  });
466 }
467 
468 /// Computes the block logical coordinates of an InterpolationTarget.
469 ///
470 /// block_logical_coords is called by an Action of InterpolationTarget.
471 ///
472 /// Currently two Actions call block_logical_coords:
473 /// - SendPointsToInterpolator (called by AddTemporalIdsToInterpolationTarget
474 /// and by FindApparentHorizon)
475 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
476 /// - InterpolationTargetSendTimeIndepPointsToElements
477 /// (in InterpolationTarget ActionList)
478 template <typename InterpolationTargetTag, typename DbTags,
479  typename Metavariables, typename TemporalId>
480 auto block_logical_coords(const db::DataBox<DbTags>& box,
482  const TemporalId& temporal_id) noexcept {
483  const auto& domain =
484  db::get<domain::Tags::Domain<Metavariables::volume_dim>>(box);
485  if constexpr (std::is_same_v<typename InterpolationTargetTag::
486  compute_target_points::frame,
487  ::Frame::Grid>) {
488  // Frame is grid frame, so don't need any FunctionsOfTime,
489  // whether or not the maps are time_dependent.
491  domain, InterpolationTargetTag::compute_target_points::points(
492  box, tmpl::type_<Metavariables>{}, temporal_id));
493  }
494 
495  if (maps_are_time_dependent<InterpolationTargetTag>(
496  box, tmpl::type_<Metavariables>{})) {
497  if constexpr (cache_contains_functions_of_time<Metavariables>::value) {
498  // Whoever calls block_logical_coords when the maps are
499  // time-dependent is responsible for ensuring
500  // that functions_of_time are up to date at temporal_id.
501  const auto& functions_of_time = get<domain::Tags::FunctionsOfTime>(cache);
503  domain,
504  InterpolationTargetTag::compute_target_points::points(
505  box, tmpl::type_<Metavariables>{}, temporal_id),
506  temporal_id.step_time().value(), functions_of_time);
507  } else {
508  // We error here because the maps are time-dependent, yet
509  // the cache does not contain FunctionsOfTime. It would be
510  // nice to make this a compile-time error; however, we want
511  // the code to compile for the completely time-independent
512  // case where there are no FunctionsOfTime in the cache at
513  // all. Unfortunately, checking whether the maps are
514  // time-dependent is currently not constexpr.
515  ERROR(
516  "There is a time-dependent CoordinateMap in at least one "
517  "of the Blocks, but FunctionsOfTime are not in the "
518  "GlobalCache. If you intend to use a time-dependent "
519  "CoordinateMap, please add FunctionsOfTime to the GlobalCache.");
520  }
521  }
522 
523  // Time-independent case.
525  domain, InterpolationTargetTag::compute_target_points::points(
526  box, tmpl::type_<Metavariables>{}, temporal_id));
527 }
528 
529 /// This is a version of block_logical_coords for when the coords
530 /// are time-independent.
531 template <typename InterpolationTargetTag, typename DbTags,
532  typename Metavariables>
533 auto block_logical_coords(const db::DataBox<DbTags>& box,
534  const tmpl::type_<Metavariables>& meta) noexcept {
535  const auto& domain =
536  db::get<domain::Tags::Domain<Metavariables::volume_dim>>(box);
538  domain, InterpolationTargetTag::compute_target_points::points(box, meta));
539 }
540 
541 /// Initializes InterpolationTarget's variables storage and lists of indices
542 /// corresponding to the supplied block logical coordinates and `temporal_id`.
543 ///
544 /// set_up_interpolation is called by an Action of InterpolationTarget.
545 ///
546 /// Currently two Actions call set_up_interpolation:
547 /// - SendPointsToInterpolator (called by AddTemporalIdsToInterpolationTarget
548 /// and by FindApparentHorizon)
549 /// - InterpolationTargetVarsFromElement (called by DgElementArray)
550 template <typename InterpolationTargetTag, typename DbTags, size_t VolumeDim,
551  typename TemporalId>
552 void set_up_interpolation(
553  const gsl::not_null<db::DataBox<DbTags>*> box,
554  const TemporalId& temporal_id,
557  tnsr::I<double, VolumeDim, typename ::Frame::Logical>>>>&
558  block_logical_coords) noexcept {
559  db::mutate<Tags::IndicesOfFilledInterpPoints<TemporalId>,
560  Tags::IndicesOfInvalidInterpPoints<TemporalId>,
561  Tags::InterpolatedVars<InterpolationTargetTag, TemporalId>>(
562  box, [&block_logical_coords, &temporal_id ](
563  const gsl::not_null<
565  indices_of_filled,
566  const gsl::not_null<
568  indices_of_invalid_points,
570  TemporalId, Variables<typename InterpolationTargetTag::
571  vars_to_interpolate_to_target>>*>
572  vars_dest_all_times) noexcept {
573  // Because we are sending new points to the interpolator,
574  // we know that none of these points have been interpolated to,
575  // so clear the list.
576  indices_of_filled->erase(temporal_id);
577 
578  // Set the indices of invalid points.
579  indices_of_invalid_points->erase(temporal_id);
580  for (size_t i = 0; i < block_logical_coords.size(); ++i) {
581  if (not block_logical_coords[i].has_value()) {
582  (*indices_of_invalid_points)[temporal_id].insert(i);
583  }
584  }
585 
586  // At this point we don't know if vars_dest exists in the map;
587  // if it doesn't then we want to default construct it.
588  auto& vars_dest = (*vars_dest_all_times)[temporal_id];
589 
590  // We will be filling vars_dest with interpolated data.
591  // Here we make sure it is allocated to the correct size.
592  if (vars_dest.number_of_grid_points() != block_logical_coords.size()) {
593  vars_dest = Variables<
594  typename InterpolationTargetTag::vars_to_interpolate_to_target>(
595  block_logical_coords.size());
596  }
597  });
598 }
599 
600 CREATE_IS_CALLABLE(should_interpolate)
601 CREATE_IS_CALLABLE_V(should_interpolate)
602 } // namespace InterpolationTarget_detail
603 } // namespace intrp
gsl::at
constexpr T & at(std::array< T, N > &arr, Size index)
Retrieve a entry from a container, with checks in Debug mode that the index being retrieved is valid.
Definition: Gsl.hpp:125
std::is_same
alg::any_of
decltype(auto) any_of(const Container &c, UnaryPredicate &&unary_predicate)
Convenience wrapper around std::any_of.
Definition: Algorithm.hpp:190
utility
Parallel::GlobalCache
Definition: ElementReceiveInterpPoints.hpp:15
Frame::Grid
Definition: IndexType.hpp:43
unordered_set
Literals.hpp
GlobalCache.hpp
intrp
Contains classes and functions for interpolation.
Definition: ElementInitInterpPoints.hpp:23
Tags.hpp
vector
CREATE_IS_CALLABLE_V
#define CREATE_IS_CALLABLE_V(METHOD_NAME)
Generate a type trait to check if a class has a member function that can be invoked with arguments of...
Definition: CreateIsCallable.hpp:68
Tags::Variables
Definition: VariablesTag.hpp:21
IdPair
A data structure that contains an ID and data associated with that ID.
Definition: IdPair.hpp:16
CREATE_HAS_STATIC_MEMBER_VARIABLE
#define CREATE_HAS_STATIC_MEMBER_VARIABLE(CONSTEXPR_NAME)
Generate a type trait to check if a class has a static constexpr variable, optionally also checking i...
Definition: CreateHasStaticMemberVariable.hpp:28
ERROR
#define ERROR(m)
prints an error message to the standard error stream and aborts the program.
Definition: Error.hpp:37
DataBox.hpp
block_logical_coordinates
auto block_logical_coordinates(const Domain< Dim > &domain, const tnsr::I< DataVector, Dim, Frame > &x, double time=std::numeric_limits< double >::signaling_NaN(), const std::unordered_map< std::string, std::unique_ptr< domain::FunctionsOfTime::FunctionOfTime >> &functions_of_time=std::unordered_map< std::string, std::unique_ptr< domain::FunctionsOfTime::FunctionOfTime >>{}) noexcept -> std::vector< std::optional< IdPair< domain::BlockId, tnsr::I< double, Dim, ::Frame::Logical >>>>
cstddef
std::deque
memory
ASSERT
#define ASSERT(a, m)
Assert that an expression should be true.
Definition: Assert.hpp:49
ActionTesting::cache
Parallel::GlobalCache< Metavariables > & cache(MockRuntimeSystem< Metavariables > &runner, const ArrayIndex &array_index) noexcept
Returns the GlobalCache of Component with index array_index.
Definition: MockRuntimeSystemFreeFunctions.hpp:382
Gsl.hpp
db::mutate_apply
constexpr decltype(auto) mutate_apply(F &&f, const gsl::not_null< DataBox< BoxTags > * > box, Args &&... args) noexcept
Apply the invokable f mutating items MutateTags and taking as additional arguments ArgumentTags and a...
Definition: DataBox.hpp:1257
CREATE_HAS_STATIC_MEMBER_VARIABLE_V
#define CREATE_HAS_STATIC_MEMBER_VARIABLE_V(CONSTEXPR_NAME)
Generate a type trait to check if a class has a static constexpr variable, optionally also checking i...
Definition: CreateHasStaticMemberVariable.hpp:43
Requires.hpp
domain::BlockId
Index a block of the computational domain.
Definition: BlockId.hpp:21
std::optional
Requires
typename Requires_detail::requires_impl< B >::template_error_type_failed_to_meet_requirements_on_template_parameters Requires
Express requirements on the template parameters of a function or class, replaces std::enable_if_t
Definition: Requires.hpp:67
std::unordered_map
TMPL.hpp
cpp20::find
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Definition: Algorithm.hpp:136
gsl::not_null
Require a pointer to not be a nullptr
Definition: ReadSpecPiecewisePolynomial.hpp:13
CREATE_IS_CALLABLE
#define CREATE_IS_CALLABLE(METHOD_NAME)
Generate a type trait to check if a class has a member function that can be invoked with arguments of...
Definition: CreateIsCallable.hpp:31