SpECTRE Documentation Coverage Report
Current view: top level - ParallelAlgorithms/LinearSolver/Schwarz - ObserveVolumeData.hpp Hit Total Coverage
Commit: 1f2210958b4f38fdc0400907ee7c6d5af5111418 Lines: 0 1 0.0 %
Date: 2025-12-05 05:03:31
Legend: Lines: hit not hit

          Line data    Source code
       1           0 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : #pragma once
       5             : 
       6             : #include <cstddef>
       7             : #include <optional>
       8             : #include <string>
       9             : #include <tuple>
      10             : #include <type_traits>
      11             : #include <utility>
      12             : #include <vector>
      13             : 
      14             : #include "DataStructures/DataBox/DataBox.hpp"
      15             : #include "Domain/Structure/ElementId.hpp"
      16             : #include "Domain/Tags.hpp"
      17             : #include "IO/H5/TensorData.hpp"
      18             : #include "IO/Observer/GetSectionObservationKey.hpp"
      19             : #include "IO/Observer/ObservationId.hpp"
      20             : #include "IO/Observer/ObserverComponent.hpp"
      21             : #include "IO/Observer/Tags.hpp"
      22             : #include "IO/Observer/TypeOfObservation.hpp"
      23             : #include "IO/Observer/VolumeActions.hpp"
      24             : #include "NumericalAlgorithms/Spectral/Mesh.hpp"
      25             : #include "Parallel/AlgorithmExecution.hpp"
      26             : #include "Parallel/ArrayComponentId.hpp"
      27             : #include "Parallel/GlobalCache.hpp"
      28             : #include "Parallel/Invoke.hpp"
      29             : #include "Parallel/Local.hpp"
      30             : #include "ParallelAlgorithms/LinearSolver/Schwarz/ElementCenteredSubdomainData.hpp"
      31             : #include "ParallelAlgorithms/LinearSolver/Schwarz/Tags.hpp"
      32             : #include "ParallelAlgorithms/LinearSolver/Tags.hpp"
      33             : #include "Utilities/Algorithm.hpp"
      34             : #include "Utilities/Gsl.hpp"
      35             : #include "Utilities/MakeString.hpp"
      36             : #include "Utilities/PrettyType.hpp"
      37             : #include "Utilities/TMPL.hpp"
      38             : #include "Utilities/TaggedTuple.hpp"
      39             : 
      40             : namespace LinearSolver::Schwarz::detail {
      41             : 
      42             : template <typename OptionsGroup, typename ArraySectionIdTag>
      43             : struct RegisterWithVolumeObserver {
      44             :   template <typename ParallelComponent, typename DbTagsList,
      45             :             typename ArrayIndex>
      46             :   static std::pair<observers::TypeOfObservation, observers::ObservationKey>
      47             :   register_info(const db::DataBox<DbTagsList>& box,
      48             :                 const ArrayIndex& /*array_index*/) {
      49             :     const std::optional<std::string> section_observation_key =
      50             :         observers::get_section_observation_key<ArraySectionIdTag>(box);
      51             :     const std::string subfile_path = "/" + pretty_type::name<OptionsGroup>() +
      52             :                                      section_observation_key.value_or("");
      53             :     return {observers::TypeOfObservation::Volume,
      54             :             observers::ObservationKey(subfile_path)};
      55             :   }
      56             : };
      57             : 
      58             : // Contribute the volume data recorded in the other actions to the observer at
      59             : // the end of a step.
      60             : template <typename FieldsTag, typename OptionsGroup, typename SubdomainOperator,
      61             :           typename ArraySectionIdTag>
      62             : struct ObserveVolumeData {
      63             :  private:
      64             :   using fields_tag = FieldsTag;
      65             :   using residual_tag =
      66             :       db::add_tag_prefix<LinearSolver::Tags::Residual, fields_tag>;
      67             :   static constexpr size_t Dim = SubdomainOperator::volume_dim;
      68             :   using SubdomainData =
      69             :       ElementCenteredSubdomainData<Dim, typename residual_tag::tags_list>;
      70             :   using volume_data_tag =
      71             :       Tags::VolumeDataForOutput<SubdomainData, OptionsGroup>;
      72             :   using VolumeDataVars = typename volume_data_tag::type::ElementData;
      73             : 
      74             :  public:
      75             :   template <typename DbTagsList, typename... InboxTags, typename Metavariables,
      76             :             size_t Dim, typename ActionList, typename ParallelComponent>
      77             :   static Parallel::iterable_action_return_t apply(
      78             :       db::DataBox<DbTagsList>& box,
      79             :       const tuples::TaggedTuple<InboxTags...>& /*inboxes*/,
      80             :       Parallel::GlobalCache<Metavariables>& cache,
      81             :       const ElementId<Dim>& element_id, const ActionList /*meta*/,
      82             :       const ParallelComponent* const /*meta*/) {
      83             :     if (not db::get<LinearSolver::Tags::OutputVolumeData<OptionsGroup>>(box)) {
      84             :       return {Parallel::AlgorithmExecution::Continue, std::nullopt};
      85             :     }
      86             :     const auto& volume_data = db::get<volume_data_tag>(box);
      87             :     const auto& observation_id =
      88             :         db::get<LinearSolver::Tags::ObservationId<OptionsGroup>>(box);
      89             :     const auto& mesh = db::get<domain::Tags::Mesh<Dim>>(box);
      90             :     const auto& inertial_coords =
      91             :         db::get<domain::Tags::Coordinates<Dim, Frame::Inertial>>(box);
      92             :     // Collect tensor components to observe
      93             :     std::vector<TensorComponent> components{};
      94             :     const auto record_tensor_components = [&components](
      95             :                                               const auto tensor_tag_v,
      96             :                                               const auto& tensor,
      97             :                                               const std::string& suffix = "") {
      98             :       using tensor_tag = std::decay_t<decltype(tensor_tag_v)>;
      99             :       using TensorType = std::decay_t<decltype(tensor)>;
     100             :       using VectorType = typename TensorType::type;
     101             :       using ValueType = typename VectorType::value_type;
     102             :       for (size_t i = 0; i < tensor.size(); ++i) {
     103             :         const std::string component_name =
     104             :             db::tag_name<tensor_tag>() + suffix + tensor.component_suffix(i);
     105             :         if constexpr (std::is_same_v<ValueType, std::complex<double>>) {
     106             :           components.emplace_back("Re(" + component_name + ")",
     107             :                                   real(tensor[i]));
     108             :           components.emplace_back("Im(" + component_name + ")",
     109             :                                   imag(tensor[i]));
     110             :         } else {
     111             :           components.emplace_back(component_name, tensor[i]);
     112             :         }
     113             :       }
     114             :     };
     115             :     record_tensor_components(domain::Tags::Coordinates<Dim, Frame::Inertial>{},
     116             :                              inertial_coords);
     117             :     const auto& all_intruding_extents =
     118             :         db::get<Tags::IntrudingExtents<Dim, OptionsGroup>>(box);
     119             :     const VolumeDataVars zero_vars{mesh.number_of_grid_points(), 0.};
     120             :     tmpl::for_each<typename VolumeDataVars::tags_list>(
     121             :         [&volume_data, &record_tensor_components, &mesh, &all_intruding_extents,
     122             :          &zero_vars, &element_id](auto tag_v) {
     123             :           using tag = tmpl::type_from<decltype(tag_v)>;
     124             :           record_tensor_components(tag{}, get<tag>(volume_data.element_data),
     125             :                                    "_Center");
     126             :           for (const auto direction : Direction<Dim>::all_directions()) {
     127             :             const auto direction_predicate =
     128             :                 [&direction](const auto& overlap_data) {
     129             :                   return overlap_data.first.direction() == direction;
     130             :                 };
     131             :             const auto num_overlaps =
     132             :                 alg::count_if(volume_data.overlap_data, direction_predicate);
     133             :             if (num_overlaps == 0) {
     134             :               // No overlap data for this direction (e.g. external boundary),
     135             :               // record zero
     136             :               record_tensor_components(tag{}, get<tag>(zero_vars),
     137             :                                        "_Overlap" + get_output(direction));
     138             :             } else if (num_overlaps == 1) {
     139             :               // Overlap data from a single neighbor, record it
     140             :               const auto& overlap_data =
     141             :                   alg::find_if(volume_data.overlap_data, direction_predicate)
     142             :                       ->second;
     143             :               const auto& intruding_extents =
     144             :                   gsl::at(all_intruding_extents, direction.dimension());
     145             :               record_tensor_components(
     146             :                   tag{},
     147             :                   get<tag>(extended_overlap_data(overlap_data, mesh.extents(),
     148             :                                                  intruding_extents, direction)),
     149             :                   "_Overlap" + get_output(direction));
     150             :             } else {
     151             :               ERROR("Multiple neighbors ("
     152             :                     << num_overlaps << ") overlap with element " << element_id
     153             :                     << " in direction " << direction
     154             :                     << ", but we can record only one for volume data output.");
     155             :             }
     156             :           }
     157             :         });
     158             : 
     159             :     // Contribute tensor components to observer
     160             :     auto& local_observer = *Parallel::local_branch(
     161             :         Parallel::get_parallel_component<observers::Observer<Metavariables>>(
     162             :             cache));
     163             :     const std::optional<std::string> section_observation_key =
     164             :         observers::get_section_observation_key<ArraySectionIdTag>(box);
     165             :     const std::string subfile_path = "/" + pretty_type::name<OptionsGroup>() +
     166             :                                      section_observation_key.value_or("");
     167             :     Parallel::simple_action<observers::Actions::ContributeVolumeData>(
     168             :         local_observer, observers::ObservationId(observation_id, subfile_path),
     169             :         subfile_path,
     170             :         Parallel::make_array_component_id<ParallelComponent>(element_id),
     171             :         ElementVolumeData{element_id, std::move(components), mesh});
     172             : 
     173             :     // Increment observation ID
     174             :     db::mutate<LinearSolver::Tags::ObservationId<OptionsGroup>>(
     175             :         [](const auto local_observation_id) { ++(*local_observation_id); },
     176             :         make_not_null(&box));
     177             :     return {Parallel::AlgorithmExecution::Continue, std::nullopt};
     178             :   }
     179             : };
     180             : 
     181             : }  // namespace LinearSolver::Schwarz::detail

Generated by: LCOV version 1.14