Skip to content

Commit b68ffd5

Browse files
Support string activation_function_type and nested activation_function_values in JSON
Co-authored-by: aabrown100-git <71424733+aabrown100-git@users.noreply.github.com>
1 parent 0b2ecf0 commit b68ffd5

4 files changed

Lines changed: 133 additions & 36 deletions

File tree

docs/pages/activation_functions.md

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ where `t_contract = max(0, t - t_active)`
3838
}
3939
```
4040

41+
Or with explicit activation function specification:
42+
```json
43+
{
44+
"type": "ChamberElastanceInductor",
45+
"name": "ventricle",
46+
"values": {
47+
"Emax": 1.057,
48+
"Emin": 0.091,
49+
"Vrd": 26.1,
50+
"Vrs": 18.0,
51+
"Impedance": 0.000351787,
52+
"activation_function_type": "half_cosine",
53+
"activation_function_values": {
54+
"t_active": 0.2,
55+
"t_twitch": 0.3
56+
}
57+
}
58+
}
59+
```
60+
4161
### 2. Piecewise Cosine Activation (Type 1)
4262

4363
The default activation function for `LinearElastanceChamber` (formerly `PiecewiseCosineChamber`). It models separate contraction and relaxation phases:
@@ -63,10 +83,13 @@ The default activation function for `LinearElastanceChamber` (formerly `Piecewis
6383
"Emax": 199.95,
6484
"Epass": 260.59,
6585
"Vrest": 26.24,
66-
"contract_start": 0.025,
67-
"relax_start": 0.08625,
68-
"contract_duration": 0.06125,
69-
"relax_duration": 0.18375
86+
"activation_function_type": "piecewise_cosine",
87+
"activation_function_values": {
88+
"contract_start": 0.025,
89+
"relax_start": 0.08625,
90+
"contract_duration": 0.06125,
91+
"relax_duration": 0.18375
92+
}
7093
}
7194
}
7295
```
@@ -107,23 +130,49 @@ C is a normalization constant ensuring maximum activation is 1.
107130
"Vrd": 26.1,
108131
"Vrs": 18.0,
109132
"Impedance": 0.000351787,
110-
"activation_type": 2,
111-
"t_shift": 0.15,
112-
"tau_1": 0.25,
113-
"tau_2": 0.35,
114-
"m1": 1.5,
115-
"m2": 10.0
133+
"activation_function_type": "two_hill",
134+
"activation_function_values": {
135+
"t_shift": 0.15,
136+
"tau_1": 0.25,
137+
"tau_2": 0.35,
138+
"m1": 1.5,
139+
"m2": 10.0
140+
}
116141
}
117142
}
118143
```
119144

120145
## Switching Between Activation Functions
121146

122-
To use a specific activation function, add the `activation_type` parameter to your chamber configuration:
147+
To use a specific activation function, add the `activation_function_type` parameter to your chamber configuration:
148+
149+
- `activation_function_type: "half_cosine"` - Half Cosine (default for ChamberElastanceInductor)
150+
- `activation_function_type: "piecewise_cosine"` - Piecewise Cosine (default for LinearElastanceChamber)
151+
- `activation_function_type: "two_hill"` - Two Hill
152+
153+
Group the activation function-specific parameters under `activation_function_values` as a nested dictionary.
154+
155+
## Backward Compatibility
156+
157+
For backward compatibility, the old flat format is also supported:
158+
159+
```json
160+
{
161+
"type": "ChamberElastanceInductor",
162+
"name": "ventricle",
163+
"values": {
164+
"Emax": 1.057,
165+
"Emin": 0.091,
166+
"Vrd": 26.1,
167+
"Vrs": 18.0,
168+
"t_active": 0.2,
169+
"t_twitch": 0.3,
170+
"Impedance": 0.000351787
171+
}
172+
}
173+
```
123174

124-
- `activation_type: 0` - Half Cosine (default for ChamberElastanceInductor)
125-
- `activation_type: 1` - Piecewise Cosine (default for LinearElastanceChamber)
126-
- `activation_type: 2` - Two Hill
175+
This format will continue to work, with the activation function determined by which parameters are provided.
127176

128177
## Elastance Calculation
129178

@@ -148,6 +197,7 @@ The two-hill activation function is described in:
148197
## Backward Compatibility
149198

150199
Existing configuration files will continue to work without modification:
151-
- `ChamberElastanceInductor` defaults to half cosine activation (type 0)
152-
- `LinearElastanceChamber` defaults to piecewise cosine activation (type 1)
153-
- `PiecewiseCosineChamber` is maintained as an alias to `LinearElastanceChamber` for backward compatibility
200+
- `ChamberElastanceInductor` defaults to half cosine activation when `t_active` and `t_twitch` are provided
201+
- `LinearElastanceChamber` defaults to piecewise cosine activation when contraction/relaxation parameters are provided
202+
- The old numeric `activation_type` parameter (0, 1, 2) is still supported but deprecated in favor of the string format
203+
- Parameters can be specified at the top level without using `activation_function_values` for backward compatibility

src/solve/SimulationParameters.cpp

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,7 +544,48 @@ void create_chambers(
544544
const auto& chamber_config = JsonWrapper(config, component, "name", i);
545545
std::string chamber_type = chamber_config["type"];
546546
std::string chamber_name = chamber_config["name"];
547-
generate_block(model, chamber_config["values"], chamber_type, chamber_name);
547+
548+
// Create a mutable copy of the values to handle activation function parameters
549+
nlohmann::json chamber_values = chamber_config["values"];
550+
551+
// Check if activation function type is specified as a string
552+
if (chamber_values.contains("activation_function_type") &&
553+
chamber_values["activation_function_type"].is_string()) {
554+
std::string act_type_str = chamber_values["activation_function_type"];
555+
556+
// Map string to numeric value
557+
int act_type_num = 0; // Default to half_cosine
558+
if (act_type_str == "half_cosine") {
559+
act_type_num = 0;
560+
} else if (act_type_str == "piecewise_cosine") {
561+
act_type_num = 1;
562+
} else if (act_type_str == "two_hill") {
563+
act_type_num = 2;
564+
} else {
565+
throw std::runtime_error("Unknown activation_function_type: " + act_type_str +
566+
" in chamber " + chamber_name);
567+
}
568+
569+
// Replace string with numeric value
570+
chamber_values["activation_type"] = act_type_num;
571+
chamber_values.erase("activation_function_type");
572+
}
573+
574+
// Check if activation function values are specified in nested dict
575+
if (chamber_values.contains("activation_function_values") &&
576+
chamber_values["activation_function_values"].is_object()) {
577+
const auto& act_values = chamber_values["activation_function_values"];
578+
579+
// Flatten the nested dictionary - move all parameters to top level
580+
for (auto& [key, value] : act_values.items()) {
581+
chamber_values[key] = value;
582+
}
583+
584+
// Remove the nested dict
585+
chamber_values.erase("activation_function_values");
586+
}
587+
588+
generate_block(model, chamber_values, chamber_type, chamber_name);
548589
DEBUG_MSG("Created chamber " << chamber_name);
549590
}
550591
}

tests/cases/chamber_two_hill_activation.json

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@
102102
"Vrd": 26.1,
103103
"Vrs": 18.0,
104104
"Impedance": 0.000351787,
105-
"activation_type": 2,
106-
"t_shift": 0.15,
107-
"tau_1": 0.25,
108-
"tau_2": 0.35,
109-
"m1": 1.5,
110-
"m2": 10.0
105+
"activation_function_type": "two_hill",
106+
"activation_function_values": {
107+
"t_shift": 0.15,
108+
"tau_1": 0.25,
109+
"tau_2": 0.35,
110+
"m1": 1.5,
111+
"m2": 10.0
112+
}
111113
}
112114
}
113115
],

tests/cases/linear_chamber_two_hill_activation.json

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,14 @@
7070
"Emax": 199.95,
7171
"Epass": 89.80375933024839,
7272
"Vrest": 41.680015938842274,
73-
"activation_type": 2,
74-
"t_shift": 0.025,
75-
"tau_1": 0.06,
76-
"tau_2": 0.15,
77-
"m1": 2.0,
78-
"m2": 8.0
73+
"activation_function_type": "two_hill",
74+
"activation_function_values": {
75+
"t_shift": 0.025,
76+
"tau_1": 0.06,
77+
"tau_2": 0.15,
78+
"m1": 2.0,
79+
"m2": 8.0
80+
}
7981
}
8082
},
8183
{
@@ -85,12 +87,14 @@
8587
"Emax": 1662.0158240056528,
8688
"Epass": 40.85565535747109,
8789
"Vrest": 72.05452710344869,
88-
"activation_type": 2,
89-
"t_shift": 0.207,
90-
"tau_1": 0.08,
91-
"tau_2": 0.22,
92-
"m1": 2.5,
93-
"m2": 12.0
90+
"activation_function_type": "two_hill",
91+
"activation_function_values": {
92+
"t_shift": 0.207,
93+
"tau_1": 0.08,
94+
"tau_2": 0.22,
95+
"m1": 2.5,
96+
"m2": 12.0
97+
}
9498
}
9599
}
96100
],

0 commit comments

Comments
 (0)