-
Notifications
You must be signed in to change notification settings - Fork 26
Data base class #155
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
djmallum
wants to merge
17
commits into
Chrismarsh:develop
Choose a base branch
from
djmallum:data_base_class
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Data base class #155
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
f8344c3
Base class for submodules: base_step.
djmallum 210c8ce
Correcting `base_step` constness, concepts, and constructors
djmallum c3d663c
Added documentation to `base_step`
djmallum 80882b4
Added `#pragma once` to `base_step.hpp`
djmallum 1e3e940
Added GNU License Header and author name
djmallum c7741da
Data base class with finer control
djmallum 13f3acd
Test of `data_base` and adding to CMakeLists
djmallum 27fb6b9
Fixing comments
djmallum 6d45782
Updating `data_base` Concepts
djmallum 689b0d6
Changed function name for clarity
djmallum 4db7bcb
New test-only constructor for `data_base`
djmallum 9cc679d
get_cache() is now const
djmallum 08e5f38
Removed name signature from base_step.hpp
djmallum 73e8f99
Added missing include
djmallum b65ebef
Added new test for basic submodule, using base_step and data_base
djmallum 694db61
Adding .rst file with instructions
djmallum caa12ac
Modified triangulation::make_module_data to accept variadic template
djmallum File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| // | ||
| // Canadian Hydrological Model - The Canadian Hydrological Model (CHM) is a novel | ||
| // modular unstructured mesh based approach for hydrological modelling | ||
| // Copyright (C) 2018 Christopher Marsh | ||
| // | ||
| // This file is part of Canadian Hydrological Model. | ||
| // | ||
| // Canadian Hydrological Model is free software: you can redistribute it and/or | ||
| // modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // | ||
| // Canadian Hydrological Model is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
| // | ||
| // You should have received a copy of the GNU General Public License | ||
| // along with Canadian Hydrological Model. If not, see | ||
| // <http://www.gnu.org/licenses/>. | ||
| // | ||
|
|
||
| #pragma once | ||
| #include <concepts> | ||
|
|
||
| /** | ||
| * @brief Base class for submodules using the Curiously Recurring Template Pattern (CRTP). | ||
| * | ||
| * This class enforces that derived classes implement an `execute_impl(Data&) const` method, | ||
| * and provides a public `execute(Data&) const` method that forwards to the derived implementation. | ||
| * | ||
| * The CRTP pattern allows compile-time polymorphism, enabling static dispatch and | ||
| * avoiding the overhead of virtual functions. This is useful for performance-critical | ||
| * code or when templates are preferred over inheritance. | ||
| * | ||
| * Usage example: | ||
| * @code | ||
| * struct MyStep : public base_step<MyStep, MyData> { | ||
| * void execute_impl(MyData& d) { | ||
| * // Step-specific logic here | ||
| * } | ||
| * }; | ||
| * MyStep step; | ||
| * MyData data; | ||
| * step.execute(data); // Calls MyStep::execute_impl(data) | ||
| * @endcode | ||
| */ | ||
|
|
||
| template<typename T, typename Data> | ||
| concept GuaranteeImplementExecute = requires(const T& t, Data& d) { | ||
| { t.execute_impl(d) } -> std::same_as<void>; | ||
| }; | ||
|
|
||
| template<class Derived, class Data> | ||
| class base_step { | ||
| protected: | ||
| base_step() {}; | ||
| public: | ||
| void execute(Data& d) const { | ||
|
|
||
| static_assert(GuaranteeImplementExecute<Derived,Data>, | ||
| "Derived class must implement: void execute_impl(Data&) const"); | ||
|
|
||
| static_cast<const Derived*>(this)->execute_impl(d); | ||
| } | ||
| ~base_step() {}; | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,224 @@ | ||
| // | ||
| // Canadian Hydrological Model - The Canadian Hydrological Model (CHM) is a novel | ||
| // modular unstructured mesh based approach for hydrological modelling | ||
| // Copyright (C) 2018 Christopher Marsh | ||
| // | ||
| // This file is part of Canadian Hydrological Model. | ||
| // | ||
| // Canadian Hydrological Model is free software: you can redistribute it and/or | ||
| // modify | ||
| // it under the terms of the GNU General Public License as published by | ||
| // the Free Software Foundation, either version 3 of the License, or | ||
| // (at your option) any later version. | ||
| // | ||
| // Canadian Hydrological Model is distributed in the hope that it will be useful, | ||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| // GNU General Public License for more details. | ||
| // | ||
| // You should have received a copy of the GNU General Public License | ||
| // along with Canadian Hydrological Model. If not, see | ||
| // <http://www.gnu.org/licenses/>. | ||
| // | ||
|
|
||
| // | ||
| // Created by Donovan Allum 2025 | ||
djmallum marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // | ||
|
|
||
| #pragma once | ||
|
|
||
| #include "global.hpp" | ||
| #include "triangulation.hpp" | ||
| #include <limits> | ||
| #include <optional> | ||
| #include <boost/shared_ptr.hpp> | ||
| #include <boost/property_tree/ptree.hpp> | ||
| #include <cstddef> | ||
| #include <stdexcept> | ||
| #include <cassert> | ||
| #include <cstdint> | ||
| #include <concepts> | ||
| #include <type_traits> | ||
|
|
||
| /** | ||
| * @brief Base class for data management with lazy caching and output handling. | ||
| * | ||
| * This class provides a framework for managing data with optional caching, | ||
| * lazy evaluation, and output assignment. It uses CRTP-like patterns with | ||
| * concepts to enforce interface contracts at compile-time. | ||
| * | ||
| * Key features: | ||
| * - Automatic cache initialization and staleness checking | ||
| * - Lazy evaluation of values with cache-aware updates | ||
| * - Type-safe output assignment with runtime checks | ||
| * - Compile-time concept enforcement for derived cache types and value/output providers | ||
| * | ||
| * The class is designed for computational scenarios where: | ||
| * - Data may be expensive to compute and should be cached | ||
| * - Cache validity depends on external timestep counters | ||
| * - Values need to be fetched lazily when accessed | ||
| * - Outputs must be accumulated safely | ||
| * | ||
| * Usage example: | ||
| * @code | ||
| * struct MyCache : public cache_base { | ||
| * double temperature = default_value<double>(); | ||
| * int iteration_count = default_value<int>(); | ||
| * }; | ||
| * | ||
| * class MyData : public data_base<MyCache> { | ||
| * public: | ||
| * MyData(const mesh_elem& face_in, const boost::shared_ptr<global> param, | ||
| * const pt::ptree& cfg) : data_base(face_in, param, cfg) {} | ||
| * | ||
| * void compute_temperature() { | ||
| * update_value( | ||
| * [this]() -> auto& { return cache_->temperature; }, | ||
| * [this]() { return expensive_temperature_calculation(); } | ||
| * ); | ||
| * } | ||
| * | ||
| * void add_to_output(double contribution) { | ||
| * set_output( | ||
| * [this]() -> auto& { return output_variable; }, | ||
| * contribution | ||
| * ); | ||
| * } | ||
| * }; | ||
| * @endcode | ||
| * | ||
| * @tparam CacheType A type derived from cache_base that provides storage | ||
| * for cached values. Must satisfy the CacheRules concept. | ||
| */ | ||
|
|
||
| struct cache_base | ||
| { | ||
| int64_t last_timestep = -1; | ||
|
|
||
| template<typename T> | ||
| static constexpr T default_value() { | ||
| if constexpr (std::is_floating_point_v<T>) | ||
| return std::numeric_limits<T>::quiet_NaN(); | ||
| else if constexpr (std::is_integral_v<T>) | ||
| return std::numeric_limits<T>::min(); | ||
| else | ||
| return T{}; | ||
| }; | ||
|
|
||
| }; | ||
|
|
||
| namespace data_base_concepts { | ||
| template<typename C> | ||
| concept CacheRules = std::derived_from<C,cache_base>; | ||
|
|
||
| template<typename V> | ||
| concept ValueRules = | ||
| requires(V v) { | ||
| {v()} -> std::same_as<std::add_lvalue_reference_t<decltype(v())>>; | ||
| }; | ||
|
|
||
| template<typename O,typename T> | ||
| concept OutputRules = ValueRules<O> && | ||
| requires(O o,const T t) | ||
| { | ||
| {o()} -> std::convertible_to<T>; | ||
| {o() += t}; | ||
| }; | ||
| }; | ||
|
|
||
| namespace pt = boost::property_tree; | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| class data_base { | ||
|
|
||
| template<typename T> | ||
| bool constexpr is_unset(T t) | ||
| { | ||
| if constexpr (!std::is_floating_point_v<T>) | ||
| return t == cache_base::default_value<T>(); | ||
| else | ||
| return std::isnan(t); | ||
| }; | ||
|
|
||
| bool is_stale(); | ||
|
|
||
| void init_cache(); | ||
|
|
||
| protected: | ||
|
|
||
| data_base(const mesh_elem& face_in, const boost::shared_ptr<global> param, | ||
| const pt::ptree& cfg); | ||
| // Test constructor to skip checks of valid mesh_elem | ||
| data_base(const mesh_elem& face_in, const boost::shared_ptr<global> param, | ||
| const pt::ptree& cfg, bool istest); | ||
| ~data_base() {}; | ||
|
|
||
| const mesh_elem face{nullptr}; | ||
| const boost::shared_ptr<global> global_param; | ||
| const pt::ptree& cfg_; | ||
| mutable std::optional<CacheType> cache_; | ||
|
|
||
| template<data_base_concepts::ValueRules Value,typename Fetch> | ||
| void update_value(Value&& value, const Fetch& fetch); | ||
|
|
||
| template<typename T,data_base_concepts::OutputRules<T> Output> | ||
| void set_output(Output&& output,const T t); | ||
|
|
||
| public: | ||
| void reset_cache() { cache_.reset(); }; | ||
| const std::optional<CacheType>& get_cache() const { return cache_; }; | ||
| }; | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| void data_base<CacheType>::init_cache() { | ||
| if (!cache_ || is_stale()) { | ||
| cache_.emplace(); | ||
| cache_->last_timestep = global_param->timestep_counter; | ||
| } | ||
| } | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| bool data_base<CacheType>::is_stale() | ||
| { | ||
| return cache_->last_timestep != global_param->timestep_counter; | ||
| } | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| data_base<CacheType>::data_base(const mesh_elem& face_in, const boost::shared_ptr<global> param, | ||
| const pt::ptree& cfg) : face(face_in), global_param(param), cfg_(cfg) | ||
| { | ||
| if (!face->is_valid()) | ||
| throw std::invalid_argument("Face handle points to an invalid face"); | ||
|
|
||
| if (!global_param) | ||
| throw std::invalid_argument("global parameter holder is null"); | ||
| }; | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| data_base<CacheType>::data_base(const mesh_elem& face_in, const boost::shared_ptr<global> param, | ||
| const pt::ptree& cfg, const bool istest) : face(face_in), global_param(param), cfg_(cfg) | ||
| { | ||
| if (!istest) | ||
| std::invalid_argument("data_base test constructor called with False istest flag. Should be true."); | ||
| }; | ||
| template<data_base_concepts::CacheRules CacheType> | ||
| template<data_base_concepts::ValueRules Value,typename Fetch> | ||
| void data_base<CacheType>::update_value(Value&& value, const Fetch& fetch) { | ||
| init_cache(); | ||
|
|
||
| auto& V = value(); | ||
| if ( is_unset(V) ) | ||
| { | ||
| V = fetch(); | ||
| } | ||
|
|
||
| }; | ||
|
|
||
| template<data_base_concepts::CacheRules CacheType> | ||
| template<typename T,data_base_concepts::OutputRules<T> Output> | ||
| void data_base<CacheType>::set_output(Output&& output,const T t) | ||
| { | ||
| init_cache(); | ||
|
|
||
| output() += t; | ||
| }; | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.