From 2b7b80d3cba3e714097143020ef278af74541227 Mon Sep 17 00:00:00 2001 From: Karthik Menon <40070586+menon-karthik@users.noreply.github.com> Date: Tue, 9 Jul 2024 18:18:20 -0700 Subject: [PATCH] Upgrading macOS in Github Actions (#116) --- .github/workflows/test.yml | 5 +- docs/Doxyfile | 1 + docs/pages/add_block.md | 158 +++++++++++++++++++++++++++++++++ docs/pages/developer_guide.md | 44 ++++++--- docs/pages/main.md | 137 ++++++++++++++++++++-------- src/model/OpenLoopCoronaryBC.h | 2 +- 6 files changed, 292 insertions(+), 55 deletions(-) create mode 100644 docs/pages/add_block.md diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e26b9ae73..2780c2b79 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -7,10 +7,13 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12] + os: [ubuntu-22.04, ubuntu-latest, macos-13, macos-latest] fail-fast: false steps: - uses: actions/checkout@v4 + - uses: conda-incubator/setup-miniconda@v3 + with: + auto-update-conda: true - name: Install ubuntu dependencies if: startsWith(matrix.os, 'ubuntu') run: sudo apt update && sudo apt install build-essential cmake lcov diff --git a/docs/Doxyfile b/docs/Doxyfile index f1cf2e449..59fff9b0a 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -225,6 +225,7 @@ USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_BIB_STYLE = plain +FORMULA_FONTSIZE = 15 #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- diff --git a/docs/pages/add_block.md b/docs/pages/add_block.md new file mode 100644 index 000000000..cf6d4ca26 --- /dev/null +++ b/docs/pages/add_block.md @@ -0,0 +1,158 @@ +@page add_block Adding New Blocks + +[TOC] + +Below are details on the steps required to implement a new block in svZeroDSolver. + +*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.* + +## 1. Name the new block. + +* The name should then be added to the following lists/dictionaries: + * `BlockType` in src/model/BlockType.h + * `block_factory_map` in src/model/Model.cpp + * *Note: In `block_factory_map`, the dictionary key should match the string specifying the type of block in the `.json` configuration/input file, and the dictionary value should match the class constructor name for the block.* + * If the new block requires special handling that is different from the current blocks (most new blocks do not), add a new category to `BlockClass` in src/model/BlockType.h + +


+ +## 2. Create a class for the new block. + +### Class constructor + +* The new class will be inherited from `Block`. Define a constructor of the form: +``` + MyNewBlock(int id, Model *model) + : Block(id, model, BlockType::block_type, BlockClass::block_class, + {{Param_1, InputParameter()}, + {Param_2, InputParameter()}, + ..., + {Param_N, InputParameter()}}) {} +``` + * `MyNewBlock` is the name of the new class + * `block_type` and `block_class` are the same as what was added in Step 1 above. + * The names of the input parameters of the block are `Param_1`, ... , `Param_N`. + * The properties of each parameter are defined by `InputParameter`, which specifies whether it is optional, an array, a scalar, a function, and its default value. + * The names `Param_1`, ... , `Param_N` must be the same as the parameter names within the block definition in the `.json` configuration/input file. + +


+ +### Set up the degrees of freedom +* The class must have a `setup_dofs(DOFHandler &dofhandler)` function. + * This function typically only includes a call to the following function: + ``` + Block::setup_dofs_(DOFHandler &dofhandler, int num_equations, const std::list &internal_var_names) + ``` + * In the above function, `num_equations` is the number of governing equations for the new block. + * `internal_var_names` is a list of strings that specify names for variables that are internal to the block, i.e. all variables for the block apart from the flow and pressure at the block's inlets and outlets. + +


+ +### Other class members + +* The class should have a `TripletsContributions num_triplets{*, *, *}` object. + * This specifies how many elements the governing equations of the block contribute to the global `F`, `E` and `dC_dy` matrices respectively. + * Details are in Step 3 below. + +


+ +* The class should have an `update_constant` function and may also contain `update_time` and `update_solution` functions. These functions implement the governing equations for the block. Details are in Steps 3-4 below. + +


+ +* *Optional:* The class can have an `enum ParamId` object that relates the parameter indices to their names. + * This makes it easier to reference the parameters while implementing the governing equations of the block (discussed below). + * The order of parameters in the `ParamId` object should match the order in the constructor. + +


+ +## 3. Set up the governing equations for the block. + +### State vector + +* The local state vector for each block is always arranged as `y = [P_in, Q_in, P_out, Q_out, InternalVariable_1, ..., InternalVariable_N]`. + * Here, `InternalVariable*` refers to any variable in the governing equations that are not the inlet and outlet flow and pressure. These are the same as those discussed above in the function `setup_dofs`. + * The corresponding time-derivative of this state vector is `ydot = dP_in/dt, dQ_in/dt, ...]`. + * *Note: The length of the state vector is typically four (inlet and outlet pressure and flow) plus the number of internal variables.* + +


+ +### Governing equations + +* The equations should be written in the form `E(t)*ydot + F(t)*y + C(y,ydot,t) = 0`. + * `y` is the local state vector mentioned above. + * `ydot` is the time-derivative of the local state vector. + * `E` and `F` are matrices of size `number_of_equations*size_of_state_vector`. + * `C` is a vector of length `number_of_equations`. + * `E` and `F` contain terms of the governing equation that multiply the respective components of `ydot` and `y` respectively. + * `C` contains all non-linear and constant terms in the equation. + * If the equation contains non-linear terms, the developer should also write out the derivative of `C` with respect to `y` and `ydot`. These will be stored in the block's `dC_dy` and `dC_dydot` matrices, both of which are size `number_of_equations*size_of_state_vector`. + +


+ +### An example + +* Assume a block has the following non-linear governing equations: + +\f$ a \frac{dQ_{in}}{dt} + b P_{in} + c \frac{dP_{in}}{dt} Q_{in} + d = 0 \f$ + +\f$ e \frac{dP_{out}}{dt} + f Q_{out} Q_{out} + g P_{out} + h I_{1} = 0 \f$ + + * For this block, \f$P_{in}\f$ and \f$Q_{in}\f$ are the pressure and flow at the inlet respectively, \f$P_{out}\f$ and \f$Q_{out}\f$ are the pressure and flow at the outlet, and \f$I_{1}\f$ is an internal variable. + * The state vector is \f$[P_{in}, Q_{in}, P_{out}, Q_{out}, I_{1}]\f$. + * The contributions to the local `F` matrix are `F[0,0] = b`, `F[1,2] = g` and `F[1,4] = h`. + * The contributions to the local `E` matrix are `E[0,1] = a` and `E[1,2] = e`. + * The contributions to the local `C` vector are `C[0] = c*(dP_in/dt)*Q_in + d` and `C[1] = f*Q_out*Q_out`. + * The contributions to the local `dC_dy` matrix are `dC_dy[0,1] = c*(dP_in/dt)` and `dC_dy[1,3] = 2*f*Q_out`. + * The contributions to the local `dC_dydot` matrix are `dC_dydot[0,0] = c*Q_in`. + * In this case, the block has 3 contributions to `F`, 2 contributions to `E`, and 2 constributions to `dC_dy`. So the class will have a member `TripletsContributions num_triplets{3, 2, 2}`. + +


+ +## 4. Implement the matrix equations for the block. + +* Implement the `update_constant`, `update_time` and `update_solution` functions. + * All matrix elements that are constant must be specified in `update_constant`. + * Matrix elements that depend only on time (not the state variables) must be specified in `update_time`. + * Matrix elements that change with the solution (i.e. depend on the state variables themselves) must be specified in `update_solution`. + * *Note: Not all blocks will require the `update_time` and `update_solution` functions.* + +


+ +### Implementation details + +* The elements of the matrices `E`, `F`, `dC_dy` and `dC_dydot` are populated using the following syntax: +``` +system.F.coeffRef(global_eqn_ids[current_block_equation_id], global_var_ids[current_block_variable_ids]) = a +``` + * Here, `current_block_equation_id` goes from 0 to `number_of_equations-1` (for the current block) and `current_block_variable_ids` goes from 0 to `size_of_state_vector-1` for the current block. + +


+ +* If the governing equations contain non-linear terms, these terms must be specified in `update_solution` as: +``` +system.C(global_eqn_ids[current_block_equation_id]) = non_linear_term +``` + +


+ +* For non-linear equations, the derivative of the terms in `C` with respect to each state variable `y` and `ydot` must also be provided. These go into `dC_dy` and `dC_dydot` matrices. + * A `dC_dy` matrix contribution can be specified using the following syntax: +``` +system.dC_dy.coeffRef(global_eqn_ids[current_block_equation_id], global_var_ids[current_block_variable_id]) = a +``` + * Here, `a` is the derivative of the non-linear term in the equation with ID `current_block_equation_id` with respect to the local state variable with ID `current_block_variable_id`. + * For example, if the non-linear term is in the first equation, then `current_block_equation_id = 0`. + * For the derivative of this term with respect to `P_in`, set `current_block_variable_id = 0`, and for the derivative of this term with respect to `P_out`, set `current_block_variable_id = 2`. + * The same indexing applies to derivatives with respect to the `ydot` state variables, i.e. for the derivative of the term with respect to `dP_in/dt`, set `current_block_variable_id = 0`. + +


+ +* *Note: Any matrix and vector components that are not specified are 0 by default.* + +


+ +## 4. Add the new block to the build system. + +* Add `MyNewBlock.h` and `MyNewBlock.cpp` to `src/model/CMakeLists.txt` + diff --git a/docs/pages/developer_guide.md b/docs/pages/developer_guide.md index 749367290..204f6ebe7 100644 --- a/docs/pages/developer_guide.md +++ b/docs/pages/developer_guide.md @@ -14,12 +14,8 @@ of svZeroDSolver, namely: * svZerodSolver in `svzerodsolver.cpp` * Python API in `pysvzerod.cpp` -The header-based library in the `src` folder contains classes and functions that are collectively used by -all applications. A good overview over the general architecture can be found in the -list of namespaces. - -## Build in debug mode +# Build in debug mode For debug purposes it is recommended to build svZeroDSolver in Debug mode. @@ -30,7 +26,7 @@ cmake -DCMAKE_BUILD_TYPE=Debug .. cmake --build . ``` -## Install with pip +# Install with pip Execute this command in the root folder to install the current source: ```bash @@ -38,7 +34,27 @@ pip install -e ".[dev]" ``` This is useful when continuously running the integration tests during development. -## Code Style +# Contributing to svZeroDSolver + +**NOTE: To contribute new developments to the main branch of svZeroDSolver, developers must first open an issue on the svZeroDSolver Github repository to describe the planned changes.** + +* The changes should be implemented in a feature branch of the developer's fork of svZeroDSolver. +* Once the changes are implemented, the developer should make sure the build, documentation, and code format tests are passing on the user's feature branch. + * The tests are automatically run when pushing changes to the developer's remote branch on Github. + * Alternatively, the developer can run the tests locally. + * The build tests can be run using the `pip` install and `pytest`. + * The tests for the C++ interface require the `CMake` install and can be run by building the tests in `svZeroDSolver/tests/test_interface`. + * Code formatting can be performed following the instructions in the Formatting section below. + * The documentation can be built following the instructions in the Documentation section below. +* Once all the tests are passing, the developer should open a pull request from the feature branch and link the relevant issue. + +# Adding new blocks + +The modular architecture of svZeroDSolver relies on "blocks", such as blood vessels, junctions, valves, boundary conditions, etc. These blocks are assembled in a manner specified by the `.json` configuration file, which dictates the assembled governing equations for the model. We are always interested in adding new blocks to expand the funcitonality of svZeroDSolver. + +Detailed steps required to implement a new block in svZeroDSolver are available [here](@ref add_block). + +# Code Style We follow the [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html). @@ -81,7 +97,7 @@ requirements. On Sherlock at Stanford, clang-format is included in the `llvm` module. -## Documentation +# Documentation We use [Doxygen](https://doxygen.nl) to automatically build an html documentation from source code. Please have at Doxygen's [Documentation Guide](https://www.doxygen.nl/manual/docblocks.html) @@ -95,7 +111,7 @@ and cannot be merged.** In the following you can find a short recap of the most important commands: -### Latex equations +## Latex equations For inline equations use `\f$a+b=c\f$` and for block equations use: ``` \f[ @@ -103,12 +119,12 @@ a+b=c \f] ``` -### Citations +## Citations If you want to cite a piece literature in your documentation, add -a respective BibTeX citation to `docs/cpp/references.bib` and use `\cite name_of_citation` to +a respective BibTeX citation to `docs/references.bib` and use `\cite name_of_citation` to cite the document. -### Drawing circuits +## Drawing circuits As the elements of the svZeroDSolver are often represented in the form of electrical circuits, we use [CircuiTikZ](https://ctan.org/pkg/circuitikz?lang=en) to draw circuits in the documentation (see blocks in Block for examples). @@ -121,7 +137,7 @@ To start a CircuitTikZ drawing use the following command: \f] ``` -### Build +## Build The documentation is automatically built in the GitHub CI/CD and published on GitHub pages. If you want to build the documentation locally, you can use: @@ -133,7 +149,7 @@ You can then view the documentation locally in your browser by opening `docs/bui If you do not have Doxygen install you can do that with `brew install doxygen` on macOS or with `sudo apt-get install doxygen` on Linux. -## Profiling +# Profiling Profiling helps to easily identify bottlenecks in the code. A profiling report lists the executation time spend on certain parts of the code. If you experience diff --git a/docs/pages/main.md b/docs/pages/main.md index 1268661f5..bbf71fbcc 100644 --- a/docs/pages/main.md +++ b/docs/pages/main.md @@ -26,7 +26,7 @@ time-dependent; they are unable to simulate spatial patterns in the hemodynamics. 0D models are analogous to electrical circuits. The flow rate simulated by 0D models represents electrical current, while the pressure represents voltage. Three primary building blocks of 0D models are resistors, -capacitors, and inductors Resistance captures the viscous effects of blood +capacitors, and inductors. Resistance captures the viscous effects of blood flow, capacitance represents the compliance and distensibility of the vessel wall, and inductance represents the inertia of the blood flow. Different combinations of these building blocks, as well as others, can be formed to @@ -34,19 +34,26 @@ reflect the hemodynamics and physiology of different cardiovascular anatomies. These 0D models are governed by differential algebraic equations (DAEs). -For more background information on 0D models, have a look at the detailed documentation: -- System of equations: SparseSystem -- Time integration: Integrator -- Overview of available 0D elements (blocks): Block +The main categories of blocks implemented in svZeroDSolver are: +- Blood vessels +- Junctions +- Boundary conditions +- Heart chambers +- Heart valves + +For an overview of available 0D elements (blocks) see: Block -You can find more details about governing equations in individual blocks, for example: +You can find more details about governing equations in individual blocks in their respective documentation pages. For example: - BloodVessel - BloodVesselJunction - WindkesselBC For implementation details, have a look at the [source code](https://github.com/simvascular/svZeroDSolver). +Mathematics details can be found in the following classes: +- System of equations: SparseSystem +- Time integration: Integrator -[About SimVascular](https://simvascular.github.io) +[More information about SimVascular](https://simvascular.github.io) # Installation @@ -93,7 +100,7 @@ cmake --build . If you are a developer and want to contribute to svZeroDSolver, you can find more helpful information in our [Developer Guide](@ref developer_guide). -# svZeroDSolver +# svZeroDSolver - Quick User Guide svZeroDSolver can be used to run zero-dimensional (0D) cardiovascular simulations based on a given configuration. @@ -107,7 +114,7 @@ file. svzerodsolver tests/cases/steadyFlow_RLC_R.json result_steadyFlow_RLC_R.csv ``` -The result will be written to a csv file. +The result will be written to a CSV file. ## Run svZeroDSolver from other programs @@ -221,7 +228,6 @@ There is also a function to retrieve the full result directly based on a given c ``` - ## Configuration svZeroDSolver is configured using either a JSON file or a Python @@ -246,23 +252,26 @@ The svZeroDSolver can be configured with the following options in the default value must be specified. -Parameter key | Description | Default value ---------------------------------------- | ----------------------------------------- | ----------- -number_of_cardiac_cycles | Number of cardiac cycles to simulate | - -number_of_time_pts_per_cardiac_cycle | Number of time steps per cardiac cycle | - -absolute_tolerance | Absolute tolerance for time integration | \f$10^{-8}\f$ -maximum_nonlinear_iterations | Maximum number of nonlinear iterations for time integration | \f$30\f$ -steady_initial | Toggle whether to use the steady solution as the initial condition for the simulation | true -output_variable_based | Output solution based on variables (i.e. flow+pressure at nodes and internal variables) | false -output_interval | The frequency of writing timesteps to the output (1 means every time step is written to output) | \f$1\f$ -output_mean_only | Write only the mean values over every timestep to output file | false -output_derivative | Write time derivatives to output file | false -output_all_cycles | Write all cardiac cycles to output file | false +Parameter key | Description | Default value +----------------------------------------- | ----------------------------------------- | ----------- +`number_of_cardiac_cycles` | Number of cardiac cycles to simulate | - +`number_of_time_pts_per_cardiac_cycle` | Number of time steps per cardiac cycle | - +`absolute_tolerance` | Absolute tolerance for time integration | \f$10^{-8}\f$ +`maximum_nonlinear_iterations` | Maximum number of nonlinear iterations for time integration | \f$30\f$ +`steady_initial` | Toggle whether to use the steady solution as the initial condition for the simulation | true +`output_variable_based` | Output solution based on variables (i.e. flow+pressure at nodes and internal variables) | false +`output_interval` | The frequency of writing timesteps to the output (1 means every time step is written to output) | \f$1\f$ +`output_mean_only` | Write only the mean values over every timestep to output file | false +`output_derivative` | Write time derivatives to output file | false +`output_all_cycles` | Write all cardiac cycles to output file | false +`use_cycle_to_cycle_error` | Use cycle-to-cycle error to determine number of cycles for convergence | false +`sim_cycle_to_cycle_percent_error` | Percentage error threshold for cycle-to-cycle pressure and flow difference | 1.0 +The option `use_cycle_to_cycle_error` allows the solver to change the number of cardiac cycles it runs depending on the cycle-to-cycle convergence of the simulation. For simulations with no RCR boundary conditions, the simulation will add extra cardiac cycles until the difference between the mean pressure and flow in consecutive cycles is below the threshold set by `sim_cycle_to_cycle_percent_error` at all inlets and outlets of the model. If there is at least one RCR boundary condition, the number of cycles is determined based on equation 21 of \cite pfaller21, using the RCR boundary condition with the largest time constant. ### Vessels -More information about the vessels can be found in their respective class references. +More information about the vessels can be found in their respective class references. Below is a template vessel block with boundary conditions, `INFLOW` and `OUT`, at its inlet and outlet respectively. ```python { @@ -277,14 +286,14 @@ More information about the vessels can be found in their respective class refere } ``` -Description | Class | `zero_d_element_type` | `zero_d_element_values` -------------------------------------- | --------------------------- | --------------------- | ------------------------ -Blood vessel with \n optional stenosis | MODEL::BloodVessel | `BloodVessel` | `C`: Capacity \n `L`: Inductance \n `R_poiseuille`: Poiseuille resistance \n `stenosis_coefficient`: Stenosis coefficient +Description | Class | `zero_d_element_type` | `zero_d_element_values` +---------------------------------------- | --------------------------- | --------------------- | ------------------------ +Blood vessel with \n optional stenosis | BloodVessel | `BloodVessel` | `C`: Capacity \n `L`: Inductance \n `R_poiseuille`: Poiseuille resistance \n `stenosis_coefficient`: Stenosis coefficient ### Junctions -More information about the junctions can be found in their respective class references. +More information about the junctions can be found in their respective class references. Below is a template junction block that connects vessel ID 0 with vessel IDs 1 and 2. ```python { @@ -296,14 +305,16 @@ More information about the junctions can be found in their respective class refe } ``` -Description | Class | `junction_type` | `junction_values` -------------------------------------- | --------------------------- | --------------------- | ----------- -Purely mass \n conserving \n junction | MODEL::Junction | `NORMAL_JUNCTION` | - -Resistive \n junction | MODEL::ResistiveJunction | `resistive_junction` | `R`: Ordered list of resistances for all inlets and outlets -Blood vessel \n junction | MODEL::BloodVesselJunction | `BloodVesselJunction` | Same as for `BloodVessel` element but \n as ordered list for each inlet and outlet +Description | Class | `junction_type` | `junction_values` +------------------------------------- | ---------------------| --------------------- | ----------- +Purely mass \n conserving \n junction | Junction | `NORMAL_JUNCTION` | - +Resistive \n junction | ResistiveJunction | `resistive_junction` | `R`: Ordered list of resistances for all inlets and outlets +Blood vessel \n junction | BloodVesselJunction | `BloodVesselJunction` | Same as for `BloodVessel` element but \n as ordered list for each inlet and outlet ### Boundary conditions +More information about the boundary conditions can be found in their respective class references. Below is a template `FLOW` boundary condition. + ```python { "bc_name": "INFLOW", # Name of the boundary condition @@ -312,15 +323,63 @@ Blood vessel \n junction | MODEL::BloodVesselJunction | `BloodVess }, ``` -Description | Class | `bc_type` | `bc_values` -------------------------------------- | --------------------------- | --------------------- | ----------- -Prescribed (transient) flow | MODEL::FlowReferenceBC | `FLOW` | `Q`: Time-dependent flow values \n `t`: Time stamps -Prescribed (transient) pressure | MODEL::PressureReferenceBC | `PRESSURE` | `P`: Time-dependent pressure values \n `t`: Time stamps -Resistance | MODEL::ResistanceBC | `RESISTANCE` | `R`: Resistance \n `Pd`: Time-dependent distal pressure \n `t`: Time stamps -Windkessel | MODEL::WindkesselBC | `RCR` | `Rp`: Proximal resistance \n `C`: Capacitance \n `Rd`: Distal resistance \n `Pd`: Distal pressure +Description | Class | `bc_type` | `bc_values` +------------------------------------- | ---------------------- | --------------------- | ----------- +Prescribed (transient) flow | FlowReferenceBC | `FLOW` | `Q`: Time-dependent flow values \n `t`: Time steps \n `fn`: Mathematical expression \n Note: Either specify `Q` and `t` together, or just `fn` +Prescribed (transient) pressure | PressureReferenceBC | `PRESSURE` | `P`: Time-dependent pressure values \n `t`: Time steps \n `fn`: Mathematical expression \n Note: Either specify `Q` and `t` together, or just `fn` +Resistance | ResistanceBC | `RESISTANCE` | `R`: Resistance \n `Pd`: Time-dependent distal pressure \n `t`: Time stamps +Windkessel | WindkesselBC | `RCR` | `Rp`: Proximal resistance \n `C`: Capacitance \n `Rd`: Distal resistance \n `Pd`: Distal pressure +Coronary outlet | OpenLoopCoronaryBC | `CORONARY` | `Ra`: Proximal resistance \n `Ram`: Microvascular resistance \n `Rv`: Venous resistance \n `Ca`: Small artery capacitance \n `Cim`: Intramyocardial capacitance \n `Pim`: Intramyocardial pressure \n `Pv`: Venous pressure + +The above table describes the most commonly used boundary conditions. In addition, svZeroDSolver includes various closed-loop boundary conditions. Examples can be found in `svZeroDSolver/tests/cases`. + +Note that the `FLOW` and `PRESSURE` boundary conditions accept mathematical expressions in `bc_values`. For example, values of the boundary condition can be specified as a function of time as follow: +```python +{ + "bc_name": "INFLOW", # Name of the boundary condition + "bc_type": "FLOW", # Type of the boundary condition + "bc_values": { + "Q": [ ..., ..., ... ], # Comma-separated list of values + "t": [ ..., ..., ... ] # Comma-separated list of corresponding time stamps + } +}, +``` +See `svZeroDSolver/tests/cases/pulsatileFlow_R_RCR.json` for an example. + +They can also be specified as a mathematica expression as follow: +```python +{ + "bc_name": "INFLOW", # Name of the boundary condition + "bc_type": "FLOW", # Type of the boundary condition + "bc_values": { + "fn": "2.0 * (4*atan(1.)) * cos(2.0 * (4*atan(1.)) * t)" + } +}, +``` +For an example with a mathematical expression for the boundary condition, see `svZeroDSolver/tests/cases/timeDep_Flow.json`. + +## Simulation Outputs + +The siumulation outputs will be saved in the specified CSV file (`.csv`) when running `svZeroDSolver` from the command line as follows: +```bash +svzerodsolver .json .csv +``` +If the name of the CSV file is not specified, the default is `output.csv`. The format of the file depends on the user-specified configuration within the `simulation_parameters` block of the JSON configuration file. + +If `output_variable_based` is set to `true`, the CSV file will contain all the degrees-of-freedom in the simulation. Otherwise, only the flow and pressure at the inlets and outlets of vessels is written. + +The degrees-of-freedom (DOFs) follow the following naming scheme: + +- Flow DOFs are labelled `flow::`. +- Pressure DOFs are labelled `pressure::`. +- Internal DOFs (i.e., variables internal to a block and not connected to upstream/downstream blocks) are labelled `:`. The internal variables for each block are listed in the blocks' [class documentation](https://simvascular.github.io/svZeroDSolver/annotated.html). + +When the outputs are written in the variable-based and vessel-based forms, the user can specify whether they want outputs written for all cardiac cycles or just the last cardiac cycle using the `output_all_cycles` option. By default, only the last cycle is written. This makes the simulation more efficient. + +The number of timesteps between each time the output is written is specified by `output_interval`. By default, output is written at every time step. -# svZeroDCalibrator +# svZeroDCalibrator - Quick User Guide svZeroDCalibrator can be used to calibrate cardiovascular 0D models (i.e. infer optimal parameters for the 0D elements) based on a given transient result (i.e. from a diff --git a/src/model/OpenLoopCoronaryBC.h b/src/model/OpenLoopCoronaryBC.h index f15c0d882..831f9ca39 100644 --- a/src/model/OpenLoopCoronaryBC.h +++ b/src/model/OpenLoopCoronaryBC.h @@ -96,7 +96,7 @@ * Parameter sequence for constructing this block * * * `0` Ra: Small artery resistance - * * `1` Ram: Microvascualr resistance + * * `1` Ram: Microvascualar resistance * * `2` Rv: Venous resistance * * `3` Ca: Small artery capacitance * * `4` Cim: Intramyocardial capacitance