Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
4ccb49e
Initial gretl in serac. Need to work on some tests, maybe documentin…
tupek2 Mar 14, 2025
77b56ab
Revert back to original gretl.
tupek2 Mar 15, 2025
f7e758b
--amend
tupek2 Mar 15, 2025
c19b7ba
Trying to get original checkpoint tests passing again.
tupek2 Mar 15, 2025
4ec0b48
Operation gretl again.
tupek2 Mar 18, 2025
b72a057
Make it a bit less likely toa accidentally no specify a valid zero_du…
tupek2 Mar 18, 2025
ae86ce3
Additional cleanup of compilation warnings.
tupek2 Mar 18, 2025
0746ec4
Add in a highly nonlinear and more complicated graph.
tupek2 Mar 18, 2025
1ce7e8d
Add in a highly nonlinear and more complicated graph.
tupek2 Mar 18, 2025
2490a51
Get test tolerance in place.
tupek2 Mar 18, 2025
471dfa5
Fix style.
tupek2 Mar 18, 2025
a928494
Try to fix some gcc build issues.
tupek2 Mar 18, 2025
449b438
Fix another gcc issue.
tupek2 Mar 19, 2025
bb271cf
add all headers to cmake lists.
tupek2 Mar 19, 2025
dbe1feb
Another header missing.
tupek2 Mar 19, 2025
f5898c5
Another gcc build fix.
tupek2 Mar 19, 2025
be0ea51
Try again to fix gcc13 warnings.
tupek2 Mar 19, 2025
96fcff9
Trying to address gcc issues.
tupek2 Mar 20, 2025
37c76a7
Try to fix gcc warnings.
tupek2 Mar 20, 2025
61fd848
Try again to resolve gcc warning.
tupek2 Mar 20, 2025
44107f6
Debugging gretl.
tupek2 Jun 6, 2025
c90d23f
Trying to simplify gretl.
tupek2 Jun 6, 2025
0469141
Simplifying gretl implementation, no checkpointing yet.
tupek2 Jun 6, 2025
ba58d95
Seemingly got gretl, no checkpoint working again.
tupek2 Jun 8, 2025
02c56fd
Cleanup the initial, not dynamically checkpointed gretl.
tupek2 Jun 8, 2025
37c7340
Remove some prints, only clear shared pointer if no one else has a ha…
tupek2 Jun 8, 2025
ddee2ce
style.
tupek2 Jun 8, 2025
80d7b4d
Fix build.
tupek2 Jun 8, 2025
fce33b1
Fix style.
tupek2 Jun 8, 2025
094c1d0
Fix style.
tupek2 Jun 9, 2025
0474505
Trying to work out the dynamic checkpointing interface.
tupek2 Jun 12, 2025
5a7c418
Working toward dynamic implementation.
tupek2 Jun 12, 2025
1cb451f
Working toward gretl redesign.
tupek2 Jun 20, 2025
fa0e7cf
Get gretl tests working again with backend refactor.
tupek2 Jun 21, 2025
9e2b7a9
Cleanup some prints.
tupek2 Jun 21, 2025
feb37e1
Get test passing again.
tupek2 Jun 23, 2025
e6ce787
Nearly working dynamic checkpointing. forward pass looks to be correct.
tupek2 Jun 24, 2025
6206f9e
still seeming have forward part operating... need to figure out rever…
tupek2 Jun 24, 2025
065a335
Trying to manage the counting of the pass through states.
tupek2 Jun 24, 2025
0b72bd6
Progressing on graph dynamic checkpointing.
tupek2 Jul 1, 2025
c6078f6
Trying to be more careful tracking states and their passthroughts.
tupek2 Jul 3, 2025
457a261
Progress on checkpointing.
tupek2 Jul 7, 2025
1cc225b
Just have a single data store... we can make the Checkpointmanager vi…
tupek2 Jul 7, 2025
dda8d50
style.
tupek2 Jul 7, 2025
19a6bed
Get all checkpointing tests working again after refactor.
tupek2 Jul 7, 2025
bd16a6b
Remove some prints
tupek2 Jul 7, 2025
6458244
Fix some warnings and small cleanups.
tupek2 Jul 8, 2025
ea31d01
Get optimizations in. Need to document and figure out how to test co…
tupek2 Jul 8, 2025
40b10a6
Some more internal asserts to ensure correctness.
tupek2 Jul 8, 2025
b648971
Get other test working.
tupek2 Jul 9, 2025
0d0fb7a
Remove comments.
tupek2 Aug 4, 2025
1b7366d
Fix style.
tupek2 Aug 4, 2025
450e7b9
Working on documenting the gretl interface a bit more.
tupek2 Aug 5, 2025
3118646
Fix style and docs.
tupek2 Aug 5, 2025
13440ea
Fix last line.
tupek2 Aug 5, 2025
b620140
More ending lines.
tupek2 Aug 5, 2025
3e1423f
More docs improvements and file naming adjustments.
tupek2 Aug 5, 2025
c7a4c66
small fix.
tupek2 Aug 5, 2025
9a67661
Change upstream implementation, fix library name to serac.
tupek2 Aug 5, 2025
6cbf528
Try to fix gcc issues.
tupek2 Aug 5, 2025
d34c80b
Fix maybe nullptr.
tupek2 Aug 5, 2025
d8caccd
Try to fix maybe nullptr.
tupek2 Aug 5, 2025
fd371bf
Merge branch 'develop' into tupek/gretl_refactor
tupek2 Aug 18, 2025
5e3204d
Merge branch 'tupek/residual_interface_adjustments' into tupek/gretl_…
tupek2 Aug 18, 2025
eadb07f
Another working adjustment.
tupek2 Aug 18, 2025
40fab88
Merge branch 'develop' into tupek/gretl_refactor
tupek2 Aug 19, 2025
e8f0ebb
Merge branch 'develop' into tupek/gretl_refactor
tupek2 Sep 18, 2025
29cf89a
Fix some commented on issues.
tupek2 Sep 18, 2025
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 src/serac/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ add_subdirectory(infrastructure)
add_subdirectory(numerics)
add_subdirectory(physics)
add_subdirectory(mesh_utils)
add_subdirectory(gretl)
47 changes: 47 additions & 0 deletions src/serac/gretl/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Copyright (c) Lawrence Livermore National Security, LLC and
# other Serac Project Developers. See the top-level LICENSE file for
# details.
#
# SPDX-License-Identifier: (BSD-3-Clause)

Copy link
Member

@white238 white238 Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
# Copyright (c) Lawrence Livermore National Security, LLC and
# other Serac Project Developers. See the top-level LICENSE file for
# details.
#
# SPDX-License-Identifier: (BSD-3-Clause)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep!

set(serac_gretl_sources
data_store.cpp
state_base.cpp
vector_state.cpp
)

set(serac_gretl_headers
checkpoint.hpp
data_store.hpp
test_utils.hpp
state_base.hpp
state.hpp
create_state.hpp
upstream_state.hpp
double_state.hpp
vector_state.hpp
print_utils.hpp
)

blt_add_library(
NAME serac_gretl
SOURCES ${serac_gretl_sources}
HEADERS ${serac_gretl_headers}
)

target_include_directories(serac_gretl PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/../..>
$<INSTALL_INTERFACE:include>
)

install(FILES ${serac_gretl_headers} DESTINATION include/serac/gretl )

install(TARGETS serac_gretl
EXPORT serac-targets
DESTINATION lib
)

if(SERAC_ENABLE_TESTS)
add_subdirectory(tests)
endif()

235 changes: 235 additions & 0 deletions src/serac/gretl/checkpoint.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
// Copyright (c) Lawrence Livermore National Security, LLC and
// other Serac Project Developers. See the top-level LICENSE file for
// details.
//
// SPDX-License-Identifier: (BSD-3-Clause)

/**
* @file checkpoint.hpp
*/

#pragma once

#include <set>
#include <map>
#include <ostream>
#include <iostream>
#include <cassert>
#include <limits>

/// @brief gretl_assert that prints line and file info before throwing in release and halting in debug
#define gretl_assert(x) \
if (!(x)) \
throw std::runtime_error{"Error on line " + std::to_string(__LINE__) + " in file " + std::string(__FILE__)}; \
assert(x);

/// @brief gretl_assert_msg that prints message, line and file info before throwing in release and halting in debug
#define gretl_assert_msg(x, msg_name_) \
if (!(x)) \
throw std::runtime_error{"Error on line " + std::to_string(__LINE__) + " in file " + std::string(__FILE__) + \
std::string(", ") + std::string(msg_name_)}; \
assert(x);

namespace gretl {

/// @brief checkpoint struct which tracks level and step per "Minimal Repetition Dynamic Checkpointing Algorithm for
/// Unsteady Adjoint Calculation", Wang, et al. , 2009.
struct Checkpoint {
size_t level; ///< level
size_t step; ///< step
static constexpr size_t infinity()
{
return std::numeric_limits<size_t>::max();
} ///< The largest possible step and level value
};

/// @brief comparison operator between two checkpoints to determine which is most disposable per the dynamic
/// checkpointing algorithm
inline bool operator<(const Checkpoint& a, const Checkpoint& b)
{
if (a.level == Checkpoint::infinity() && b.level == Checkpoint::infinity()) {
return a.step > b.step;
}
if (a.level == Checkpoint::infinity()) return false;
if (b.level == Checkpoint::infinity()) return true;
return a.step > b.step;
}

/// @brief output stream for a single checkpoint
inline std::ostream& operator<<(std::ostream& stream, const Checkpoint& p);

/// @brief CheckpointManager class which encapsulates the logic of when and which steps should be dynamically saved a
/// fetched
struct CheckpointManager {
static constexpr size_t invalidCheckpointIndex =
std::numeric_limits<size_t>::max(); ///< magic number of invalid checkpoint

/// @brief utilty for checking if an index is valid. There is a magic number, invalidCheckpointIndex, which
/// represents an invalid checkpoint
static bool valid_checkpoint_index(size_t i) { return i != invalidCheckpointIndex; }

/// @brief returns const_iterator to currently most dispensable checkpoint step
std::set<gretl::Checkpoint>::const_iterator most_dispensable() const
{
size_t maxHigherTimeLevel = 0;
for (auto rIter = cps.begin(); rIter != cps.end(); ++rIter) {
if (rIter->level < maxHigherTimeLevel) {
return rIter;
}
maxHigherTimeLevel = std::max(rIter->level, maxHigherTimeLevel);
}
return cps.end();
}

/// @brief this does multiple things
/// 1. it adds checkpoints into the database, and updates internal data structures
/// 2. it determines if a checkpoint needs to be removed
/// 3. if a checkpoint needs to be removed, it returns the index for that checkpoint
/// 4. otherwise, it returns zero
size_t add_checkpoint_and_get_index_to_remove(size_t step, bool persistent = false)
{
size_t levelupAmount = 1; //= relativeCost >= 2.0 ? 3 : 1;

Checkpoint nextStep{.level = levelupAmount - 1, .step = step};

size_t nextEraseStep = invalidCheckpointIndex;

// don't include persistent data in data quota. MRT, this might change
if (persistent) {
maxNumStates++;
nextStep.level = Checkpoint::infinity();
gretl_assert(cps.size() < maxNumStates);
}

if (cps.size() < maxNumStates) {
cps.insert(nextStep);
} else {
auto iterToMostDispensable = most_dispensable();
if (iterToMostDispensable != cps.end()) {
nextEraseStep = iterToMostDispensable->step;
cps.erase(iterToMostDispensable);
cps.insert(nextStep);
} else {
nextEraseStep = cps.begin()->step;
nextStep.level = cps.begin()->level + levelupAmount;

cps.erase(cps.begin());
cps.insert(nextStep);
}
}

return nextEraseStep;
}

/// @brief return largest currently checkpointed step
size_t last_checkpoint_step() const { return cps.begin()->step; }

/// @brief erase
bool erase_step(size_t stepIndex)
{
for (std::set<Checkpoint>::iterator it = cps.begin(); it != cps.end(); ++it) {
if (it->step == stepIndex) {
if (it->level != Checkpoint::infinity()) {
cps.erase(it);
return true;
}
}
}
return false;
}

/// @brief check if this step is currently checkpointed. This could potentially use performance optimization down the
/// way.
bool contains_step(size_t stepIndex) const
{
for (auto& c : cps) {
if (c.step == stepIndex) {
return true;
}
}
return false;
}

/// @brief erase all non persistent checkpoints
void reset()
{
for (auto cp_it = cps.begin(); cp_it != cps.end(); ++cp_it) {
if (cp_it->level == Checkpoint::infinity()) {
cps.erase(cps.begin(), cp_it);
break;
}
}
}

size_t maxNumStates =
20; ///< The maximum number of non-persistent, not-in-scope states stored by the CheckpointManager
std::set<Checkpoint> cps; ///< Vector of checkpoints
};

/// @brief interface to run forward with a linear graph, checkpoint, then automatically backpropagate the sensitivities
/// given the reverse_callback vjp.
/// @tparam T type of each state's data
/// @param numSteps number of forward iterations
/// @param storageSize maximum states to save in memory at a time
/// @param x initial condition
/// @param update_func function which evaluates the forward response
/// @param reverse_callback vjp function (action of Jacobian-transposed) to back propagate sensitivities
/// @return
template <typename T>
T advance_and_reverse_steps(size_t numSteps, size_t storageSize, T x, std::function<T(size_t n, const T&)> update_func,
std::function<void(size_t n, const T&)> reverse_callback)
{
gretl::CheckpointManager cps{.maxNumStates = storageSize, .cps{}};
std::map<size_t, T> savedCps;
savedCps[0] = x;

cps.add_checkpoint_and_get_index_to_remove(0, true);
for (size_t i = 0; i < numSteps; ++i) {
x = update_func(i, savedCps[i]);
size_t eraseStep = cps.add_checkpoint_and_get_index_to_remove(i + 1, false);
if (cps.valid_checkpoint_index(eraseStep)) {
savedCps.erase(eraseStep);
}

savedCps[i + 1] = x;
}

double xf = x;

for (size_t i = numSteps; i + 1 > 0; --i) {
while (cps.last_checkpoint_step() < i) {
size_t lastCp = cps.last_checkpoint_step();
x = update_func(lastCp, savedCps[lastCp]);
size_t eraseStep = cps.add_checkpoint_and_get_index_to_remove(lastCp + 1, false);
if (cps.valid_checkpoint_index(eraseStep)) {
savedCps.erase(eraseStep);
}
savedCps[lastCp + 1] = x;
}
reverse_callback(i, savedCps[i]);

cps.erase_step(i);
savedCps.erase(i);
}

return xf;
}

/// @brief ostream operator for writing out checkpoint information
inline std::ostream& operator<<(std::ostream& stream, const Checkpoint& p)
{
return stream << " lvl=" << p.level << ", step=" << p.step;
}

/// @brief ostream operator for writing out information about the entire checkpoint manager to see the set of currently
/// checkpointed states
inline std::ostream& operator<<(std::ostream& stream, const CheckpointManager& set)
{
stream << "CHECKPOINTS: capacity = " << set.maxNumStates << std::endl;
for (const auto& s : set.cps) {
stream << s << "\n";
}
return stream;
}

} // namespace gretl
Loading