Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config.cmake.in
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
3 changes: 2 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
40 changes: 40 additions & 0 deletions src/pcms/transient/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
set(PCMS_TRANSIENT_HEADERS
participant.hpp
accelerator.hpp
timestepper.hpp)

set(PCMS_TRANSIENT_SOURCES
participant.cpp
accelerator.cpp
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 $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)

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)
65 changes: 65 additions & 0 deletions src/pcms/transient/accelerator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "pcms/transient/accelerator.hpp"

#include <algorithm>
#include <cmath>
#include <cstddef>
#include <utility>

namespace pcms::transient
{

Real InterfaceAccelerator::Norm(const std::vector<Real>& r)
{
Real sum = 0.0;
for (Real value : r)
sum += value * value;
return std::sqrt(sum);
}

AitkenRelaxation::AitkenRelaxation(Real omega0, Real omega_max)
: omega0_(omega0), omega_(omega0), omega_max_(omega_max)
{
}
Comment on lines +19 to +22

void AitkenRelaxation::BeginWindow()
{
omega_ = omega0_;
have_prev_ = false;
}

Real AitkenRelaxation::Update(const std::vector<Real>& x_in,
const std::vector<Real>& x_out,
std::vector<Real>& x_next)
{
const std::size_t size = x_in.size();
std::vector<Real> residual_values(size);
for (std::size_t i = 0; i < size; ++i)
residual_values[i] = x_out[i] - x_in[i];
const Real residual = Norm(residual_values);
Comment on lines +34 to +38

if (have_prev_) {
Real numerator = 0.0;
Real denominator = 0.0;
for (std::size_t i = 0; i < size; ++i) {
const Real residual_delta = residual_values[i] - r_prev_[i];
numerator += r_prev_[i] * residual_delta;
denominator += residual_delta * residual_delta;
}
if (denominator > 0.0) {
omega_ = -omega_ * numerator / denominator;
if (!std::isfinite(omega_) || omega_ == 0.0)
omega_ = omega0_;
omega_ = std::clamp(omega_, -omega_max_, omega_max_);
}
}

x_next.resize(size);
for (std::size_t i = 0; i < size; ++i)
x_next[i] = x_in[i] + omega_ * residual_values[i];

r_prev_ = std::move(residual_values);
have_prev_ = true;
return residual;
}

} // namespace pcms::transient
57 changes: 57 additions & 0 deletions src/pcms/transient/accelerator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#ifndef PCMS_TRANSIENT_ACCELERATOR_HPP
#define PCMS_TRANSIENT_ACCELERATOR_HPP

#include "pcms/utility/types.h"
#include <vector>

namespace pcms::transient
{

// Updates interface values during a fixed-point iteration.
class InterfaceAccelerator
{
public:
// Reset iteration history before solving a new coupling window.
virtual void BeginWindow() = 0;

// Compute the next interface iterate from equally sized input and output
// vectors. Return the residual norm used to test convergence.
virtual Real Update(const std::vector<Real>& x_in,
const std::vector<Real>& x_out,
std::vector<Real>& x_next) = 0;

virtual ~InterfaceAccelerator() = default;

protected:
// Compute the local L2 norm of a residual vector. Distributed
// implementations must reduce the squared sum across ranks.
static Real Norm(const std::vector<Real>& r);
};

// Aitken relaxation with a factor updated from consecutive residuals.
class AitkenRelaxation : public InterfaceAccelerator
{
public:
// omega0 is the first-iteration relaxation factor. omega_max limits the
// magnitude of factors computed from later residuals.
explicit AitkenRelaxation(Real omega0 = 0.5, Real omega_max = 1e6);

// Restore the initial factor and discard the previous residual.
void BeginWindow() override;

// Form r = x_out - x_in, update the relaxation factor when history exists,
// and write x_next = x_in + omega*r.
Real Update(const std::vector<Real>& x_in, const std::vector<Real>& x_out,
std::vector<Real>& x_next) override;

private:
Real omega0_;
Real omega_;
Real omega_max_;
std::vector<Real> r_prev_;
bool have_prev_ = false;
};

} // namespace pcms::transient

#endif // PCMS_TRANSIENT_ACCELERATOR_HPP
41 changes: 41 additions & 0 deletions src/pcms/transient/participant.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#include "pcms/transient/participant.hpp"

#include <utility>

namespace pcms::transient
{

InterfaceState::InterfaceState() = default;

InterfaceState::InterfaceState(std::size_t n, Real value) : dofs_(n, value) {}

InterfaceState::InterfaceState(std::vector<Real> dofs) : dofs_(std::move(dofs))
{
}

std::size_t InterfaceState::Size() const noexcept
{
return dofs_.size();
}

Real& InterfaceState::operator[](std::size_t i) noexcept
{
return dofs_[i];
}

Real InterfaceState::operator[](std::size_t i) const noexcept
{
return dofs_[i];
}

std::span<const Real> InterfaceState::View() const noexcept
{
return dofs_;
}

std::span<const Real> Participant::ReportQoI() const
{
return {};
}

} // namespace pcms::transient
101 changes: 101 additions & 0 deletions src/pcms/transient/participant.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#ifndef PCMS_TRANSIENT_PARTICIPANT_HPP
#define PCMS_TRANSIENT_PARTICIPANT_HPP

#include "pcms/utility/types.h"
#include <any>
#include <cstddef>
#include <span>
#include <string_view>
#include <vector>

// Transient simulation interfaces.
namespace pcms::transient
{
// Stores interface values retained by the Schwarz fixed-point iteration.
// Schwarz must preserve x_in while a participant advances or restores and may
// overwrite its FieldData. Aitken also needs stable current and previous
// residuals to compute the next iterate. A view into FieldData cannot provide
// that lifetime, so these iteration values are copied into owned storage.
class InterfaceState
{
public:
// Create an empty state when no interface values are available yet.
InterfaceState();

// Create n interface DOFs initialized to value.
explicit InterfaceState(std::size_t n, Real value = 0.0);

// Take ownership of an existing vector of interface DOFs.
explicit InterfaceState(std::vector<Real> dofs);

// Return the number of interface DOFs.
[[nodiscard]] std::size_t Size() const noexcept;

// Access one DOF for modification.
[[nodiscard]] Real& operator[](std::size_t i) noexcept;

// Read one DOF without allowing modification.
[[nodiscard]] Real operator[](std::size_t i) const noexcept;

// Borrow all retained DOFs without transferring ownership.
[[nodiscard]] std::span<const Real> View() const noexcept;

private:
std::vector<Real> dofs_;
};

// Restart state saved at the beginning of a coupling window.
struct Checkpoint
{
Real time = 0.0;
std::any state; // Participant-defined payload.
};

// Optional features supported by a participant.
struct Capabilities
{
bool can_restart = false;
bool has_dense_output = false;
bool reports_qoi = false;
};

// Interface implemented by each solver participating in the simulation.
class Participant
{
public:
// Return the stable name used to identify this participant.
[[nodiscard]] virtual std::string_view Name() const = 0;

// Advance the solver from its current state to t_target.
virtual void AdvanceTo(Real t_target) = 0;

// Capture all state required to repeat the current coupling window.
virtual Checkpoint Save() const = 0;

// Restore a checkpoint previously created by this participant.
virtual void Restore(const Checkpoint&) = 0;

// Borrow values produced on the requested configured interface. The returned
// view must remain valid until the next operation that changes participant
// state.
[[nodiscard]] virtual std::span<const Real> GetInterface(
std::string_view name) const = 0;

// Apply borrowed values with the size and ordering expected by the named
// interface. Implementations must consume or copy them before returning.
virtual void SetInterface(std::string_view name,
std::span<const Real> values) = 0;

// Return optional scalar quantities used for error or conservation checks.
// The returned storage must remain valid until the participant is advanced.
[[nodiscard]] virtual std::span<const Real> ReportQoI() const;

// Report the features this implementation can reliably provide.
[[nodiscard]] virtual Capabilities GetCapabilities() const = 0;

virtual ~Participant() = default;
};

} // namespace pcms::transient

#endif // PCMS_TRANSIENT_PARTICIPANT_HPP
18 changes: 18 additions & 0 deletions src/pcms/transient/timestepper.cpp
Original file line number Diff line number Diff line change
@@ -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<bool, Real> FixedTimestepper::Update(Real, Real)
{
return {true, dt_};
}

} // namespace pcms::transient
43 changes: 43 additions & 0 deletions src/pcms/transient/timestepper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
#ifndef PCMS_TRANSIENT_TIMESTEPPER_HPP
#define PCMS_TRANSIENT_TIMESTEPPER_HPP

#include "pcms/utility/types.h"
#include <utility>

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<bool, Real> 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<bool, Real> Update(Real dt, Real err) override;

private:
Real dt_;
};

} // namespace pcms::transient

#endif // PCMS_TRANSIENT_TIMESTEPPER_HPP
Loading
Loading