Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
101 changes: 86 additions & 15 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,48 +7,86 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-22.04, ubuntu-latest, macos-13, macos-latest]
os: [ubuntu-22.04, ubuntu-latest, macos-13, macos-latest, windows-latest]
version: [13] # GCC version
fail-fast: false
env:
GCC_V: ${{ matrix.version }}
CONDA_ENV: zerod
PYTHONPATH: ${{ github.workspace }}
steps:
- uses: actions/checkout@v4
- uses: conda-incubator/setup-miniconda@v3
with:
auto-update-conda: true
activate-environment: ${{env.CONDA_ENV}}
python-version: "3.11.4"
- name: Install ubuntu dependencies
if: startsWith(matrix.os, 'ubuntu')
run: sudo apt update && sudo apt install build-essential cmake lcov
- name: Create conda environment
run: |
#export PATH="/usr/share/miniconda/bin:$PATH"
#alias conda="$CONDA/bin/conda"
conda create -n zerod python=3.11.4

- name: Install dependencies to get correct version numbers (Ubuntu)
if: startsWith(matrix.os, 'ubuntu')
run: conda install -n zerod -c conda-forge libstdcxx-ng=${GCC_V} gcc=${GCC_V}
run: conda install -c conda-forge libstdcxx-ng=${GCC_V} gcc=${GCC_V}

- name: Install dependencies to get correct version numbers (MacOS)
if: startsWith(matrix.os, 'macos')
run: |
brew install gcc@${GCC_V}
ln -s /usr/local/bin/gcc-${GCC_V} /usr/local/bin/gcc
- name: Install svZeroDSolver
run: conda run -n zerod pip install -e ".[dev]"

- name: Install dependencies for windows
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
choco install mingw --no-progress
conda install -y -c conda-forge cmake graphviz python-graphviz pydot
pip install --upgrade cmake-setuptools

- name: Install POISX-like svZeroDSolver
if: ${{!startsWith(matrix.os, 'windows')}}
run: conda run pip install -e ".[dev]"

- name: Install Windows svZeroDSolver
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
$Env:CMAKE_GENERATOR = 'MinGW Makefiles'
Write-Host "→ Using CMAKE_GENERATOR = $Env:CMAKE_GENERATOR"
pip install --no-build-isolation -v .[dev]
pip show pysvzerod

- name: Install Networkx
run: |
conda run -n zerod pip install networkx
conda run pip install networkx

- name: Test the build
run: |
cd tests
conda run -n zerod pytest -v --durations=0 --ignore=test_dirgraph.py
- name: Build using CMake
conda run pytest -v --durations=0 --ignore=test_dirgraph.py

- name: Build using CMake for POISX-like Systems
if: ${{!startsWith(matrix.os, 'windows')}}
run: |
mkdir Release
cd Release
cmake -DCMAKE_BUILD_TYPE=Release -DENABLE_DISTRIBUTION=ON ..
make -j2
- name: Test interface

- name: Build using CMake for Windows Systems
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
mkdir Release
cd Release
cmake -G "MinGW Makefiles" `
-DCMAKE_BUILD_TYPE=Release `
-DENABLE_DISTRIBUTION=ON `
..
cmake --build . --parallel 2

- name: Test interface POISX-like Systems
if: ${{!startsWith(matrix.os, 'windows')}}
run: |
cd tests/test_interface
mkdir build_tests
Expand All @@ -59,32 +97,65 @@ jobs:
./svZeroD_interface_test01 ../../../../Release ../../test_01/svzerod_3Dcoupling.json
cd ../test_02
./svZeroD_interface_test02 ../../../../Release ../../test_02/svzerod_tuned.json

- name: Test interface Windows Systems
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
cd tests/test_interface
mkdir build_tests
cd build_tests
cmake -G "MinGW Makefiles" ..
cmake --build . --parallel 2
cd test_01
./svZeroD_interface_test01.exe `
../../../../Release `
../../test_01/svzerod_3Dcoupling.json

cd ../test_02
./svZeroD_interface_test02 `
../../../../Release `
../../test_02/svzerod_tuned.json

- name: Generate code coverage
if: startsWith(matrix.os, 'ubuntu-22.04')
run: |
cd Release
cmake -DENABLE_COVERAGE=ON ..
make -j2
cd ../tests
conda run -n zerod pytest -v --durations=0 --coverage --ignore=test_dirgraph.py
conda run pytest -v --durations=0 --coverage --ignore=test_dirgraph.py
cd ../Release
make coverage

- name: Save coverage report
if: startsWith(matrix.os, 'ubuntu-22.04')
uses: actions/upload-artifact@v4
with:
name: coverage_report
path: Release/coverage

- name: Upload coverage reports to Codecov
if: startsWith(matrix.os, 'ubuntu-22.04')
uses: codecov/codecov-action@v4
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Build installer

- name: Build installer POISX-like Systems
if: ${{!startsWith(matrix.os, 'windows')}}
run: |
cd Release
cpack
cp distribution/svZeroDSolver_* ..

- name: Build installer Windows Systems
if: startsWith(matrix.os, 'windows')
shell: pwsh
run: |
cd Release
cpack
Copy-Item distribution\svZeroDSolver_* -Destination ..\

- name: Upload installer
uses: actions/upload-artifact@v4
with:
Expand Down
68 changes: 67 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,22 @@ if(ENABLE_COVERAGE)
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
endif()

if (WIN32 AND MSVC)
# CMake ≥ 3.15 has a proper variable
if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.15")
set(CMAKE_MSVC_RUNTIME_LIBRARY
"MultiThreaded$<$<CONFIG:Debug>:Debug>")
else()
# CMake < 3.15: manually swap /MD → /MT in all flags for static
# versions of the runtime libraries
foreach(_var
CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE
CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
CMAKE_SHARED_LINKER_FLAGS)
string(REPLACE "/MD" "/MT" ${_var} "${${_var}}")
endforeach()
endif()
endif()
# -----------------------------------------------------------------------------
# Set the location to store the binaries and libraries created by this project.
# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -159,7 +175,38 @@ add_executable(svzerodcalibrator applications/svzerodcalibrator.cpp
# -----------------------------------------------------------------------------
# Replace EXCLUDE_FROM_ALL with SHARED to test building the Python
# shared library.
pybind11_add_module(pysvzerod EXCLUDE_FROM_ALL applications/pysvzerod.cpp)

pybind11_add_module(pysvzerod applications/pysvzerod.cpp)
if(WIN32 AND "${CMAKE_GENERATOR}" STREQUAL "MinGW Makefiles")
message(STATUS ">> Applying static‑link flags to pysvzerod")

include(CheckCXXCompilerFlag)
set(_static_flags
-static
-static-libgcc
-static-libstdc++
)
# test for winpthread support before adding
check_cxx_compiler_flag("-static-libwinpthread" HAVE_WINPTHREAD)
if(HAVE_WINPTHREAD)
list(APPEND _static_flags -static-libwinpthread)
else()
find_package(Threads REQUIRED)
target_link_libraries(pysvzerod PRIVATE Threads::Threads)
endif()
# apply to compile *and* link
foreach(_f IN LISTS _static_flags)
target_compile_options(pysvzerod PRIVATE ${_f})
# CMake ≥3.13:
target_link_options (pysvzerod PRIVATE ${_f})
endforeach()

# verify in the configure log for static compilation:
get_target_property(_ccopts pysvzerod COMPILE_OPTIONS)
message(STATUS ">>> pysvzerod COMPILE_OPTIONS = ${_ccopts}")
get_target_property(_lnkopts pysvzerod LINK_OPTIONS)
message(STATUS ">>> pysvzerod LINK_OPTIONS = ${_lnkopts}")
endif()

# -----------------------------------------------------------------------------
# Add source sub-directories.
Expand Down Expand Up @@ -232,3 +279,22 @@ add_custom_target(codeformat
# check code format
add_custom_target(codecheck
COMMAND find ${SDIR}/*.h ${SDIR}/*.cpp | xargs clang-format -style=file:${PROJECT_SOURCE_DIR}/.clang-format --dry-run --Werror)

set_target_properties(pysvzerod PROPERTIES
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/python
)

# standard install target locations
install(TARGETS pysvzerod
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
RUNTIME DESTINATION "${CMAKE_INSTALL_LIBDIR}"
)

# append correct suffix for windows python runtime files
if (WIN32)
set_target_properties(pysvzerod PROPERTIES
PREFIX ""
SUFFIX ".pyd"
)
endif()
33 changes: 32 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,38 @@
import os
import shutil
from setuptools import setup
from cmake_setuptools import CMakeExtension, CMakeBuildExt

class CustomCMakeBuild(CMakeBuildExt):
def run(self):
# -------------------------------------------------
# 1. Build the C++ extension *without* the default
# setuptools copy step (set inplace False)
# -------------------------------------------------
inplace_orig = self.inplace # remember
self.inplace = False # inhibit copy_extensions_to_source
super().run() # runs CMake
self.inplace = inplace_orig # restore flag

# -------------------------------------------------
# 2. Locate the compiled library
# -------------------------------------------------
build_temp = os.path.abspath(self.build_temp)
search_root = os.path.join(build_temp, "python")
dest_dir = os.path.dirname(self.get_ext_fullpath("pysvzerod"))

for root, _, files in os.walk(search_root):
for f in files:
if f.startswith("pysvzerod") and f.endswith((".so", ".pyd", ".dll", ".dylib")):
src = os.path.join(root, f)
os.makedirs(dest_dir, exist_ok=True)
shutil.copy2(src, os.path.join(dest_dir, f))
print(f"[INFO] copied {src} -> {dest_dir}")
return

raise RuntimeError("pysvzerod binary not found in build tree")

setup(
ext_modules=[CMakeExtension("pysvzerod")],
cmdclass={"build_ext": CMakeBuildExt},
cmdclass={"build_ext": CustomCMakeBuild},
)
10 changes: 5 additions & 5 deletions src/model/ClosedLoopHeartPulmonary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ void ClosedLoopHeartPulmonary::get_activation_and_elastance_functions(
AA = 0.0;
if (t_in_cycle <= tpwave) {
AA = (0.5) * (1.0 - cos(2.0 * M_PI * (t_in_cycle - tpwave + Tsa) / Tsa));
} else if ((t_in_cycle >= (T_cardiac - Tsa) + tpwave) and
} else if ((t_in_cycle >= (T_cardiac - Tsa) + tpwave) &&
(t_in_cycle < T_cardiac)) {
AA = (0.5) * (1.0 - cos(2.0 * M_PI *
(t_in_cycle - tpwave - (T_cardiac - Tsa)) / Tsa));
Expand Down Expand Up @@ -280,29 +280,29 @@ void ClosedLoopHeartPulmonary::get_valve_positions(
auto pressure_ra = y[global_var_ids[0]];
auto pressure_rv = y[global_var_ids[6]];
auto outflow_ra = y[global_var_ids[5]];
if ((pressure_ra <= pressure_rv) and (outflow_ra <= 0.0)) {
if ((pressure_ra <= pressure_rv) && (outflow_ra <= 0.0)) {
valves[5] = 0.0;
}

// RV to pulmonary
auto pressure_pulmonary = y[global_var_ids[9]];
auto outflow_rv = y[global_var_ids[8]];
if ((pressure_rv <= pressure_pulmonary) and (outflow_rv <= 0.0)) {
if ((pressure_rv <= pressure_pulmonary) && (outflow_rv <= 0.0)) {
valves[8] = 0.0;
}

// LA to LV
auto pressure_la = y[global_var_ids[10]];
auto pressure_lv = y[global_var_ids[13]];
auto outflow_la = y[global_var_ids[12]];
if ((pressure_la <= pressure_lv) and (outflow_la <= 0.0)) {
if ((pressure_la <= pressure_lv) && (outflow_la <= 0.0)) {
valves[12] = 0.0;
}

// LV to aorta
auto pressure_aorta = y[global_var_ids[2]];
auto outflow_lv = y[global_var_ids[15]];
if ((pressure_lv <= pressure_aorta) and (outflow_lv <= 0.0)) {
if ((pressure_lv <= pressure_aorta) && (outflow_lv <= 0.0)) {
valves[15] = 0.0;
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/model/Parameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@
#ifndef SVZERODSOLVER_MODEL_PARAMETER_HPP_
#define SVZERODSOLVER_MODEL_PARAMETER_HPP_

#include <math.h>

#include <algorithm>
#include <cmath>
#include <iostream>
#include <numeric>
#include <vector>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#include "LPNSolverInterface.h"
#include <dlfcn.h>
#include <iostream>
#include <string>

Expand Down
Loading
Loading