SpECTRE Documentation Coverage Report
Current view: top level - ControlSystem/Systems - Shape.hpp Coverage Total Hit
Commit: 0d1d717af84a81fb1284a20c4013708fe85cc2f0 Lines: 7.1 % 14 1
Test Date: 2026-10-22 17:29:42
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 <array>
       7              : #include <cmath>
       8              : #include <cstddef>
       9              : #include <optional>
      10              : #include <string>
      11              : 
      12              : #include "ControlSystem/Component.hpp"
      13              : #include "ControlSystem/ControlErrors/Shape.hpp"
      14              : #include "ControlSystem/Measurements/BothHorizons.hpp"
      15              : #include "ControlSystem/Measurements/SingleHorizon.hpp"
      16              : #include "ControlSystem/Protocols/ControlError.hpp"
      17              : #include "ControlSystem/Protocols/ControlSystem.hpp"
      18              : #include "ControlSystem/Protocols/Measurement.hpp"
      19              : #include "ControlSystem/Tags/QueueTags.hpp"
      20              : #include "ControlSystem/Tags/SystemTags.hpp"
      21              : #include "ControlSystem/UpdateControlSystem.hpp"
      22              : #include "DataStructures/DataBox/DataBox.hpp"
      23              : #include "DataStructures/DataBox/Tag.hpp"
      24              : #include "DataStructures/LinkedMessageQueue.hpp"
      25              : #include "Domain/Structure/ObjectLabel.hpp"
      26              : #include "NumericalAlgorithms/SphericalHarmonics/SpherepackIterator.hpp"
      27              : #include "NumericalAlgorithms/Strahlkorper/Strahlkorper.hpp"
      28              : #include "NumericalAlgorithms/Strahlkorper/Tags.hpp"
      29              : #include "Parallel/GlobalCache.hpp"
      30              : #include "Parallel/Printf/Printf.hpp"
      31              : #include "ParallelAlgorithms/Actions/UpdateMessageQueue.hpp"
      32              : #include "Utilities/GetOutput.hpp"
      33              : #include "Utilities/ProtocolHelpers.hpp"
      34              : #include "Utilities/TMPL.hpp"
      35              : 
      36              : /// \cond
      37              : namespace Frame {
      38              : struct Distorted;
      39              : }  // namespace Frame
      40              : /// \endcond
      41              : 
      42              : namespace control_system::Systems {
      43              : /*!
      44              :  * \brief Controls the \link domain::CoordinateMaps::TimeDependent::Shape Shape
      45              :  * \endlink map
      46              :  *
      47              :  * \details Controls the functions \f$ \lambda_{lm}(t) \f$ in the \link
      48              :  * domain::CoordinateMaps::TimeDependent::Shape Shape \endlink map to match the
      49              :  * shape of the excision sphere to the shape of the horizon.
      50              :  *
      51              :  * Requirements:
      52              :  * - This control system requires that there be at least one excision surface in
      53              :  *   the simulation
      54              :  * - Currently this control system can only be used with the \link
      55              :  *   control_system::measurements::BothHorizons BothHorizons \endlink
      56              :  * measurement
      57              :  * - Currently this control system can only be used with the \link
      58              :  *   control_system::ControlErrors::Shape Shape \endlink control error
      59              :  */
      60              : template <::domain::ObjectLabel Object, size_t DerivOrder, typename Measurement>
      61            1 : struct Shape : tt::ConformsTo<protocols::ControlSystem> {
      62            0 :   static constexpr size_t deriv_order = DerivOrder;
      63              : 
      64            0 :   static std::string name() { return "Shape"s + ::domain::name(Object); }
      65              : 
      66            0 :   static std::optional<std::string> component_name(
      67              :       const size_t i, const size_t num_components) {
      68              :     // num_components = 2 * (l_max + 1)**2 if l_max == m_max which it is for the
      69              :     // shape map. This is why we can divide by 2 and take the sqrt without
      70              :     // worrying about odd numbers or non-perfect squares
      71              :     const size_t l_max = -1 + sqrt(num_components / 2);
      72              :     ylm::SpherepackIterator iter(l_max, l_max);
      73              :     const auto compact_index = iter.compact_index(i);
      74              :     if (compact_index.has_value()) {
      75              :       iter.set(compact_index.value());
      76              :       const int m = iter.coefficient_array() ==
      77              :                             ylm::SpherepackIterator::CoefficientArray::a
      78              :                         ? static_cast<int>(iter.m())
      79              :                         : -static_cast<int>(iter.m());
      80              :       return {"l"s + get_output(iter.l()) + "m"s + get_output(m)};
      81              :     } else {
      82              :       return std::nullopt;
      83              :     }
      84              :   }
      85              : 
      86            0 :   using measurement = Measurement;
      87              :   static_assert(
      88              :       std::is_same_v<measurement, measurements::SingleHorizon<Object>> or
      89              :           std::is_same_v<measurement, measurements::BothHorizons>,
      90              :       "Must use either SingleHorizon or BothHorizon measurement for Shape "
      91              :       "control system.");
      92              :   static_assert(
      93              :       tt::conforms_to_v<measurement, control_system::protocols::Measurement>);
      94              : 
      95            0 :   using control_error = ControlErrors::Shape<Object>;
      96              :   static_assert(tt::conforms_to_v<control_error,
      97              :                                   control_system::protocols::ControlError>);
      98              : 
      99              :   // tag goes in control component
     100            0 :   struct MeasurementQueue : db::SimpleTag {
     101            0 :     using type = LinkedMessageQueue<
     102              :         double, tmpl::list<QueueTags::Horizon<Frame::Distorted, Object>>>;
     103              :   };
     104              : 
     105            0 :   using simple_tags = tmpl::list<MeasurementQueue>;
     106              : 
     107            0 :   struct process_measurement {
     108              :     template <typename Submeasurement>
     109            0 :     using argument_tags = tmpl::list<ylm::Tags::Strahlkorper<Frame::Distorted>>;
     110              : 
     111              :     template <typename Metavariables>
     112            0 :     static void apply(typename measurements::SingleHorizon<
     113              :                           Object>::Submeasurement submeasurement,
     114              :                       const ylm::Strahlkorper<Frame::Distorted>& strahlkorper,
     115              :                       Parallel::GlobalCache<Metavariables>& cache,
     116              :                       const LinkedMessageId<double>& measurement_id) {
     117              :       auto& control_sys_proxy = Parallel::get_parallel_component<
     118              :           ControlComponent<Metavariables, Shape>>(cache);
     119              : 
     120              :       Parallel::simple_action<::Actions::UpdateMessageQueue<
     121              :           MeasurementQueue, UpdateControlSystem<Shape>,
     122              :           QueueTags::Horizon<Frame::Distorted, Object>>>(
     123              :           control_sys_proxy, measurement_id, strahlkorper);
     124              : 
     125              :       if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) {
     126              :         Parallel::printf("%s, time = %.16f: Received measurement '%s'.\n",
     127              :                          name(), measurement_id.id,
     128              :                          pretty_type::name(submeasurement));
     129              :       }
     130              :     }
     131              : 
     132              :     template <::domain::ObjectLabel MeasureHorizon, typename Metavariables>
     133            0 :     static void apply(
     134              :         measurements::BothHorizons::FindHorizon<MeasureHorizon> submeasurement,
     135              :         const ylm::Strahlkorper<Frame::Distorted>& strahlkorper,
     136              :         Parallel::GlobalCache<Metavariables>& cache,
     137              :         const LinkedMessageId<double>& measurement_id) {
     138              :       // The measurement event will call this for both horizons, but we only
     139              :       // need one of the horizons. So if it is called for the wrong horizon,
     140              :       // just do nothing.
     141              :       if constexpr (MeasureHorizon == Object) {
     142              :         auto& control_sys_proxy = Parallel::get_parallel_component<
     143              :             ControlComponent<Metavariables, Shape>>(cache);
     144              : 
     145              :         Parallel::simple_action<::Actions::UpdateMessageQueue<
     146              :             MeasurementQueue, UpdateControlSystem<Shape>,
     147              :             QueueTags::Horizon<Frame::Distorted, Object>>>(
     148              :             control_sys_proxy, measurement_id, strahlkorper);
     149              : 
     150              :         if (Parallel::get<Tags::Verbosity>(cache) >= ::Verbosity::Verbose) {
     151              :           Parallel::printf("%s, time = %.16f: Received measurement '%s'.\n",
     152              :                            name(), measurement_id.id,
     153              :                            pretty_type::name(submeasurement));
     154              :         }
     155              :       } else {
     156              :         (void)submeasurement;
     157              :         (void)strahlkorper;
     158              :         (void)cache;
     159              :         (void)measurement_id;
     160              :       }
     161              :     }
     162              :   };
     163              : };
     164              : }  // namespace control_system::Systems
        

Generated by: LCOV version 2.0-1