From 79d316a80fe8e405e0fe3d893ff7ade992f79142 Mon Sep 17 00:00:00 2001 From: hgangwar Date: Thu, 20 Aug 2026 20:58:25 -0400 Subject: [PATCH 1/3] adding_timestepper --- config.cmake.in | 1 + src/CMakeLists.txt | 3 +- src/pcms/transient/CMakeLists.txt | 33 ++++++++++++++++++++++ src/pcms/transient/timestepper.cpp | 18 ++++++++++++ src/pcms/transient/timestepper.hpp | 43 +++++++++++++++++++++++++++++ test/CMakeLists.txt | 5 ++++ test/test_transient_timestepper.cpp | 25 +++++++++++++++++ 7 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 src/pcms/transient/CMakeLists.txt create mode 100644 src/pcms/transient/timestepper.cpp create mode 100644 src/pcms/transient/timestepper.hpp create mode 100644 test/test_transient_timestepper.cpp diff --git a/config.cmake.in b/config.cmake.in index bf8b4882..b9b8fc91 100644 --- a/config.cmake.in +++ b/config.cmake.in @@ -30,6 +30,7 @@ if(@PCMS_ENABLE_OMEGA_H@) endif() include("${CMAKE_CURRENT_LIST_DIR}/pcms_utility-targets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/pcms_transient-targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/pcms_discretization-targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/pcms_localization-targets.cmake") include("${CMAKE_CURRENT_LIST_DIR}/pcms_field-targets.cmake") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 143889fe..3ca83730 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -14,6 +14,7 @@ configure_file(pcms/configuration.h.in pcms/configuration.h) list(APPEND PCMS_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/pcms/version.h ${CMAKE_CURRENT_BINARY_DIR}/pcms/configuration.h) add_subdirectory(pcms/utility) +add_subdirectory(pcms/transient) add_subdirectory(pcms/discretization) add_subdirectory(pcms/localization) add_subdirectory(pcms/field) @@ -87,7 +88,7 @@ install( ) add_library(pcms_pcms INTERFACE) -target_link_libraries(pcms_pcms INTERFACE pcms::core) +target_link_libraries(pcms_pcms INTERFACE pcms::core pcms::transient) set_target_properties(pcms_pcms PROPERTIES EXPORT_NAME pcms) if (PCMS_ENABLE_Python) # Disable LTO/IPO before adding Python subdirectory to avoid fatbinData conflicts diff --git a/src/pcms/transient/CMakeLists.txt b/src/pcms/transient/CMakeLists.txt new file mode 100644 index 00000000..c64c9e36 --- /dev/null +++ b/src/pcms/transient/CMakeLists.txt @@ -0,0 +1,33 @@ +set(PCMS_TRANSIENT_HEADERS timestepper.hpp) +set(PCMS_TRANSIENT_SOURCES timestepper.cpp) + +add_library(pcms_transient ${PCMS_TRANSIENT_SOURCES}) +set_target_properties(pcms_transient PROPERTIES EXPORT_NAME transient) +add_library(pcms::transient ALIAS pcms_transient) + +target_sources( + pcms_transient + PUBLIC FILE_SET transient + TYPE HEADERS + BASE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/.. + FILES ${PCMS_TRANSIENT_HEADERS}) +target_compile_features(pcms_transient PUBLIC cxx_std_20) +target_link_libraries(pcms_transient PUBLIC pcms::utility) +target_include_directories( + pcms_transient + PUBLIC $ + $) + +install( + TARGETS pcms_transient + EXPORT pcms_transient-targets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/pcms/transient + FILE_SET transient DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/pcms) + +install( + EXPORT pcms_transient-targets + NAMESPACE pcms:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pcms) diff --git a/src/pcms/transient/timestepper.cpp b/src/pcms/transient/timestepper.cpp new file mode 100644 index 00000000..14755b9a --- /dev/null +++ b/src/pcms/transient/timestepper.cpp @@ -0,0 +1,18 @@ +#include "pcms/transient/timestepper.hpp" + +namespace pcms::transient +{ + +FixedTimestepper::FixedTimestepper(Real dt) : dt_(dt) {} + +Real FixedTimestepper::InitialStep() const +{ + return dt_; +} + +std::pair FixedTimestepper::Update(Real, Real) +{ + return {true, dt_}; +} + +} // namespace pcms::transient diff --git a/src/pcms/transient/timestepper.hpp b/src/pcms/transient/timestepper.hpp new file mode 100644 index 00000000..8b59e088 --- /dev/null +++ b/src/pcms/transient/timestepper.hpp @@ -0,0 +1,43 @@ +#ifndef PCMS_TRANSIENT_TIMESTEPPER_HPP +#define PCMS_TRANSIENT_TIMESTEPPER_HPP + +#include "pcms/utility/types.h" +#include + +namespace pcms::transient +{ + +// Decides whether to accept a completed time window and selects the next step. +class Timestepper +{ +public: + // Return the positive step size used for the first coupling window. + [[nodiscard]] virtual Real InitialStep() const = 0; + + // Given the step that was actually completed and its normalized error, + // return whether to accept it and the positive step size to try next. + virtual std::pair Update(Real dt, Real err) = 0; + + virtual ~Timestepper() = default; +}; + +// Always accepts and keeps a constant time step. +class FixedTimestepper : public Timestepper +{ +public: + // Store the positive step size used for every window. + explicit FixedTimestepper(Real dt); + + // Return the configured fixed step. + Real InitialStep() const override; + + // Ignore the completed step and error, accept, and keep the configured step. + std::pair Update(Real dt, Real err) override; + +private: + Real dt_; +}; + +} // namespace pcms::transient + +#endif // PCMS_TRANSIENT_TIMESTEPPER_HPP diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 9a7eb845..7b6a12f6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -399,6 +399,10 @@ find_package(Catch2 3) if(Catch2_FOUND) message( STATUS "Found Catch2: ${Catch2_DIR} (found version ${Catch2_VERSION})") + add_executable(test_transient_timestepper test_transient_timestepper.cpp) + target_link_libraries(test_transient_timestepper + PRIVATE Catch2::Catch2WithMain pcms::transient) + set(PCMS_UNIT_TEST_SOURCES unit_test_main.cpp test_coordinate_transform.cpp test_coordinate.cpp test_bounding_box.cpp) if(PCMS_ENABLE_XGC) @@ -474,6 +478,7 @@ if(Catch2_FOUND) include(Catch) Catch_discover_tests(unit_tests) + Catch_discover_tests(test_transient_timestepper) else() message(WARNING "Catch2 not found. Disabling Unit Tests") endif() diff --git a/test/test_transient_timestepper.cpp b/test/test_transient_timestepper.cpp new file mode 100644 index 00000000..c588581c --- /dev/null +++ b/test/test_transient_timestepper.cpp @@ -0,0 +1,25 @@ +#include +#include + +#include "pcms/transient/timestepper.hpp" + +namespace tr = pcms::transient; + +TEST_CASE("FixedTimestepper always accepts its configured step", "[transient]") +{ + // 0.25 represents the positive fixed window size selected by the user. + tr::FixedTimestepper timestepper(0.25); + + // The completed step (0.1) and large normalized error (100) are deliberately + // different from the configured step. A fixed controller must ignore both. + const auto [accepted, next_step] = timestepper.Update(0.1, 100.0); + + // The first window must use the user-configured size. + REQUIRE(timestepper.InitialStep() == Catch::Approx(0.25)); + + // A fixed timestepper never rejects a completed window based on error. + REQUIRE(accepted); + + // Subsequent windows must retain the same configured size. + REQUIRE(next_step == Catch::Approx(0.25)); +} From 55566ad591230d22b7bbd4895b073e2181e61bcd Mon Sep 17 00:00:00 2001 From: hgangwar Date: Sat, 22 Aug 2026 02:38:56 -0400 Subject: [PATCH 2/3] format_and_comments --- src/pcms/transient/timestepper.cpp | 2 +- src/pcms/transient/timestepper.hpp | 4 ++-- test/CMakeLists.txt | 2 +- test/test_transient_timestepper.cpp | 10 +++------- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/pcms/transient/timestepper.cpp b/src/pcms/transient/timestepper.cpp index 14755b9a..ca856d41 100644 --- a/src/pcms/transient/timestepper.cpp +++ b/src/pcms/transient/timestepper.cpp @@ -15,4 +15,4 @@ std::pair FixedTimestepper::Update(Real, Real) return {true, dt_}; } -} // namespace pcms::transient +} //namespace pcms::transient diff --git a/src/pcms/transient/timestepper.hpp b/src/pcms/transient/timestepper.hpp index 8b59e088..8a01a63b 100644 --- a/src/pcms/transient/timestepper.hpp +++ b/src/pcms/transient/timestepper.hpp @@ -14,7 +14,7 @@ class Timestepper // Return the positive step size used for the first coupling window. [[nodiscard]] virtual Real InitialStep() const = 0; - // Given the step that was actually completed and its normalized error, + // Given the current time step that was actually completed and its normalized error, // return whether to accept it and the positive step size to try next. virtual std::pair Update(Real dt, Real err) = 0; @@ -31,7 +31,7 @@ class FixedTimestepper : public Timestepper // Return the configured fixed step. Real InitialStep() const override; - // Ignore the completed step and error, accept, and keep the configured step. + // Keep the configured fixed time step. std::pair Update(Real dt, Real err) override; private: diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 7b6a12f6..482e582a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -401,7 +401,7 @@ if(Catch2_FOUND) STATUS "Found Catch2: ${Catch2_DIR} (found version ${Catch2_VERSION})") add_executable(test_transient_timestepper test_transient_timestepper.cpp) target_link_libraries(test_transient_timestepper - PRIVATE Catch2::Catch2WithMain pcms::transient) + PRIVATE Catch2::Catch2WithMain pcms::transient) set(PCMS_UNIT_TEST_SOURCES unit_test_main.cpp test_coordinate_transform.cpp test_coordinate.cpp test_bounding_box.cpp) diff --git a/test/test_transient_timestepper.cpp b/test/test_transient_timestepper.cpp index c588581c..8b2bad5b 100644 --- a/test/test_transient_timestepper.cpp +++ b/test/test_transient_timestepper.cpp @@ -7,19 +7,15 @@ namespace tr = pcms::transient; TEST_CASE("FixedTimestepper always accepts its configured step", "[transient]") { - // 0.25 represents the positive fixed window size selected by the user. + // 0.25 represents a positive fixed window size. tr::FixedTimestepper timestepper(0.25); - // The completed step (0.1) and large normalized error (100) are deliberately - // different from the configured step. A fixed controller must ignore both. + // The completed step (0.1) and large normalized error (100). + // A fixed controller ignores both. const auto [accepted, next_step] = timestepper.Update(0.1, 100.0); // The first window must use the user-configured size. REQUIRE(timestepper.InitialStep() == Catch::Approx(0.25)); - - // A fixed timestepper never rejects a completed window based on error. REQUIRE(accepted); - - // Subsequent windows must retain the same configured size. REQUIRE(next_step == Catch::Approx(0.25)); } From d3d0bcb24c6bc3e62eb45d1a120d0a588cd9c4ef Mon Sep 17 00:00:00 2001 From: hgangwar Date: Sat, 22 Aug 2026 11:52:53 -0400 Subject: [PATCH 3/3] format --- src/pcms/transient/timestepper.cpp | 2 +- src/pcms/transient/timestepper.hpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pcms/transient/timestepper.cpp b/src/pcms/transient/timestepper.cpp index ca856d41..14755b9a 100644 --- a/src/pcms/transient/timestepper.cpp +++ b/src/pcms/transient/timestepper.cpp @@ -15,4 +15,4 @@ std::pair FixedTimestepper::Update(Real, Real) return {true, dt_}; } -} //namespace pcms::transient +} // namespace pcms::transient diff --git a/src/pcms/transient/timestepper.hpp b/src/pcms/transient/timestepper.hpp index 8a01a63b..8ef47ca7 100644 --- a/src/pcms/transient/timestepper.hpp +++ b/src/pcms/transient/timestepper.hpp @@ -14,8 +14,8 @@ class Timestepper // Return the positive step size used for the first coupling window. [[nodiscard]] virtual Real InitialStep() const = 0; - // Given the current time step that was actually completed and its normalized error, - // return whether to accept it and the positive step size to try next. + // Given the current time step that was actually completed and its normalized + // error, return whether to accept it and the positive step size to try next. virtual std::pair Update(Real dt, Real err) = 0; virtual ~Timestepper() = default;