Skip to content

Commit a1046bd

Browse files
mrp089EmmaJVEncdorn
authored
Spherical ventricle block (#176)
Co-authored-by: Emma Van Epps <[email protected]> Co-authored-by: ncdorn <[email protected]>
1 parent 4cc4e5b commit a1046bd

22 files changed

+834
-11
lines changed

.github/workflows/codechecks.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@ name: Codechecks
33
on: [push, pull_request]
44
jobs:
55
clang-format:
6-
runs-on: ubuntu-latest
6+
runs-on: macos-latest
77
steps:
88
- uses: actions/checkout@v3
99
- name: Install dependencies
1010
run: |
11-
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
12-
sudo apt-get install clang-format-19
11+
brew install clang-format
1312
- name: Run clang-format
1413
run: |
1514
mkdir Release

docs/pages/add_block.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
[TOC]
44

5-
Below are details on the steps required to implement a new block in svZeroDSolver.
5+
Below are details on the steps required to implement a new block in svZeroDSolver. To help with defining the block matrices, you can use the [Jacobian Generator](@ref jacobian).
66

77
*Note: The best way to implement a new block is to look at examples of existing block classes. See the `ValveTanh` class for an example.*
88

@@ -68,6 +68,8 @@ Below are details on the steps required to implement a new block in svZeroDSolve
6868

6969
## 3. Set up the governing equations for the block.
7070

71+
Use the [Jacobian Generator](@ref jacobian) to calculate matrix contributions symbolically.
72+
7173
### State vector
7274

7375
* The local state vector for each block is always arranged as `y = [P_in, Q_in, P_out, Q_out, InternalVariable_1, ..., InternalVariable_N]`.
@@ -111,7 +113,7 @@ Below are details on the steps required to implement a new block in svZeroDSolve
111113

112114
## 4. Implement the matrix equations for the block.
113115

114-
* Implement the `update_constant`, `update_time` and `update_solution` functions.
116+
* Implement the `update_constant`, `update_time` and `update_solution` functions (which can be output by the [Jacobian Generator](@ref jacobian)).
115117
* All matrix elements that are constant must be specified in `update_constant`.
116118
* Matrix elements that depend only on time (not the state variables) must be specified in `update_time`.
117119
* Matrix elements that change with the solution (i.e. depend on the state variables themselves) must be specified in `update_solution`.

docs/pages/jacobian.md

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
@page jacobian Jacobian Generator for svZeroDSolver
2+
3+
This tool generates C++ code for block implementations in the svZeroDSolver framework using symbolic mathematics.
4+
5+
## Overview
6+
7+
The script `script/jacobian.py` reads block definitions from YAML files and generates C++ code for implementing the mathematical models in the solver. It uses symbolic differentiation (via SymPy) to automatically derive the necessary Jacobian matrices and system contributions.
8+
9+
## Usage
10+
11+
```bash
12+
python jacobian.py <yaml_file>
13+
```
14+
15+
## YAML File Format
16+
17+
The YAML files define the mathematical model of a block with the following structure:
18+
19+
### Required Sections
20+
21+
- `variables`: List of variable names in the model
22+
- `derivatives`: List of derivative names (must match variables with `_dt` suffix)
23+
- `constants`: List of parameter names
24+
- `residuals`: List of residual equations that define the system
25+
26+
### Optional Sections
27+
28+
- `time_dependent`: List of parameters that depend on time (e.g., activation functions)
29+
- `helper_functions`: Python code defining helper functions used in the residuals
30+
31+
### Example
32+
33+
```yaml
34+
variables:
35+
- Pin
36+
- Qin
37+
- Pout
38+
- Qout
39+
40+
derivatives:
41+
- dPin_dt
42+
- dQin_dt
43+
- dPout_dt
44+
- dQout_dt
45+
46+
constants:
47+
- R
48+
- C
49+
- L
50+
- S
51+
52+
residuals:
53+
- Pin - Pout - (R + S * abs(Qin)) * Qin - L * dQout_dt
54+
- Qin - Qout - C * dPin_dt + C * (R + 2 * S * abs(Qin)) * dQin_dt
55+
```
56+
57+
## Output
58+
59+
The script generates three C++ function implementations:
60+
61+
1. `update_constant` - Sets up constant matrix coefficients for the system
62+
2. `update_time` - Updates time-dependent parameters
63+
3. `update_solution` - Computes solution-dependent terms and Jacobians
64+
65+
## Workflow
66+
67+
1. Create a YAML file defining your block's mathematical model
68+
2. Run `jacobian.py` on this file to generate C++ code
69+
3. Copy the generated code to your block implementation file
70+
4. Complete the implementation with necessary boilerplate code
71+
72+
## Tips
73+
74+
- Ensure the number of variables equals the number of derivatives
75+
- The number of residuals should be equal to the number of variables minus 2
76+
- Use helper functions for complex expressions to improve readability
77+
- Define time-dependent constants separately
78+
79+
## Examples
80+
81+
See the provided YAML examples:
82+
- `ChamberSphere.yaml` - Spherical heart chamber model
83+
- `BloodVessel.yaml` - Blood vessel model with optional stenosis
84+
- `ClosedLoopCoronaryBC.yaml` - Coronary boundary condition model

docs/references.bib

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,17 @@ @article{kerckhoffs2007coupling
111111
year={2007},
112112
publisher={Springer}
113113
}
114+
115+
@article{caruel13,
116+
author = {M. Caruel and R. Chabiniok and P. Moireau and Y. Lecarpentier and D. Chapelle},
117+
doi = {10.1007/s10237-013-0544-6},
118+
journal = {Biomechanics and Modeling in Mechanobiology},
119+
month = {dec},
120+
number = {4},
121+
pages = {897--914},
122+
publisher = {Springer Science and Business Media {LLC}},
123+
timestamp = {2022-02-28},
124+
title = {Dimensional reductions of a cardiac model for effective validation and calibration},
125+
volume = {13},
126+
year = {2013}
127+
}

scripts/BloodVessel.yaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
variables:
2+
- Pin
3+
- Qin
4+
- Pout
5+
- Qout
6+
7+
derivatives:
8+
- dPin_dt
9+
- dQin_dt
10+
- dPout_dt
11+
- dQout_dt
12+
13+
constants:
14+
- R
15+
- C
16+
- L
17+
- S
18+
19+
residuals:
20+
- Pin - Pout - (R + S * abs(Qin)) * Qin - L * dQout_dt
21+
- Qin - Qout - C * dPin_dt + C * (R + 2 * S * abs(Qin)) * dQin_dt

scripts/ChamberSphere.yaml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
variables:
2+
- Pin
3+
- Qin
4+
- Pout
5+
- Qout
6+
- radius
7+
- velo
8+
- stress
9+
- tau
10+
- volume
11+
12+
derivatives:
13+
- dPin_dt
14+
- dQin_dt
15+
- dPout_dt
16+
- dQout_dt
17+
- dradius_dt
18+
- dvelo_dt
19+
- dstress_dt
20+
- dtau_dt
21+
- dvolume_dt
22+
23+
constants:
24+
- rho
25+
- thick0
26+
- radius0
27+
- W1
28+
- W2
29+
- eta
30+
- act
31+
- act_plus
32+
- sigma_max
33+
34+
time_dependent:
35+
- act
36+
- act_plus
37+
38+
helper_functions: |
39+
def CG(radius):
40+
return (1 + (radius / radius0)) ** 2
41+
42+
def dCG(radius, dradius_dt):
43+
return 2 * (1 + (radius / radius0)) * (1 / radius0) * dradius_dt
44+
45+
residuals:
46+
- rho * thick0 * dvelo_dt + (thick0 / radius0) * (1 + (radius / radius0)) * stress - Pout * CG(radius)
47+
- -stress + tau + 4 * (1 - CG(radius) ** -3) * (W1 + CG(radius) * W2) + 2 * eta * dCG(radius, dradius_dt) * (1 - 2 * CG(radius) ** -6)
48+
- 4 * pi * radius0 ** 2 * CG(radius) * velo - dvolume_dt
49+
- dtau_dt + act * tau - sigma_max * act_plus
50+
- dradius_dt - velo
51+
- Qin - Qout - dvolume_dt
52+
- Pin - Pout

scripts/ClosedLoopCoronaryBC.yaml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
variables:
2+
- Pin
3+
- Qin
4+
- Pout
5+
- Qout
6+
- Vim
7+
- Pa
8+
9+
derivatives:
10+
- dPin_dt
11+
- dQin_dt
12+
- dPout_dt
13+
- dQout_dt
14+
- dVim_dt
15+
- dPa_dt
16+
17+
constants:
18+
- Ra
19+
- Ram
20+
- Rv
21+
- Ca
22+
- Cim
23+
- Pim
24+
25+
time_dependent:
26+
- Pim
27+
28+
residuals:
29+
- Pout - Pin + (Ram + Ra) * Qin + Rv * Qout + Ram * Ca * dPa_dt - Ram * Ca * dPin_dt + Ram * Ra * Ca * dQin_dt
30+
- Qin - Qout + Ca * dPa_dt - Ca * dPin_dt + Ca * Ra * dQin_dt - dVim_dt
31+
- Cim * Pout + Cim * Rv * Qout - Cim * Pim - Vim
32+
- Pa - Pin - Ra * Qin

scripts/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# svZeroDSolver scripts
2+
3+
The [Jacobian Generator](../docs/pages/jacobian.md) tool generates C++ code for new block implementations using symbolic math.

0 commit comments

Comments
 (0)