svZeroDSolver
Loading...
Searching...
No Matches
ActivationFunction.h
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) Stanford University, The Regents of the
2// University of California, and others. SPDX-License-Identifier: BSD-3-Clause
3
4/**
5 * @file ActivationFunction.h
6 * @brief Activation function classes for cardiac chamber models
7 */
8
9#ifndef SVZERODSOLVER_MODEL_ACTIVATIONFUNCTION_HPP_
10#define SVZERODSOLVER_MODEL_ACTIVATIONFUNCTION_HPP_
11
12#include <map>
13#include <memory>
14#include <string>
15#include <vector>
16
17#include "Parameter.h"
18
19/**
20 * @brief Base class for activation functions
21 *
22 * Activation functions compute the activation value (between 0 and 1) at a
23 * given time point within a cardiac cycle. These are used to modulate
24 * chamber elastance over time.
25 */
27 public:
28 /**
29 * @brief Properties of the input parameters for this activation function
30 * [(name, InputParameter), ...]
31 */
32 const std::vector<std::pair<std::string, InputParameter>>
34
35 /**
36 * @brief Construct activation function
37 *
38 * @param cardiac_period Cardiac cycle period
39 * @param input_param_properties Properties of the input parameters
40 * [(name, InputParameter), ...] for this activation function
41 */
42 ActivationFunction(double cardiac_period,
43 const std::vector<std::pair<std::string, InputParameter>>&
45
46 /**
47 * @brief Virtual destructor
48 */
49 virtual ~ActivationFunction() = default;
50
51 /**
52 * @brief Compute activation value at given time
53 *
54 * @param time Current time
55 * @return Activation value between 0 and 1
56 */
57 virtual double compute(double time) = 0;
58
59 /**
60 * @brief Create a default activation function from activation function type
61 *
62 * @param type_str One of: "half_cosine", "piecewise_cosine", "two_hill",
63 * "double_tanh", "wrapping_cosine", "fourier"
64 * @param cardiac_period Cardiac cycle period
65 * @return Unique pointer to the created activation function
66 */
67 static std::unique_ptr<ActivationFunction> create_default(
68 const std::string& type_str, double cardiac_period);
69
70 /**
71 * @brief Set a scalar parameter value by name.
72 *
73 * Calling function must validate the parameter name and value
74 *
75 * @param name Parameter name
76 * @param value Parameter value
77 */
78 void set_param(const std::string& name, double value);
79
80 /**
81 * @brief Called after all parameters are set (e.g. by loader).
82 *
83 * Default no-op. TwoHillActivation overrides to recompute normalization.
84 */
85 virtual void finalize() {}
86
87 protected:
88 /**
89 * @brief Time duration of one cardiac cycle
90 */
92
93 /**
94 * @brief Map of parameter names to their values
95 */
96 std::map<std::string, double> params_;
97};
98
99/**
100 * @brief Half cosine activation function
101 *
102 * This implements the activation function used in the original
103 * ChamberElastanceInductor. The activation follows a half cosine wave
104 * during the contraction period.
105 *
106 * \f[
107 * A(t) = \begin{cases}
108 * -\frac{1}{2}\cos(2\pi t_{contract}/t_{twitch}) + \frac{1}{2}, & \text{if }
109 * t_{contract} \le t_{twitch} \\ 0, & \text{otherwise}
110 * \end{cases}
111 * \f]
112 *
113 * where \f$t_{contract} = \max(0, t_{in\_cycle} - t_{active})\f$
114 */
116 public:
117 /**
118 * @brief Construct with default parameter values (loader fills via
119 * set_param).
120 *
121 * @param cardiac_period Cardiac cycle period
122 */
123 explicit HalfCosineActivation(double cardiac_period)
124 : ActivationFunction(cardiac_period, {{"t_active", InputParameter()},
125 {"t_twitch", InputParameter()}}) {}
126
127 double compute(double time) override;
128};
129
130/**
131 * @brief Piecewise cosine activation function
132 *
133 * This implements the activation function from the LinearElastanceChamber
134 * (Regazzoni chamber model). The activation consists of separate contraction
135 * and relaxation phases, each following a cosine curve.
136 *
137 * \f[
138 * \phi(t, t_C, t_R, T_C, T_R) = \begin{cases}
139 * \frac{1}{2}\left[1 - \cos\left(\frac{\pi}{T_C} \bmod(t - t_C,
140 * T_{HB})\right)\right],
141 * & \text{if } 0 \le \bmod(t - t_C, T_{HB}) < T_C \\
142 * \frac{1}{2}\left[1 + \cos\left(\frac{\pi}{T_R} \bmod(t - t_R,
143 * T_{HB})\right)\right],
144 * & \text{if } 0 \le \bmod(t - t_R, T_{HB}) < T_R \\
145 * 0, & \text{otherwise}
146 * \end{cases}
147 * \f]
148 */
150 public:
151 /**
152 * @brief Construct with default parameter values (loader fills via
153 * set_param).
154 *
155 * @param cardiac_period Cardiac cycle period
156 */
157 explicit PiecewiseCosineActivation(double cardiac_period)
158 : ActivationFunction(cardiac_period,
159 {{"contract_start", InputParameter()},
160 {"relax_start", InputParameter()},
161 {"contract_duration", InputParameter()},
162 {"relax_duration", InputParameter()}}) {}
163
164 double compute(double time) override;
165};
166
167/**
168 * @brief Two hill activation function
169 *
170 * This implements the two-hill activation function which provides more
171 * flexible and physiologically realistic waveforms. See
172 * https://link.springer.com/article/10.1007/s10439-022-03047-3
173 *
174 * The activation is computed as:
175 * \f[
176 * A(t) = C \cdot \frac{g_1(t)}{1 + g_1(t)} \cdot \frac{1}{1 + g_2(t)}
177 * \f]
178 *
179 * where:
180 * \f[
181 * g_1(t) = \left(\frac{t_{shifted}}{\tau_1}\right)^{m_1}, \quad
182 * g_2(t) = \left(\frac{t_{shifted}}{\tau_2}\right)^{m_2}
183 * \f]
184 *
185 * and \f$t_{shifted} = (t - t_{shift}) \bmod T_{cardiac}\f$, and \f$C\f$ is a
186 * normalization constant to ensure max activation is 1.
187 */
189 public:
190 /**
191 * @brief Construct with default parameter values (loader fills via
192 * set_param).
193 *
194 * @param cardiac_period Cardiac cycle period
195 */
196 explicit TwoHillActivation(double cardiac_period)
197 : ActivationFunction(cardiac_period, {{"t_shift", InputParameter()},
198 {"tau_1", InputParameter()},
199 {"tau_2", InputParameter()},
200 {"m1", InputParameter()},
201 {"m2", InputParameter()}}),
202 normalization_factor_(1.0),
203 normalization_initialized_(false) {}
204
205 double compute(double time) override;
206
207 void finalize() override;
208
209 private:
210 void calculate_normalization_factor();
211
212 double normalization_factor_;
213 bool normalization_initialized_;
214};
215
216/**
217 * @brief Double tanh (systole/diastole sigmoid product) activation function
218 *
219 * This implements the original ChamberSphere activation: a smooth indicator
220 * function built from the product of two tanh sigmoids, one rising at
221 * systole and one falling at diastole.
222 *
223 * \f[
224 * f(t) = S_+ (t_{in\_cycle} - t_sys) \cdot S_- (t_{in\_cycle} - t_dias), \quad S_\pm (\Delta t) = \frac{1}{2} \left(1.0 \pm
225 * \text{tanh}\left( \frac{\Delta t} {\gamma}
226 * \right) \right)
227 * \f]
228 */
230 public:
231 /**
232 * @brief Construct with default parameter values (loader fills via
233 * set_param).
234 *
235 * @param cardiac_period Cardiac cycle period
236 */
237 explicit DoubleTanhActivation(double cardiac_period)
238 : ActivationFunction(cardiac_period, {{"tsys", InputParameter()},
239 {"tdias", InputParameter()},
240 {"steepness", InputParameter()}}) {}
241
242 double compute(double time) override;
243};
244
245/**
246 * @brief Wrapping cosine activation function
247 *
248 * Reproduces the atrial activation AA(t) from \cite sankaran2012patient
249 * and \cite menon2023predictors. The cosine wraps across the cardiac
250 * cycle boundary, which half_cosine and piecewise_cosine cannot do.
251 *
252 * Parameters:
253 * * `Tsa` — Atrial systole time fraction (multiplied by cardiac period)
254 * * `tpwave` — P-wave divisor (cardiac period is divided by this)
255 */
257 public:
258 /**
259 * @brief Construct a new WrappingCosineActivation object
260 *
261 * @param cardiac_period Cardiac cycle period
262 */
263 explicit WrappingCosineActivation(double cardiac_period)
264 : ActivationFunction(cardiac_period, {{"Tsa", InputParameter()},
265 {"tpwave", InputParameter()}}) {}
266
267 double compute(double time) override;
268};
269
270/**
271 * @brief Fourier series activation function
272 *
273 * 25-mode Fourier series for ventricular elastance activation, based on
274 * J. Tran's tuning framework (\cite menon2023predictors). The series is
275 * normalized so the output ranges from 0 (diastole) to 1 (peak systole).
276 * No user parameters are needed; the Fourier coefficients are hardcoded.
277 *
278 * Combined with ChamberElastanceInductor using
279 * Emax = Fourier_peak * E_scale, Emin = Fourier_trough * E_scale
280 * this reproduces E(t) = Fourier(t) * E_scale exactly.
281 */
283 public:
284 /**
285 * @brief Construct a new FourierActivation object
286 *
287 * @param cardiac_period Cardiac cycle period
288 */
289 explicit FourierActivation(double cardiac_period)
290 : ActivationFunction(cardiac_period, {}),
291 norm_min_(0.0),
292 norm_range_(1.0),
293 normalization_initialized_(false) {}
294
295 double compute(double time) override;
296 void finalize() override;
297
298 private:
299 void calculate_normalization();
300 double compute_raw(double t_in_cycle) const;
301
302 double norm_min_;
303 double norm_range_;
304 bool normalization_initialized_;
305};
306
307#endif // SVZERODSOLVER_MODEL_ACTIVATIONFUNCTION_HPP_
model::Parameter source file
static std::unique_ptr< ActivationFunction > create_default(const std::string &type_str, double cardiac_period)
Create a default activation function from activation function type.
Definition ActivationFunction.cpp:33
double cardiac_period_
Time duration of one cardiac cycle.
Definition ActivationFunction.h:91
virtual double compute(double time)=0
Compute activation value at given time.
virtual ~ActivationFunction()=default
Virtual destructor.
void set_param(const std::string &name, double value)
Set a scalar parameter value by name.
Definition ActivationFunction.cpp:29
ActivationFunction(double cardiac_period, const std::vector< std::pair< std::string, InputParameter > > &input_param_properties)
Construct activation function.
Definition ActivationFunction.cpp:14
const std::vector< std::pair< std::string, InputParameter > > input_param_properties
Properties of the input parameters for this activation function [(name, InputParameter),...
Definition ActivationFunction.h:33
std::map< std::string, double > params_
Map of parameter names to their values.
Definition ActivationFunction.h:96
virtual void finalize()
Called after all parameters are set (e.g. by loader).
Definition ActivationFunction.h:85
DoubleTanhActivation(double cardiac_period)
Construct with default parameter values (loader fills via set_param).
Definition ActivationFunction.h:237
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:162
FourierActivation(double cardiac_period)
Construct a new FourierActivation object.
Definition ActivationFunction.h:289
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:246
void finalize() override
Called after all parameters are set (e.g. by loader).
Definition ActivationFunction.cpp:244
HalfCosineActivation(double cardiac_period)
Construct with default parameter values (loader fills via set_param).
Definition ActivationFunction.h:123
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:59
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:77
PiecewiseCosineActivation(double cardiac_period)
Construct with default parameter values (loader fills via set_param).
Definition ActivationFunction.h:157
TwoHillActivation(double cardiac_period)
Construct with default parameter values (loader fills via set_param).
Definition ActivationFunction.h:196
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:140
void finalize() override
Called after all parameters are set (e.g. by loader).
Definition ActivationFunction.cpp:138
WrappingCosineActivation(double cardiac_period)
Construct a new WrappingCosineActivation object.
Definition ActivationFunction.h:263
double compute(double time) override
Compute activation value at given time.
Definition ActivationFunction.cpp:181
Handles the properties of input parameters.
Definition Parameter.h:100