Skip to content
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

Add Levenberg-Marquardt model calibration #31

Merged
merged 87 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from 85 commits
Commits
Show all changes
87 commits
Select commit Hold shift + click to select a range
fb6ec67
Split json handling from config reader
richterjakob Mar 14, 2023
003953a
Add documentation
richterjakob Mar 14, 2023
f24f747
Try to fix ubuntu build problems by fixing simdjson version
richterjakob Mar 14, 2023
775f26a
try with CMAKE_POSITION_INDEPENDENT_CODE again
richterjakob Mar 14, 2023
90bc3a0
Adress reviewers comments
richterjakob Mar 15, 2023
920836c
Move block count increment out of loop
richterjakob Mar 19, 2023
ad06bca
Rename time dependent parameter
richterjakob Mar 19, 2023
3c880ed
Add block method for model class
richterjakob Mar 19, 2023
73e8f02
Revise parameter class
richterjakob Mar 19, 2023
e85be8c
Make elements use parameter IDs
richterjakob Mar 25, 2023
2f73c6c
Fix bug and support more elements
richterjakob Mar 25, 2023
317c44a
Support blood vessel junction
richterjakob Mar 25, 2023
8695fa6
Fix gradient of blood vessel and add calibrator
richterjakob Mar 26, 2023
237cc37
Add gradient update to blood vessel junction
richterjakob Mar 26, 2023
43b9043
Support normal BC names
richterjakob Mar 26, 2023
c6a6107
Write calibrated parameter values back into config
richterjakob Mar 26, 2023
cd860bd
Add support for open loop coronary back
richterjakob Mar 26, 2023
ac3d73b
Add support for resistive junction back
richterjakob Mar 26, 2023
fee12f7
Clean up
richterjakob Mar 26, 2023
ed4da69
Fix bugs in calibrator and adapt after cleanup
richterjakob Mar 26, 2023
317f006
Reduce blood vessel system size
richterjakob Mar 30, 2023
b9433b2
Update bloodvessel junction to new blood vessel system
richterjakob Mar 30, 2023
4e29f16
Some fixes
richterjakob Mar 30, 2023
cd893cb
Fix bugs
richterjakob Mar 31, 2023
bdd8e65
Fix stenosis coeff gradient
richterjakob Mar 31, 2023
1b73f13
Add support for remaining blocks back
richterjakob Apr 1, 2023
8504234
Move determination of cardiac cycle period to model
richterjakob Apr 1, 2023
e961901
Clean up reader
richterjakob Apr 2, 2023
bc49689
Use nlohmann json
richterjakob Apr 2, 2023
959adbf
Add gradient info to documentation
richterjakob Apr 2, 2023
6b5dd29
Fix calibrator
richterjakob Apr 2, 2023
3f8f678
Improve python binding
richterjakob Apr 2, 2023
f5608b0
Adapt solver interface
richterjakob Apr 3, 2023
7f56c6e
Add Levenberg Marquardt optimizer
richterjakob Apr 7, 2023
08ea72e
Full LM algorithm and fixes for capacitance
richterjakob Apr 8, 2023
89e21eb
Fix bug with calibrating stenosis coefficient
richterjakob Apr 10, 2023
dd947d5
Fix bug with capacitance in steady model
richterjakob Apr 10, 2023
12a8b7c
Add termination criteria
richterjakob Apr 10, 2023
04a2791
Fix pytest
richterjakob Apr 10, 2023
ebc6e7f
Move solver to own class
richterjakob Apr 14, 2023
a6aa38f
New python binding with thread safety
richterjakob Apr 14, 2023
62c9636
Dockerfile
richterjakob Apr 15, 2023
029f7b6
Fix profiling
richter-e7d Apr 15, 2023
f226763
Allow installation via pip
richterjakob Apr 15, 2023
45a2f92
Add reading derivative of initial condition
richterjakob Apr 16, 2023
0cfe6f5
Get rid of Jsonhandler
richter-e7d May 29, 2023
5c331d2
Dockerize profiling
richter-e7d May 29, 2023
82ad486
Adapt svzerodcalibrator
richter-e7d May 29, 2023
53e79d2
Use output last cycle only as default
richter-e7d May 29, 2023
35c4587
Clean up
richter-e7d Jun 4, 2023
aba010f
Fix interface
richter-e7d Jun 11, 2023
164edd3
Fix tests
richter-e7d Jun 11, 2023
4060b01
Setup for new documentation
richter-e7d Jun 11, 2023
7d16e72
update main page
richter-e7d Jul 1, 2023
c46d59c
Add svzerodsolver Guide
richter-e7d Jul 1, 2023
348438e
Finalize
richter-e7d Aug 14, 2023
fe87e51
Fix clang-format
richter-e7d Aug 14, 2023
28bb45a
Fix bug
richter-e7d Aug 14, 2023
51f7e18
Try to fix documentation
richter-e7d Aug 14, 2023
b18946b
Another try
richter-e7d Aug 14, 2023
c630f33
New try
richter-e7d Aug 14, 2023
1e9af41
fix typo
mrp089 Aug 14, 2023
24d67be
fix bug using calibration_parameters
mrp089 Aug 14, 2023
bed62ed
clang format
mrp089 Aug 15, 2023
a43d840
add script to generate calibration problems from test cases
mrp089 Aug 15, 2023
d65c654
add VMR model 0075_1001
mrp089 Aug 15, 2023
24c8c7d
Blood vessel junction without internal variables
richter-e7d Aug 15, 2023
041a9c6
exit normally if LM doesn't converge and use sci notation
mrp089 Aug 16, 2023
63c5d25
add vmr 0d models. tried calibration from 3d, doesn't work. giving up
mrp089 Aug 19, 2023
29f46d1
Fix bug
richter-e7d Aug 19, 2023
f47419b
clang format
richter-e7d Aug 19, 2023
b85e70a
Address reviewer's comments
richter-e7d Aug 20, 2023
5a6b3ed
Typo in error msg
Aug 23, 2023
002e450
Make specifying the output file optional
Aug 23, 2023
894bfe9
default cardiac cycle period
Aug 24, 2023
e16c267
Fix bug
richter-e7d Aug 28, 2023
1811a5d
make cmake compile interface by default
Aug 29, 2023
9083fa4
make specifying output file optional
Aug 29, 2023
a4c42e0
added get_block_type
Aug 29, 2023
7434685
bug fix: update_parameter_value
Aug 30, 2023
4c3b27e
update initial condition reading and other debugging
Aug 30, 2023
c4931da
interface working again
Aug 30, 2023
3312652
Merge branch 'least-squares' of github.com:richterjakob/svZeroDPlus i…
Aug 30, 2023
8624c31
clang format
Aug 30, 2023
b78ebf8
updated parameter descriptions for heart model
Aug 30, 2023
2cbebf3
Add calibration tests using vmr geometries
richter-e7d Sep 1, 2023
1d4a4ff
remove python script for plotting calibration
mrp089 Sep 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
run: mkdir docs/html
- name: Build doxygen documentation
continue-on-error: true
uses: mattnotmitt/[email protected].4
uses: mattnotmitt/[email protected].5
with:
working-directory: '.'
doxyfile-path: 'docs/cpp/Doxyfile'
Expand Down
10 changes: 2 additions & 8 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,14 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-18.04, ubuntu-20.04, ubuntu-22.04, macos-11, macos-12]
os: [ubuntu-20.04, ubuntu-22.04, macos-11, macos-12]
fail-fast: false
steps:
- uses: actions/checkout@v2
- name: Install ubuntu dependencies
if: ${{ matrix.os == 'ubuntu-*' }}
run: sudo apt update && sudo apt install build-essential cmake
- name: Build svZeroDSolver
run: |
mkdir Release
cd Release
cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build .
- name: Install test dependencies
- name: Install svZeroDPlus
richterjakob marked this conversation as resolved.
Show resolved Hide resolved
run: |
conda create -n zerod python=3.9
conda run -n zerod pip install pytest pytest-cov pytest-mock
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ docs/python/build
Release*/
Debug*/
externals/
*.so
build
45 changes: 29 additions & 16 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,6 @@ set(CMAKE_CXX_STANDARD_REQUIRED True)
project(svZeroDSolver)
include(FetchContent)

# -----------------------------------------------------------------------------
# Fetch simdjson
# -----------------------------------------------------------------------------
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
FetchContent_Declare(
simdjson
GIT_REPOSITORY https://github.com/simdjson/simdjson.git
GIT_TAG master
GIT_SHALLOW TRUE)
FetchContent_MakeAvailable(simdjson)

# -----------------------------------------------------------------------------
# Fetch Eigen
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -44,17 +33,41 @@ if(NOT pybind11_POPULATED)
add_subdirectory(${pybind11_SOURCE_DIR} ${pybind11_BINARY_DIR})
endif()

# -----------------------------------------------------------------------------
# Fetch nlohmann/json
# -----------------------------------------------------------------------------
FetchContent_Declare(
json
URL https://github.com/nlohmann/json/releases/download/v3.11.2/json.tar.xz
)
FetchContent_MakeAvailable(json)

# -----------------------------------------------------------------------------
# Fetch pybind11_json
# -----------------------------------------------------------------------------
FetchContent_Declare(
pybind11_json
GIT_REPOSITORY https://github.com/pybind/pybind11_json.git
GIT_TAG master
)
FetchContent_MakeAvailable(pybind11_json)

# -----------------------------------------------------------------------------
# Set executable and python library
# -----------------------------------------------------------------------------
add_executable(svzerodsolver src/main.cpp)
pybind11_add_module(libsvzerodsolver src/python.cpp)
include_directories(src)
add_executable(svzerodsolver applications/svzerodsolver.cpp)
add_executable(svzerodcalibrator applications/svzerodcalibrator.cpp)
pybind11_add_module(svzerodplus EXCLUDE_FROM_ALL applications/svzerodplus.cpp)
add_subdirectory("src/interface")

# -----------------------------------------------------------------------------
# Link libraries
# -----------------------------------------------------------------------------
target_link_libraries(svzerodsolver PRIVATE Eigen3::Eigen)
target_link_libraries(svzerodsolver PRIVATE simdjson)
target_link_libraries(libsvzerodsolver PRIVATE Eigen3::Eigen)
target_link_libraries(libsvzerodsolver PRIVATE simdjson)
target_link_libraries(svzerodsolver PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(svzerodcalibrator PRIVATE Eigen3::Eigen)
target_link_libraries(svzerodcalibrator PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(svzerodplus PRIVATE Eigen3::Eigen)
target_link_libraries(svzerodplus PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(svzerodplus PRIVATE pybind11_json)
64 changes: 64 additions & 0 deletions applications/svzerodcalibrator.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
// Copyright (c) Stanford University, The Regents of the University of
// California, and others.
//
// All Rights Reserved.
//
// See Copyright-SimVascular.txt for additional details.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @file svzerodcalibrator.cpp
* @brief Main routine for svZeroDCalibrator
*/
#include "optimize/calibrate.hpp"

// Setting scalar type to double
typedef double T;

int main(int argc, char* argv[]) {
DEBUG_MSG("Starting svZeroDCalibrator");

// Get input and output file name
if (argc != 3) {
std::cout
<< "Usage: svzerodcalibrator path/to/config.json path/to/output.json"
<< std::endl;
exit(1);
}

// Get input and output file names
std::string input_file = argv[1];
std::string output_file = argv[2];

// Parse the configuration
DEBUG_MSG("Parse configuration");
std::ifstream ifs(input_file);
const auto& config = nlohmann::json::parse(ifs);

auto output_config = OPT::calibrate<T>(config);

// Write optimized simulation config
std::ofstream o(output_file);
o << std::setw(4) << output_config << std::endl;
}
richterjakob marked this conversation as resolved.
Show resolved Hide resolved
104 changes: 104 additions & 0 deletions applications/svzerodplus.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright (c) Stanford University, The Regents of the University of
// California, and others.
//
// All Rights Reserved.
//
// See Copyright-SimVascular.txt for additional details.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject
// to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
// IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
// PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
// OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @file svzerodplus.cpp
* @brief Python interface for svZeroDSolver
*/
#include <pybind11/eigen.h>
#include <pybind11/operators.h>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

#include "optimize/calibrate.hpp"
#include "pybind11_json/pybind11_json.hpp"
#include "solve/solver.hpp"

namespace py = pybind11;

PYBIND11_MODULE(svzerodplus, m) {
using Solver = SOLVE::Solver<double>;
m.doc() = "svZeroDSolver";
py::class_<Solver>(m, "Solver")
.def(py::init([](py::dict& config) {
const nlohmann::json& config_json = config;
return Solver(config_json);
}))
.def(py::init([](std::string config_file) {
std::ifstream ifs(config_file);
const auto& config_json = nlohmann::json::parse(ifs);
return Solver(config_json);
}))
.def("copy", [](Solver& solver) { return Solver(solver); })
.def("run", &Solver::run)
.def("get_single_result", &Solver::get_single_result)
.def("get_single_result_avg", &Solver::get_single_result_avg)
.def("update_block_params", &Solver::update_block_params);

m.def("simulate", [](py::dict& config) {
const nlohmann::json& config_json = config;
auto solver = Solver(config_json);
solver.run();
return solver.get_full_result();
});
m.def("calibrate", [](py::dict& config) {
const nlohmann::json& config_json = config;
return OPT::calibrate<double>(config);
});
m.def("run_simulation_cli", []() {
py::module_ sys = py::module_::import("sys");
auto argv = sys.attr("argv").cast<std::vector<std::string>>();
if (argv.size() != 3) {
std::cout
<< "Usage: svzerodsolver path/to/config.json path/to/output.json"
<< std::endl;
exit(1);
}
std::ifstream ifs(argv[1]);
const auto& config = nlohmann::json::parse(ifs);
auto solver = SOLVE::Solver<double>(config);
solver.run();
solver.write_result_to_csv(argv[2]);
});
m.def("run_calibration_cli", []() {
py::module_ sys = py::module_::import("sys");
auto argv = sys.attr("argv").cast<std::vector<std::string>>();
if (argv.size() != 3) {
std::cout
<< "Usage: svzerodcalibrator path/to/config.json path/to/output.json"
<< std::endl;
exit(1);
}
std::ifstream ifs(argv[1]);
const auto& config = nlohmann::json::parse(ifs);
auto output_config = OPT::calibrate<double>(config);
std::ofstream o(argv[2]);
o << std::setw(4) << output_config << std::endl;
});
}
43 changes: 26 additions & 17 deletions src/main.cpp → applications/svzerodsolver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
/**
* @file main.cpp
* @file svzerodsolver.cpp
* @brief Main routine of svZeroDSolver
*/
#include "main.hpp"
#include "solve/solver.hpp"

/**
*
Expand All @@ -50,28 +50,37 @@
* @param argv Command line arguments
* @return Return code
*/
int main(int argc, char *argv[]) {
int main(int argc, char* argv[]) {
DEBUG_MSG("Starting svZeroDSolver");

// Get input and output file name
if (argc != 3) {
std::cout << "Usage: svzerodsolver path/to/config.json path/to/output.csv"
<< std::endl;
exit(1);
if (argc < 2 && argc > 3) {
std::runtime_error(
"Usage: svzerodsolver path/to/config.json "
"(optional:path/to/output.csv)");
}
std::string input_file = argv[1];
std::string output_file = argv[2];

std::ifstream input_file_stream(input_file);
std::stringstream buffer;
buffer << input_file_stream.rdbuf();
std::string config = buffer.str();
std::string output_file;
if (argc == 3) {
output_file = argv[2];
} else {
// If output file is not provided, default is <path to .json>+"output.csv"
std::size_t end_of_path = input_file.rfind("/");
if (end_of_path == std::string::npos) {
end_of_path = input_file.rfind("\\"); // For Windows paths (?)
if (end_of_path == std::string::npos) {
std::runtime_error("Could not find path to .json file.");
}
}
output_file = input_file.substr(0, end_of_path) + "output.csv";
}

auto output = run(config);
std::ifstream ifs(input_file);
const auto& config = nlohmann::json::parse(ifs);

std::ofstream ofs(output_file);
ofs << output;
ofs.close();
auto solver = SOLVE::Solver<double>(config);
solver.run();
solver.write_result_to_csv(output_file);

return 0;
}
32 changes: 32 additions & 0 deletions container/profiling/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM ubuntu:22.04

# Install dependencies
RUN apt-get -q update && \
DEBIAN_FRONTEND=noninteractive \
TZ=Europe/Berlin \
apt-get -q -y --no-install-recommends install \
git \
gcc \
g++ \
make \
cmake \
python3 \
python3-dev \
ca-certificates \
google-perftools \
libgoogle-perftools-dev \
graphviz \
ghostscript \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

COPY . /opt/svzerodplus

RUN mkdir -p /opt/svzerodplus-build/relwithdebinfo && \
cd /opt/svzerodplus-build/relwithdebinfo && \
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo /opt/svzerodplus && \
cmake --build . --target svzerodsolver

WORKDIR /opt/data
RUN chmod +x /opt/svzerodplus/container/profiling/entrypoint.sh
ENTRYPOINT ["/opt/svzerodplus/container/profiling/entrypoint.sh"]
5 changes: 5 additions & 0 deletions container/profiling/entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#! /bin/bash

export LIBPROFILER=$(find /usr/lib -name "libprofiler.so")
LD_PRELOAD=$LIBPROFILER CPUPROFILE=/opt/main.prof CPUPROFILE_FREQUENCY=100000 /opt/svzerodplus-build/relwithdebinfo/svzerodsolver $@ /opt/output.csv
google-pprof --pdf /opt/svzerodplus-build/relwithdebinfo/svzerodsolver /opt/main.prof > profiling_report.pdf
Loading
Loading