diff --git a/src/Evolution/Imex/Actions/CMakeLists.txt b/src/Evolution/Imex/Actions/CMakeLists.txt new file mode 100644 index 000000000000..bbf30479b0fd --- /dev/null +++ b/src/Evolution/Imex/Actions/CMakeLists.txt @@ -0,0 +1,11 @@ +# Distributed under the MIT License. +# See LICENSE.txt for details. + +spectre_target_headers( + ${LIBRARY} + INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src + HEADERS + DoImplicitStep.hpp + NamespaceDocs.hpp + RecordTimeStepperData.hpp + ) diff --git a/src/Evolution/Imex/Actions/DoImplicitStep.hpp b/src/Evolution/Imex/Actions/DoImplicitStep.hpp new file mode 100644 index 000000000000..749ac51ffe7e --- /dev/null +++ b/src/Evolution/Imex/Actions/DoImplicitStep.hpp @@ -0,0 +1,90 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "Evolution/Imex/Protocols/ImexSystem.hpp" +#include "Evolution/Imex/SolveImplicitSector.hpp" +#include "Parallel/AlgorithmExecution.hpp" +#include "Time/TimeStepId.hpp" +#include "Utilities/CleanupRoutine.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +/// \cond +namespace Parallel { +template +class GlobalCache; +} // namespace Parallel +namespace Tags { +template +struct Next; +struct Time; +struct TimeStepId; +} // namespace Tags +namespace db { +template +class DataBox; +} // namespace db +namespace tuples { +template +class TaggedTuple; +} // namespace tuples +/// \endcond + +namespace imex::Actions { +/// \ingroup ActionsGroup +/// \brief Perform implicit variable updates for one substep +/// +/// Uses: +/// - DataBox: +/// - Tags::Next +/// - Tags::Time +/// - Tags::TimeStep +/// - Tags::TimeStepper +/// - imex::Tags::Mode +/// - imex::Tags::SolveTolerance +/// - as required by system implicit sectors +/// +/// DataBox changes: +/// - variables_tag +/// - imex::Tags::ImplicitHistory for each sector +template +struct DoImplicitStep { + template + static Parallel::iterable_action_return_t apply( + db::DataBox& box, tuples::TaggedTuple& /*inboxes*/, + const Parallel::GlobalCache& /*cache*/, + const ArrayIndex& /*array_index*/, ActionList /*meta*/, + const ParallelComponent* const /*meta*/) { + static_assert(tt::assert_conforms_to_v); + + const double original_time = db::get<::Tags::Time>(box); + const CleanupRoutine reset_time = [&]() { + db::mutate<::Tags::Time>( + [&](const gsl::not_null time) { *time = original_time; }, + make_not_null(&box)); + }; + db::mutate<::Tags::Time>( + [](const gsl::not_null time, + const TimeStepId& next_time_step_id) { + *time = next_time_step_id.substep_time(); + }, + make_not_null(&box), db::get<::Tags::Next<::Tags::TimeStepId>>(box)); + + tmpl::for_each([&](auto sector_v) { + using sector = tmpl::type_from; + db::mutate_apply< + SolveImplicitSector>( + make_not_null(&box)); + }); + return {Parallel::AlgorithmExecution::Continue, std::nullopt}; + } +}; +} // namespace imex::Actions diff --git a/src/Evolution/Imex/Actions/NamespaceDocs.hpp b/src/Evolution/Imex/Actions/NamespaceDocs.hpp new file mode 100644 index 000000000000..923231b1d054 --- /dev/null +++ b/src/Evolution/Imex/Actions/NamespaceDocs.hpp @@ -0,0 +1,7 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +/// Actions related to evolution using implicit-explicit time stepping. +namespace imex::Actions {} diff --git a/src/Evolution/Imex/Actions/RecordTimeStepperData.hpp b/src/Evolution/Imex/Actions/RecordTimeStepperData.hpp new file mode 100644 index 000000000000..3cfa58b62174 --- /dev/null +++ b/src/Evolution/Imex/Actions/RecordTimeStepperData.hpp @@ -0,0 +1,102 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "DataStructures/DataBox/PrefixHelpers.hpp" +#include "DataStructures/DataBox/Prefixes.hpp" +#include "DataStructures/Variables.hpp" +#include "Evolution/Imex/Protocols/ImexSystem.hpp" +#include "Evolution/Imex/Tags/ImplicitHistory.hpp" +#include "Parallel/AlgorithmExecution.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +/// \cond +class TimeStepId; +namespace Parallel { +template +class GlobalCache; +} // namespace Parallel +namespace Tags { +struct TimeStepId; +} // namespace Tags +namespace tuples { +template +class TaggedTuple; +} // namespace tuples +/// \endcond + +namespace imex::Actions { +/// \ingroup ActionsGroup +/// \brief Records the implicit sources in the implicit time stepper history. +/// +/// Uses: +/// - GlobalCache: nothing +/// - DataBox: +/// - Tags::TimeStepId +/// - system::variables_tag +/// - as required by source terms +/// +/// DataBox changes: +/// - imex::Tags::ImplicitHistory for each sector +template +struct RecordTimeStepperData { + template + static Parallel::iterable_action_return_t apply( + db::DataBox& box, tuples::TaggedTuple& /*inboxes*/, + const Parallel::GlobalCache& /*cache*/, + const ArrayIndex& /*array_index*/, ActionList /*meta*/, + const ParallelComponent* const /*meta*/) { // NOLINT const + static_assert(tt::assert_conforms_to_v); + + const size_t number_of_grid_points = + db::get(box).number_of_grid_points(); + + tmpl::for_each([&](auto sector_v) { + using sector = tmpl::type_from; + using source = + typename tmpl::front::source; + using history_tag = Tags::ImplicitHistory; + using DtSectorVars = + Variables>; + db::mutate_apply< + tmpl::list, + tmpl::push_front>( + [&](const gsl::not_null history, + const TimeStepId& time_step_id, const auto&... source_arguments) { + history->insert_in_place( + time_step_id, history_tag::type::no_value, + [&](const gsl::not_null source_result) { + source_result->initialize(number_of_grid_points); + tmpl::as_pack( + [&](auto... source_tags) { + // The history stores derivatives as + // ::Tags::dt, but the source provides + // ::Tags::Source. Since the only + // implicit equations we support are source + // terms, these quantities are equal, but we + // still need to make the types match. + source::apply( + make_not_null( + &get<::Tags::dt>>>( + *source_result))..., + source_arguments...); + }); + }); + }, + make_not_null(&box)); + }); + + return {Parallel::AlgorithmExecution::Continue, std::nullopt}; + } +}; +} // namespace imex::Actions diff --git a/src/Evolution/Imex/CMakeLists.txt b/src/Evolution/Imex/CMakeLists.txt index 15b023f69bff..8451e1b81fa5 100644 --- a/src/Evolution/Imex/CMakeLists.txt +++ b/src/Evolution/Imex/CMakeLists.txt @@ -17,6 +17,7 @@ spectre_target_headers( INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/src HEADERS GuessResult.hpp + Initialize.hpp Mode.hpp NamespaceDocs.hpp SolveImplicitSector.hpp @@ -36,5 +37,6 @@ target_link_libraries( Utilities ) +add_subdirectory(Actions) add_subdirectory(Protocols) add_subdirectory(Tags) diff --git a/src/Evolution/Imex/Initialize.hpp b/src/Evolution/Imex/Initialize.hpp new file mode 100644 index 000000000000..ceb08c47a2d2 --- /dev/null +++ b/src/Evolution/Imex/Initialize.hpp @@ -0,0 +1,57 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include "Evolution/Imex/Protocols/ImexSystem.hpp" +#include "Evolution/Imex/Tags/ImplicitHistory.hpp" +#include "Evolution/Imex/Tags/Mode.hpp" +#include "Evolution/Imex/Tags/SolveFailures.hpp" +#include "Evolution/Imex/Tags/SolveTolerance.hpp" +#include "Time/History.hpp" +#include "Time/Tags/HistoryEvolvedVariables.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/MakeWithValue.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +namespace imex { +/// Create the IMEX structures and options. +template +struct Initialize; + +/// \cond +template +struct Initialize> { + static_assert(tt::assert_conforms_to_v); + + using example_tensor_tag = + tmpl::front>::tensors>; + + using const_global_cache_tags = tmpl::list; + using mutable_global_cache_tags = tmpl::list<>; + using simple_tags_from_options = tmpl::list<>; + using simple_tags = tmpl::list..., + Tags::SolveFailures...>; + using compute_tags = tmpl::list<>; + + using return_tags = simple_tags; + using argument_tags = + tmpl::list<::Tags::HistoryEvolvedVariables<>, example_tensor_tag>; + + static void apply( + const gsl::not_null< + typename Tags::ImplicitHistory::type*>... histories, + const gsl::not_null< + typename Tags::SolveFailures::type*>... solve_failures, + const TimeSteppers::History& + explicit_history, + const typename example_tensor_tag::type& example_tensor) { + const auto order = explicit_history.integration_order(); + expand_pack((histories->integration_order(order), 0)...); + expand_pack(*solve_failures = make_with_value>( + example_tensor, 0.0)...); + } +}; +/// \endcond +} // namespace imex diff --git a/tests/Unit/Evolution/Imex/Actions/CMakeLists.txt b/tests/Unit/Evolution/Imex/Actions/CMakeLists.txt new file mode 100644 index 000000000000..2c35240a0927 --- /dev/null +++ b/tests/Unit/Evolution/Imex/Actions/CMakeLists.txt @@ -0,0 +1,8 @@ +# Distributed under the MIT License. +# See LICENSE.txt for details. + +set(LIBRARY_SOURCES + ${LIBRARY_SOURCES} + Actions/Test_DoImplicitStep.cpp + Actions/Test_RecordTimeStepperData.cpp + PARENT_SCOPE) diff --git a/tests/Unit/Evolution/Imex/Actions/Test_DoImplicitStep.cpp b/tests/Unit/Evolution/Imex/Actions/Test_DoImplicitStep.cpp new file mode 100644 index 000000000000..bfca7d2d0257 --- /dev/null +++ b/tests/Unit/Evolution/Imex/Actions/Test_DoImplicitStep.cpp @@ -0,0 +1,181 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Framework/TestingFramework.hpp" + +#include +#include +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "DataStructures/DataBox/Prefixes.hpp" +#include "DataStructures/DataVector.hpp" +#include "DataStructures/Tensor/Tensor.hpp" +#include "DataStructures/Tensor/TypeAliases.hpp" +#include "Evolution/Imex/Actions/DoImplicitStep.hpp" +#include "Evolution/Imex/Mode.hpp" +#include "Evolution/Imex/Tags/ImplicitHistory.hpp" +#include "Evolution/Imex/Tags/Mode.hpp" +#include "Evolution/Imex/Tags/SolveFailures.hpp" +#include "Evolution/Imex/Tags/SolveTolerance.hpp" +#include "Framework/ActionTesting.hpp" +#include "Helpers/Evolution/Imex/DoImplicitStepSector.hpp" +#include "Parallel/Phase.hpp" +#include "Parallel/PhaseDependentActionList.hpp" +#include "Time/Slab.hpp" +#include "Time/Tags/Time.hpp" +#include "Time/Tags/TimeStep.hpp" +#include "Time/Tags/TimeStepId.hpp" +#include "Time/Tags/TimeStepper.hpp" +#include "Time/TimeStepId.hpp" +#include "Time/TimeSteppers/Heun2.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/MakeWithValue.hpp" +#include "Utilities/Serialization/RegisterDerivedClassesWithCharm.hpp" +#include "Utilities/TMPL.hpp" + +namespace { +template +struct Component { + using metavariables = Metavariables; + using chare_type = ActionTesting::MockArrayChare; + using array_index = int; + using simple_tags = + tmpl::push_front, + Tags::TimeStep, ::Tags::Time, + Tags::Next, + typename Metavariables::system::variables_tag, + imex::Tags::Mode, imex::Tags::SolveTolerance>; + + using compute_tags = time_stepper_ref_tags; + using phase_dependent_action_list = tmpl::list< + Parallel::PhaseActions>>, + Parallel::PhaseActions>>>; +}; + +template +struct Metavariables { + using system = System; + using component_list = tmpl::list>; + using system_tags = SystemTags; +}; + +namespace helpers = do_implicit_step_helpers; + +void test_basic_functionality() { + using metavariables = Metavariables< + helpers::System, + tmpl::list>, + imex::Tags::ImplicitHistory>, + imex::Tags::SolveFailures>, + imex::Tags::SolveFailures>>>; + using component = Component; + + const size_t number_of_grid_points = 5; + + const Slab slab(1.0, 3.0); + const TimeStepId time_step_id(true, 0, slab.start()); + const auto time_step = slab.duration(); + + helpers::System::variables_tag::type initial_vars(number_of_grid_points); + get(get(initial_vars)) = 2.0; + get(get(initial_vars)) = 3.0; + + imex::Tags::ImplicitHistory>::type history1(2); + history1.insert(time_step_id, decltype(history1)::no_value, + -get(get(initial_vars))); + imex::Tags::ImplicitHistory>::type history2(2); + history2.insert(time_step_id, decltype(history2)::no_value, + -get(get(initial_vars))); + Scalar solve_failures1(DataVector(number_of_grid_points, 0.0)); + Scalar solve_failures2(DataVector(number_of_grid_points, 0.0)); + + const double tolerance = 1.0e-10; + + ActionTesting::MockRuntimeSystem runner{{}}; + + ActionTesting::emplace_component_and_initialize( + &runner, 0, + {std::make_unique(), time_step, + time_step_id.substep_time(), + TimeSteppers::Heun2{}.next_time_id(time_step_id, time_step), + initial_vars, imex::Mode::Implicit, tolerance, std::move(history1), + std::move(history2), std::move(solve_failures1), + std::move(solve_failures2)}); + ActionTesting::set_phase(make_not_null(&runner), Parallel::Phase::Testing); + runner.next_action(0); + + const auto& box = ActionTesting::get_databox(runner, 0); + CHECK(db::get<::Tags::Time>(box) == time_step_id.substep_time()); + const auto& final_vars = db::get(box); + + const double dt = time_step.value(); + const double step_factor = (1.0 - 0.5 * dt) / (1.0 + 0.5 * dt); + + CHECK(get(get(final_vars)) == + step_factor * get(get(initial_vars))); + CHECK(get(get(final_vars)) == + step_factor * get(get(initial_vars))); +} + +void test_nonautonomous() { + using sector = helpers::NonautonomousSector; + using Vars = helpers::NonautonomousSystem::variables_tag::type; + using history_tag = imex::Tags::ImplicitHistory; + using metavariables = + Metavariables>>; + using component = Component; + + const size_t number_of_grid_points = 5; + + const Slab slab(1.0, 3.0); + const TimeStepId time_step_id(true, 0, slab.start()); + const auto time_step = slab.duration(); + + Vars initial_vars(number_of_grid_points); + get(get(initial_vars)) = 2.0; + + auto expected_var = get(initial_vars); + // Function is dy/dt = t + get(expected_var) += + 0.5 * (square(slab.end().value()) - square(slab.start().value())); + + history_tag::type history(2); + history.insert(time_step_id, decltype(history)::no_value, + make_with_value( + initial_vars, time_step_id.substep_time())); + Scalar solve_failures(DataVector(number_of_grid_points, 0.0)); + + const double tolerance = 1.0e-10; + + ActionTesting::MockRuntimeSystem runner{{}}; + + ActionTesting::emplace_component_and_initialize( + &runner, 0, + {std::make_unique(), time_step, + time_step_id.substep_time(), + TimeSteppers::Heun2{}.next_time_id(time_step_id, time_step), + initial_vars, imex::Mode::Implicit, tolerance, std::move(history), + std::move(solve_failures)}); + ActionTesting::set_phase(make_not_null(&runner), Parallel::Phase::Testing); + runner.next_action(0); + + const auto& box = ActionTesting::get_databox(runner, 0); + CHECK(db::get<::Tags::Time>(box) == time_step_id.substep_time()); + const auto& final_var = db::get(box); + CHECK_ITERABLE_APPROX(final_var, expected_var); +} +} // namespace + +SPECTRE_TEST_CASE("Unit.Evolution.Imex.Actions.DoImplicitStep", + "[Unit][Evolution][Actions]") { + register_classes_with_charm(); + test_basic_functionality(); + test_nonautonomous(); +} diff --git a/tests/Unit/Evolution/Imex/Actions/Test_RecordTimeStepperData.cpp b/tests/Unit/Evolution/Imex/Actions/Test_RecordTimeStepperData.cpp new file mode 100644 index 000000000000..3c5a986b31d6 --- /dev/null +++ b/tests/Unit/Evolution/Imex/Actions/Test_RecordTimeStepperData.cpp @@ -0,0 +1,202 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Framework/TestingFramework.hpp" + +#include + +#include "DataStructures/DataBox/DataBox.hpp" +#include "DataStructures/DataBox/Prefixes.hpp" +#include "DataStructures/DataBox/Tag.hpp" +#include "DataStructures/DataVector.hpp" +#include "DataStructures/Tensor/Tensor.hpp" +#include "DataStructures/Tensor/TypeAliases.hpp" +#include "DataStructures/Variables.hpp" +#include "DataStructures/VariablesTag.hpp" +#include "Evolution/Imex/Actions/RecordTimeStepperData.hpp" +#include "Evolution/Imex/GuessResult.hpp" +#include "Evolution/Imex/Protocols/ImplicitSector.hpp" +#include "Evolution/Imex/Tags/ImplicitHistory.hpp" +#include "Framework/ActionTesting.hpp" +#include "Parallel/Phase.hpp" +#include "Parallel/PhaseDependentActionList.hpp" +#include "Time/Slab.hpp" +#include "Time/Tags/TimeStepId.hpp" +#include "Time/TimeStepId.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +namespace { +struct Var1 : db::SimpleTag { + using type = Scalar; +}; + +struct Var2 : db::SimpleTag { + using type = Scalar; +}; + +struct Var3 : db::SimpleTag { + using type = Scalar; +}; + +struct OtherVar : db::SimpleTag { + using type = Scalar; +}; + +struct Sector1 : tt::ConformsTo { + using tensors = tmpl::list; + using initial_guess = imex::GuessExplicitResult; + + struct SolveAttempt { + struct source { + using return_tags = tmpl::list>; + using argument_tags = tmpl::list; + static void apply(const gsl::not_null*> source, + const Scalar& other_var) { + get(*source) = get(other_var); + } + }; + + struct jacobian { + using return_tags = tmpl::list<>; + using argument_tags = tmpl::list<>; + static void apply(); + }; + + using tags_from_evolution = tmpl::list<>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + using solve_attempts = tmpl::list; +}; + +struct Sector2 : tt::ConformsTo { + using tensors = tmpl::list; + using initial_guess = imex::GuessExplicitResult; + + struct InitialAttempt { + struct source { + using return_tags = tmpl::list, Tags::Source>; + using argument_tags = tmpl::list; + static void apply(const gsl::not_null*> source3, + const gsl::not_null*> source2, + const Scalar& var1) { + get(*source2) = 3.0 * get(var1); + get(*source3) = 5.0 * get(var1); + } + }; + + struct jacobian { + using return_tags = tmpl::list<>; + using argument_tags = tmpl::list<>; + static void apply(); + }; + + using tags_from_evolution = tmpl::list<>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + + struct Fallback { + struct source { + using return_tags = tmpl::list, Tags::Source>; + using argument_tags = tmpl::list<>; + static void apply(const gsl::not_null*> /*source3*/, + const gsl::not_null*> /*source2*/) { + CHECK(false); + } + }; + + struct jacobian { + using return_tags = tmpl::list<>; + using argument_tags = tmpl::list<>; + static void apply(); + }; + + using tags_from_evolution = tmpl::list<>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + using solve_attempts = tmpl::list; +}; + +struct System : tt::ConformsTo { + using variables_tag = Tags::Variables>; + using implicit_sectors = tmpl::list; +}; + +template +struct Component { + using metavariables = Metavariables; + using chare_type = ActionTesting::MockArrayChare; + using array_index = int; + using simple_tags = + db::AddSimpleTags, + imex::Tags::ImplicitHistory>; + using compute_tags = db::AddComputeTags<>; + using phase_dependent_action_list = tmpl::list< + Parallel::PhaseActions>>, + Parallel::PhaseActions< + Parallel::Phase::Testing, + tmpl::list>>>; +}; + +struct Metavariables { + using system = System; + using component_list = tmpl::list>; +}; +} // namespace + +SPECTRE_TEST_CASE("Unit.Evolution.Imex.Actions.RecordTimeStepperData", + "[Unit][Evolution][Actions]") { + using component = Component; + + const size_t number_of_grid_points = 5; + + const Slab slab(1., 3.); + const TimeStepId time_step_id(true, 0, slab.start()); + + System::variables_tag::type vars(number_of_grid_points); + get(get(vars)) = 2.0; + get(get(vars)) = 3.0; + get(get(vars)) = 4.0; + + const Scalar other_var(DataVector(number_of_grid_points, 5.0)); + + ActionTesting::MockRuntimeSystem runner{{}}; + + ActionTesting::emplace_component_and_initialize( + &runner, 0, + {time_step_id, vars, other_var, + imex::Tags::ImplicitHistory::type(2), + imex::Tags::ImplicitHistory::type(2)}); + ActionTesting::set_phase(make_not_null(&runner), Parallel::Phase::Testing); + runner.next_action(0); + + const auto& box = ActionTesting::get_databox(runner, 0); + const auto& history1 = db::get>(box); + const auto& history2 = db::get>(box); + + CHECK(history1.size() == 1); + CHECK(history1[0].time_step_id == time_step_id); + CHECK(not history1[0].value.has_value()); + CHECK(get>(history1[0].derivative) == other_var); + + CHECK(history2.size() == 1); + CHECK(history2[0].time_step_id == time_step_id); + CHECK(not history2[0].value.has_value()); + CHECK(get(get>(history2[0].derivative)) == + 3.0 * get(get(vars))); + CHECK(get(get>(history2[0].derivative)) == + 5.0 * get(get(vars))); +} diff --git a/tests/Unit/Evolution/Imex/CMakeLists.txt b/tests/Unit/Evolution/Imex/CMakeLists.txt index d12d2754a203..5ab03a9d95a4 100644 --- a/tests/Unit/Evolution/Imex/CMakeLists.txt +++ b/tests/Unit/Evolution/Imex/CMakeLists.txt @@ -5,10 +5,12 @@ set(LIBRARY "Test_Imex") set(LIBRARY_SOURCES Test_GuessResult.cpp + Test_Initialize.cpp Test_Mode.cpp Test_SolveImplicitSector.cpp ) +add_subdirectory(Actions) add_subdirectory(Tags) add_test_library(${LIBRARY} "${LIBRARY_SOURCES}") diff --git a/tests/Unit/Evolution/Imex/Test_Initialize.cpp b/tests/Unit/Evolution/Imex/Test_Initialize.cpp new file mode 100644 index 000000000000..f6bfbebfe8e1 --- /dev/null +++ b/tests/Unit/Evolution/Imex/Test_Initialize.cpp @@ -0,0 +1,95 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Framework/TestingFramework.hpp" + +#include "DataStructures/DataBox/DataBox.hpp" +#include "DataStructures/DataBox/Prefixes.hpp" +#include "DataStructures/DataBox/Tag.hpp" +#include "DataStructures/DataVector.hpp" +#include "DataStructures/Tensor/Tensor.hpp" +#include "DataStructures/Tensor/TypeAliases.hpp" +#include "DataStructures/Variables.hpp" +#include "DataStructures/VariablesTag.hpp" +#include "Evolution/Imex/GuessResult.hpp" +#include "Evolution/Imex/Initialize.hpp" +#include "Evolution/Imex/Protocols/ImexSystem.hpp" +#include "Evolution/Imex/Protocols/ImplicitSector.hpp" +#include "Evolution/Imex/Tags/ImplicitHistory.hpp" +#include "Time/Tags/HistoryEvolvedVariables.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +namespace { +template +struct Sector : tt::ConformsTo { + using tensors = tmpl::list; + + struct initial_guess { + using return_tags = tmpl::list; + using argument_tags = tmpl::list<>; + static imex::GuessResult apply( + gsl::not_null*> var, + const Variables>& inhomogeneous_terms, + double implicit_weight); + }; + + struct SolveAttempt { + struct source { + using return_tags = tmpl::list>; + using argument_tags = tmpl::list; + static void apply(gsl::not_null*> source); + }; + + using jacobian = imex::NoJacobianBecauseSolutionIsAnalytic; + + using tags_from_evolution = tmpl::list<>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + using solve_attempts = tmpl::list; +}; + +struct Var1 : db::SimpleTag { + using type = Scalar; +}; + +struct Var2 : db::SimpleTag { + using type = Scalar; +}; + +struct System : tt::ConformsTo { + using variables_tag = Tags::Variables>; + using implicit_sectors = tmpl::list, Sector>; +}; +} // namespace + +SPECTRE_TEST_CASE("Unit.Evolution.Imex.Initialize", "[Unit][Evolution]") { + using initialize_imex = imex::Initialize; + using explicit_history_tag = + Tags::HistoryEvolvedVariables; + auto box = + db::create>(); + db::mutate( + [](const gsl::not_null variables, + const gsl::not_null explicit_history) { + variables->initialize(5); + explicit_history->integration_order(3); + }, + make_not_null(&box)); + + db::mutate_apply(make_not_null(&box)); + + CHECK(db::get>>(box) + .integration_order() == 3); + CHECK(db::get>>(box) + .integration_order() == 3); + CHECK(db::get>>(box) == + Scalar(DataVector(5, 0.0))); + CHECK(db::get>>(box) == + Scalar(DataVector(5, 0.0))); +} diff --git a/tests/Unit/Helpers/Evolution/Imex/CMakeLists.txt b/tests/Unit/Helpers/Evolution/Imex/CMakeLists.txt index 5df5d9313a02..81cbf7051283 100644 --- a/tests/Unit/Helpers/Evolution/Imex/CMakeLists.txt +++ b/tests/Unit/Helpers/Evolution/Imex/CMakeLists.txt @@ -3,18 +3,25 @@ set(LIBRARY "ImexHelpers") -add_spectre_library(${LIBRARY} INTERFACE) +add_spectre_library(${LIBRARY}) spectre_target_headers( ${LIBRARY} INCLUDE_DIRECTORY ${CMAKE_SOURCE_DIR}/tests/Unit HEADERS + DoImplicitStepSector.hpp TestSector.hpp ) +spectre_target_sources( + ${LIBRARY} + PRIVATE + DoImplicitStepInstantiate.cpp + ) + target_link_libraries( ${LIBRARY} - INTERFACE + PUBLIC DataStructures Imex Utilities diff --git a/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepInstantiate.cpp b/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepInstantiate.cpp new file mode 100644 index 000000000000..8a6b3ab4478e --- /dev/null +++ b/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepInstantiate.cpp @@ -0,0 +1,14 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#include "Evolution/Imex/SolveImplicitSector.hpp" +#include "Evolution/Imex/SolveImplicitSector.tpp" +#include "Helpers/Evolution/Imex/DoImplicitStepSector.hpp" + +namespace helpers = do_implicit_step_helpers; +template struct imex::SolveImplicitSector>; +template struct imex::SolveImplicitSector>; +template struct imex::SolveImplicitSector< + helpers::NonautonomousSystem::variables_tag, helpers::NonautonomousSector>; diff --git a/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepSector.hpp b/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepSector.hpp new file mode 100644 index 000000000000..e8a9370a1c29 --- /dev/null +++ b/tests/Unit/Helpers/Evolution/Imex/DoImplicitStepSector.hpp @@ -0,0 +1,119 @@ +// Distributed under the MIT License. +// See LICENSE.txt for details. + +#pragma once + +#include + +#include "DataStructures/DataBox/Prefixes.hpp" +#include "DataStructures/DataBox/Tag.hpp" +#include "DataStructures/DataVector.hpp" +#include "DataStructures/Tensor/Tensor.hpp" +#include "DataStructures/Tensor/TypeAliases.hpp" +#include "DataStructures/Variables.hpp" +#include "DataStructures/VariablesTag.hpp" +#include "Evolution/Imex/GuessResult.hpp" +#include "Evolution/Imex/Protocols/ImexSystem.hpp" +#include "Evolution/Imex/Protocols/ImplicitSector.hpp" +#include "Time/Tags/Time.hpp" +#include "Utilities/Gsl.hpp" +#include "Utilities/ProtocolHelpers.hpp" +#include "Utilities/TMPL.hpp" + +// Separated from Test_DoImplicitStep.cpp to test explicit +// instantiation of SolveSimplcitSector (in +// DoImplicitStepInstantiate.cpp). +namespace do_implicit_step_helpers { +template +struct Sector : tt::ConformsTo { + using tensors = tmpl::list; + + struct initial_guess { + using return_tags = tmpl::list; + using argument_tags = tmpl::list<>; + static std::vector apply( + const gsl::not_null*> var, + const Variables>& inhomogeneous_terms, + const double implicit_weight) { + get(*var) = get(get(inhomogeneous_terms)) / (1.0 + implicit_weight); + return {get(*var).size(), imex::GuessResult::ExactSolution}; + } + }; + + struct SolveAttempt { + struct source { + using return_tags = tmpl::list>; + using argument_tags = tmpl::list; + static void apply(const gsl::not_null*> source, + const Scalar& var) { + get(*source) = -get(var); + } + }; + + using jacobian = imex::NoJacobianBecauseSolutionIsAnalytic; + + using tags_from_evolution = tmpl::list<>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + + using solve_attempts = tmpl::list; +}; + +struct Var1 : db::SimpleTag { + using type = Scalar; +}; + +struct Var2 : db::SimpleTag { + using type = Scalar; +}; + +struct System : tt::ConformsTo { + using variables_tag = Tags::Variables>; + using implicit_sectors = tmpl::list, Sector>; +}; + +struct NonautonomousSector : tt::ConformsTo { + using tensors = tmpl::list; + + struct initial_guess { + using return_tags = tmpl::list; + using argument_tags = tmpl::list<::Tags::Time>; + static std::vector apply( + const gsl::not_null*> var, const double time, + const Variables>& inhomogeneous_terms, + const double implicit_weight) { + get(*var) = get(get(inhomogeneous_terms)) + implicit_weight * time; + return {get(*var).size(), imex::GuessResult::ExactSolution}; + } + }; + + struct SolveAttempt { + struct source { + using return_tags = tmpl::list>; + using argument_tags = tmpl::list<::Tags::Time>; + static void apply(const gsl::not_null*> source, + const double time) { + get(*source) = time; + } + }; + + using jacobian = imex::NoJacobianBecauseSolutionIsAnalytic; + + using tags_from_evolution = tmpl::list<::Tags::Time>; + using simple_tags = tmpl::list<>; + using compute_tags = tmpl::list<>; + using source_prep = tmpl::list<>; + using jacobian_prep = tmpl::list<>; + }; + + using solve_attempts = tmpl::list; +}; + +struct NonautonomousSystem : tt::ConformsTo { + using variables_tag = Tags::Variables>; + using implicit_sectors = tmpl::list; +}; +} // namespace do_implicit_step_helpers