From 25a1e0c4837789c114570b4a087dba53d6cad264 Mon Sep 17 00:00:00 2001 From: "Stanley C." <19547104+stanbot8@users.noreply.github.com> Date: Sun, 16 Aug 2026 15:45:10 -0700 Subject: [PATCH] Remove the build dependency --- .devcontainer/Dockerfile | 79 +- .devcontainer/paraview-wrapper.sh | 4 +- .github/workflows/README.md | 11 - .github/workflows/ci.yml | 173 + .github/workflows/macos-ci.yml | 61 - .github/workflows/macos-system-ci.yml | 114 - .github/workflows/repository-checks.yml | 30 - .github/workflows/singularity-integration.yml | 42 - .github/workflows/ubuntu-ci.yml | 132 - .github/workflows/ubuntu-system-ci.yml | 173 - CMakeLists.txt | 197 +- CONTRIBUTING.md | 44 +- Singularity | 103 +- cli/config_command.py | 2 - cmake/BioDynaMo.cmake | 234 +- cmake/FindROOT.cmake | 204 -- cmake/FindTBB.cmake | 293 -- cmake/Findtcmalloc.cmake | 1 - cmake/Installation.cmake | 21 +- cmake/Notebooks.cmake | 55 - cmake/RootUseFile.cmake | 3 - cmake/Testing.cmake | 10 +- cmake/UseBioDynaMo.cmake.in | 23 +- cmake/Versioning.cmake | 2 +- cmake/Website.cmake | 8 - cmake/bdm-dictionary | 132 - cmake/env/bdm-config.in | 17 +- cmake/env/launcher.sh | 4 +- cmake/env/sh_functions/paraview | 5 - cmake/env/sh_functions/pvbatch | 5 - cmake/env/sh_functions/pvpython | 5 - cmake/env/sh_functions/root | 6 - cmake/env/thisbdm.fish | 178 - cmake/env/thisbdm.sh | 209 -- cmake/external/ParaView.cmake | 26 - cmake/external/Qt.cmake | 22 - cmake/external/ROOT.cmake | 98 - cmake/external/SHA256Digests.cmake | 134 - cmake/selection-libVisualizationAdaptor.xml | 8 - cmake/selection-libbiodynamo.xml | 160 - cmake/selection.xml | 193 -- cmake/utils.cmake | 109 +- demo/binding_cells/CMakeLists.txt | 29 - demo/binding_cells/analysis.ipynb | 103 - demo/binding_cells/bdm.toml | 24 - demo/binding_cells/params.json | 19 - demo/binding_cells/run.sh | 3 - demo/binding_cells/src/agents/monocyte.h | 74 - demo/binding_cells/src/agents/t_cell.h | 101 - demo/binding_cells/src/binding_cells.cc | 27 - demo/binding_cells/src/binding_cells.h | 172 - .../connect_within_radius_module.h | 95 - .../constant_displacement_module.h | 92 - .../src/biology_modules/inhibitation_module.h | 72 - .../biology_modules/physical_bond_module.h | 60 - .../src/biology_modules/random_walk_module.h | 107 - .../src/biology_modules/spring_force_module.h | 72 - .../biology_modules/stokes_velocity_module.h | 91 - demo/binding_cells/src/macro.C | 10 - demo/binding_cells/src/plot_graph.h | 49 - demo/epidemiology/CMakeLists.txt | 26 - demo/epidemiology/measles.json | 27 - demo/epidemiology/optim.json | 29 - demo/epidemiology/plot-style.json | 31 - demo/epidemiology/render.py | 136 - demo/epidemiology/run.sh | 11 - demo/epidemiology/src/analytical-solution.cc | 71 - demo/epidemiology/src/analytical-solution.h | 21 - demo/epidemiology/src/behavior.h | 90 - demo/epidemiology/src/epidemiology.cc | 78 - demo/epidemiology/src/epidemiology.h | 95 - demo/epidemiology/src/evaluate.h | 107 - demo/epidemiology/src/person.h | 32 - demo/epidemiology/src/sim-param.h | 42 - demo/epidemiology/test.sh | 4 - demo/epidemiology/visualize.sh | 13 - demo/makefile_project/Makefile | 13 +- demo/makefile_project/README.md | 4 +- .../src/multiple_simulations.h | 2 +- doc/dev_guide/build.md | 53 +- doc/sidebars/userguide.yaml | 4 - doc/user_guide/Singularity.md | 20 +- doc/user_guide/docs/notebooks.md | 89 - doc/user_guide/installation.md | 2 +- doc/user_guide/multi_simulation.md | 143 - doc/user_guide/parameter.md | 154 +- doc/user_guide/prerequisites.md | 8 +- .../simulation_parameter_tutorial.md | 370 +-- etc/bdm.rootrc | 4 - notebook/ST01-model-initializer.ipynb | 348 -- ...r-defined-random-number-distribution.ipynb | 164 - .../ST03-agent-reproduction-mortality.ipynb | 204 -- ...04-agent-reproduction-with-behaviors.ipynb | 218 -- .../ST05-agent-reproduction-advanced.ipynb | 380 --- notebook/ST06-environment-search.ipynb | 179 - notebook/ST07-multi-scale-simulation.ipynb | 179 - notebook/ST08-histograms.ipynb | 164 - notebook/ST09-timeseries-plotting-basic.ipynb | 209 -- ...T10-timeseries-plotting-and-analysis.ipynb | 296 -- ...ple-experiments-statistical-analysis.ipynb | 217 -- notebook/ST12-hierarchical-model.ipynb | 253 -- notebook/ST13-dynamic-scheduling.ipynb | 322 -- notebook/ST14-randomize-iteration-order.ipynb | 164 - notebook/ST15-replace-interaction-force.ipynb | 246 -- src/biodynamo.h | 4 - src/core/analysis/line_graph.cc | 200 -- src/core/analysis/line_graph.h | 95 - src/core/analysis/style.cc | 335 -- src/core/analysis/style.h | 169 - src/core/analysis/time_series.cc | 17 - src/core/analysis/time_series.h | 61 +- .../multi_simulation/algorithm/algorithm.h | 41 - .../algorithm/algorithm_registry.cc | 59 - .../algorithm/algorithm_registry.h | 84 - .../algorithm/parameter_sweep.cc | 63 - .../algorithm/particle_swarm.cc | 146 - src/core/multi_simulation/database.h | 43 - src/core/multi_simulation/dynamic_loop.h | 66 - src/core/multi_simulation/experiment.h | 87 - src/core/multi_simulation/mpi_helper.h | 84 - src/core/multi_simulation/multi_simulation.cc | 103 - src/core/multi_simulation/multi_simulation.h | 59 - .../multi_simulation_manager.cc | 283 -- .../multi_simulation_manager.h | 125 - .../multi_simulation/optimization_param.h | 48 - .../optimization_param_type/log_range_param.h | 77 - .../optimization_param_type.h | 58 - .../particle_swarm_param.h | 73 - .../optimization_param_type/range_param.h | 73 - .../optimization_param_type/set_param.h | 48 - src/core/param/command_line_options.cc | 107 +- src/core/param/command_line_options.h | 10 +- src/core/param/param.cc | 133 +- src/core/param/param.h | 82 +- src/core/param/param_group.h | 7 +- src/core/scheduler.cc | 55 +- src/core/scheduler.h | 36 +- src/core/simulation.cc | 102 +- src/core/simulation.h | 35 +- src/core/simulation_backup.cc | 71 - src/core/simulation_backup.h | 126 - src/core/util/io.cc | 63 +- src/core/util/io.h | 112 - src/core/util/jit.cc | 212 -- src/core/util/jit.h | 93 - src/core/util/plot_memory_layout.cc | 190 -- src/core/util/plot_memory_layout.h | 35 - src/core/util/root.cc | 38 - src/core/util/root.h | 215 -- src/core/visualization/root/adaptor.h | 218 -- src/core/visualization/root/notebook_util.h | 39 - test/installation-test.sh | 7 +- test/system/backup_restore.sh | 59 - test/system/backup_restore/CMakeLists.txt | 29 - .../backup_restore/src/backup_restore.cc | 21 - .../backup_restore/src/backup_restore.h | 80 - test/system/multi_simulation.sh | 50 - test/system/multi_simulation/CMakeLists.txt | 30 - test/system/multi_simulation/optim.json | 27 - .../src/multi_simulation_test.cc | 28 - .../src/multi_simulation_test.h | 62 - .../multi_simulation/src/test_algorithm.cc | 86 - test/unit/core/analysis/time_series_test.cc | 96 +- test/unit/core/command_line_options_test.cc | 2 - .../core/multi_simulation/algorithm_test.cc | 62 - .../multi_simulation/dynamic_loop_test.cc | 64 - .../optimization_param_type_test.cc | 73 - test/unit/core/param/param_test.cc | 158 - test/unit/core/param/test.json | 33 - test/unit/core/scheduler_test.cc | 41 +- test/unit/core/scheduler_test.h | 127 - test/unit/core/simulation_backup_test.cc | 148 - test/unit/core/simulation_test.cc | 590 +--- test/unit/core/util/io_test.cc | 54 - test/unit/test_util/io_test.h | 78 - test/util.inc | 10 +- third_party/OptionParser.h | 2889 ----------------- third_party/cpptoml/cpptoml.h | 1 + util/build-third-party/build-all.sh | 13 +- util/build-third-party/build-paraview.sh | 131 - util/build-third-party/build-qt.sh | 101 - util/build-third-party/build-root.sh | 187 -- util/build-third-party/paraview/build.sh | 145 - .../paraview/checkout-code.sh | 43 - util/build-third-party/paraview/env.sh | 34 - .../paraview/make_macos_pvsdk_relocatable.py | 1347 -------- util/build-third-party/paraview/package.sh | 73 - .../paraview-superbuild-openmp.v5.9.0.patch | 19 - .../paraview/prerequisites.sh | 127 - .../qt-silent-install-linux.js | 67 - .../qt-silent-install-macos.js | 67 - .../third-party-prerequisites.sh | 30 +- util/clean-build-dir.sh | 3 - util/demo_to_notebook.py | 486 --- util/git/pr_checklist.md | 2 +- util/install | 9 +- util/installation/centos-7/Dockerfile | 2 - util/installation/osx/package_list_required | 2 - util/installation/osx/prerequisites.sh | 5 - util/installation/ubuntu-18.04/Dockerfile | 2 - util/installation/ubuntu-20.04/Dockerfile | 2 - util/installation/ubuntu-22.04/Dockerfile | 2 - util/installation/ubuntu-24.04/Dockerfile | 2 - util/makefile-build/bdm-code-generation | 70 - util/valgrind-bdm.supp | 624 ---- util/valgrind.sh | 4 - 206 files changed, 662 insertions(+), 22074 deletions(-) delete mode 100644 .github/workflows/README.md create mode 100644 .github/workflows/ci.yml delete mode 100644 .github/workflows/macos-ci.yml delete mode 100644 .github/workflows/macos-system-ci.yml delete mode 100644 .github/workflows/repository-checks.yml delete mode 100644 .github/workflows/singularity-integration.yml delete mode 100644 .github/workflows/ubuntu-ci.yml delete mode 100644 .github/workflows/ubuntu-system-ci.yml delete mode 100644 cmake/FindROOT.cmake delete mode 100644 cmake/FindTBB.cmake delete mode 100644 cmake/Notebooks.cmake delete mode 100644 cmake/RootUseFile.cmake delete mode 100755 cmake/bdm-dictionary delete mode 100755 cmake/env/sh_functions/paraview delete mode 100755 cmake/env/sh_functions/pvbatch delete mode 100755 cmake/env/sh_functions/pvpython delete mode 100755 cmake/env/sh_functions/root delete mode 100644 cmake/external/ParaView.cmake delete mode 100644 cmake/external/Qt.cmake delete mode 100644 cmake/external/ROOT.cmake delete mode 100644 cmake/selection-libVisualizationAdaptor.xml delete mode 100644 cmake/selection-libbiodynamo.xml delete mode 100644 cmake/selection.xml delete mode 100755 demo/binding_cells/CMakeLists.txt delete mode 100644 demo/binding_cells/analysis.ipynb delete mode 100644 demo/binding_cells/bdm.toml delete mode 100644 demo/binding_cells/params.json delete mode 100755 demo/binding_cells/run.sh delete mode 100644 demo/binding_cells/src/agents/monocyte.h delete mode 100644 demo/binding_cells/src/agents/t_cell.h delete mode 100644 demo/binding_cells/src/binding_cells.cc delete mode 100644 demo/binding_cells/src/binding_cells.h delete mode 100644 demo/binding_cells/src/biology_modules/connect_within_radius_module.h delete mode 100644 demo/binding_cells/src/biology_modules/constant_displacement_module.h delete mode 100644 demo/binding_cells/src/biology_modules/inhibitation_module.h delete mode 100644 demo/binding_cells/src/biology_modules/physical_bond_module.h delete mode 100644 demo/binding_cells/src/biology_modules/random_walk_module.h delete mode 100644 demo/binding_cells/src/biology_modules/spring_force_module.h delete mode 100644 demo/binding_cells/src/biology_modules/stokes_velocity_module.h delete mode 100644 demo/binding_cells/src/macro.C delete mode 100644 demo/binding_cells/src/plot_graph.h delete mode 100644 demo/epidemiology/CMakeLists.txt delete mode 100644 demo/epidemiology/measles.json delete mode 100644 demo/epidemiology/optim.json delete mode 100644 demo/epidemiology/plot-style.json delete mode 100755 demo/epidemiology/render.py delete mode 100755 demo/epidemiology/run.sh delete mode 100644 demo/epidemiology/src/analytical-solution.cc delete mode 100644 demo/epidemiology/src/analytical-solution.h delete mode 100644 demo/epidemiology/src/behavior.h delete mode 100644 demo/epidemiology/src/epidemiology.cc delete mode 100644 demo/epidemiology/src/epidemiology.h delete mode 100644 demo/epidemiology/src/evaluate.h delete mode 100644 demo/epidemiology/src/person.h delete mode 100644 demo/epidemiology/src/sim-param.h delete mode 100644 demo/epidemiology/test.sh delete mode 100755 demo/epidemiology/visualize.sh delete mode 100644 doc/user_guide/docs/notebooks.md delete mode 100644 doc/user_guide/multi_simulation.md delete mode 100644 etc/bdm.rootrc delete mode 100644 notebook/ST01-model-initializer.ipynb delete mode 100644 notebook/ST02-user-defined-random-number-distribution.ipynb delete mode 100644 notebook/ST03-agent-reproduction-mortality.ipynb delete mode 100644 notebook/ST04-agent-reproduction-with-behaviors.ipynb delete mode 100644 notebook/ST05-agent-reproduction-advanced.ipynb delete mode 100644 notebook/ST06-environment-search.ipynb delete mode 100644 notebook/ST07-multi-scale-simulation.ipynb delete mode 100644 notebook/ST08-histograms.ipynb delete mode 100644 notebook/ST09-timeseries-plotting-basic.ipynb delete mode 100644 notebook/ST10-timeseries-plotting-and-analysis.ipynb delete mode 100644 notebook/ST11-multiple-experiments-statistical-analysis.ipynb delete mode 100644 notebook/ST12-hierarchical-model.ipynb delete mode 100644 notebook/ST13-dynamic-scheduling.ipynb delete mode 100644 notebook/ST14-randomize-iteration-order.ipynb delete mode 100644 notebook/ST15-replace-interaction-force.ipynb delete mode 100644 src/core/analysis/line_graph.cc delete mode 100644 src/core/analysis/line_graph.h delete mode 100644 src/core/analysis/style.cc delete mode 100644 src/core/analysis/style.h delete mode 100644 src/core/multi_simulation/algorithm/algorithm.h delete mode 100644 src/core/multi_simulation/algorithm/algorithm_registry.cc delete mode 100644 src/core/multi_simulation/algorithm/algorithm_registry.h delete mode 100644 src/core/multi_simulation/algorithm/parameter_sweep.cc delete mode 100644 src/core/multi_simulation/algorithm/particle_swarm.cc delete mode 100644 src/core/multi_simulation/database.h delete mode 100644 src/core/multi_simulation/dynamic_loop.h delete mode 100644 src/core/multi_simulation/experiment.h delete mode 100644 src/core/multi_simulation/mpi_helper.h delete mode 100644 src/core/multi_simulation/multi_simulation.cc delete mode 100644 src/core/multi_simulation/multi_simulation.h delete mode 100644 src/core/multi_simulation/multi_simulation_manager.cc delete mode 100644 src/core/multi_simulation/multi_simulation_manager.h delete mode 100644 src/core/multi_simulation/optimization_param.h delete mode 100644 src/core/multi_simulation/optimization_param_type/log_range_param.h delete mode 100644 src/core/multi_simulation/optimization_param_type/optimization_param_type.h delete mode 100644 src/core/multi_simulation/optimization_param_type/particle_swarm_param.h delete mode 100644 src/core/multi_simulation/optimization_param_type/range_param.h delete mode 100644 src/core/multi_simulation/optimization_param_type/set_param.h delete mode 100644 src/core/simulation_backup.cc delete mode 100644 src/core/simulation_backup.h delete mode 100644 src/core/util/jit.cc delete mode 100644 src/core/util/jit.h delete mode 100644 src/core/util/plot_memory_layout.cc delete mode 100644 src/core/util/plot_memory_layout.h delete mode 100644 src/core/util/root.cc delete mode 100644 src/core/util/root.h delete mode 100644 src/core/visualization/root/adaptor.h delete mode 100644 src/core/visualization/root/notebook_util.h delete mode 100755 test/system/backup_restore.sh delete mode 100644 test/system/backup_restore/CMakeLists.txt delete mode 100644 test/system/backup_restore/src/backup_restore.cc delete mode 100644 test/system/backup_restore/src/backup_restore.h delete mode 100755 test/system/multi_simulation.sh delete mode 100644 test/system/multi_simulation/CMakeLists.txt delete mode 100644 test/system/multi_simulation/optim.json delete mode 100644 test/system/multi_simulation/src/multi_simulation_test.cc delete mode 100644 test/system/multi_simulation/src/multi_simulation_test.h delete mode 100644 test/system/multi_simulation/src/test_algorithm.cc delete mode 100644 test/unit/core/multi_simulation/algorithm_test.cc delete mode 100644 test/unit/core/multi_simulation/dynamic_loop_test.cc delete mode 100644 test/unit/core/multi_simulation/optimization_param_type_test.cc delete mode 100644 test/unit/core/param/param_test.cc delete mode 100644 test/unit/core/param/test.json delete mode 100644 test/unit/core/scheduler_test.h delete mode 100644 test/unit/core/simulation_backup_test.cc delete mode 100644 test/unit/core/util/io_test.cc delete mode 100644 test/unit/test_util/io_test.h delete mode 100644 third_party/OptionParser.h delete mode 100755 util/build-third-party/build-paraview.sh delete mode 100755 util/build-third-party/build-qt.sh delete mode 100755 util/build-third-party/build-root.sh delete mode 100755 util/build-third-party/paraview/build.sh delete mode 100755 util/build-third-party/paraview/checkout-code.sh delete mode 100755 util/build-third-party/paraview/env.sh delete mode 100755 util/build-third-party/paraview/make_macos_pvsdk_relocatable.py delete mode 100755 util/build-third-party/paraview/package.sh delete mode 100644 util/build-third-party/paraview/paraview-superbuild-openmp.v5.9.0.patch delete mode 100755 util/build-third-party/paraview/prerequisites.sh delete mode 100644 util/build-third-party/qt-silent-install-linux.js delete mode 100644 util/build-third-party/qt-silent-install-macos.js delete mode 100644 util/demo_to_notebook.py delete mode 100755 util/makefile-build/bdm-code-generation delete mode 100644 util/valgrind-bdm.supp diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6a612a823..46828bd1e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,74 +1,45 @@ -FROM ubuntu:20.04 +FROM ubuntu:24.04 ENV DEBIAN_FRONTEND=noninteractive ENV TZ=Europe/Berlin -ENV PYENV_ROOT="/opt/.pyenv" -ENV PATH="$PYENV_ROOT/bin:$PATH" -ENV PATH="/opt/.pyenv/versions/3.9.1/bin/:$PATH" ENV DISPLAY=:1 ENV XDG_RUNTIME_DIR=/tmp/runtime-root -RUN unset Qt5_DIR ParaView_DIR ROOT_INCLUDE_PATH CMAKE_PREFIX_PATH PYENV_ROOT BDMSYS CC CXX - -RUN apt-get -y update && \ - apt-get -y install apt-utils software-properties-common python python3 git curl make gcc g++ wget \ - wamerican libffi-dev libncurses5-dev zlib1g zlib1g-dev bzip2 aptitude libreadline-dev libssl-dev \ - libsqlite3-dev openmpi-bin libopenmpi-dev libxkbcommon-x11-dev bsdmainutils clang clang-format \ - clang-tidy doxygen graphviz libxml2-dev llvm-7 llvm-7-dev llvm-7-runtime valgrind libgsl-dev \ - freeglut3-dev libbz2-dev libnuma-dev libomp5 libomp-dev libpthread-stubs0-dev zlib1g-dev \ - libffi-dev liblzma-dev libreadline-dev libsqlite3-dev libssl-dev python-openssl tk-dev xz-utils \ - zlib1g-dev sudo libblas-dev liblapack-dev nano locales locales-all ninja-build python3-pip \ - freeglut3-dev valgrind xvfb libtbb-dev \ - x11vnc fluxbox websockify \ - novnc dbus-x11 x11-utils x11-xserver-utils xterm && \ - dpkg-reconfigure locales && locale-gen && \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + ca-certificates cmake curl fluxbox g++ gcc git libblas-dev libboost-dev \ + libdouble-conversion-dev liblapack-dev libnuma-dev libomp-dev \ + libopenmpi-dev libutfcpp-dev ninja-build novnc openmpi-bin paraview \ + paraview-dev python3 sudo websockify wget x11-utils x11vnc \ + x11-xserver-utils xterm xvfb && \ apt-get clean && rm -rf /var/lib/apt/lists/* -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash && \ - eval "$(pyenv init --path)" && \ - eval "$(pyenv init -)" && \ - PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.1 && \ - pyenv global 3.9.1 && \ - pyenv shell 3.9.1 - -RUN wget https://bootstrap.pypa.io/get-pip.py && \ - python3 get-pip.py && \ - python3 -m pip install -U pip && \ - python3 -m pip install numpy - -RUN pip install 'cmake<4' - RUN git config --system user.name "Test User" && \ git config --system user.email user@test.com -RUN export BDM_BRANCH="master" && \ - git clone https://github.com/BioDynaMo/biodynamo.git && \ - cd biodynamo && \ - git checkout $BDM_BRANCH && \ - git rev-parse HEAD > /commit_hash.txt && \ - cat /commit_hash.txt && \ - mkdir build && \ - cd build && \ - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -Dtest=OFF -Dgtest=OFF -Dbenchmark=OFF \ - -Dparaview=ON -DCMAKE_POLICY_DEFAULT_CMP0048=NEW -DCMAKE_POLICY_DEFAULT_CMP0054=NEW \ - -DCMAKE_POLICY_DEFAULT_CMP0056=NEW -DCMAKE_POLICY_DEFAULT_CMP0066=NEW \ - -DCMAKE_POLICY_DEFAULT_CMP0067=NEW -DCMAKE_POLICY_DEFAULT_CMP0074=NEW .. && \ - ninja -j $(($(nproc) - 1)) +RUN git clone --depth 1 --branch master https://github.com/BioDynaMo/biodynamo.git /biodynamo && \ + cmake -S /biodynamo -B /biodynamo/build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dopencl=OFF \ + -Dparaview=ON \ + -Dsbml=OFF \ + -Dtest=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Release && \ + cmake --build /biodynamo/build --parallel RUN useradd -m -s /bin/bash codespace && \ - echo "codespace ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - -RUN mkdir -p /tmp/runtime-root && chmod 700 /tmp/runtime-root + echo "codespace ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers && \ + mkdir -p /tmp/runtime-root /opt/scripts && \ + chmod 700 /tmp/runtime-root RUN echo 'source /biodynamo/build/bin/thisbdm.sh 2>/dev/null' >> /etc/bash.bashrc COPY novnc-index.html /usr/share/novnc/index.html - -RUN mkdir -p /opt/scripts -COPY start-vnc.sh /opt/scripts/start-vnc.sh -RUN chmod +x /opt/scripts/start-vnc.sh -COPY demo-picker.sh /opt/scripts/demo-picker.sh -RUN chmod +x /opt/scripts/demo-picker.sh +COPY start-vnc.sh demo-picker.sh /opt/scripts/ +RUN chmod +x /opt/scripts/start-vnc.sh /opt/scripts/demo-picker.sh COPY paraview-wrapper.sh /usr/local/bin/paraview RUN chmod +x /usr/local/bin/paraview diff --git a/.devcontainer/paraview-wrapper.sh b/.devcontainer/paraview-wrapper.sh index 7b9829b50..b468e3da1 100644 --- a/.devcontainer/paraview-wrapper.sh +++ b/.devcontainer/paraview-wrapper.sh @@ -6,6 +6,4 @@ echo "Switch to the port 6080 browser tab to see the GUI." echo "If not open yet: Ports tab -> 6080 -> Open in Browser" echo "" -# Find the real paraview binary (skip this wrapper) -REAL_PARAVIEW=$(which -a paraview | grep -v /usr/local/bin | head -1) -exec "$REAL_PARAVIEW" "$@" +exec /usr/bin/paraview "$@" diff --git a/.github/workflows/README.md b/.github/workflows/README.md deleted file mode 100644 index 3994bb307..000000000 --- a/.github/workflows/README.md +++ /dev/null @@ -1,11 +0,0 @@ -Debug github actions. - -Add the following step before the failing step. -ssh into the tmate session immediately. -Otherwise the session times out and doesn't accept any input. - -``` - - name: Setup tmate session - uses: mxschmitt/action-tmate@v2 -``` - diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..b8eee0d48 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,173 @@ +name: CI + +on: + push: + pull_request: + branches: [master] + schedule: + - cron: '0 3 * * *' + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + linux: + strategy: + fail-fast: false + matrix: + os: [ubuntu-22.04, ubuntu-24.04] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libblas-dev libboost-dev liblapack-dev libnuma-dev libomp-dev \ + libopenmpi-dev ninja-build + - name: Configure + run: | + cmake -S . -B build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dopencl=OFF \ + -Dparaview=OFF \ + -Dsbml=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Release + - name: Build + run: cmake --build build --parallel + - name: Test + run: cmake --build build --target run-unit-tests + + macos: + strategy: + fail-fast: false + matrix: + os: [macos-14, macos-15] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: brew install boost cmake libomp ninja open-mpi + - name: Configure + run: | + cmake -S . -B build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dopencl=OFF \ + -Dparaview=OFF \ + -Dsbml=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Release + - name: Build + run: cmake --build build --parallel + - name: Test + run: cmake --build build --target run-unit-tests + + paraview: + runs-on: ubuntu-24.04 + env: + QT_QPA_PLATFORM: offscreen + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libblas-dev libboost-dev liblapack-dev libomp-dev \ + libdouble-conversion-dev libopenmpi-dev libutfcpp-dev ninja-build \ + paraview paraview-dev + - name: Configure + run: | + cmake -S . -B build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dnuma=OFF \ + -Dopencl=OFF \ + -Dparaview=ON \ + -Dsbml=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Release + - name: Build + run: cmake --build build --parallel + - name: Test + run: cmake --build build --target run-unit-tests + + sanitizers: + runs-on: ubuntu-24.04 + env: + ASAN_OPTIONS: detect_leaks=1:halt_on_error=1 + UBSAN_OPTIONS: halt_on_error=1:print_stacktrace=1 + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y \ + libblas-dev libboost-dev liblapack-dev libomp-dev \ + libopenmpi-dev ninja-build + - name: Configure + run: | + cmake -S . -B build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dnuma=OFF \ + -Dopencl=OFF \ + -Dparaview=OFF \ + -Dsbml=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Debug \ + -DCMAKE_C_FLAGS='-fsanitize=address,undefined -fno-omit-frame-pointer' \ + -DCMAKE_CXX_FLAGS='-fsanitize=address,undefined -fno-omit-frame-pointer' \ + -DCMAKE_EXE_LINKER_FLAGS='-fsanitize=address,undefined' \ + -DCMAKE_SHARED_LINKER_FLAGS='-fsanitize=address,undefined' + - name: Build + run: cmake --build build --parallel + - name: Test + run: cmake --build build --target run-unit-tests + + singularity: + runs-on: ubuntu-24.04 + container: + image: quay.io/singularity/singularity:v3.9.0 + options: --privileged --workdir /data + steps: + - uses: actions/checkout@v4 + - name: Configure fakeroot + run: | + echo root:100000:65536 >> /etc/subuid + echo root:100000:65536 >> /etc/subgid + - name: Build image + run: singularity build --fakeroot biodynamo.sif Singularity + - name: Run demo + run: | + singularity exec --cleanenv biodynamo.sif bash -lc ' + source /biodynamo/build/bin/thisbdm.sh + cd "$(mktemp -d)" + bdm demo tumor_concept + cd tumor_concept + bdm run' + + repository: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y clang-format + - name: Check formatting + run: | + ./util/housekeeping/run-clang-format.sh \ + "$(pwd)" clang-format 0 $(./util/housekeeping/get-all-src-files.sh .) + - name: Check copyright + run: | + ./util/housekeeping/check-copyright.sh \ + util/housekeeping/copyright_cpp.txt \ + $(./util/housekeeping/get-all-src-files.sh .) diff --git a/.github/workflows/macos-ci.yml b/.github/workflows/macos-ci.yml deleted file mode 100644 index 45b19a546..000000000 --- a/.github/workflows/macos-ci.yml +++ /dev/null @@ -1,61 +0,0 @@ -name: macOS CI - -on: - push: - pull_request: - branches: - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - matrix: - os: [macos-14, macos-15] - - runs-on: ${{ matrix.os }} - - steps: - - name: Install dependencies - run: | - export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 - # GHA macOS: unpin CMake to fix Homebrew conflict (actions/runner-images#12912) - brew uninstall --force cmake || true - brew untap local/pinned || true - brew install libomp open-mpi python@3.9 wget cmake ninja qt@5 libgit2 boost - - - name: Checkout BioDynaMo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # - name: Cache Third Party Packages - # uses: actions/cache@v4 - # with: - # path: build/third_party - # key: ${{ runner.os }}-third-party-${{ hashFiles('cmake/external/SHA256Digests.cmake') }} - - - name: Build BioDynaMo - shell: bash - run: | - cmake -G Ninja \ - -Dopencl=OFF \ - -Dparaview=ON \ - -Dbenchmark=ON \ - -Dlibgit2=ON \ - -DCMAKE_BUILD_TYPE=Release \ - -B build - cmake --build build --parallel --config Release - - - name: Unit tests BioDynaMo - shell: bash - working-directory: build - run: | - . bin/thisbdm.sh - root --version - root -config - bdm config - ninja run-unit-tests diff --git a/.github/workflows/macos-system-ci.yml b/.github/workflows/macos-system-ci.yml deleted file mode 100644 index cc0b46270..000000000 --- a/.github/workflows/macos-system-ci.yml +++ /dev/null @@ -1,114 +0,0 @@ -# Runs the installation tests in the following cases: -# 1) every day at 3 am -# 2) a pull request to the master branch - -name: macOS System CI - -on: - schedule: - # Every day at 3 am - - cron: '0 3 * * *' - pull_request: - # Upon pull requests - branches: - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - matrix: - os: [macos-14, macos-15] - - runs-on: ${{ matrix.os }} - - steps: - - name: Set GHA_BRANCH_NAME - run: | - if [ "${{ github.event_name }}" = "push" ]; then - echo "GHA_BRANCH_NAME=${GITHUB_REF##*/}" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "GHA_BRANCH_NAME=${{ github.head_ref }}" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "schedule" ]; then - echo "GHA_BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - fi - - echo "GHA_REPOSITORY=${{ github.event.pull_request.head.repo.full_name || github.repository }}" >> $GITHUB_ENV - - - name: Install BioDynaMo - shell: zsh {0} - run: | - brew install curl - # GHA macOS: unpin CMake to fix Homebrew conflict (actions/runner-images#12912) - brew uninstall --force cmake || true - brew untap local/pinned || true - curl https://raw.githubusercontent.com/${GHA_REPOSITORY}/${GHA_BRANCH_NAME}/util/install | bash - # remove whole bidynamo repository to catch errors related to paths pointing into the build dir - mktemp -d - find /tmp -iname biodynamo -type d || true - rm -rf $(find $(mktemp -d)/../* -maxdepth 1 -iname biodynamo -type d 2>/dev/null) - echo "Removed" - find /tmp -iname biodynamo -type d || true - - - name: Checkout BioDynaMo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set INSTALL_DIR - run: | - if [ "${{ github.event_name }}" = "push" ]; then - echo "INSTALL_DIR=${GITHUB_WORKSPACE}/build" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "INSTALL_DIR=${GITHUB_WORKSPACE}/build" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "schedule" ]; then - echo "INSTALL_DIR=$(echo ${HOME}/biodynamo-*)" >> $GITHUB_ENV - fi - - # - name: Cache Third Party Packages - # uses: actions/cache@v4 - # with: - # path: build/third_party - # key: ${{ runner.os }}-third-party-${{ hashFiles('cmake/external/SHA256Digests.cmake') }} - - - name: Build BioDynaMo - shell: zsh {0} - run: | - cmake \ - -Dopencl=OFF \ - -Dparaview=ON \ - -Dbenchmark=ON \ - -Dlibgit2=ON \ - -DCMAKE_BUILD_TYPE=Release \ - -B build - cmake --build build --parallel --config Release - - # Don't do this in the `Build BioDynaMo step`, because notebooks might time out in GHA - # runners, while waiting for other targets to be compiled. Run notebooks only on - # macOS 10.15 until we managed to compile ROOT for 11.6 again. - - name: Run notebooks - shell: zsh {0} - run: | - cmake \ - -Dnotebooks=ON \ - -B build - cmake --build build --parallel --config Release --target notebooks -- -j1 - if: matrix.os == 'macos-10.15' - - - name: System tests BioDynaMo - shell: zsh {0} - working-directory: build - run: | - source $(find /Users -path "*/bin/*" -name "*thisbdm.sh") - root --version - root -config - git config --system user.name "Test User" - git config --system user.email user@test.com - make run-demos diff --git a/.github/workflows/repository-checks.yml b/.github/workflows/repository-checks.yml deleted file mode 100644 index 95bba694c..000000000 --- a/.github/workflows/repository-checks.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: repository-check - -on: - push: - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - code-style: - runs-on: ubuntu-22.04 - - steps: - - - name: Install dependencies - run: | - sudo apt update - sudo apt install clang-format - - - name: Checkout BioDynaMo - uses: actions/checkout@v4 - - - name: Run clang-format code style check - run: | - ./util/housekeeping/run-clang-format.sh $(pwd) clang-format 0 $(./util/housekeeping/get-all-src-files.sh .) - - - name: Check if Copyright information is correct - run: | - ./util/housekeeping/check-copyright.sh util/housekeeping/copyright_cpp.txt $(util/housekeeping/get-all-src-files.sh .) diff --git a/.github/workflows/singularity-integration.yml b/.github/workflows/singularity-integration.yml deleted file mode 100644 index 5a7295eda..000000000 --- a/.github/workflows/singularity-integration.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Singularity Integration - -on: - push: - branches: - - master - pull_request: - types: [opened, synchronize, reopened] - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - name: Build - runs-on: ubuntu-latest - container: - image: quay.io/singularity/singularity:v4.3.1 - options: "--privileged --workdir /data" - steps: - - uses: actions/checkout@v4 - - - name: Add root user to subuid and subgid... - run: | - echo root:100000:65536 >> /etc/subuid - echo root:100000:65536 >> /etc/subgid - - - name: Set correct branch... - run: | - export GITHUB_BRANCH_NAME=${{ github.head_ref || github.ref_name }} - sed -i "s|BDM_BRANCH=\"master\"|BDM_BRANCH=\"$GITHUB_BRANCH_NAME\"|" Singularity - - - name: Build singularity image... - run: | - chmod 777 . - singularity build --fakeroot Singularity.sif Singularity - - - name: Source Biodynamo and run demo... - run: | - singularity exec --cleanenv -i Singularity.sif bash -c "source /biodynamo/build/third_party/root/bin/thisroot.sh && source /biodynamo/build/bin/thisbdm.sh && \ - export DISPLAY=:99.0 && /biodynamo/util/xvfb-initd.sh start && cd $(mktemp -d) && bdm demo tumor_concept && cd tumor_concept && bdm clean && bdm run" diff --git a/.github/workflows/ubuntu-ci.yml b/.github/workflows/ubuntu-ci.yml deleted file mode 100644 index 5c5c2823b..000000000 --- a/.github/workflows/ubuntu-ci.yml +++ /dev/null @@ -1,132 +0,0 @@ -name: Ubuntu CI - -on: - push: - pull_request: - branches: - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - matrix: - os: [ubuntu-22.04, ubuntu-24.04] - runs-on: ${{ matrix.os }} - - steps: - - name: Set python openssl package - run: | - if [ "${{ env.OSVERS }}" = "ubuntu-20.04" ]; then - echo "PYOPENSSL=python-openssl" >> $GITHUB_ENV - fi - if [ "${{ env.OSVERS }}" = "ubuntu-22.04" ]; then - echo "PYOPENSSL=python3-openssl" >> $GITHUB_ENV - fi - if [ "${{ env.OSVERS }}" = "ubuntu-24.04" ]; then - echo "PYOPENSSL=python3-openssl" >> $GITHUB_ENV - fi - - - name: Install dependencies - run: | - sudo apt-get update - sudo apt-get install -y libopenmpi-dev gcc-11 g++-11 libomp5 libomp-dev libnuma-dev freeglut3-dev \ - libreadline-dev libsqlite3-dev tk-dev ${{ env.PYOPENSSL }} ninja-build libblas-dev liblapack-dev libgit2-dev \ - libboost-dev - curl -L -O https://github.com/Kitware/CMake/releases/download/v3.19.3/cmake-3.19.3-Linux-x86_64.sh - chmod +x cmake-3.19.3-Linux-x86_64.sh - sudo ./cmake-3.19.3-Linux-x86_64.sh --skip-license --prefix=/usr/local - - - name: Start Xvfb - run: | - set -e - sudo apt-get -y install xvfb - XVFBARGS=":99 -ac -screen 0 2560x1440x24" - /usr/bin/Xvfb $XVFBARGS >> /tmp/Xvfb.out 2>&1 & - disown -ar - sleep 3 - - - name: Set OSVERS - run: | - ID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"') - VERSION=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"') - echo "OSVERS=$ID-$VERSION" >> $GITHUB_ENV - - - name: Cache pyenv - uses: actions/cache@v4 - id: pyenv-cache - with: - path: ~/.pyenv - key: ${{ env.OSVERS }}-pyenv-3.9.1 - - - name: Install pyenv dependency - if: steps.pyenv-cache.outputs.cache-hit != 'true' - run: | - if [ ! -f "$HOME/.pyenv/bin/pyenv" ]; then - curl https://pyenv.run | bash - fi - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.1 - pyenv shell 3.9.1 - - - name: Checkout BioDynaMo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Cache Third Party Packages - uses: actions/cache@v4 - with: - path: build/third_party - key: ${{ env.OSVERS }}-third-party-${{ hashFiles('cmake/external/SHA256Digests.cmake') }} - - - name: Build BioDynaMo - shell: bash - run: | - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv shell 3.9.1 - cmake -G Ninja \ - -Dparaview=ON \ - -Dbenchmark=ON \ - -Dlibgit2=ON \ - -DCMAKE_BUILD_TYPE=Release \ - -B build - cmake --build build --parallel --config Release - - - name: Unit tests BioDynaMo - shell: bash - working-directory: build - run: | - . bin/thisbdm.sh - bdm config - export DISPLAY=:99.0 - ninja run-unit-tests - - - name: Style guide checks - shell: bash - run: | - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv shell 3.9.1 - wget https://apt.llvm.org/llvm-snapshot.gpg.key - sudo apt-key add llvm-snapshot.gpg.key - sudo add-apt-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" - sudo apt update - sudo apt install -y cloc clang-tidy clang-format - cloc --exclude-dir=build . - cmake -B build - cd build - cmake --build . --target fetch-master - cmake --build . --target gtest || true - cmake --build . --target show-format || true - cmake --build . --target show-tidy || true - cmake --build . --target check-cpplint || true - if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-22.04' diff --git a/.github/workflows/ubuntu-system-ci.yml b/.github/workflows/ubuntu-system-ci.yml deleted file mode 100644 index 78fb49199..000000000 --- a/.github/workflows/ubuntu-system-ci.yml +++ /dev/null @@ -1,173 +0,0 @@ -# Runs the installation tests and valgrind tests in the following cases: -# 1) every day at 3 am -# 2) a pull request to the master branch - -name: Ubuntu System CI - -on: - schedule: - # Every day at 3 am - - cron: '0 3 * * *' - pull_request: - # Upon pull requests - branches: - - master - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -jobs: - build: - strategy: - matrix: - os: [ubuntu-22.04, ubuntu-24.04] - runs-on: ${{ matrix.os }} - - steps: - - name: Set GHA_BRANCH_NAME - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "GHA_BRANCH_NAME=${{ github.head_ref }}" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "schedule" ]; then - echo "GHA_BRANCH_NAME=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV - fi - - echo "GHA_REPOSITORY=${{ github.event.pull_request.head.repo.full_name || github.repository }}" >> $GITHUB_ENV - - - name: Set OSVERS - run: | - ID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"') - VERSION=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"') - echo "OSVERS=$ID-$VERSION" >> $GITHUB_ENV - - - name: Start Xvfb - run: | - set -e - sudo apt update - sudo apt-get -y install xvfb - XVFBARGS=":99 -ac -screen 0 2560x1440x24" - /usr/bin/Xvfb $XVFBARGS >> /tmp/Xvfb.out 2>&1 & - disown -ar - sleep 3 - - - name: Install BioDynaMo - shell: bash - run: | - sudo apt update - sudo apt install -y curl - curl https://raw.githubusercontent.com/${GHA_REPOSITORY}/${GHA_BRANCH_NAME}/util/install | bash - # remove whole bidynamo repository to catch errors related to paths pointing into the build dir - mktemp -d - find /tmp -iname biodynamo -type d || true - rm -rf $(find $(mktemp -d)/../* -maxdepth 1 -iname biodynamo -type d 2>/dev/null) - echo "Removed" - find /tmp -iname biodynamo -type d || true - - - name: Checkout BioDynaMo - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Set INSTALL_DIR - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "INSTALL_DIR=${GITHUB_WORKSPACE}/build" >> $GITHUB_ENV - fi - if [ "${{ github.event_name }}" = "schedule" ]; then - echo "INSTALL_DIR=$(echo ${HOME}/biodynamo-*)" >> $GITHUB_ENV - fi - - - name: Cache pyenv - uses: actions/cache@v4 - id: pyenv-cache - with: - path: ~/.pyenv - key: ${{ env.OSVERS }}-pyenv-3.9.1 - - - name: Install pyenv dependency - if: steps.pyenv-cache.outputs.cache-hit != 'true' - run: | - if [ ! -f "$HOME/.pyenv/bin/pyenv" ]; then - curl https://pyenv.run | bash - fi - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - if [ ! -f "$HOME/.pyenv/versions/3.9.1/lib/libpython3.so" ]; then - PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.1 - fi - pyenv shell 3.9.1 - - - name: Cache Third Party Packages - uses: actions/cache@v4 - with: - path: build/third_party - key: ${{ env.OSVERS }}-third-party-${{ hashFiles('cmake/external/SHA256Digests.cmake') }} - - # Set floating point precision - - name: Set floating-point-precision - run: | - if [ "${{ env.OSVERS }}" = "ubuntu-20.04" ]; then - echo "REALT=float" >> $GITHUB_ENV - fi - if [ "${{ env.OSVERS }}" = "ubuntu-22.04" ]; then - echo "REALT=double" >> $GITHUB_ENV - fi - if [ "${{ env.OSVERS }}" = "ubuntu-24.04" ]; then - echo "REALT=double" >> $GITHUB_ENV - fi - - # Don't do this in the `Build BioDynaMo step`, because notebooks might time out in GHA - # runners, while waiting for other targets to be compiled. Run notebooks only - # if the event is a pull request, and on ubuntu-22.04. - - name: Run notebooks - shell: bash - run: | - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv shell 3.9.1 - cmake \ - -Dnotebooks=ON \ - -Dsbml=OFF \ - -Dnuma=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -Dreal_t=${{ env.REALT }} \ - -B build - cmake --build build --parallel --config Release --target notebooks -- -j1 - if: github.event_name == 'pull_request' && matrix.os == 'ubuntu-22.04' - - - - name: Build BioDynaMo - shell: bash - run: | - export PATH="$HOME/.pyenv/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv shell 3.9.1 - cmake \ - -Dnotebooks=OFF \ - -Dparaview=ON \ - -Dbenchmark=ON \ - -Dlibgit2=ON \ - -Dsbml=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -Dreal_t=${{ env.REALT }} \ - -B build - cmake --build build --config Release - - - name: Run valgrind and system tests - shell: bash - working-directory: build - run: | - . $INSTALL_DIR/bin/thisbdm.sh - sudo git config --system user.name "Test User" - sudo git config --system user.email user@test.com - export DISPLAY=:99.0 - biodynamo new test-sim - . ../test/util.inc - run_cmake_simulation test-sim - make run-valgrind - make run-demos diff --git a/CMakeLists.txt b/CMakeLists.txt index 8856b2f5c..a8c27a23e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,9 +137,7 @@ option(test "Build all tests." ON) # Makes boolean 'test' available. option(benchmark "Build benchmark suite." OFF) option(cuda "Enable CUDA code generation for GPU acceleration" OFF) option(opencl "Enable OpenCL code generation for GPU acceleration" OFF) -option(dict "Build with ROOT dictionaries" ON) -option(paraview "Enable ParaView" ON) -option(notebooks "Generate BioDynaMo notebooks" OFF) +option(paraview "Enable ParaView" OFF) option(numa "Enable NUMA-awareness in BioDynaMo." ON) option(sbml "Enable SBML" OFF) option(libgit2 "Enable automatic git documentation for simulations." OFF) @@ -155,9 +153,6 @@ option(real_t "Define data type for real numbers. Currently supported: float, option(boost "Enable Boost-based behaviors (e.g. RegulatoryNetwork)." ON) if(APPLE) - # ParaView on Apple devices - set(CMAKE_BDM_PVVERSION "5.10") - # Ignore Fink (/sw) and MacPorts (/opt/local) packages, only consider Brew set(CMAKE_IGNORE_PATH) foreach(_prefix /sw /opt/local) @@ -166,7 +161,6 @@ if(APPLE) endif() if(UNIX AND NOT APPLE) - set(CMAKE_BDM_PVVERSION "5.9") set(LINUX TRUE) add_definitions("-DLINUX") endif() @@ -178,12 +172,6 @@ if(real_t) add_definitions("-DBDM_REALT=${real_t}") add_definitions("-DBDM_CL_REALT=cl_${real_t}") set(BDM_CONFIG_REALT "${real_t}") - if(notebooks AND real_t STREQUAL "float") - # This if statement turns of the notebooks when we run with real_t=float. - # Currently, the notebooks do not support BDM with float for unknown reasons. - message(WARNING "Notebooks are not supported with real_t=float. Disabling notebooks.") - set(notebooks OFF) - endif() else() message(STATUS "Using default real_t (double)") set(BDM_CONFIG_REALT "float") @@ -220,40 +208,7 @@ if (jemalloc) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ljemalloc -L ${JEMALLOC_LIBRARY_DIR}") endif() -if (APPLE) - set(NOPYENV YES) -endif() - - -if(NOPYENV) - # On macOS - # need to give hint which binary to find, however ideally it should be taken from the range spec - set(Python3_EXECUTABLE "${BREW_PREFIX}/bin/python3.9") - find_package(Python3 3.9.1...<3.10 COMPONENTS Interpreter Development) - set(pythonvers ${Python_VERSION}) - if (NOT Python3_FOUND) - message(FATAL_ERROR "We did not find the Python 3.9 interpreter. " - "Please run ./prerequisites.sh (or \"brew install python@3.9\") " - "again before calling cmake. The Python 3.9 interpreter " - "is required in order to successfully use BioDynaMo.") - endif() -else() - # Check if Python 3.9.1 from PyEnv is installed - set(pythonvers "3.9.1") - find_package(Python ${pythonvers} EXACT COMPONENTS Interpreter Development) - if (NOT Python_FOUND) - message(FATAL_ERROR "We did not find the Python ${pythonvers} interpreter from PyEnv. " - "Make sure you executed \"pyenv shell ${pythonvers}\" before running cmake. " - "If that doesn't work, run ./prerequisites.sh again. The Python ${pythonvers} " - "interpreter is required in order to successfully use BioDynaMo." - "You may also try the following sequence of commands that has often resolved" - "the problem: \n" - "export PATH=\"$HOME/.pyenv/bin:$PATH\" \n" - "eval \"$(pyenv init --path)\" \n" - "eval \"$(pyenv init -)\" \n" - "pyenv shell ${pythonvers}") - endif() -endif() +find_package(Python3 REQUIRED COMPONENTS Interpreter) # Check if OpenMPI is present find_package(MPI COMPONENTS C CXX) @@ -270,18 +225,6 @@ if(APPLE) set(numa OFF) endif() -# Check if GLUT is present. If we do not have it, then we disable directly paraview. -if(paraview) - find_package(GLUT) - if(NOT GLUT_FOUND) - PRINT_WARNING() - MESSAGE("GLUT libraries were not found. In order to use ParaView they need to be installed. - Please run ./prerequisites.sh before calling cmake.") - PRINT_LINE() - SET(paraview OFF) - endif() -endif() - if(APPLE) # After migrating to libomp 15.0.3, libomp is no longer symlinked into # $(brew --prefix)/lib/libomp.dylib. Instead, it is located in @@ -304,7 +247,6 @@ calling cmake.") endif() if (test) - # must be before include(${ROOT_USE_FILE}) otherwise test compile fails find_package(Threads) endif() @@ -331,13 +273,6 @@ endif() # Check if we have git installed find_package(Git) -# Find ROOT and check its installation -find_package(ROOT COMPONENTS Geom Gui GenVector) -verify_ROOT() - -if (dict) - add_definitions("-DUSE_DICT") -endif() find_package(ClangTools) if ("$ENV{CMAKE_EXPORT_COMPILE_COMMANDS}" STREQUAL "1" OR CLANG_TIDY_FOUND) # Generate a Clang compile_commands.json "compilation database" file for use @@ -357,88 +292,11 @@ if(numa) endif() if(paraview) - # If we specify a custom location for ParaView then we need to specify also a custom location for Qt. - if ((DEFINED ENV{ParaView_DIR} AND NOT DEFINED ENV{Qt5_DIR}) OR (NOT DEFINED ENV{ParaView_DIR} AND DEFINED ENV{Qt5_DIR})) - MESSAGE(FATAL_ERROR "\nFATAL ERROR \nYou need to specify both ParaView_DIR and Qt5_DIR in order to build " - "BioDynaMo. This is needed only if you want to use your own versions of ParaView and Qt.") - endif() - - # If Qt5_DIR is not set by the user, we will set it to the default directory - # where it's downloaded to. This is done in case the user runs CMake again, - # after which the find_package(ParaView) might complain that it can't find - # a compatible Qt5 installation - if(NOT DEFINED Qt5_DIR OR NOT DEFINED ${Qt5_DIR}) - if(APPLE) - set(Qt5_DIR ${BREW_PREFIX}/opt/qt@5/lib/cmake/Qt5) - set(QT_CMAKE_DIR ${BREW_PREFIX}/opt/qt@5/lib/cmake/Qt5) - set(DYLD_LIBRARY_PATH ${DYLD_LIBRARY_PATH} ${BREW_PREFIX}/opt/qt@5/lib) - else() - set(Qt5_DIR ${CMAKE_THIRD_PARTY_DIR}/qt/lib/cmake/Qt5) - endif(APPLE) - endif() - # Check the first time if ParaView exists in the system. - find_package(ParaView ${CMAKE_BDM_PVVERSION} CONFIG COMPONENTS Catalyst PythonCatalyst VTKExtensionsIOCore - PATHS ${CMAKE_THIRD_PARTY_DIR}/paraview ENV{ParaView_DIR}) - - if(ParaView_FOUND) - # Check if found ParaView is BDM installed (matchres > -1) - string(FIND ${ParaView_PREFIX_PATH} ${CMAKE_THIRD_PARTY_DIR} matchres) - if (${matchres} GREATER -1) - # check SHA256 of ParaView to see if it matches currently supported ParaView - if (IS_DIRECTORY ${CMAKE_THIRD_PARTY_DIR}/paraview) - if (EXISTS ${CMAKE_THIRD_PARTY_DIR}/paraview/tar-sha256) - # check if SHA256 of installed ParaView is the same as the expected one - file(READ ${CMAKE_THIRD_PARTY_DIR}/paraview/tar-sha256 TAR_SHA256) - if(NOT "${TAR_SHA256}" STREQUAL "${${DETECTED_OS_VERS}-ParaView}") - # BDM installed ParaView has wrong SHA256... deleting it - message(WARNING "The found ParaView version is not compatible... deleting it...") - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/paraview) - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/qt) - unset(ParaView_FOUND) - endif() - else() - # BDM installed ParaView exists but no SHA256 file... deleting it - message(WARNING "The found ParaView version cannot be determined... deleting it...") - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/paraview) - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/qt) - unset(ParaView_FOUND) - endif() - endif() - endif() - endif() - - if(NOT ParaView_FOUND) - - # If we did not found paraview then we will install it automatically with the Qt package. - if(APPLE) - PRINT_WARNING() - MESSAGE("We did not find any ParaView installed on the system. We will proceed to download it. " - "ParaView will be installed in the location ${CMAKE_THIRD_PARTY_DIR}/paraview. " - "Using brew Qt5 in ${Qt5_DIR} for ParaView.") - PRINT_LINE() - else() - PRINT_WARNING() - MESSAGE("We did not find any ParaView installed on the system. We will proceed to download it " - "together with Qt5. ParaView will be installed in the location ${CMAKE_THIRD_PARTY_DIR}/paraview.") - PRINT_LINE() - include(external/Qt) - PRINT_LINE() - MESSAGE("Qt5 was successfully downloaded and installed. We will proceed now with ParaView.") - endif(APPLE) - PRINT_LINE() - include(external/ParaView) - - # We run again the find_package command such to find correctly the location of Qt and ParaView - find_package(Qt5 REQUIRED COMPONENTS Widgets HINTS ${Qt5_DIR} NO_CMAKE_PATH NO_CMAKE_ENVIRONMENT_PATH) - if(Qt5_FOUND) - message("-- Found Qt5 (version ${Qt5_VERSION})") - endif() - find_package(ParaView ${CMAKE_BDM_PVVERSION} CONFIG COMPONENTS Catalyst PythonCatalyst VTKExtensionsIOCore - PATHS ${CMAKE_THIRD_PARTY_DIR}/paraview) - endif() - - include_directories(${ParaView_PREFIX_PATH}/include/paraview-${CMAKE_BDM_PVVERSION}) - add_definitions("-DUSE_PARAVIEW") + find_package(ParaView REQUIRED CONFIG COMPONENTS + Catalyst PythonCatalyst VTKExtensionsIOCore) + set(CMAKE_BDM_PVVERSION + "${ParaView_VERSION_MAJOR}.${ParaView_VERSION_MINOR}") + add_definitions("-DUSE_PARAVIEW") endif() if(sbml) @@ -576,7 +434,6 @@ execute_process(COMMAND ${CMAKE_COMMAND} -E tar xf "${CMAKE_SOURCE_DIR}/third_pa # -------------------- build shared library libbiodynamo ----------------------- # add the headers into the project -include(${ROOT_USE_FILE}) include_directories("${CMAKE_SOURCE_DIR}/src") include_directories("${CMAKE_SOURCE_DIR}/test") include_directories("${CMAKE_SOURCE_DIR}/third_party") @@ -588,10 +445,6 @@ include_directories("${CMAKE_SOURCE_DIR}/third_party/cxxopts-v2.2.1") include_directories("${EXTRACTED_THIRD_PARTY_LIBS}") include_directories("${CMAKE_CURRENT_BINARY_DIR}/version") -# Since including the directory where omp.h resides can cause rootcling to -# search for system / C++ standard headers in that same directory, we instead -# copy omp.h to our local build directory and include that -fix_rootcling_omp_issue() fix_macos_opencl_header_issue() # build libbiodynamo @@ -605,10 +458,9 @@ filter_list(LIB_SOURCES "${LIB_SOURCES}" "paraview/*") filter_list(HEADERS "${HEADERS}" "paraview/*") build_shared_library(biodynamo - SELECTION selection-libbiodynamo.xml SOURCES ${LIB_SOURCES} HEADERS ${HEADERS} - LIBRARIES ${BDM_REQUIRED_LIBRARIES} ${ROOT_LIBRARIES}) + LIBRARIES ${BDM_REQUIRED_LIBRARIES}) # libbiodynamo must be built before optimlib; otherwise optimlib could be missing during # the linking stage of libbiodynamo @@ -622,17 +474,11 @@ if(paraview) # We link against python3 libraries, so that the paraview libraries can # resolve missing python symbols when creating binaries - if(APPLE) - set(REQUIRED_PARAVIEW_LIBRARIES "${ParaView_LIBRARIES};${Python3_LIBRARIES}") - else() - set(REQUIRED_PARAVIEW_LIBRARIES "${ParaView_LIBRARIES};${Python_LIBRARIES}") - endif() + set(REQUIRED_PARAVIEW_LIBRARIES "${ParaView_LIBRARIES}") build_shared_library(VisualizationAdaptor - SELECTION selection-libVisualizationAdaptor.xml SOURCES ${PV_SOURCES} HEADERS ${PV_HEADERS} - LIBRARIES ${REQUIRED_PARAVIEW_LIBRARIES} biodynamo - PLUGIN "TRUE") + LIBRARIES ${REQUIRED_PARAVIEW_LIBRARIES} biodynamo) set(REQUIRED_PARAVIEW_LIBRARIES "${REQUIRED_PARAVIEW_LIBRARIES};VisualizationAdaptor") if(LINUX) @@ -688,8 +534,6 @@ add_custom_target(libbdmclean COMMAND ${CMAKE_COMMAND} -P "${CMAKE_BINARY_DIR}/C add_custom_target(bdmclean) add_dependencies(bdmclean libbdmclean) -generate_rootlogon() - # create cmake files used by external builds configure_file("cmake/UseBioDynaMo.cmake.in" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/UseBioDynaMo.cmake" @ONLY) @@ -711,7 +555,6 @@ if (test) ${CMAKE_SOURCE_DIR}/test/unit/core/execution_context/*.cc ${CMAKE_SOURCE_DIR}/test/unit/core/memory/*.cc ${CMAKE_SOURCE_DIR}/test/unit/core/operation/*.cc - ${CMAKE_SOURCE_DIR}/test/unit/core/multi_simulation/*.cc ${CMAKE_SOURCE_DIR}/test/unit/core/param/*.cc ${CMAKE_SOURCE_DIR}/test/unit/core/agent/*.cc ${CMAKE_SOURCE_DIR}/test/unit/core/util/*.cc @@ -768,9 +611,6 @@ if(benchmark) include(Benchmarking) endif() -# -------------------- Generate notebooks -------------------------------------- -include(Notebooks) - # -------------------- Install configuration ----------------------------------- include(Installation) @@ -805,9 +645,9 @@ install_inside_build() #---Populate the configure arguments returned by 'bdm-config --config' get_cmake_property(variables CACHE_VARIABLES) foreach(var ${variables}) - if(("${var}" MATCHES "_(LIBRARIES|LIBRARY|INCLUDE|VERSION)") AND - (NOT "${${var}}" STREQUAL "") AND - (NOT "${${var}}" MATCHES "NOTFOUND")) + if((var MATCHES "_(LIBRARIES|LIBRARY|INCLUDE|VERSION)") AND + (NOT ${${var}} STREQUAL "") AND + (NOT ${var} MATCHES "NOTFOUND")) if (var MATCHES "^QT_") # filter out the very long list of Qt libraries and include dirs if (var MATCHES "(QT_LIBRARY_DIR|QT_QTCORE_INCLUDE_DIR)") @@ -822,10 +662,13 @@ foreach(var ${variables}) endforeach() #--Local bdm-config and thisbdm -EXECUTE_PROCESS(COMMAND ${ROOT_CONFIG_EXECUTABLE} --arch COMMAND tr -d '\n' OUTPUT_VARIABLE architecture) -EXECUTE_PROCESS(COMMAND ${ROOT_CONFIG_EXECUTABLE} --platform COMMAND tr -d '\n' OUTPUT_VARIABLE platform) -EXECUTE_PROCESS(COMMAND ${ROOT_CONFIG_EXECUTABLE} --version COMMAND tr -d '\n' OUTPUT_VARIABLE rootvers) -EXECUTE_PROCESS(COMMAND ${ROOT_CONFIG_EXECUTABLE} --ncpu COMMAND tr -d '\n' OUTPUT_VARIABLE ncpu) +set(architecture "${CMAKE_SYSTEM_PROCESSOR}") +set(platform "${CMAKE_SYSTEM_NAME}") +include(ProcessorCount) +ProcessorCount(ncpu) +if(NOT ncpu) + set(ncpu 1) +endif() get_property(cxxdefinesraw DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_DEFINITIONS) set(altcxx ${CMAKE_CXX_COMPILER}) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3a641ccfa..4a8ebb88d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,4 +1,42 @@ -# Contributing Guidelines +# Contributing -You can find our contributing guidelines in our -[developer guide](https://biodynamo.org/docs/devguide/contribute/). +BioDynaMo welcomes focused fixes, features, tests, and documentation. + +## Build + +Install the platform prerequisites, then configure a lightweight development +build from the repository root: + +```bash +cmake -S . -B build -G Ninja \ + -DCMAKE_BUILD_TYPE=Debug \ + -Dparaview=OFF +cmake --build build --parallel +``` + +ParaView support uses a system installation. Enable it with +`-Dparaview=ON` when the change affects visualization. On Ubuntu, install +`paraview`, `paraview-dev`, `libdouble-conversion-dev`, and `libutfcpp-dev`. + +## Test + +Run the complete unit suite before submitting a pull request: + +```bash +cmake --build build --target run-unit-tests +``` + +Run the repository-owned formatting and copyright checks: + +```bash +cmake --build build --target check-format-all +./util/housekeeping/check-copyright.sh \ + util/housekeeping/copyright_cpp.txt \ + $(./util/housekeeping/get-all-src-files.sh .) +``` + +Add a regression test for changed behavior. Keep commits focused and explain +the observed problem, the change, and the verified result in the pull request. + +The [developer guide](https://biodynamo.org/docs/devguide/contribute/) +contains the complete contribution workflow. diff --git a/Singularity b/Singularity index 1925cb945..fe3a7dba5 100644 --- a/Singularity +++ b/Singularity @@ -1,82 +1,33 @@ -Bootstrap:docker -From:ubuntu:20.04 +Bootstrap: docker +From: ubuntu:24.04 -%environment +%files + . /biodynamo %post -c /bin/bash + set -eux + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install -y --no-install-recommends \ + ca-certificates cmake g++ gcc git libblas-dev libboost-dev liblapack-dev \ + libnuma-dev libomp-dev libopenmpi-dev ninja-build openmpi-bin python3 + rm -rf /var/lib/apt/lists/* + cmake -S /biodynamo -B /biodynamo/build -G Ninja \ + -Dbenchmark=OFF \ + -Dcuda=OFF \ + -Dlibgit2=OFF \ + -Dopencl=OFF \ + -Dparaview=OFF \ + -Dsbml=OFF \ + -Dtest=OFF \ + -Dvalgrind=OFF \ + -DCMAKE_BUILD_TYPE=Release + cmake --build /biodynamo/build --parallel - export DEBIAN_FRONTEND=noninteractive - export TZ=Europe/Berlin - unset Qt5_DIR - unset ParaView_DIR - unset ROOT_INCLUDE_PATH - unset CMAKE_PREFIX_PATH - unset PYENV_ROOT - unset BDMSYS - unset CC - unset CXX - - - apt-get -y update - apt-get -y install apt-utils - apt-get -y install software-properties-common - apt-get -y install python python3 git curl make gcc g++ wget wamerican wget wamerican libffi-dev libncurses5-dev zlib1g zlib1g-dev bzip2 aptitude libreadline-dev libssl-dev libsqlite3-dev \ - openmpi-bin libopenmpi-dev libxkbcommon-x11-dev bsdmainutils clang clang-format clang-tidy doxygen graphviz libxml2-dev llvm-7 llvm-7-dev llvm-7-runtime valgrind libgsl-dev freeglut3-dev \ - libbz2-dev libnuma-dev libomp5 libomp-dev libopenmpi-dev libpthread-stubs0-dev zlib1g-dev libbz2-dev libffi-dev liblzma-dev libreadline-dev libsqlite3-dev libssl-dev python-openssl tk-dev \ - xz-utils zlib1g-dev sudo libblas-dev liblapack-dev nano locales locales-all ninja-build python3-pip freeglut3-dev valgrind xvfb - - CMAKE_VER=3.19.3 - CMAKE_SH="cmake-${CMAKE_VER}-linux-x86_64.sh" - curl -L -O https://github.com/Kitware/CMake/releases/download/v${CMAKE_VER}/${CMAKE_SH} - bash "${CMAKE_SH}" --prefix=/usr/local --skip-license - rm "${CMAKE_SH}" - - - dpkg-reconfigure locales - locale-gen - - wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh - bash Miniconda3-latest-Linux-x86_64.sh -b -f -p /miniconda3/ - rm Miniconda3-latest-Linux-x86_64.sh - - export PATH="/miniconda3/bin:$PATH" - conda install -y -c conda-forge pip numpy - conda update -y --all - - export PYENV_ROOT="/opt/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.1 - echo 'export PATH="/opt/.pyenv/versions/3.9.1/bin/:$PATH"' >> $SINGULARITY_ENVIRONMENT - export PATH="/opt/.pyenv/versions/3.9.1/bin/:$PATH" - - pyenv shell 3.9.1 - - wget https://bootstrap.pypa.io/get-pip.py - python3 get-pip.py - python3 -m pip install -U pip - python3 -m pip install --upgrade pip - python3 -m pip install numpy - - # pip install cmake --upgrade - pyenv global 3.9.1 - - git config --system user.name "Test User" - git config --system user.email user@test.com - - export BDM_BRANCH="master" - git clone https://github.com/BioDynaMo/biodynamo.git - cd biodynamo - git checkout $BDM_BRANCH - - mkdir build - cd build - - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release .. - - ninja -j $(($(nproc) - 1)) - +%environment + export BDMSYS=/biodynamo/build + export PATH=/biodynamo/build/bin:$PATH + export LD_LIBRARY_PATH=/biodynamo/build/lib:$LD_LIBRARY_PATH %runscript + exec /bin/bash "$@" diff --git a/cli/config_command.py b/cli/config_command.py index e3b05a396..0791fd62e 100644 --- a/cli/config_command.py +++ b/cli/config_command.py @@ -56,7 +56,6 @@ def ConfigCommand(): "cxx": "Alternative C++ compiler specified when BDM was built", "ld": "Alternative Linker specified when BDM was built", "cmake-invoke": "The BioDynaMo cmake invocation", - "root-version": "The version of ROOT used to build BioDynaMo", } # 1. Get path to bdm-config @@ -65,7 +64,6 @@ def ConfigCommand(): # 2. Extract all information via bdm-config arguments = [ "version", - "root-version", "cxxflags", "cxxincludes", "ldflags", diff --git a/cmake/BioDynaMo.cmake b/cmake/BioDynaMo.cmake index 9f0593245..b43ac5fab 100644 --- a/cmake/BioDynaMo.cmake +++ b/cmake/BioDynaMo.cmake @@ -5,233 +5,35 @@ # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. -# # See the LICENSE file distributed with this work for details. # See the NOTICE file distributed with this work for additional information # regarding copyright ownership. # # ----------------------------------------------------------------------------- -# This file contains functions required to build BioDynaMo - -# function get_implicit_dependencies( RET_VAR -# SOURCES source1 source2 ...) -# Returns a list of biodynamo headers that are included from a list of source -# files. -# \param RET_VAR variable in which the list of headers will be stored -# \param SOURCES list of source files that should be analyzed -function(get_implicit_dependencies RET_VAR) - cmake_parse_arguments(ARG "" "" "SOURCES" ${ARGN} ) - - # build include path string - get_directory_property(INCLUDE_DIRS INCLUDE_DIRECTORIES) - set(INCLUDE_OPTIONS) - foreach( DIR ${INCLUDE_DIRS}) - set(INCLUDE_OPTIONS "${INCLUDE_OPTIONS} -I${DIR}") - endforeach() - - # grep pattern to extract bdm headers - set(BDM_HEADER_PATTERN "^${PROJECT_SOURCE_DIR}/src/|^${PROJECT_SOURCE_DIR}/test/|^${PROJECT_SOURCE_DIR}/demo/|^src/|^test/|^demo/") - - # execute shell script and store result into variable - execute_process( - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} - COMMAND cmake/get_bdm_includes.sh ${CMAKE_CXX_COMPILER} "${INCLUDE_OPTIONS}" ${BDM_HEADER_PATTERN} ${ARG_SOURCES} - OUTPUT_VARIABLE CMD_RESULT) - - # return result - set(${RET_VAR} ${CMD_RESULT} PARENT_SCOPE) -endfunction(get_implicit_dependencies) - -# function bdm_add_executable( TARGET -# SOURCES source1 source2 ... -# HEADERS header1 header2 ... -# LIBRARIES lib1 lib2 ...) -# BioDynaMo's version of add_executable -# This is required because ROOT dictionaries must be built beforehand. -# To make debugging of compile errors easier an object library with SOURCES -# is compiled first, then dictionaries are generated. Afterwards these -# dictionaries are compiled and linked with the object files compiled in the -# first step. -# Uses the variable `BDMSYS` to point to the cmake directory. This is -# necessary, since this function is used from within the BioDynaMo repository -# and external simulation projects. -# \param TARGET target name for the executable -# \param SOURCES list of source files -# \param LIBRARIES list of *shared* libraries that should be linked to the executable. -# can also be a target name of a library. -# STATIC libraries not compiled with -fPIC must be linked in a separate command using -# target_link_libraries(${TARGET} static-lib-wo-fpic) function(bdm_add_executable TARGET) - cmake_parse_arguments(ARG "" "" "SOURCES;HEADERS;LIBRARIES" ${ARGN} ) - - if(dict) - if (OPENCL_FOUND) - # Do this here; we don't want libbiodynamo.so to contain any OpenCL symbols - set(ARG_LIBRARIES ${ARG_LIBRARIES} ${OPENCL_LIBRARIES}) - endif() - if(mpi AND MPI_FOUND) - set(ARG_LIBRARIES ${ARG_LIBRARIES} ${MPI_mpi_LIBRARY}) - set(ARG_LIBRARIES ${ARG_LIBRARIES} ${MPI_mpi_cxx_LIBRARY}) - endif() - build_shared_library(${TARGET} - SELECTION selection.xml - HEADERS ${ARG_HEADERS} - SOURCES ${ARG_SOURCES} - LIBRARIES ${ARG_LIBRARIES}) - file(WRITE ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${TARGET}-main.cc "int main(int argc, const char** argv);") - add_executable(${TARGET}-bin ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${TARGET}-main.cc) - target_link_libraries(${TARGET}-bin ${TARGET}) - if (LINUX) - set_target_properties(${TARGET}-bin PROPERTIES LINK_FLAGS "-Wl,-rpath,$ORIGIN") - else() - set_target_properties(${TARGET}-bin PROPERTIES LINK_FLAGS "-Wl,-rpath,@loader_path") - endif() - set_target_properties(${TARGET}-bin PROPERTIES OUTPUT_NAME ${TARGET}) - else() - add_executable(${TARGET} ${ARG_SOURCES}) - target_link_libraries(${TARGET} ${ARG_LIBRARIES}) - endif() -endfunction(bdm_add_executable) + cmake_parse_arguments(ARG "" "" "SOURCES;HEADERS;LIBRARIES" ${ARGN}) + add_executable(${TARGET} ${ARG_SOURCES} ${ARG_HEADERS}) + target_link_libraries(${TARGET} ${ARG_LIBRARIES}) +endfunction() -# function build_shared_library( TARGET -# SELECTION selection.xml -# SOURCES source1 source2 ... -# HEADERS header1 header2 ... -# LIBRARIES lib1 lib2 ... -# PLUGIN <"TRUE">) -# build shared library with ROOT dictionaries. If ARG_PLUGIN is set, we will -# always generate dictionaries (as required by ROOT's plugin manager) function(build_shared_library TARGET) - cmake_parse_arguments(ARG "" "" "SELECTION;SOURCES;HEADERS;LIBRARIES;PLUGIN" ${ARGN} ) - - # We always need dictionaries for the plugins (plugin manager requires class - # information) - if(dict OR DEFINED ARG_PLUGIN) - # generate dictionary using genreflex - set(DICT_FILE "${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET}_dict") - set(BDM_DICT_FILE "${CMAKE_CURRENT_BINARY_DIR}/lib${TARGET}_bdm_dict.cc") + cmake_parse_arguments(ARG "" "" "SOURCES;HEADERS;LIBRARIES" ${ARGN}) + add_library(${TARGET} SHARED ${ARG_SOURCES} ${ARG_HEADERS}) + target_link_libraries(${TARGET} ${ARG_LIBRARIES}) +endfunction() - # Since the location of the CMake files differ in the build and installation - # directory, we check if BDM_CMAKE_DIR is already set (in build directory - # case). Otherwise, set it to the installation directory - if(NOT DEFINED BDM_CMAKE_DIR) - set(BDM_CMAKE_DIR $ENV{BDMSYS}/share/cmake) - endif() - REFLEX_GENERATE_DICTIONARY(${DICT_FILE} ${ARG_HEADERS} SELECTION ${BDM_CMAKE_DIR}/${ARG_SELECTION}) - if (BDM_OUT_OF_SOURCE) - set(BDM_DICT_BIN_PATH "$ENV{BDMSYS}/bin") - else() - set(BDM_DICT_BIN_PATH "${PROJECT_SOURCE_DIR}/cmake") - endif() - get_property(INCLUDE_DIRS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES) - if (BDM_OUT_OF_SOURCE) - set(BDM_OUT_OF_SRC_ARG "--out-of-source") - else() - set(BDM_OUT_OF_SRC_ARG --bdm-source ${CMAKE_SOURCE_DIR}) - endif() - add_custom_command(OUTPUT "${BDM_DICT_FILE}" - COMMAND ${Python_EXECUTABLE} ${BDM_DICT_BIN_PATH}/bdm-dictionary ${BDM_OUT_OF_SRC_ARG} --output ${BDM_DICT_FILE} --include-dirs ${INCLUDE_DIRS} --headers ${ARG_HEADERS} - DEPENDS ${ARG_HEADERS} ${BDM_DICT_BIN_PATH}/bdm-dictionary) - # generate shared library - add_library(${TARGET} SHARED ${ARG_SOURCES} ${DICT_FILE}.cc ${BDM_DICT_FILE}) - if (OPENCL_FOUND) - target_compile_definitions(${TARGET} PUBLIC -DUSE_OPENCL) - endif() - target_link_libraries(${TARGET} ${ARG_LIBRARIES}) - if (DEFINED CMAKE_INSTALL_LIBDIR) - add_custom_command(TARGET ${TARGET} - POST_BUILD - COMMAND ${CMAKE_COMMAND} -E copy ${DICT_FILE}_rdict.pcm ${CMAKE_INSTALL_LIBDIR}) - endif() - else() - add_library(${TARGET} SHARED ${ARG_SOURCES}) - target_link_libraries(${TARGET} ${ARG_LIBRARIES}) - endif() -endfunction(build_shared_library) - -# function generate_rootlogon -# generates rootlogon.C which is required by ROOT's C++ interpreter cling -function(generate_rootlogon) - get_directory_property(INCLUDE_DIRS INCLUDE_DIRECTORIES) - set(INCLUDE_OPTIONS) - - set(CONTENT "{") - # if USE_DICT is set for libbiodynamo.so, we also need to set it for rootcling - # when we want to use the interpreter or notebooks. Otherwise there would break - # the one-definition rule - if(real_t) - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"#define BDM_REALT ${real_t}\")\;") - endif() - if (dict) - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"#define USE_DICT\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"R__ADD_INCLUDE_PATH($BDMSYS/include)\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"R__ADD_LIBRARY_PATH($BDMSYS/lib)\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"R__LOAD_LIBRARY(libbiodynamo)\")\;") - # We add this one because the ROOT visualization require it, and it's not one - # of the core libraries that is loaded by default in rootcling - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"R__LOAD_LIBRARY(GenVector)\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"#include \\\"biodynamo.h\\\"\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"using namespace bdm\;\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"Simulation simulation(\\\"simulation\\\")\;\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"cout << \\\"INFO: Created simulation object 'simulation' with UniqueName='simulation'.\\\" << endl\;\")\;") - else() - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"cout << \\\"ERROR: Loading BioDynaMo into ROOT failed!\\\" << endl\;\")\;") - set(CONTENT "${CONTENT}\n gROOT->ProcessLine(\"cout << \\\" BioDynaMo was not built with dict=ON\\\" << endl\;\")\;") - endif() - - set(CONTENT "${CONTENT}\n}\n") - file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/rootlogon.C" ${CONTENT}) -endfunction(generate_rootlogon) - -# Fix for rootcling not able to find omp.h. We cannot include the entire include -# directory of the compiler (where omp.h is in), because rootcling starts using -# the intrinsics found in there. Therefore we do a local copy into the build dir. -function(fix_rootcling_omp_issue) - execute_process(COMMAND ${CMAKE_CXX_COMPILER} --print-file-name=include/omp.h - OUTPUT_VARIABLE OMP_HEADER_PATH) - # above command returns path with "\n" appended - string(REGEX REPLACE "\n$" "" OMP_HEADER_PATH "${OMP_HEADER_PATH}") - - # Get major GCC version - execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion - OUTPUT_VARIABLE GCC_VERSION) - string(REGEX REPLACE "\n$" "" GCC_VERSION "${GCC_VERSION}") - string(REGEX MATCH "^[0-9]+" GCC_VERSION_MAJOR "${GCC_VERSION}") - - # Use third_party/omp/omp.h if compiler didn't resolve full path or gcc version > 11 - if ("${OMP_HEADER_PATH}" STREQUAL "include/omp.h" OR GCC_VERSION_MAJOR GREATER 11) - if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/omp/omp.h") - execute_process(COMMAND cp -a ${CMAKE_SOURCE_DIR}/third_party/omp ${CMAKE_BINARY_DIR}) - elseif(EXISTS "$ENV{BDMSYS}/third_party/omp/omp.h") - execute_process(COMMAND cp -a $ENV{BDMSYS}/third_party/omp ${CMAKE_BINARY_DIR}) - elseif(EXISTS "$ENV{BDMSYS}/omp/omp.h") - execute_process(COMMAND cp -a $ENV{BDMSYS}/omp ${CMAKE_BINARY_DIR}) +function(fix_macos_opencl_header_issue) + if(APPLE) + if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/opencl/cl2.hpp") + execute_process(COMMAND cp -a ${CMAKE_SOURCE_DIR}/third_party/opencl ${CMAKE_BINARY_DIR}) + elseif(EXISTS "$ENV{BDMSYS}/third_party/opencl/cl2.hpp") + execute_process(COMMAND cp -a $ENV{BDMSYS}/third_party/opencl ${CMAKE_BINARY_DIR}) + elseif(EXISTS "$ENV{BDMSYS}/opencl/cl2.hpp") + execute_process(COMMAND cp -a $ENV{BDMSYS}/opencl ${CMAKE_BINARY_DIR}) else() message(FATAL_ERROR "The BioDynaMo environment is not set up correctly. Please execute 'source /bin/thisbdm.sh' and retry this command.") endif() - else() - execute_process(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/omp) - execute_process(COMMAND cp -f ${OMP_HEADER_PATH} ${CMAKE_BINARY_DIR}/omp) - endif() - include_directories("${CMAKE_BINARY_DIR}/omp") -endfunction(fix_rootcling_omp_issue) - -# Fix to be able to find opencl C++ include file cl2.hpp. On macOS this include -# is missing so we should make sure it is available during compilation on macOS. -function(fix_macos_opencl_header_issue) - - if (APPLE) - if(EXISTS "${CMAKE_SOURCE_DIR}/third_party/opencl/cl2.hpp") - execute_process(COMMAND cp -a ${CMAKE_SOURCE_DIR}/third_party/opencl ${CMAKE_BINARY_DIR}) - elseif(EXISTS "$ENV{BDMSYS}/third_party/opencl/cl2.hpp") - execute_process(COMMAND cp -a $ENV{BDMSYS}/third_party/opencl ${CMAKE_BINARY_DIR}) - elseif(EXISTS "$ENV{BDMSYS}/opencl/cl2.hpp") - execute_process(COMMAND cp -a $ENV{BDMSYS}/opencl ${CMAKE_BINARY_DIR}) - else() - message(FATAL_ERROR "The BioDynaMo environment is not set up correctly. Please execute 'source /bin/thisbdm.sh' and retry this command.") - endif() - include_directories("${CMAKE_BINARY_DIR}/opencl") + include_directories("${CMAKE_BINARY_DIR}/opencl") endif() - -endfunction(fix_macos_opencl_header_issue) +endfunction() diff --git a/cmake/FindROOT.cmake b/cmake/FindROOT.cmake deleted file mode 100644 index 5443a8479..000000000 --- a/cmake/FindROOT.cmake +++ /dev/null @@ -1,204 +0,0 @@ -# - Finds ROOT installation -# This module sets up ROOT information -# It defines: -# ROOT_FOUND If the ROOT is found -# ROOT_INCLUDE_DIR PATH to the include directory -# ROOT_INCLUDE_DIRS PATH to the include directories (not cached) -# ROOT_LIBRARIES Most common libraries -# ROOT__LIBRARY Full path to the library -# ROOT_LIBRARY_DIR PATH to the library directory -# ROOT_ETC_DIR PATH to the etc directory -# ROOT_DEFINITIONS Compiler definitions -# ROOT_CXX_FLAGS Compiler flags to be used by client packages -# ROOT_C_FLAGS Compiler flags to be used by client packages -# ROOT_EXE_LINKER_FLAGS Linker flags to be used by client packages -# -# Updated by K. Smith (ksmith37@nd.edu) to properly handle -# dependencies in ROOT_GENERATE_DICTIONARY - -find_program(ROOT_CONFIG_EXECUTABLE NAMES root-config - HINTS "$ENV{ROOTSYS}/bin" "$ENV{BDM_ROOT_DIR}/bin" "${CMAKE_THIRD_PARTY_DIR}/root/bin") - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --prefix - OUTPUT_VARIABLE ROOTSYS - OUTPUT_STRIP_TRAILING_WHITESPACE) - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --version - OUTPUT_VARIABLE ROOT_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --incdir - OUTPUT_VARIABLE ROOT_INCLUDE_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(ROOT_INCLUDE_DIRS ${ROOT_INCLUDE_DIR}) - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --etcdir - OUTPUT_VARIABLE ROOT_ETC_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(ROOT_ETC_DIRS ${ROOT_ETC_DIR}) - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --libdir - OUTPUT_VARIABLE ROOT_LIBRARY_DIR - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(ROOT_LIBRARY_DIRS ${ROOT_LIBRARY_DIR}) - -set(rootlibs Core RIO Net Hist Graf Graf3d Gpad Tree Rint Postscript Matrix Physics MathCore Thread MultiProc Imt) -set(ROOT_LIBRARIES) -foreach(_cpt ${rootlibs} ${ROOT_FIND_COMPONENTS}) - find_library(ROOT_${_cpt}_LIBRARY ${_cpt} HINTS ${ROOT_LIBRARY_DIR}) - if(ROOT_${_cpt}_LIBRARY) - mark_as_advanced(ROOT_${_cpt}_LIBRARY) - list(APPEND ROOT_LIBRARIES ${ROOT_${_cpt}_LIBRARY}) - if(ROOT_FIND_COMPONENTS) - list(REMOVE_ITEM ROOT_FIND_COMPONENTS ${_cpt}) - endif() - endif() -endforeach() -if(ROOT_LIBRARIES) - list(REMOVE_DUPLICATES ROOT_LIBRARIES) -endif() - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --cflags - OUTPUT_VARIABLE __cflags - OUTPUT_STRIP_TRAILING_WHITESPACE) -string(REGEX MATCHALL "-(D|U)[^ ]*" ROOT_DEFINITIONS "${__cflags}") -string(REGEX REPLACE "(^|[ ]*)-I[^ ]*" "" ROOT_CXX_FLAGS "${__cflags}") -string(REGEX REPLACE "(^|[ ]*)-I[^ ]*" "" ROOT_C_FLAGS "${__cflags}") - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --ldflags - OUTPUT_VARIABLE __ldflags - OUTPUT_STRIP_TRAILING_WHITESPACE) -set(ROOT_EXE_LINKER_FLAGS "${__ldflags}") - -set(ROOT_USE_FILE ${CMAKE_CURRENT_LIST_DIR}/RootUseFile.cmake) - -execute_process( - COMMAND ${ROOT_CONFIG_EXECUTABLE} --features - OUTPUT_VARIABLE _root_options - OUTPUT_STRIP_TRAILING_WHITESPACE) -separate_arguments(_root_options) -foreach(_opt ${_root_options}) - set(ROOT_${_opt}_FOUND TRUE) -endforeach() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(ROOT DEFAULT_MSG ROOT_CONFIG_EXECUTABLE - ROOTSYS ROOT_VERSION ROOT_INCLUDE_DIR ROOT_LIBRARIES ROOT_LIBRARY_DIR) - -mark_as_advanced(ROOT_CONFIG_EXECUTABLE) - -include(CMakeParseArguments) -find_program(ROOTCLING_EXECUTABLE rootcling - HINTS "$ENV{ROOTSYS}/bin" "$ENV{BDM_ROOT_DIR}/bin" "${CMAKE_THIRD_PARTY_DIR}/root/bin") -find_program(GENREFLEX_EXECUTABLE genreflex - HINTS "$ENV{ROOTSYS}/bin" "$ENV{BDM_ROOT_DIR}/bin" "${CMAKE_THIRD_PARTY_DIR}/root/bin") -#find_package(GCCXML) - -# We use the launcher script to emulate a `source thisbdm.sh` call -if(NOT BDM_OUT_OF_SOURCE) - set(LAUNCHER ${CMAKE_BINARY_DIR}/launcher.sh) -endif() - -#---------------------------------------------------------------------------- -# function ROOT_GENERATE_DICTIONARY( dictionary -# header1 header2 ... -# LINKDEF linkdef1 ... -# OPTIONS opt1...) -function(ROOT_GENERATE_DICTIONARY dictionary) - CMAKE_PARSE_ARGUMENTS(ARG "" "" "LINKDEF;OPTIONS" "" ${ARGN}) - #---Get the list of include directories------------------ - get_directory_property(incdirs INCLUDE_DIRECTORIES) - set(includedirs) - foreach( d ${incdirs}) - set(includedirs ${includedirs} -I${d}) - endforeach() - #---Get the list of header files------------------------- - set(headerfiles) - foreach(fp ${ARG_UNPARSED_ARGUMENTS}) - if(${fp} MATCHES "[*?]") # Is this header a globbing expression? - file(GLOB files ${fp}) - foreach(f ${files}) - if(NOT f MATCHES LinkDef) # skip LinkDefs from globbing result - set(headerfiles ${headerfiles} ${f}) - endif() - endforeach() - else() - find_file(headerFile ${fp} HINTS ${incdirs}) - set(headerfiles ${headerfiles} ${headerFile}) - unset(headerFile CACHE) - endif() - endforeach() - #---Get LinkDef.h file------------------------------------ - set(linkdefs) - foreach( f ${ARG_LINKDEF}) - find_file(linkFile ${f} HINTS ${incdirs}) - set(linkdefs ${linkdefs} ${linkFile}) - unset(linkFile CACHE) - endforeach() - #---call rootcling------------------------------------------ - add_custom_command(OUTPUT ${dictionary}.cxx - OUTPUT ${dictionary}_rdict.pcm - COMMAND ${LAUNCHER} ${ROOTCLING_EXECUTABLE} -f ${dictionary}.cxx - ${ARG_OPTIONS} ${includedirs} ${headerfiles} ${linkdefs} - DEPENDS ${headerfiles} ${linkdefs} VERBATIM) -endfunction() - -#---------------------------------------------------------------------------- -# function REFLEX_GENERATE_DICTIONARY(dictionary -# header1 header2 ... -# SELECTION selectionfile ... -# OPTIONS opt1...) -function(REFLEX_GENERATE_DICTIONARY dictionary) - CMAKE_PARSE_ARGUMENTS(ARG "" "" "SELECTION;OPTIONS" "" ${ARGN}) - #---Get the list of header files------------------------- - set(headerfiles) - foreach(fp ${ARG_UNPARSED_ARGUMENTS}) - file(GLOB files ${fp}) - if(files) - foreach(f ${files}) - set(headerfiles ${headerfiles} ${f}) - endforeach() - else() - set(headerfiles ${headerfiles} ${fp}) - endif() - endforeach() - #---Get Selection file------------------------------------ - if(IS_ABSOLUTE ${ARG_SELECTION}) - set(selectionfile ${ARG_SELECTION}) - else() - set(selectionfile ${CMAKE_CURRENT_SOURCE_DIR}/${ARG_SELECTION}) - endif() - #---Get the list of include directories------------------ - get_directory_property(incdirs INCLUDE_DIRECTORIES) - set(includedirs) - foreach( d ${incdirs}) - set(includedirs ${includedirs} -I${d}) - endforeach() - #---Get preprocessor definitions-------------------------- - get_directory_property(defs COMPILE_DEFINITIONS) - foreach( d ${defs}) - set(definitions ${definitions} -D${d}) - endforeach() - #---Nanes and others--------------------------------------- - set(gensrcdict ${dictionary}.cc) - if(MSVC) - set(gccxmlopts "--gccxmlopt=\"--gccxml-compiler cl\"") - else() - #set(gccxmlopts "--gccxmlopt=\'--gccxml-cxxflags -m64 \'") - set(gccxmlopts) - endif() - #set(rootmapname ${dictionary}Dict.rootmap) - #set(rootmapopts --rootmap=${rootmapname} --rootmap-lib=${libprefix}${dictionary}Dict) - #---Actual command---------------------------------------- - add_custom_command(OUTPUT ${gensrcdict} ${rootmapname} ${dictionary}_rdict.pcm - COMMAND ${LAUNCHER} ${GENREFLEX_EXECUTABLE} ${headerfiles} -o ${gensrcdict} ${rootmapopts} --select=${selectionfile} --noIncludePaths - ${ARG_OPTIONS} ${includedirs} ${definitions} - DEPENDS ${headerfiles} ${selectionfile}) -endfunction() diff --git a/cmake/FindTBB.cmake b/cmake/FindTBB.cmake deleted file mode 100644 index 6f7c0b9c4..000000000 --- a/cmake/FindTBB.cmake +++ /dev/null @@ -1,293 +0,0 @@ -# Module for locating Intel's Threading Building Blocks (TBB). -# -# Customizable variables: -# TBB_ROOT_DIR -# Specifies TBB's root directory. -# -# Read-only variables: -# TBB_FOUND -# Indicates whether the library has been found. -# -# TBB_INCLUDE_DIRS -# Specifies TBB's include directory. -# -# TBB_LIBRARIES -# Specifies TBB libraries that should be passed to target_link_libararies. -# -# TBB__LIBRARIES -# Specifies the libraries of a specific . -# -# TBB__FOUND -# Indicates whether the specified was found. -# -# -# Copyright (c) 2012 Sergiu Dotenco -# -# 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. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTTBBLAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -INCLUDE (FindPackageHandleStandardArgs) - -IF (CMAKE_VERSION VERSION_GREATER 2.8.7) - SET (_TBB_CHECK_COMPONENTS FALSE) -ELSE (CMAKE_VERSION VERSION_GREATER 2.8.7) - SET (_TBB_CHECK_COMPONENTS TRUE) -ENDIF (CMAKE_VERSION VERSION_GREATER 2.8.7) - -FIND_PATH (TBB_ROOT_DIR - NAMES include/tbb/tbb.h - PATHS ENV TBB - ENV TBBROOT - ENV TBB_ROOT - ENV TBB40_INSTALL_DIR - ENV TBB30_INSTALL_DIR - ENV TBB22_INSTALL_DIR - ENV TBB21_INSTALL_DIR - DOC "TBB root directory") - -FIND_PATH (TBB_INCLUDE_DIR - NAMES tbb/tbb.h - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES include - DOC "TBB include directory") - -IF (MSVC15) - SET (_TBB_COMPILER vc14) -ELSEIF (MSVC14) - SET (_TBB_COMPILER vc14) -ELSEIF (MSVC12) - SET (_TBB_COMPILER vc12) -ELSEIF (MSVC11) - SET (_TBB_COMPILER vc11) -ELSEIF (MSVC10) - SET (_TBB_COMPILER vc10) -ELSEIF (MSVC90) - SET (_TBB_COMPILER vc9) -ELSEIF (MSVC80) - SET (_TBB_COMPILER vc8) -ELSEIF (WIN32) - SET (_TBB_COMPILER vc_mt) -ENDIF (MSVC15) - -IF (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET (_TBB_POSSIBLE_LIB_SUFFIXES lib/intel64/${_TBB_COMPILER}) - SET (_TBB_POSSIBLE_BIN_SUFFIXES bin/intel64/${_TBB_COMPILER}) -ELSE (CMAKE_SIZEOF_VOID_P EQUAL 8) - SET (_TBB_POSSIBLE_LIB_SUFFIXES lib/ia32/${_TBB_COMPILER}) - SET (_TBB_POSSIBLE_BIN_SUFFIXES bin/ia32/${_TBB_COMPILER}) -ENDIF (CMAKE_SIZEOF_VOID_P EQUAL 8) - -LIST (APPEND _TBB_POSSIBLE_LIB_SUFFIXES lib/$ENV{TBB_ARCH_PLATFORM}) - -FIND_LIBRARY (TBB_LIBRARY_RELEASE - NAMES tbb - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES ${_TBB_POSSIBLE_LIB_SUFFIXES} - DOC "TBB release library") - -FIND_LIBRARY (TBB_LIBRARY_DEBUG - NAMES tbb_debug - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES ${_TBB_POSSIBLE_LIB_SUFFIXES} - DOC "TBB debug library") - -IF (TBB_LIBRARY_RELEASE AND TBB_LIBRARY_DEBUG) - IF (NOT TBB_LIBRARY) - SET (TBB_LIBRARY optimized ${TBB_LIBRARY_RELEASE} debug ${TBB_LIBRARY_DEBUG} - CACHE STRING "TBB library" FORCE) - ENDIF (NOT TBB_LIBRARY) -ELSEIF (TBB_LIBRARY_RELEASE) - IF (NOT TBB_LIBRARY) - SET (TBB_LIBRARY ${TBB_LIBRARY_RELEASE} CACHE STRING "TBB library" FORCE) - ENDIF (NOT TBB_LIBRARY) -ENDIF (TBB_LIBRARY_RELEASE AND TBB_LIBRARY_DEBUG) - -IF (TBB_LIBRARY_DEBUG) - LIST (APPEND _TBB_ALL_LIBS ${TBB_LIBRARY_DEBUG}) -ENDIF (TBB_LIBRARY_DEBUG) - -IF (TBB_LIBRARY_RELEASE) - LIST (APPEND _TBB_ALL_LIBS ${TBB_LIBRARY_RELEASE}) -ENDIF (TBB_LIBRARY_RELEASE) - -FOREACH (_TBB_COMPONENT ${TBB_FIND_COMPONENTS}) - STRING (TOUPPER ${_TBB_COMPONENT} _TBB_COMPONENT_UPPER) - SET (_TBB_LIBRARY_BASE TBB_${_TBB_COMPONENT_UPPER}_LIBRARY) - - IF (${_TBB_COMPONENT} STREQUAL preview) - SET (_TBB_LIBRARY_NAME tbb_${_TBB_COMPONENT}) - ELSE (${_TBB_COMPONENT} STREQUAL preview) - SET (_TBB_LIBRARY_NAME tbb${_TBB_COMPONENT}) - ENDIF (${_TBB_COMPONENT} STREQUAL preview) - - FIND_LIBRARY (${_TBB_LIBRARY_BASE}_RELEASE - NAMES ${_TBB_LIBRARY_NAME} - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES ${_TBB_POSSIBLE_LIB_SUFFIXES} - DOC "TBB ${_TBB_COMPONENT} release library") - - FIND_LIBRARY (${_TBB_LIBRARY_BASE}_DEBUG - NAMES ${_TBB_LIBRARY_NAME}_debug - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES ${_TBB_POSSIBLE_LIB_SUFFIXES} - DOC "TBB ${_TBB_COMPONENT} debug library") - - MARK_AS_ADVANCED (${_TBB_LIBRARY_BASE} ${_TBB_LIBRARY_BASE}_DEBUG) - - SET (TBB_${_TBB_COMPONENT_UPPER}_FOUND TRUE) - - IF (${_TBB_LIBRARY_BASE}_DEBUG AND ${_TBB_LIBRARY_BASE}_RELEASE) - SET (${_TBB_LIBRARY_BASE} - debug ${${_TBB_LIBRARY_BASE}_DEBUG} - optimized ${${_TBB_LIBRARY_BASE}_RELEASE} CACHE DOC - "TBB ${_TBB_COMPONENT} library") - ELSEIF (${_TBB_LIBRARY_BASE}_DEBUG) - SET (${_TBB_LIBRARY_BASE} ${${_TBB_LIBRARY_BASE}_DEBUG}) - ELSEIF (${_TBB_LIBRARY_BASE}_RELEASE) - SET (${_TBB_LIBRARY_BASE} ${${_TBB_LIBRARY_BASE}_RELEASE} - CACHE DOC "TBB ${_TBB_COMPONENT} library") - ELSE (${_TBB_LIBRARY_BASE}_DEBUG AND ${_TBB_LIBRARY_BASE}_RELEASE) - # Component missing: record it for a later report - LIST (APPEND _TBB_MISSING_COMPONENTS ${_TBB_COMPONENT}) - SET (TBB_${_TBB_COMPONENT_UPPER}_FOUND FALSE) - ENDIF (${_TBB_LIBRARY_BASE}_DEBUG AND ${_TBB_LIBRARY_BASE}_RELEASE) - - IF (${_TBB_LIBRARY_BASE}_DEBUG) - LIST (APPEND _TBB_ALL_LIBS ${${_TBB_LIBRARY_BASE}_DEBUG}) - ENDIF (${_TBB_LIBRARY_BASE}_DEBUG) - - IF (${_TBB_LIBRARY_BASE}_RELEASE) - LIST (APPEND _TBB_ALL_LIBS ${${_TBB_LIBRARY_BASE}_RELEASE}) - ENDIF (${_TBB_LIBRARY_BASE}_RELEASE) - - SET (TBB_${_TBB_COMPONENT}_FOUND ${TBB_${_TBB_COMPONENT_UPPER}_FOUND}) - - IF (${_TBB_LIBRARY_BASE}) - # setup the TBB__LIBRARIES variable - SET (TBB_${_TBB_COMPONENT_UPPER}_LIBRARIES ${${_TBB_LIBRARY_BASE}}) - LIST (APPEND TBB_LIBRARIES ${${_TBB_LIBRARY_BASE}}) - ELSE (${_TBB_LIBRARY_BASE}) - LIST (APPEND _TBB_MISSING_LIBRARIES ${_TBB_LIBRARY_BASE}) - ENDIF (${_TBB_LIBRARY_BASE}) -ENDFOREACH (_TBB_COMPONENT ${TBB_FIND_COMPONENTS}) - -LIST (APPEND TBB_LIBRARIES ${TBB_LIBRARY}) -SET (TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIR}) - -IF (DEFINED _TBB_MISSING_COMPONENTS AND _TBB_CHECK_COMPONENTS) - IF (NOT TBB_FIND_QUIETLY) - MESSAGE (STATUS "One or more TBB components were not found:") - # Display missing components indented, each on a separate line - FOREACH (_TBB_MISSING_COMPONENT ${_TBB_MISSING_COMPONENTS}) - MESSAGE (STATUS " " ${_TBB_MISSING_COMPONENT}) - ENDFOREACH (_TBB_MISSING_COMPONENT ${_TBB_MISSING_COMPONENTS}) - ENDIF (NOT TBB_FIND_QUIETLY) -ENDIF (DEFINED _TBB_MISSING_COMPONENTS AND _TBB_CHECK_COMPONENTS) - -# Determine library's version - -SET (_TBB_VERSION_HEADER ${TBB_INCLUDE_DIR}/tbb/tbb_stddef.h) - -IF (EXISTS ${_TBB_VERSION_HEADER}) - FILE (READ ${_TBB_VERSION_HEADER} _TBB_VERSION_CONTENTS) - - STRING (REGEX REPLACE ".*#define TBB_VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" - TBB_VERSION_MAJOR "${_TBB_VERSION_CONTENTS}") - STRING (REGEX REPLACE ".*#define TBB_VERSION_MINOR[ \t]+([0-9]+).*" "\\1" - TBB_VERSION_MINOR "${_TBB_VERSION_CONTENTS}") - - SET (TBB_VERSION ${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}) - SET (TBB_VERSION_COMPONENTS 2) -ENDIF (EXISTS ${_TBB_VERSION_HEADER}) - -IF (WIN32) - FIND_PROGRAM (LIB_EXECUTABLE NAMES lib - HINTS "$ENV{VS110COMNTOOLS}/../../VC/bin" - "$ENV{VS100COMNTOOLS}/../../VC/bin" - "$ENV{VS90COMNTOOLS}/../../VC/bin" - "$ENV{VS71COMNTOOLS}/../../VC/bin" - "$ENV{VS80COMNTOOLS}/../../VC/bin" - DOC "Library manager") - - MARK_AS_ADVANCED (LIB_EXECUTABLE) -ENDIF (WIN32) - -MACRO (GET_LIB_REQUISITES LIB REQUISITES) - IF (LIB_EXECUTABLE) - GET_FILENAME_COMPONENT (_LIB_PATH ${LIB_EXECUTABLE} PATH) - - IF (MSVC) - # Do not redirect the output - UNSET (ENV{VS_UNICODE_OUTPUT}) - ENDIF (MSVC) - - EXECUTE_PROCESS (COMMAND ${LIB_EXECUTABLE} /nologo /list ${LIB} - WORKING_DIRECTORY ${_LIB_PATH}/../../Common7/IDE - OUTPUT_VARIABLE _LIB_OUTPUT ERROR_QUIET) - - STRING (REPLACE "\n" ";" "${REQUISITES}" "${_LIB_OUTPUT}") - LIST (REMOVE_DUPLICATES ${REQUISITES}) - ENDIF (LIB_EXECUTABLE) -ENDMACRO (GET_LIB_REQUISITES) - -IF (_TBB_ALL_LIBS) - # collect lib requisites using the lib tool - FOREACH (_TBB_COMPONENT ${_TBB_ALL_LIBS}) - GET_LIB_REQUISITES (${_TBB_COMPONENT} _TBB_REQUISITES) - ENDFOREACH (_TBB_COMPONENT) -ENDIF (_TBB_ALL_LIBS) - -IF (NOT TBB_BINARY_DIR) - SET (_TBB_UPDATE_BINARY_DIR TRUE) -ELSE (NOT TBB_BINARY_DIR) - SET (_TBB_UPDATE_BINARY_DIR FALSE) -ENDIF (NOT TBB_BINARY_DIR) - -SET (_TBB_BINARY_DIR_HINTS ${_TBB_POSSIBLE_BIN_SUFFIXES}) - -IF (_TBB_REQUISITES) - FIND_FILE (TBB_BINARY_DIR NAMES ${_TBB_REQUISITES} - HINTS ${TBB_ROOT_DIR} - PATH_SUFFIXES ${_TBB_BINARY_DIR_HINTS} NO_DEFAULT_PATH) -ENDIF (_TBB_REQUISITES) - -IF (TBB_BINARY_DIR AND _TBB_UPDATE_BINARY_DIR) - SET (_TBB_BINARY_DIR ${TBB_BINARY_DIR}) - UNSET (TBB_BINARY_DIR CACHE) - - IF (_TBB_BINARY_DIR) - GET_FILENAME_COMPONENT (TBB_BINARY_DIR ${_TBB_BINARY_DIR} PATH) - ENDIF (_TBB_BINARY_DIR) -ENDIF (TBB_BINARY_DIR AND _TBB_UPDATE_BINARY_DIR) - -SET (TBB_BINARY_DIR ${TBB_BINARY_DIR} CACHE PATH "TBB binary directory") - -MARK_AS_ADVANCED (TBB_INCLUDE_DIR TBB_LIBRARY TBB_LIBRARY_RELEASE - TBB_LIBRARY_DEBUG TBB_BINARY_DIR) - -IF (NOT _TBB_CHECK_COMPONENTS) - SET (_TBB_FPHSA_ADDITIONAL_ARGS HANDLE_COMPONENTS) -ENDIF (NOT _TBB_CHECK_COMPONENTS) - -IF (CMAKE_VERSION VERSION_GREATER 2.8.2) - LIST (APPEND _TBB_FPHSA_ADDITIONAL_ARGS VERSION_VAR TBB_VERSION) -ENDIF (CMAKE_VERSION VERSION_GREATER 2.8.2) - -FIND_PACKAGE_HANDLE_STANDARD_ARGS (TBB REQUIRED_VARS TBB_ROOT_DIR - TBB_INCLUDE_DIR TBB_LIBRARY ${_TBB_MISSING_LIBRARIES} - ${_TBB_FPHSA_ADDITIONAL_ARGS}) diff --git a/cmake/Findtcmalloc.cmake b/cmake/Findtcmalloc.cmake index 8633b494b..4c5bbfffb 100644 --- a/cmake/Findtcmalloc.cmake +++ b/cmake/Findtcmalloc.cmake @@ -1,4 +1,3 @@ -# from ROOT # - Locate tcmalloc library # Defines: # diff --git a/cmake/Installation.cmake b/cmake/Installation.cmake index eb1b56319..a6e8a95dd 100644 --- a/cmake/Installation.cmake +++ b/cmake/Installation.cmake @@ -14,12 +14,10 @@ # This file contains configuration for the install step -# Reduce the amount of install messages (especially if we need -# to install ROOT, Paraview and Qt). +# Reduce the amount of install messages. if (NOT verbose) set(CMAKE_INSTALL_MESSAGE NEVER) endif() - # We set the default installation directory to $HOME/ if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "$ENV{HOME}" CACHE PATH "The BioDynaMo installation path" FORCE) @@ -93,14 +91,6 @@ install(DIRECTORY ${CMAKE_BIODYNAMO_BUILD_ROOT}/etc DESTINATION ${DIRNAME} USE_SOURCE_PERMISSIONS FILES_MATCHING PATTERN "*") -if(notebooks) - install(DIRECTORY ${CMAKE_BIODYNAMO_BUILD_ROOT}/notebook - DESTINATION ${DIRNAME} - USE_SOURCE_PERMISSIONS - FILES_MATCHING PATTERN "*" - PATTERN "*.tar.gz" EXCLUDE) -endif() - # We need to install manually these targets in order to clear their RPATH. # They have been already copied inside the final install directory by the # previous instruction, but their RPATH still points to files in the build @@ -111,15 +101,6 @@ install(TARGETS biodynamo if(test) install(TARGETS biodynamo-unit-tests - LIBRARY - DESTINATION ${DIRNAME}/lib) - install(TARGETS biodynamo-unit-tests-bin RUNTIME DESTINATION ${DIRNAME}/bin) endif() - -if (notebooks) - install(DIRECTORY ${CMAKE_BIODYNAMO_BUILD_ROOT}/notebooks DESTINATION ${DIRNAME} - FILES_MATCHING - PATTERN "*.ipynb" PATTERN "*.h" PATTERN "*.C" PATTERN "*.html") -endif() diff --git a/cmake/Notebooks.cmake b/cmake/Notebooks.cmake deleted file mode 100644 index 83e1746b0..000000000 --- a/cmake/Notebooks.cmake +++ /dev/null @@ -1,55 +0,0 @@ -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -# Adds a target to generate JupyROOT notebooks (interactive mode and static -# html) and ROOT macros from the available notebooks - -# Macro to get all subdirectories from a directory -MACRO(SUBDIRLIST result curdir) - FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) - SET(dirlist "") - FOREACH(child ${children}) - IF(IS_DIRECTORY ${curdir}/${child}) - LIST(APPEND dirlist ${child}) - ENDIF() - ENDFOREACH() - SET(${result} ${dirlist}) -ENDMACRO() - -# Generate notebook from demo NB_NAME -function(GenerateNotebookTarget NB_NAME) - set(ENV{PYTHONPATH} "${ROOTSYS}/lib") - if(NOT BDM_OUT_OF_SOURCE) - set(LAUNCHER ${CMAKE_BINARY_DIR}/launcher.sh) - endif() - add_custom_command( - OUTPUT "${CMAKE_BINARY_DIR}/notebook/${NB_NAME}.html" - DEPENDS biodynamo copy_files_bdm "${CMAKE_BINARY_DIR}/notebook/${NB_NAME}.ipynb" - COMMAND bash -c "${LAUNCHER} jupyter nbconvert --to=html --ExecutePreprocessor.timeout=180 --execute ${CMAKE_BINARY_DIR}/notebook/${NB_NAME}.ipynb") -endfunction(GenerateNotebookTarget) - -if(notebooks) - file(GLOB NOTEBOOKS_PATHS LIST_DIRECTORIES false CONFIGURE_DEPENDS "${PROJECT_SOURCE_DIR}/notebook/*.ipynb") - set(NOTEBOOKS "") - foreach(FILE ${NOTEBOOKS_PATHS}) - get_filename_component(NB_NAME ${FILE} NAME_WE) - list(APPEND NOTEBOOKS ${NB_NAME}) - endforeach() - set(NOTEBOOKS_DEPENDENCIES "") - foreach(NB_NAME ${NOTEBOOKS}) - GenerateNotebookTarget(${NB_NAME}) - list(APPEND NOTEBOOKS_DEPENDENCIES "${CMAKE_BINARY_DIR}/notebook/${NB_NAME}.html") - endforeach() - add_custom_target(notebooks ALL DEPENDS ${NOTEBOOKS_DEPENDENCIES}) -endif() diff --git a/cmake/RootUseFile.cmake b/cmake/RootUseFile.cmake deleted file mode 100644 index c5ce73236..000000000 --- a/cmake/RootUseFile.cmake +++ /dev/null @@ -1,3 +0,0 @@ -#---Set Link and include directories-------------------------------------------------------------- -include_directories(${ROOT_INCLUDE_DIRS}) -link_directories(${ROOT_LIBRARY_DIR}) diff --git a/cmake/Testing.cmake b/cmake/Testing.cmake index 1e2c48b91..4dc867445 100644 --- a/cmake/Testing.cmake +++ b/cmake/Testing.cmake @@ -18,7 +18,7 @@ ExternalProject_Add( URL "${CMAKE_SOURCE_DIR}/third_party/gtest-1.17.0.zip" PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gtest" CMAKE_ARGS - -DPYTHON_EXECUTABLE=${Python_EXECUTABLE} + -DPYTHON_EXECUTABLE=${Python3_EXECUTABLE} -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON -DCMAKE_VISIBILITY_INLINES_HIDDEN:BOOL=ON -DCMAKE_POLICY_DEFAULT_CMP0063=NEW @@ -52,7 +52,9 @@ include_directories("${CMAKE_BINARY_DIR}/gtest/src/gtest/googletest/include") add_custom_target(run-check COMMAND ${CMAKE_CTEST_COMMAND} --force-new-ctest-process --output-on-failure) # create target for running biodynamo-unit-tests -add_custom_target(run-unit-tests COMMAND ${CMAKE_BINARY_DIR}/bin/biodynamo-unit-tests) +add_custom_target(run-unit-tests + COMMAND ${CMAKE_BINARY_DIR}/launcher.sh + ${CMAKE_BINARY_DIR}/bin/biodynamo-unit-tests) add_dependencies(run-unit-tests biodynamo-unit-tests) # add custom clean target for test project @@ -96,9 +98,9 @@ function(bdm_add_test_executable TEST_TARGET) if (valgrind AND VALGRIND_FOUND AND NOT coverage) # filter out tests that would take too long if tested under valgrind add_test(NAME "valgrind_${TEST_TARGET}" - COMMAND ${CMAKE_BINARY_DIR}/launcher.sh ${CMAKE_SOURCE_DIR}/util/valgrind.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET} -- --gtest_filter=-*DeathTest.*:IOTest.InvalidRead:SchedulerTest.Backup:ResourceManagerTest.SortAndForEachAgentParallel*:InlineVector*:NeuriteElementBehaviour.*:MechanicalInteraction.*:DiffusionTest.*Convergence*:FLAKY_ParaviewIntegrationTest*:AgentVectorTest.Equality:SchedulerTest::LoadAndBalanceAfterEnvironment) + COMMAND ${CMAKE_BINARY_DIR}/launcher.sh ${CMAKE_SOURCE_DIR}/util/valgrind.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET} -- --gtest_filter=-*DeathTest.*:IOTest.InvalidRead:ResourceManagerTest.SortAndForEachAgentParallel*:InlineVector*:NeuriteElementBehaviour.*:MechanicalInteraction.*:DiffusionTest.*Convergence*:FLAKY_ParaviewIntegrationTest*:AgentVectorTest.Equality:SchedulerTest::LoadAndBalanceAfterEnvironment) add_custom_target(run-valgrind - COMMAND ${CMAKE_BINARY_DIR}/launcher.sh ${CMAKE_SOURCE_DIR}/util/valgrind.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET} -- --gtest_filter=-*DeathTest.*:IOTest.InvalidRead:SchedulerTest.Backup:ResourceManagerTest.SortAndForEachAgentParallel*:InlineVector*:NeuriteElementBehaviour.*:MechanicalInteraction.*:DiffusionTest.*Convergence*:FLAKY_ParaviewIntegrationTest*:AgentVectorTest.Equality:SchedulerTest::LoadAndBalanceAfterEnvironment) + COMMAND ${CMAKE_BINARY_DIR}/launcher.sh ${CMAKE_SOURCE_DIR}/util/valgrind.sh ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${TEST_TARGET} -- --gtest_filter=-*DeathTest.*:IOTest.InvalidRead:ResourceManagerTest.SortAndForEachAgentParallel*:InlineVector*:NeuriteElementBehaviour.*:MechanicalInteraction.*:DiffusionTest.*Convergence*:FLAKY_ParaviewIntegrationTest*:AgentVectorTest.Equality:SchedulerTest::LoadAndBalanceAfterEnvironment) add_dependencies(run-valgrind biodynamo-unit-tests) endif() diff --git a/cmake/UseBioDynaMo.cmake.in b/cmake/UseBioDynaMo.cmake.in index 80e8020e1..5aa660615 100644 --- a/cmake/UseBioDynaMo.cmake.in +++ b/cmake/UseBioDynaMo.cmake.in @@ -38,7 +38,6 @@ include(utils) # Option set when biodynamo was built SET(cuda_default @cuda@) SET(opencl_default @opencl@) -SET(dict_default @dict@) SET(numa_default @numa@) SET(sbml_default @sbml@) SET(vtune_default @vtune@) @@ -51,7 +50,6 @@ SET(boost_default @boost@) # Options. Turn on with 'cmake -Dmyvarname=ON'. option(cuda "Enable CUDA code generation for GPU acceleration" @cuda@) option(opencl "Enable OpenCL code generation for GPU acceleration" @opencl@) -option(dict "Build with ROOT dictionaries" @dict@) option(numa "Enable Numa support" @numa@) option(sbml "Enable SBML support" @sbml@) option(vtune "Enable VTune performance analysis" @vtune@) @@ -69,10 +67,6 @@ if (opencl AND NOT opencl_default) MESSAGE(FATAL_ERROR "One of the option which you provided (-Dopencl=${opencl}) is not compatible with \ BioDynaMo. BioDynaMo was built by setting -Dopencl to ${opencl_default}. Please change -Dopencl to -Dopencl=${opencl_default}.") endif() -if (dict AND NOT dict_default) - MESSAGE(FATAL_ERROR "One of the option which you provided (-Ddict=${dict}) is not compatible with \ -BioDynaMo. BioDynaMo was built by setting -Ddict to ${dict_default}. Please change -Ddict to -Ddict=${dict_default}.") -endif() if (numa AND NOT numa_default) MESSAGE(FATAL_ERROR "One of the option which you provided (-Dnuma=${numa}) is not compatible with \ BioDynaMo. BioDynaMo was built by setting -Dnuma to ${numa_default}. Please change -Dnuma to -Dnuma=${numa_default}.") @@ -146,10 +140,7 @@ if (jemalloc) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -ljemalloc -L ${JEMALLOC_LIBRARY_DIR}") endif() -# In order to correctly compile and link the multi simulation manager with MPI, -# you need to set CMAKE_[CXX|C]_COMPILER to [mpic++|mpicc] -# We still however need to explicitly add the mpi.h include path to our include_directories -# because rootcling will complain about missing mpi.h +# BioDynaMo uses MPI for distributed simulation support. find_package(MPI COMPONENTS CXX) if(MPI_FOUND) set(CMAKE_CXX_COMPILER ${MPI_CXX_COMPILER}) @@ -212,12 +203,6 @@ if(numa) endif() endif() -find_package(ROOT REQUIRED COMPONENTS Geom Gui Eve GenVector) -verify_root() -if (dict) - add_definitions("-DUSE_DICT") -endif() - if (vtune) find_package(VTune) if(${VTune_FOUND}) @@ -347,13 +332,9 @@ endfunction(bdm_add_test) # -------------------- includes ----------------------------------------------- set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${BDMSYS}/share/cmake") include("${BDMSYS}/share/cmake/BioDynaMo.cmake") -include(${ROOT_USE_FILE}) - -fix_rootcling_omp_issue() fix_macos_opencl_header_issue() -list(REMOVE_ITEM ROOT_LIBRARIES "$ENV{BDMSYS}/third_party/root/lib/libEve.so") -set(BDM_REQUIRED_LIBRARIES ${BDM_REQUIRED_LIBRARIES} biodynamo ${ROOT_LIBRARIES}) +set(BDM_REQUIRED_LIBRARIES ${BDM_REQUIRED_LIBRARIES} biodynamo) include_directories("$ENV{BDMSYS}/include") # armadillo is added as a subdirectory in optimlib diff --git a/cmake/Versioning.cmake b/cmake/Versioning.cmake index f0c610316..f0740d661 100644 --- a/cmake/Versioning.cmake +++ b/cmake/Versioning.cmake @@ -18,7 +18,7 @@ be done statically. In order to enable the automatic detection, please run prere endif() execute_process( - COMMAND ${Python_EXECUTABLE} util/version/generate_version_files.py ${GIT_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR} + COMMAND ${Python3_EXECUTABLE} util/version/generate_version_files.py ${GIT_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR} ${PROJECT_VERSION} ${CMAKE_SOURCE_DIR}/.git WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) diff --git a/cmake/Website.cmake b/cmake/Website.cmake index fdc3fe205..63ff619f2 100644 --- a/cmake/Website.cmake +++ b/cmake/Website.cmake @@ -32,14 +32,6 @@ function(GenerateStaticFiles TARGET FLAGS) endif() add_dependencies(${TARGET} doc) - # BDM notebook dependency - if (notebooks) - add_dependencies(${TARGET} notebooks) - else() - message(FATAL_ERROR "You cannot build the website without building the BioDynaMo notebooks first. -Enable the notebook feature by adding the following cmake parameter: -Dnotebooks=ON -") - endif() endfunction() if (website) diff --git a/cmake/bdm-dictionary b/cmake/bdm-dictionary deleted file mode 100755 index 527b1cb5b..000000000 --- a/cmake/bdm-dictionary +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python3 -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -# This script generates BioDynaMo dictionaries -import argparse -import os -import platform - -def AppendPrefix(prefix, prefixes): - if prefix.endswith("/"): - prefixes.append(prefix) - else: - prefixes.append("{}/".format(prefix)) - -def RemoveLongestPrefix(search, prefixes): - lengths = [len(prefix) for prefix in prefixes if search.startswith(prefix)] - if lengths: - return search[max(lengths):] - else: - return search - -def ReplaceSpecialPaths(include_dir, environmentals): - for e in environmentals: - path = os.getenv(e) - if path == None: - continue - if not path.endswith("/"): - path = "{}/".format(path) - if include_dir.startswith(path): - return 'std::getenv("{0}") << "/{1}"'.format(e, include_dir[len(path):]) - return '"{}"'.format(include_dir) - -if __name__ == '__main__': - parser = argparse.ArgumentParser(prog='bdm-dictionary', - description='This script generates the biodynamo c++ dictionary file.', - epilog='') - - parser.add_argument('--output', action='store', type=str, required=True, help='Filename of the bdm dictionary that will be generated.') - parser.add_argument('--out-of-source', action='store_true', help='Generate bdm dictionary for an out-of-source build. e.g. a simulation.') - parser.add_argument('--bdm-source', action='store', type=str, required=False, help='Source directory of BioDynaMo for bdm build.') - parser.add_argument('--include-dirs', nargs='+', type=str, required=True, help='At least one directory that contains the header files.') - parser.add_argument('--headers', nargs='+', type=str, required=True, help='At least one header file containing biodynamo definitions.') - - args = parser.parse_args() - - with open(args.output, "w") as f: - f.write(""" -// BioDynaMo dictionary. -// This file was generated. -// Do NOT change it. -// Changes will be lost the next time this file is generated. - -#include "core/util/jit.h" -#include -#include -namespace { - -void AppendEnvVar(std::stringstream& s, const char* var_name, - const char* suffix) { - auto val = std::getenv(var_name); - if (val) { - s << val << suffix << ":"; - } -} - -static struct BioDynaMoDictInit { - BioDynaMoDictInit() { - std::stringstream idirs; -""") - - prefixes = [] - environmentals = ["ParaView_DIR", "ROOTSYS", "BDMSYS"] - if not args.out_of_source: - # For Apple machines, ParaView is version 5.10 - system_config = platform.uname() - if (system_config.system == "Darwin"): - include_suffix = ["/include/paraview-5.10", - "/include", - "/include"] - else: - include_suffix = ["/include/paraview-5.9", - "/include", - "/include"] - cnt = 0 - # default includes - for e in environmentals: - f.write(' AppendEnvVar(idirs, "{0}", "{1}");\n'.format(e, include_suffix[cnt])) - cnt = cnt + 1 - for id in args.include_dirs: - if id.startswith("{}/{}".format(args.bdm_source, "demo")): - bdmsys_subdir = id.replace(args.bdm_source, "") - f.write(' AppendEnvVar(idirs, "{0}", "{1}");\n'.format("BDMSYS", bdmsys_subdir)) - elif id.startswith("{}/{}".format(args.bdm_source, "benchmark")): - f.write(' AppendEnvVar(idirs, "{0}", "{1}");\n'.format("BDMSYS", "/benchmark")) - AppendPrefix(id, prefixes) - else: - for e in environmentals: - env = os.getenv(e) - if env != None: - AppendPrefix(env, prefixes) - for id in args.include_dirs: - id_processed = ReplaceSpecialPaths(id, environmentals) - if id_processed != "": - AppendPrefix(id, prefixes) - f.write(' idirs << {0} << ":";\n'.format(id_processed)) - - for h in args.headers: - f.write(' bdm::JitHeaders::Register("{0}");\n'.format(RemoveLongestPrefix(h, prefixes))) - - f.write(""" - AppendEnvVar(idirs, "ROOT_INCLUDE_PATH", ""); - setenv("ROOT_INCLUDE_PATH", idirs.str().c_str(), true); - } -} bdm_dict_initializer; - -} - - -""") - diff --git a/cmake/env/bdm-config.in b/cmake/env/bdm-config.in index b881bc01c..1c623e5d4 100755 --- a/cmake/env/bdm-config.in +++ b/cmake/env/bdm-config.in @@ -76,7 +76,6 @@ split_multiple_lib_path() { arch=@architecture@ platform=@platform@ -rootvers=@rootvers@ bindir=@bindir@ libdir=@libdir@ incdir=@incdir@ @@ -108,7 +107,7 @@ cxxversionflag="-std=c++${cxxstd}" ### end of machine and compiler dependent settings ### usage="\ -Usage: bdm-config [--version] [--root-version]\ +Usage: bdm-config [--version]\ [--debug] [--opt] [--cxxflags] [--cxxincludes]\ [--ldflags] [--libs] [--bindir] [--libdir] [--incdir]\ [--cxx] [--ld ] [--cmakedir] [--cmake-invoke] [--config]\ @@ -145,24 +144,19 @@ while test $# -gt 0; do exit 1 fi ;; - --root-version) - ### Output the ROOT version number used to build BDM with. - out="$out $rootvers" - ;; --cxxflags) ### Output the compiler flags if test ${incdir} != /usr/include; then includes=-I${incdir} fi - out="$out $includes $cxxdefines $cxxversionflag $cxxflags $cxxoptflags $cxxdebflags $(root-config --cflags)" + out="$out $includes $cxxdefines $cxxversionflag $cxxflags $cxxoptflags $cxxdebflags" ;; --cxxincludes) ### Output only the include flags for BioDynaMo headers if test ${incdir} != /usr/include; then includes=-I${incdir} fi - out="$out $includes $(root-config --noauxcflags --cflags)" - # local omp directory needed for rootcling (used in bdm-code-generation) + out="$out $includes" out="$out -I${incdir}/../omp" ;; --cxxdefines) @@ -171,7 +165,7 @@ while test $# -gt 0; do ;; --ldflags) ### Output linker flags - out="$out $ldflags $cxxflags $cxxoptflags $cxxdebflags $(root-config --ldflags)" + out="$out $ldflags $cxxflags $cxxoptflags $cxxdebflags" ;; --libs) if test ${libdir} != /usr/lib; then @@ -181,7 +175,7 @@ while test $# -gt 0; do split_multiple_lib_path $omplibs omplibs=$found_libs fi - libs="$bdmlibs $(root-config --libs) $omplibs" + libs="$bdmlibs $omplibs" out="$out $libdirs $libs" ;; --bindir) @@ -268,7 +262,6 @@ while test $# -gt 0; do echo " --cmake-invoke Print the BioDynaMo cmake invocation" echo " --config Print the cmake configuration options" echo " --version Print the BioDynaMo version" - echo " --root-version Print the version of ROOT used to build BioDynaMo" echo " --ncpu Print number of available (hyperthreaded) cores" echo " --cxx Print alternative C++ compiler specified when BDM was built" echo " --ld Print alternative Linker specified when BDM was built" diff --git a/cmake/env/launcher.sh b/cmake/env/launcher.sh index 1828e3979..6023ddf20 100755 --- a/cmake/env/launcher.sh +++ b/cmake/env/launcher.sh @@ -10,6 +10,6 @@ export BDM_THISBDM_SILENT=true # We redirect to /dev/null to ignore the success message when we want to # extract output in CMake (e.g. in Installation.cmake we want to obtain the # version number). -source @CMAKE_INSTALL_ROOT@/bin/thisbdm.sh +source @CMAKE_INSTALL_ROOT@/bin/thisbdm.sh || exit $? -$@ +exec "$@" diff --git a/cmake/env/sh_functions/paraview b/cmake/env/sh_functions/paraview deleted file mode 100755 index 948fa900b..000000000 --- a/cmake/env/sh_functions/paraview +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -paraview() { - "${ParaView_DIR}/bin/paraview" "$@" -} diff --git a/cmake/env/sh_functions/pvbatch b/cmake/env/sh_functions/pvbatch deleted file mode 100755 index 8e01891fb..000000000 --- a/cmake/env/sh_functions/pvbatch +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -pvbatch() { - "${ParaView_DIR}/bin/pvbatch" "$@" -} diff --git a/cmake/env/sh_functions/pvpython b/cmake/env/sh_functions/pvpython deleted file mode 100755 index 6bdc594fb..000000000 --- a/cmake/env/sh_functions/pvpython +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env bash - -pvpython() { - "${ParaView_DIR}/bin/pvpython" "$@" -} diff --git a/cmake/env/sh_functions/root b/cmake/env/sh_functions/root deleted file mode 100755 index 701205697..000000000 --- a/cmake/env/sh_functions/root +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/env bash - -root() { - "${BDM_ROOT_DIR}"/bin/root -l -e \ - 'cout << "Loading BioDynaMo into ROOT..." << endl; gROOT->LoadMacro("'"${BDMSYS}"'/etc/rootlogon.C");' "$@" -} diff --git a/cmake/env/thisbdm.fish b/cmake/env/thisbdm.fish index 875851f88..17bc18d54 100755 --- a/cmake/env/thisbdm.fish +++ b/cmake/env/thisbdm.fish @@ -166,29 +166,7 @@ function source_thisbdm set -gx LDFLAGS "-L$BREWPREFIX/opt/libomp/lib $LDFLAGS" end - # paraview versions might be different between OSes - set -l bdm_pv_version '5.9' - if test (uname) = 'Darwin' - set -l bdm_pv_version '5.9' - end - - # Clear the env from previously set ParaView and Qt paths. set -l with_paraview @with_paraview@ - if test "$with_paraview" = 'ON' - if test -n "$old_bdmsys" - _drop_from_var ParaView_DIR "$old_bdmsys/third_party/paraview/lib/cmake/paraview-$bdm_pv_version" - _drop_from_var ParaView_LIB_DIR "$old_bdmsys/third_party/paraview/lib" - _drop_from_var PV_PLUGIN_PATH "$old_bdmsys/lib/pv_plugin" - _drop_from_var PATH "$old_bdmsys/third_party/paraview/bin" - _drop_from_var Qt5_DIR "$old_bdmsys/third_party/qt/lib/cmake/Qt5" - _drop_from_var QT_QPA_PLATFORM_PLUGIN_PATH "$old_bdmsys/third_party/qt/plugins" - _drop_from_var DYLD_LIBRARY_PATH "$old_bdmsys/third_party/paraview/lib" - _drop_from_var DYLD_LIBRARY_PATH "$old_bdmsys/third_party/qt/lib" - _drop_from_var LD_LIBRARY_PATH "$old_bdmsys/third_party/paraview/lib" - _drop_from_var LD_LIBRARY_PATH "$old_bdmsys/third_party/qt/lib" - end - end - ######### set -l default_manpath if test -z "$MANPATH" @@ -269,146 +247,13 @@ function source_thisbdm end ######## - #### ROOT Specific Configurations #### - if test -z "$BDM_CUSTOM_ROOT" - if test -z "$ROOTSYS" - set -gx BDM_CUSTOM_ROOT false - else - set -gx BDM_CUSTOM_ROOT true - end - end - - if begin; - test -z "$BDM_ROOT_DIR"; and test -z "$ROOTSYS"; - end; or test "$BDM_CUSTOM_ROOT" = false - set -gx BDM_ROOT_DIR "$BDMSYS/third_party/root" - set -gx BDM_CUSTOM_ROOT false - end - - if test "$BDM_CUSTOM_ROOT" = true; and test -n "$ROOTSYS" - _bdm_info "[INFO] Custom ROOT 'ROOTSYS=$ROOTSYS'" - set orvers "@rootvers@" - set crvers ("$ROOTSYS"/bin/root-config --version; or echo '') - if test "$crvers" = "$orvers" - set -gx BDM_ROOT_DIR "$ROOTSYS" - else - _bdm_warn "[WARN] ROOTSYS points to ROOT version '$crvers'," - _bdm_warn " while BDM was built with version '$orvers'." - _bdm_warn " You may encounter errors as compatibility is not guaranteed." - # no longer fatal as user probably wants to override this for a reason. - end - end - - if not test -d "$BDM_ROOT_DIR" - _bdm_err "[ERR] We are unable to source ROOT! Please make sure ROOT is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export BDM_ROOT_DIR=path/to/root', before running cmake." - return 1 - end - - function __bdm_root - "$BDM_ROOT_DIR"/bin/root -l -e 'cout << "Loading BioDynaMo into ROOT..." << endl; gROOT->LoadMacro("'"$BDMSYS"'/etc/rootlogon.C");' $argv - end - funcsave __bdm_root - . "$BDM_ROOT_DIR/bin/thisroot.fish" - ######## - #### ParaView Specific Configurations #### if test "$with_paraview" = 'ON' - if test -z "$BDM_CUSTOM_PV" - if test -z "$ParaView_DIR" - set -gx BDM_CUSTOM_PV false - else - set -gx BDM_CUSTOM_PV true - end - end - - if test "$BDM_CUSTOM_PV" = false; or test -z "$ParaView_DIR" - set -gx ParaView_DIR "$BDMSYS/third_party/paraview" - else - _bdm_info "[INFO] Custom ParaView 'ParaView_DIR=$ParaView_DIR'" - end - - if not test -d "$ParaView_DIR" - _bdm_err "[ERR] We are unable to find ParaView! Please make sure it is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export ParaView_DIR=path/to/paraview' together with" - _bdm_err " 'export Qt5_DIR=path/to/qt', before running cmake." - return 1 - end - - if test -z "$ParaView_LIB_DIR" - set -gx ParaView_LIB_DIR "$ParaView_DIR/lib" - else - set -pgx ParaView_LIB_DIR "$ParaView_DIR/lib" - end - if test -z "$PV_PLUGIN_PATH" set -gx PV_PLUGIN_PATH "$BDMSYS/lib/pv_plugin" else set -pgx PV_PLUGIN_PATH "$BDMSYS/lib/pv_plugin" end - - # We don't add the ParaView site-packages path to PYTHONPATH, because pip in the - # pyenv environment will not function anymore: ModuleNotFoundError: No module named 'pip._internal' - alias __bdm_paraview='$ParaView_DIR/bin/paraview'; funcsave __bdm_paraview - # aliases are just wrapped functions in fish, so they have the desired behavior - alias __bdm_pvpython='$ParaView_DIR/bin/pvpython'; funcsave __bdm_pvpython - alias __bdm_pvbatch='$ParaView_DIR/bin/pvbatch'; funcsave __bdm_pvbatch - - if test -z "$LD_LIBRARY_PATH" - set -gx LD_LIBRARY_PATH "$ParaView_LIB_DIR" - else - set -pgx LD_LIBRARY_PATH "$ParaView_LIB_DIR" - end - - if test -z "$DYLD_LIBRARY_PATH" - set -gx DYLD_LIBRARY_PATH "$ParaView_LIB_DIR" - else - set -pgx DYLD_LIBRARY_PATH "$ParaView_LIB_DIR" - end - ######## - - #### Qt5 Specific Configurations #### - if test -z "$BDM_CUSTOM_QT" - if test -z "$Qt5_DIR" - set -gx BDM_CUSTOM_QT false - else - set -gx BDM_CUSTOM_QT true - end - end - - if test "$BDM_CUSTOM_QT" = false; or test -z "$Qt5_DIR" - set -gx Qt5_DIR "$BDMSYS/third_party/qt" - else - _bdm_info "[INFO] Custom Qt5 'Qt5_DIR=$QT5_DIR'" - end - - if not test -d "$Qt5_DIR" - _bdm_err "[ERR] We are unable to find Qt5! Please make sure it is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export Qt5_DIR=path/to/qt' together with" - _bdm_err " 'export ParaView_DIR=path/to/paraview', before running cmake." - return 1 - end - - if test -z "$QT_QPA_PLATFORM_PLUGIN_PATH" - set -gx QT_QPA_PLATFORM_PLUGIN_PATH "$Qt5_DIR/plugins" - else - set -pgx QT_QPA_PLATFORM_PLUGIN_PATH "$Qt5_DIR/plugins" - end - - if test -z "$LD_LIBRARY_PATH" - set -gx LD_LIBRARY_PATH "$Qt5_DIR/lib" - else - set -pgx LD_LIBRARY_PATH "$Qt5_DIR/lib" - end - - if test -z "$DYLD_LIBRARY_PATH" - set -gx DYLD_LIBRARY_PATH "$Qt5_DIR/lib" - else - set -pgx DYLD_LIBRARY_PATH "$Qt5_DIR/lib" - end end ####### @@ -440,29 +285,6 @@ function source_thisbdm end ####### - ### Enable commands in child shells (like in bash) ### - function __bdm_fish_functions - if test -d "$BDMSYS" - if test -d "$BDM_ROOT_DIR" - alias root='__bdm_root' - end - if test -d "$ParaView_DIR" - alias paraview='__bdm_paraview' - alias pvpython='__bdm_pvpython' - alias pvbatch='__bdm_pvbatch' - end - end - end - funcsave __bdm_fish_functions - set -l marker ' # >>thisbdm<<' - if test -e $__fish_config_dir/config.fish - # ensure the above is only called once in config.fish - sed -i.bak '/^.*'"$marker"'$/,$d' $__fish_config_dir/config.fish; and rm "$__fish_config_dir/config.fish.bak"; or return 1 - end - - echo "__bdm_fish_functions$marker" >> $__fish_config_dir/config.fish; or return 1 - __bdm_fish_functions; or return 1 - ### Environment Indicator ### if not test "$BDM_THISBDM_NOPROMPT" = true set -gx __bdm_major_minor (biodynamo --shortversion) diff --git a/cmake/env/thisbdm.sh b/cmake/env/thisbdm.sh index 262165bc2..1b88a25ed 100755 --- a/cmake/env/thisbdm.sh +++ b/cmake/env/thisbdm.sh @@ -249,55 +249,7 @@ _source_thisbdm() export LDFLAGS="-L$BREWPREFIX/opt/libomp/lib $LDFLAGS" fi - # paraview versions might be different between OSes - local bdm_pv_version='5.9' - if [ "$(uname)" = 'Darwin' ]; then - bdm_pv_version='5.10' - fi - - # Clear the env from previously set ParaView and Qt paths. local with_paraview=@with_paraview@ - if [ "$with_paraview" = 'ON' ]; then - if [ -n "${old_bdmsys}" ]; then - if [ -n "${ParaView_DIR}" ]; then - _drop_bdm_from_path "$ParaView_DIR" "${old_bdmsys}/third_party/paraview/lib/cmake/paraview-$bdm_pv_version" - ParaView_DIR=$_newpath - fi - if [ -n "${ParaView_LIB_DIR}" ]; then - _drop_bdm_from_path "$ParaView_LIB_DIR" "${old_bdmsys}/third_party/paraview/lib" - ParaView_LIB_DIR=$_newpath - fi - if [ -n "${PV_PLUGIN_PATH}" ]; then - _drop_bdm_from_path "$PV_PLUGIN_PATH" "${old_bdmsys}/lib/pv_plugin" - PV_PLUGIN_PATH=$_newpath - fi - if [ -n "${PATH}" ]; then - _drop_bdm_from_path "$PATH" "${old_bdmsys}/third_party/paraview/bin" - PATH=$_newpath - fi - if [ -n "${Qt5_DIR}" ]; then - _drop_bdm_from_path "$Qt5_DIR" "${old_bdmsys}/third_party/qt/lib/cmake/Qt5" - Qt5_DIR=$_newpath - fi - if [ -n "${QT_QPA_PLATFORM_PLUGIN_PATH}" ]; then - _drop_bdm_from_path "$QT_QPA_PLATFORM_PLUGIN_PATH" "${old_bdmsys}/third_party/qt/plugins" - QT_QPA_PLATFORM_PLUGIN_PATH=$_newpath - fi - if [ -n "${DYLD_LIBRARY_PATH}" ]; then - _drop_bdm_from_path "$DYLD_LIBRARY_PATH" "${old_bdmsys}/third_party/paraview/lib" - DYLD_LIBRARY_PATH=$_newpath - _drop_bdm_from_path "$DYLD_LIBRARY_PATH" "${old_bdmsys}/third_party/qt/lib" - DYLD_LIBRARY_PATH=$_newpath - fi - if [ -n "${LD_LIBRARY_PATH}" ]; then - _drop_bdm_from_path "$LD_LIBRARY_PATH" "${old_bdmsys}/third_party/paraview/lib" - LD_LIBRARY_PATH=$_newpath - _drop_bdm_from_path "$LD_LIBRARY_PATH" "${old_bdmsys}/third_party/qt/lib" - LD_LIBRARY_PATH=$_newpath - fi - fi - fi - ######### if [ -z "${MANPATH}" ]; then local default_manpath @@ -386,156 +338,14 @@ _source_thisbdm() export CMAKE_PREFIX_PATH ######## - #### ROOT Specific Configurations #### - if [ -z "$BDM_CUSTOM_ROOT" ]; then - if [ -z "${ROOTSYS}" ]; then - export BDM_CUSTOM_ROOT=false - else - export BDM_CUSTOM_ROOT=true - fi - fi - - if [[ ( -z "${BDM_ROOT_DIR}" && -z "${ROOTSYS}" ) || "$BDM_CUSTOM_ROOT" = false ]]; then - BDM_ROOT_DIR=${BDMSYS}/third_party/root - export BDM_CUSTOM_ROOT=false - fi - - if [ "$BDM_CUSTOM_ROOT" = true ] && [ -n "${ROOTSYS}" ]; then - _bdm_info "[INFO] Custom ROOT 'ROOTSYS=${ROOTSYS}'" - local orvers="@rootvers@" - local crvers - crvers=$("$ROOTSYS"/bin/root-config --version || echo '') - if [ "$crvers" = "$orvers" ]; then - BDM_ROOT_DIR=${ROOTSYS} - else - _bdm_warn "[WARN] ROOTSYS points to ROOT version '$crvers'," - _bdm_warn " while BDM was built with version '$orvers'." - _bdm_warn " You may encounter errors as compatibility is not guaranteed." - # no longer fatal as user probably wants to override this for a reason. - fi - fi - - if ! [ -d "$BDM_ROOT_DIR" ]; then - _bdm_err "[ERR] We are unable to source ROOT! Please make sure ROOT is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export BDM_ROOT_DIR=path/to/root', before running cmake." - return 1 - fi - - export BDM_ROOT_DIR - # shellcheck disable=SC1090 - . "${BDM_ROOT_DIR}"/bin/thisroot.sh || return 1 - _bdm_define_command root || return 1 - ######## - #### ParaView Specific Configurations #### if [ "$with_paraview" = 'ON' ]; then - if [ -z "$BDM_CUSTOM_PV" ]; then - if [ -z "${ParaView_DIR}" ]; then - export BDM_CUSTOM_PV=false - else - export BDM_CUSTOM_PV=true - fi - fi - - if [ "$BDM_CUSTOM_PV" = false ] || [ -z "${ParaView_DIR}" ]; then - ParaView_DIR=${BDMSYS}/third_party/paraview; export ParaView_DIR - else - _bdm_info "[INFO] Custom ParaView 'ParaView_DIR=${ParaView_DIR}'" - fi - - if ! [ -d "$ParaView_DIR" ]; then - _bdm_err "[ERR] We are unable to find ParaView! Please make sure it is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export ParaView_DIR=path/to/paraview' together with" - _bdm_err " 'export Qt5_DIR=path/to/qt', before running cmake." - return 1 - fi - - if [ -z "${ParaView_LIB_DIR}" ]; then - ParaView_LIB_DIR="${ParaView_DIR}/lib" - else - ParaView_LIB_DIR="${ParaView_DIR}/lib":$ParaView_LIB_DIR - fi - export ParaView_LIB_DIR - if [ -z "${PV_PLUGIN_PATH}" ]; then PV_PLUGIN_PATH="${BDMSYS}/lib/pv_plugin" else PV_PLUGIN_PATH="${BDMSYS}/lib/pv_plugin":$PV_PLUGIN_PATH fi export PV_PLUGIN_PATH - - # We don't add the ParaView site-packages path to PYTHONPATH, because pip in the - # pyenv environment will not function anymore: ModuleNotFoundError: No module named 'pip._internal' - _bdm_define_command paraview || return 1 - _bdm_define_command pvpython || return 1 - _bdm_define_command pvbatch || return 1 - - if [ -z "${LD_LIBRARY_PATH}" ]; then - LD_LIBRARY_PATH="${ParaView_LIB_DIR}" - else - LD_LIBRARY_PATH="${ParaView_LIB_DIR}":$LD_LIBRARY_PATH - fi - export LD_LIBRARY_PATH - - if [ -z "${DYLD_LIBRARY_PATH}" ]; then - DYLD_LIBRARY_PATH="${ParaView_LIB_DIR}" - else - DYLD_LIBRARY_PATH="${ParaView_LIB_DIR}":$DYLD_LIBRARY_PATH - fi - export DYLD_LIBRARY_PATH - ######## - - #### Qt5 Specific Configurations #### - if [ -z "$BDM_CUSTOM_QT" ]; then - if [ -z "${Qt5_DIR}" ]; then - export BDM_CUSTOM_QT=false - else - export BDM_CUSTOM_QT=true - fi - fi - - if [ "$BDM_CUSTOM_QT" = false ] || [ -z "${Qt5_DIR}" ]; then - # On Apple devices we use the brew install of Qt5 - if [ "$(uname)" = 'Darwin' ];then - Qt5_DIR=$(brew --prefix)/opt/qt@5 - else - Qt5_DIR=${BDMSYS}/third_party/qt - fi - export Qt5_DIR - else - _bdm_info "[INFO] Custom Qt5 'Qt5_DIR=${QT5_DIR}'" - fi - - if ! [ -d "$Qt5_DIR" ]; then - _bdm_err "[ERR] We are unable to find Qt5! Please make sure it is installed" - _bdm_err " on your system! You can manually specify its location by executing" - _bdm_err " 'export Qt5_DIR=path/to/qt' together with" - _bdm_err " 'export ParaView_DIR=path/to/paraview', before running cmake." - return 1 - fi - - if [ -z "${QT_QPA_PLATFORM_PLUGIN_PATH}" ]; then - QT_QPA_PLATFORM_PLUGIN_PATH="${Qt5_DIR}/plugins" - else - QT_QPA_PLATFORM_PLUGIN_PATH="${Qt5_DIR}/plugins":$QT_QPA_PLATFORM_PLUGIN_PATH - fi - export QT_QPA_PLATFORM_PLUGIN_PATH - - if [ -z "${LD_LIBRARY_PATH}" ]; then - LD_LIBRARY_PATH="${Qt5_DIR}/lib" - else - LD_LIBRARY_PATH="${Qt5_DIR}/lib":$LD_LIBRARY_PATH - fi - export LD_LIBRARY_PATH - - if [ -z "${DYLD_LIBRARY_PATH}" ]; then - DYLD_LIBRARY_PATH="${Qt5_DIR}/lib" - else - DYLD_LIBRARY_PATH="${Qt5_DIR}/lib":$DYLD_LIBRARY_PATH - fi - export DYLD_LIBRARY_PATH fi ####### @@ -586,25 +396,6 @@ _source_thisbdm() autoload -Uz __bdm_zsh_completions || return 1 # compinit || return 1 # FIXME zsh completion broken - ### Enable commands in child shells (like in bash) ### - local ld_root='if [ -d "${BDM_ROOT_DIR}" ]; then autoload -Uz root; fi;' - local ld_pv='if [ -d "${ParaView_DIR}" ]; then autoload -Uz paraview pvpython pvbatch; fi;' - local marker=' # >>thisbdm<<' - local zshenv_line='if [ -d "${BDMSYS}" ]; then; '"${ld_root} ""${ld_pv}"' ; fi;'"${marker}" - local zsh_config_dir="$HOME" - if [ -n "$ZDOTDIR" ]; then - zsh_config_dir="$ZDOTDIR" - fi - - local zshenv_file="${zsh_config_dir}/.zshenv" - if ! [ -f "$zshenv_file" ]; then - _bdm_info "[INFO] creating .zshenv file '$zshenv_file'" - touch "$zshenv_file" - fi - - # ensure the above is only called once in .zshrc - sed -i.bak '/^.*'"$marker"'$/,$d' "$zshenv_file" && rm "${zshenv_file}.bak" || return 1 - echo "$zshenv_line" >> "$zshenv_file" fi ### Environment Indicator ### diff --git a/cmake/external/ParaView.cmake b/cmake/external/ParaView.cmake deleted file mode 100644 index 2cfc6de92..000000000 --- a/cmake/external/ParaView.cmake +++ /dev/null @@ -1,26 +0,0 @@ -include(utils) - -SET(PARAVIEW_SOURCE_DIR "${CMAKE_THIRD_PARTY_DIR}/paraview") - -if(APPLE AND "${DETECTED_ARCH}" STREQUAL "i386") - # The release of cmake 3.23.0 broke our build of ParaView on MacOSX. - # The build was fixed with a reupload and carries the additional tag cm233. - SET(PARAVIEW_TAR_FILE paraview_v5.10.0_cm323_${DETECTED_OS_VERS}_default.tar.gz) -elseif(APPLE AND "${DETECTED_ARCH}" STREQUAL "arm64") - SET(PARAVIEW_TAR_FILE paraview_v5.10.0_${DETECTED_OS_VERS}_default.tar.gz) -else() - SET(PARAVIEW_TAR_FILE paraview_v5.9.0_${DETECTED_OS_VERS}_default.tar.gz) -endif() -set(PARAVIEW_SHA_KEY ${DETECTED_OS_VERS}-ParaView) -set(PARAVIEW_SHA ${${PARAVIEW_SHA_KEY}}) - -message(STATUS "Using ParaView tarball : ${PARAVIEW_TAR_FILE}") -message(STATUS "Using ParaView source dir : ${PARAVIEW_SOURCE_DIR}") -message(STATUS "Using ParaView SHA key : ${PARAVIEW_SHA_KEY}") -message(STATUS "Verify ParaView SHA : ${PARAVIEW_SHA}") - -download_verify_extract( - http://cern.ch/biodynamo-lfs/third-party/${PARAVIEW_TAR_FILE} - ${PARAVIEW_SOURCE_DIR} - ${PARAVIEW_SHA} -) diff --git a/cmake/external/Qt.cmake b/cmake/external/Qt.cmake deleted file mode 100644 index 2ae195edc..000000000 --- a/cmake/external/Qt.cmake +++ /dev/null @@ -1,22 +0,0 @@ -include(utils) - -SET(QT_SOURCE_DIR "${CMAKE_THIRD_PARTY_DIR}/qt") - -set(QT_TAR_FILE qt_v5.12.10_${DETECTED_OS_VERS}.tar.gz) - -download_verify_extract( - http://cern.ch/biodynamo-lfs/third-party/${QT_TAR_FILE} - ${QT_SOURCE_DIR} - ${${DETECTED_OS_VERS}-Qt} -) - -# temporal workaround to avoid libprotobuf error for paraview -# use only until patched archive has been uploaded -IF (NOT APPLE) - execute_process(COMMAND rm ${QT_SOURCE_DIR}/plugins/platformthemes/libqgtk3.so - WORKING_DIRECTORY ${QT_SOURCE_DIR}) - execute_process(COMMAND rm ${QT_SOURCE_DIR}/lib/cmake/Qt5Gui/Qt5Gui_QGtk3ThemePlugin.cmake - WORKING_DIRECTORY ${QT_SOURCE_DIR}) - execute_process(COMMAND touch ${QT_SOURCE_DIR}/lib/cmake/Qt5Gui/Qt5Gui_QGtk3ThemePlugin.cmake - WORKING_DIRECTORY ${QT_SOURCE_DIR}) -ENDIF() diff --git a/cmake/external/ROOT.cmake b/cmake/external/ROOT.cmake deleted file mode 100644 index 9d62ac9b9..000000000 --- a/cmake/external/ROOT.cmake +++ /dev/null @@ -1,98 +0,0 @@ -include(utils) - -# Directory in which ROOT will be downloaded -SET(ROOT_SOURCE_DIR "${CMAKE_THIRD_PARTY_DIR}/root") - -set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_${DETECTED_OS_VERS}.tar.gz) -set(ROOT_SHA_KEY ${DETECTED_OS_VERS}-ROOT) -if(APPLE) - if("${DETECTED_OS_VERS}" MATCHES "^osx-15" OR - "${DETECTED_OS_VERS}" MATCHES "^osx-14" OR - "${DETECTED_OS_VERS}" MATCHES "^osx-13" OR - "${DETECTED_OS_VERS}" MATCHES "^osx-12" OR - "${DETECTED_OS_VERS}" MATCHES "^osx-11.6" OR - "${DETECTED_OS_VERS}" MATCHES "^osx-11.7") - execute_process(COMMAND bash "-c" "xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9\.]*)/\\1/p'" OUTPUT_VARIABLE XCODE_VERS) - message(STATUS "##### XCODE version: ${XCODE_VERS}") - if("${XCODE_VERS}" GREATER_EQUAL "16.4") - message(STATUS "##### Using ROOT builds for XCODE 16.4") - set(ROOT_TAR_FILE root_v6.36.00_cxx17_python3.9_osx-xcode-16.4-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-16.4-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "16.3") - message(STATUS "##### Using ROOT builds for XCODE 16.3") - set(ROOT_TAR_FILE root_v6.34.08_cxx17_python3.9_osx-xcode-16.3-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-16.3-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "16.2") - message(STATUS "##### Using ROOT builds for XCODE 16.2") - set(ROOT_TAR_FILE root_v6.32.08_cxx17_python3.9_osx-xcode-16.2-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-16.2-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "16.1") - message(STATUS "##### Using ROOT builds for XCODE 16.1") - set(ROOT_TAR_FILE root_v6.32.06_cxx17_python3.9_osx-xcode-16.1-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-16.1-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "16.0") - message(STATUS "##### Using ROOT builds for XCODE 16.0") - set(ROOT_TAR_FILE root_v6.33.01_cxx17_python3.9_osx-xcode-16.0-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-16.0-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "15.4") - message(STATUS "##### Using ROOT builds for XCODE 15.4") - set(ROOT_TAR_FILE root_v6.30.06_cxx17_python3.9_osx-xcode-15.4-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-15.4-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "15.3") - message(STATUS "##### Using ROOT builds for XCODE 15.3") - set(ROOT_TAR_FILE root_v6.30.06_cxx17_python3.9_osx-xcode-15.3-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-15.3-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "15.0") - message(STATUS "##### Using ROOT builds for XCODE 15.2") - set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-15.2-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-15.2-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "14.3") - message(STATUS "##### Using ROOT builds for XCODE 14.3") - set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-14.3-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-14.3-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "14.2") - message(STATUS "##### Using ROOT builds for XCODE 14.2") - set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-14.2-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-14.2-${DETECTED_ARCH}-ROOT) - elseif("${XCODE_VERS}" GREATER_EQUAL "14.1") - message(STATUS "##### Using ROOT builds for XCODE 14.1") - set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-14.1-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-14.1-${DETECTED_ARCH}-ROOT) - else() - message(STATUS "##### Using ROOT builds for XCODE 13.1") - set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_osx-xcode-13.1-${DETECTED_ARCH}.tar.gz) - set(ROOT_SHA_KEY osx-xcode-13.1-${DETECTED_ARCH}-ROOT) - endif() - elseif("${DETECTED_OS_VERS}" MATCHES "^osx-11") - message(FATAL_ERROR "We officially only support the latest macOS 11 versions 11.6, 11.7.") - endif() -#else() - #if("${DETECTED_OS_VERS}" MATCHES "^ubuntu-23" AND - #"${DETECTED_ARCH}" STREQUAL "aarch64") - #set(ROOT_SHA_KEY ubuntu-23.04-${DETECTED_ARCH}-ROOT) - #set(ROOT_TAR_FILE root_v6.30.02_cxx17_python3.9_ubuntu-23.04-${DETECTED_ARCH}.tar.gz) -# endif() -endif() -set(ROOT_SHA ${${ROOT_SHA_KEY}}) - -message(STATUS "Using ROOT tarball : ${ROOT_TAR_FILE}") -message(STATUS "Using ROOT source dir : ${ROOT_SOURCE_DIR}") -message(STATUS "Using ROOT SHA key : ${ROOT_SHA_KEY}") -message(STATUS "Verify ROOT SHA : ${ROOT_SHA}") - -download_verify_extract( - http://cern.ch/biodynamo-lfs/third-party/${ROOT_TAR_FILE} - ${ROOT_SOURCE_DIR} - ${ROOT_SHA} -) - -# Run again find_package in order to find ROOT -find_package(ROOT COMPONENTS Geom Gui GenVector REQUIRED) - -# Set ROOTSYS variable -string(REGEX REPLACE "/include$" "" TMP_ROOT_PATH ${ROOT_INCLUDE_DIRS}) -set(ENV{ROOTSYS} ${TMP_ROOT_PATH}) - -# Set ROOT_CONFIG_EXECUTABLE variable -find_program(ROOT_CONFIG_EXECUTABLE NAMES root-config HINTS "${TMP_ROOT_PATH}/bin") -SET(ROOT_CONFIG_EXECUTABLE ${ROOT_CONFIG_EXECUTABLE} PARENT_SCOPE) diff --git a/cmake/external/SHA256Digests.cmake b/cmake/external/SHA256Digests.cmake index e82005e35..a83eb093d 100644 --- a/cmake/external/SHA256Digests.cmake +++ b/cmake/external/SHA256Digests.cmake @@ -1,139 +1,5 @@ -SET(osx-11.0-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.0-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.1-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.1-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.2-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.3-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.4-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.5-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.6-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-11.6-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.6-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-11.7-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-11.7-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-11.7-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-12.0-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.0-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-12.0-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.1-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.1-i386-Qt 7af9eed30be9f25bbdcf7e5747ab53eaaf077c6b2a974c2e520ac678f5a147a7) -SET(osx-12.1-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.2-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.3-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.4-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.5-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.6-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.6-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-12.7-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-12.7-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.0-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.0-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.1-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.1-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.2-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.3-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.4-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.5-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.6-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.6-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-13.7-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-13.7-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.0-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.0-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.1-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.1-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.2-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.3-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.4-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.5-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.6-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.6-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.7-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.7-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-14.8-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-14.8-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.0-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.0-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.1-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.1-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.2-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.2-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.3-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.3-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.4-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.4-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.5-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.5-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.6-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.6-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-15.7-i386-ParaView d2e89df30ab0e2729b28539de37753e09c061b4c434b0a68e80554f7fa617ccb) -SET(osx-15.7-arm64-ParaView 5e89b785ac0c56bbca31e2ae101a8986953e90227fe42a1ef7adcc70a0ff6fc4) -SET(osx-xcode-13.1-i386-ROOT be97dd72022c8d082fbe4394f18b55c4920f20b138cfff1b5fc2b41d397ac203) -SET(osx-xcode-13.1-arm64-ROOT 0a55b91c6df42d152b7943912e134f05c3872a73e73fcc129ee87fd847240ec8) -SET(osx-xcode-14.1-i386-ROOT 001311608512b24535bb9710b8baf006bd00e9b0595fd6bdf900d28b1e22c395) -SET(osx-xcode-14.1-arm64-ROOT fcbc0e4cdf49b8fd320f168461f8094464a1053c16a466d48aea7163686f01cb) -SET(osx-xcode-14.2-i386-ROOT db040341c9ab59d911c6e90110879495e7a9d089b41f1f52f1f56d5703d8d29a) -SET(osx-xcode-14.2-arm64-ROOT fcbc0e4cdf49b8fd320f168461f8094464a1053c16a466d48aea7163686f01cb) -SET(osx-xcode-14.3-i386-ROOT c4f4c7a9848121ae19f3fe3c40c5812813ed42d9dfa7f1948f67907ed47fa083) -SET(osx-xcode-14.3-arm64-ROOT 6ffcfaadd4de627cffde2e42fded9175b730769071396d7abdabeefc2714839a) -SET(osx-xcode-15.2-i386-ROOT 3dea500451dc2c84d150a7d5f4b27d2cba3e867d7c775b744ac898f9f6e51249) -SET(osx-xcode-15.2-arm64-ROOT 677429937f13a44a088b71851f0af111509bf81a9a25a299c905b6c9f7249587) -SET(osx-xcode-15.3-i386-ROOT 52cef545acf679c3e491c9ef14e18edee454c90309b7fcf5f36fc2e659bdbde5) -SET(osx-xcode-15.3-arm64-ROOT 3ee0885c329fab9a965c278cc491db82dcbde3999a96ac80d6f5145fb6794d1e) -SET(osx-xcode-15.4-i386-ROOT 360983914520c4c9f1d3dd03c5ccdc251b9f6835cf1bcd4b5e83e2748e04811a) -SET(osx-xcode-15.4-arm64-ROOT c50d3664b2eee3ed255ca3ae23f350aac0513bd740884b1133e0efb177bf1928) -SET(osx-xcode-16.0-i386-ROOT cab41b0f2e45990775f8d322713fb9c7904350fdf7f057b4b3cd6e73ad654bf1) -SET(osx-xcode-16.0-arm64-ROOT f48163b667df74038fd450ffa9dc96637ea535af4b9ff21f4643c121f30bdbfe) -SET(osx-xcode-16.1-i386-ROOT 5d8261b8a694151c802d9de2957e91380b31ddb2fa5c1028ed49afdf6baae6d9) -SET(osx-xcode-16.1-arm64-ROOT b339a8fac8e360087e533a30b4cd1d2a8059ec84d5826a3f9c8c64109fff1c41) -SET(osx-xcode-16.2-i386-ROOT b0be8291d14c0c66f250297e524debc1d6888a95da32e80918fc51c5c582fc8b) -SET(osx-xcode-16.2-arm64-ROOT 4cd66eca15c97b3ffbf159fb7aeb728483c745b275ef89b3679812561cf0e346) -SET(osx-xcode-16.3-i386-ROOT b0be8291d14c0c66f250297e524debc1d6888a95da32e80918fc51c5c582fc8b) -SET(osx-xcode-16.3-arm64-ROOT b525e0d360eb6c1912ab1cfcbf7fe30bfa8d55c48b80bcae65b62bf403ca0d9c) -SET(osx-xcode-16.4-i386-ROOT 7de1ad1d658363ca13687dddd7164f039d58fb549a4befe4a622a8e60eede62f) -SET(osx-xcode-16.4-arm64-ROOT 88810d081e0237e2fe436dc937e783bdf3f1c5d86ed7b3ff766d969dfe6bd0b3) - SET(ubuntu-18.04-Libroadrunner bf9293c1c95d0b65227bd7e08c0048116ba851bcec5028ef72ea13762ef79276) -SET(ubuntu-18.04-ParaView e3fd74b13e9a4086988c5104c6b8d95c56365d25b491706a8e72018d0e5c76f1) -SET(ubuntu-18.04-Qt 6e7143986d2039b5384475671d4fe27db0a473baf2c3f3204a62ea2691e84733) -SET(ubuntu-18.04-ROOT 9f5ff80c871839188cd17e5ac6227b3e55eb37a3064fecb6740afec1766ff58c) - SET(ubuntu-20.04-Libroadrunner bdf92f30d49f332ec5a15b53fe04c0f8ffb518db62010ee1269ba55698e1b651) -SET(ubuntu-20.04-ParaView 0b87c6c79eb13b3c485a366509cf9deba06731b591f6e54b134d45afc95c8276) -SET(ubuntu-20.04-Qt b2388d1bcca4e3741ab5b2b0fb95395aeb6c448951a0d3cdeb6db33b64a7d41c) -SET(ubuntu-20.04-ROOT a1654cefce7b61fcfb4ae8057296fab9166d5f8bc135891b45dff899e877742b) - SET(ubuntu-22.04-Libroadrunner bdf92f30d49f332ec5a15b53fe04c0f8ffb518db62010ee1269ba55698e1b651) -SET(ubuntu-22.04-ParaView afc803835973fdb8b963fe10eaf1103f2e1650e4573141964c1322053ec852cc) -SET(ubuntu-22.04-Qt b2388d1bcca4e3741ab5b2b0fb95395aeb6c448951a0d3cdeb6db33b64a7d41c) -SET(ubuntu-22.04-ROOT 24921a85b53c5cfbe9f192e523263781d595c59c9c553818349992e61efc64ac) - -SET(ubuntu-23.04-aarch64-ROOT 7d2fcaaeb1e452c38c1d8436288e3171d1b6935f5b6f25d5df16b21e00ca45d8) -SET(ubuntu-23.10-aarch64-ROOT 8f6fa9db579e011ef4ae7e96830d8ab1284b6df95a1b2f46e6a1cea56fd4626f) - SET(ubuntu-24.04-Libroadrunner bdf92f30d49f332ec5a15b53fe04c0f8ffb518db62010ee1269ba55698e1b651) -SET(ubuntu-24.04-ParaView afc803835973fdb8b963fe10eaf1103f2e1650e4573141964c1322053ec852cc) -SET(ubuntu-24.04-Qt b2388d1bcca4e3741ab5b2b0fb95395aeb6c448951a0d3cdeb6db33b64a7d41c) -SET(ubuntu-24.04-ROOT 24921a85b53c5cfbe9f192e523263781d595c59c9c553818349992e61efc64ac) - SET(centos-7-Libroadrunner a0b49487a28aedc4b909a71c66263d4a388964008e2b23073dd744231251470c) -SET(centos-7-ParaView 45d545e75baf32c9fe30944781b4f6b172d4efd7d6cd794dcd19ec671cc5ead0) -SET(centos-7-Qt 4308621ff9ec84585c3aead92a9d2de787b3c700323333b6e78ed45d04a0d2a4) -SET(centos-7-ROOT 54298aa5f13dc2942925c10d755768f81f53d7135ac1a3e698e9b7ef1a3dfd1e) - diff --git a/cmake/selection-libVisualizationAdaptor.xml b/cmake/selection-libVisualizationAdaptor.xml deleted file mode 100644 index 1c3e243f6..000000000 --- a/cmake/selection-libVisualizationAdaptor.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/cmake/selection-libbiodynamo.xml b/cmake/selection-libbiodynamo.xml deleted file mode 100644 index 01b08e2f1..000000000 --- a/cmake/selection-libbiodynamo.xml +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cmake/selection.xml b/cmake/selection.xml deleted file mode 100644 index e2ccaae4f..000000000 --- a/cmake/selection.xml +++ /dev/null @@ -1,193 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 2dd29ef4f..ebbfa6915 100644 --- a/cmake/utils.cmake +++ b/cmake/utils.cmake @@ -51,86 +51,6 @@ function(detect_os) endif() endfunction() -# Try to find the ROOT package. It is an hard requirement -# for the project. If ROOT is not found on the system, it -# will be downloaded. If the found cached ROOT is not the right -# version (SHA256 check with builtin expected SHA256) then -# a new version will be downloaded. -# If a user installed ROOT is found we will check if ROOT -# was compiled using c++17. -function(verify_ROOT) - if(ROOT_FOUND AND CMAKE_THIRD_PARTY_DIR) - # check if found ROOT is BDM installed (matchres > -1) - string(FIND ${ROOT_INCLUDE_DIRS} ${CMAKE_THIRD_PARTY_DIR} matchres) - if (${matchres} GREATER -1) - # check SHA256 of ROOT to see if it matches currently supported ROOT - if (IS_DIRECTORY ${CMAKE_THIRD_PARTY_DIR}/root) - if (EXISTS ${CMAKE_THIRD_PARTY_DIR}/root/tar-sha256) - # check if SHA256 of installed ROOT is the same as the expected one - file(READ ${CMAKE_THIRD_PARTY_DIR}/root/tar-sha256 TAR_SHA256) - if(APPLE) - execute_process(COMMAND bash "-c" "xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9\.]*)/\\1/p' | tr -d '\\n'" OUTPUT_VARIABLE XCODE_VERS) - set(ROOT_SHA_KEY osx-xcode-${XCODE_VERS}-${DETECTED_ARCH}-ROOT) - else() - set(ROOT_SHA_KEY ${DETECTED_OS_VERS}-ROOT) - endif() - set(ROOT_SHA ${${ROOT_SHA_KEY}}) - if(NOT "${TAR_SHA256}" STREQUAL "${ROOT_SHA}") - # BDM installed ROOT has wrong SHA256... deleting it - message(WARNING "The found ROOT version is not compatible... deleting it...") - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/root) - unset(ROOT_FOUND) - else() - message(STATUS "Found a compatible ROOT version in ${CMAKE_THIRD_PARTY_DIR}/root") - endif() - else() - # BDM installed ROOT exists but no SHA256 file... deleting it - message(WARNING "The found ROOT version cannot be determined... deleting it...") - file(REMOVE_RECURSE ${CMAKE_THIRD_PARTY_DIR}/root) - unset(ROOT_FOUND) - endif() - endif() - endif() - endif() - if(NOT ROOT_FOUND) - print_warning() - message("We did not find any ROOT installed on the system. We will proceed to download it. " - "ROOT will be installed in the location ${CMAKE_THIRD_PARTY_DIR}/root.") - print_line() - include(external/ROOT) - - # Propagate the needed variables to the parent - SET(ROOT_FOUND ${ROOT_FOUND} PARENT_SCOPE) - SET(ROOT_VERSION ${ROOT_VERSION} PARENT_SCOPE) - SET(ROOT_LIBRARIES ${ROOT_LIBRARIES} PARENT_SCOPE) - SET(ROOT_LIBRARY_DIR ${ROOT_LIBRARY_DIR} PARENT_SCOPE) - SET(ROOT_INCLUDE_DIRS ${ROOT_INCLUDE_DIRS} PARENT_SCOPE) - SET(ROOT_ETC_DIR ${ROOT_ETC_DIR} PARENT_SCOPE) - SET(ROOT_CONFIG_EXECUTABLE ${ROOT_CONFIG_EXECUTABLE} PARENT_SCOPE) - SET(ROOTCLING_EXECUTABLE ${ROOTCLING_EXECUTABLE} PARENT_SCOPE) - SET(GENREFLEX_EXECUTABLE ${GENREFLEX_EXECUTABLE} PARENT_SCOPE) - else() - # When ROOT is found, but it's not C++17 compliant, we exit the installation, because ROOT needs - # to be properly sourced prior to invoking CMake (CMake cannot do this for us, because it requires - # reverting the previous find_package() call, which is not possible.) - if(NOT ROOT_cxx17_FOUND) - message(FATAL_ERROR "The ROOT installation found in ${ROOTSYS} is not C++17 compliant. " - "Please unset ROOTSYS and re-run cmake so that a compatible version of ROOT will be downloaded.") - endif() - - if (NOT DEFINED ROOTSYS OR NOT DEFINED ${ROOTSYS}) - # Set ROOTSYS variable - string(REGEX REPLACE "/include$" "" TMP_ROOT_PATH ${ROOT_INCLUDE_DIRS}) - set(ENV{ROOTSYS} ${TMP_ROOT_PATH}) - endif() - endif() - - # ROOT must be 6.22 or newer - if("${ROOT_VERSION}" VERSION_LESS "6.22/00") - message(FATAL_ERROR "The ROOT version must be 6.22 or newer, current version is ${ROOT_VERSION}") - endif() -endfunction() - # Convert a list to a better representation # https://stackoverflow.com/questions/17666003/cmake-output-a-list-with-delimiters function (ListToString result delim) @@ -246,23 +166,9 @@ function(install_inside_build) GLOB "*" ".*" ) - # Copy notebook files - add_copy_directory(copy_files_bdm - ${CMAKE_SOURCE_DIR}/notebook - DESTINATION ${CMAKE_INSTALL_ROOT}/notebook - GLOB "*" ".*" - ) - - add_copy_files(copy_files_bdm - ${CMAKE_BINARY_DIR}/rootlogon.C - DESTINATION ${CMAKE_INSTALL_ROOT}/etc - ) - add_copy_files(copy_files_bdm DESTINATION ${CMAKE_INSTALL_BINDIR} ${CMAKE_BINARY_DIR}/version/bdm_version.py - ${CMAKE_SOURCE_DIR}/util/makefile-build/bdm-code-generation - ${CMAKE_SOURCE_DIR}/cmake/bdm-dictionary ) # Copy some cmake files @@ -272,14 +178,12 @@ function(install_inside_build) ${CMAKE_SOURCE_DIR}/cmake/BioDynaMo.cmake ${CMAKE_SOURCE_DIR}/cmake/SetCompilerFlags.cmake ${CMAKE_SOURCE_DIR}/cmake/FindLibroadrunner.cmake - ${CMAKE_SOURCE_DIR}/cmake/FindROOT.cmake ${CMAKE_SOURCE_DIR}/cmake/FindVTune.cmake ${CMAKE_SOURCE_DIR}/cmake/FindOpenCL.cmake ${CMAKE_SOURCE_DIR}/cmake/FindNuma.cmake ${CMAKE_SOURCE_DIR}/cmake/FindClangTools.cmake ${CMAKE_SOURCE_DIR}/cmake/Findtcmalloc.cmake ${CMAKE_SOURCE_DIR}/cmake/Findjemalloc.cmake - ${CMAKE_SOURCE_DIR}/cmake/RootUseFile.cmake ${CMAKE_SOURCE_DIR}/cmake/CppStyleGuideChecks.cmake ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/UseBioDynaMo.cmake ${CMAKE_SOURCE_DIR}/cmake/utils.cmake @@ -430,10 +334,6 @@ function(add_bdm_packages_properties) DESCRIPTION "Open Source Distributed Version Control System. (OPTIONAL)" TYPE REQUIRED ) - SET_PACKAGE_PROPERTIES(ROOT PROPERTIES - DESCRIPTION "CERN's Modular Scientific Software Toolkit. (REQUIRED)" - TYPE REQUIRED - ) SET_PACKAGE_PROPERTIES(ClangTools PROPERTIES DESCRIPTION "Standalone command line tools that provide developer-oriented functionalities. (OPTIONAL)" TYPE REQUIRED @@ -444,7 +344,7 @@ function(add_bdm_packages_properties) ) SET_PACKAGE_PROPERTIES(ParaView PROPERTIES DESCRIPTION "Open Source, multi-platform data analysis and visualization application. (OPTIONAL)" - TYPE REQUIRED + TYPE OPTIONAL ) SET_PACKAGE_PROPERTIES(Valgrind PROPERTIES DESCRIPTION "A suite of tools for debugging and profiling. (OPTIONAL)" @@ -466,11 +366,6 @@ function(add_bdm_packages_properties) DESCRIPTION "Package Manager System for Python. (REQUIRED)" TYPE REQUIRED ) - SET_PACKAGE_PROPERTIES(Qt5 PROPERTIES - DESCRIPTION "Open Source widget toolkit for creating user interfaces. It is needed by Paraview. (OPTIONAL)" - TYPE REQUIRED - ) - endfunction() # Add a small description to the -D flags which we can use @@ -481,7 +376,6 @@ function(add_bdm_feature_properties) ADD_FEATURE_INFO(benchmark benchmark "Build BioDynaMo's benchmark suite.") ADD_FEATURE_INFO(cuda cuda "Enable CUDA code generation for GPU acceleration.") ADD_FEATURE_INFO(opencl opencl "Enable OpenCL code generation for GPU acceleration.") - ADD_FEATURE_INFO(dict dict "Build with ROOT dictionaries.") ADD_FEATURE_INFO(numa numa "Enable NUMA-Awareness in BioDynaMo.") ADD_FEATURE_INFO(paraview paraview "Enable ParaView.") ADD_FEATURE_INFO(sbml sbml "Enable SBML integration.") @@ -490,7 +384,6 @@ function(add_bdm_feature_properties) ADD_FEATURE_INFO(verbose verbose "Enable verbosity when running make install.") ADD_FEATURE_INFO(tcmalloc tcmalloc "Use tcmalloc for memory allocations.") ADD_FEATURE_INFO(jemalloc jemalloc "Use jemalloc for memory allocations.") - ADD_FEATURE_INFO(notebooks notebooks "Generate ROOT notebooks") endfunction() # Method used to give execution permissions to a file diff --git a/demo/binding_cells/CMakeLists.txt b/demo/binding_cells/CMakeLists.txt deleted file mode 100755 index 2e40ad88c..000000000 --- a/demo/binding_cells/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) The BioDynaMo Project. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- -cmake_minimum_required(VERSION 3.19.3) - -project(binding_cells) - -find_package(BioDynaMo REQUIRED) -include(${BDM_USE_FILE}) -include_directories("src") - -file(GLOB_RECURSE HEADERS src/*.h) -file(GLOB_RECURSE SOURCES src/*.cc) - -bdm_add_executable(binding_cells - HEADERS ${HEADERS} - SOURCES ${SOURCES} - LIBRARIES ${BDM_REQUIRED_LIBRARIES}) diff --git a/demo/binding_cells/analysis.ipynb b/demo/binding_cells/analysis.ipynb deleted file mode 100644 index 854d81200..000000000 --- a/demo/binding_cells/analysis.ipynb +++ /dev/null @@ -1,103 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import ROOT\n", - "from ROOT import TFile, TCanvas, TGraph, gROOT, gSystem\n", - "from array import array\n", - "ROOT.enableJSVis()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# The directory of the binding_cells demo\n", - "output_dir = \"/path/to/binding_cells\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "dict_dir = output_dir + \"/build/libbinding_cells.so\"\n", - "gSystem.Load(dict_dir)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "file = output_dir + \"/results.root\"\n", - "f = TFile(file)\n", - "results = gROOT.FindObject(\"binding_cells\")\n", - "\n", - "marker = 3500\n", - "\n", - "c1 = TCanvas( 'c1', 'A Simple Graph Example', 200, 10, 700, 500 )\n", - "c1.SetGrid()\n", - "\n", - "activity_at_marker = []\n", - "initial_concentration = []\n", - "for event in results:\n", - " initial_concentration.append(event.binding_cells.initial_concentration)\n", - " activity_at_marker.append(event.binding_cells.activity[marker])\n", - "\n", - "activity_at_marker = [x for y, x in sorted(zip(initial_concentration, activity_at_marker))]\n", - "initial_concentration = sorted(initial_concentration)\n", - "percentages = [100 * (x / max(activity_at_marker)) for x in activity_at_marker]\n", - "# print(activity_at_marker)\n", - "# print(initial_concentration)\n", - "gr = TGraph(len(activity_at_marker), array('d', initial_concentration), array('d', percentages))\n", - "gr.SetTitle('Effect of Anti-PD-1 Concentration on T-Cell Activation ')\n", - "gr.GetXaxis().SetTitle( 'Log [mAb] (M)' )\n", - "gr.GetYaxis().SetTitle( 'Activated T-Cells (%)' )\n", - "gr.SetLineWidth( 2 )\n", - "gr.GetXaxis().SetTitleOffset(1.4);\n", - "c1.SetLogx()\n", - "gr.Draw('ALP')\n", - "\n", - "c1.Update()\n", - "c1.Draw()\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/demo/binding_cells/bdm.toml b/demo/binding_cells/bdm.toml deleted file mode 100644 index d75555952..000000000 --- a/demo/binding_cells/bdm.toml +++ /dev/null @@ -1,24 +0,0 @@ -[simulation] -bound_space = true -min_bound = 0 -max_bound = 200 -leaking_edges = false - -[visualization] -# export = false -# export_interval = 1 - - [[visualize_sim_object]] - name = "TCell" - additional_data_members = [ "diameter_", "color_" ] - - [[visualize_sim_object]] - name = "Monocyte" - additional_data_members = [ "diameter_", "color_" ] - - [[visualize_diffusion]] - name = "Antibody" - gradient = false - -# [development] -# statistics = true diff --git a/demo/binding_cells/params.json b/demo/binding_cells/params.json deleted file mode 100644 index eff17c025..000000000 --- a/demo/binding_cells/params.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "bdm::SimParam": { - "timesteps" : 100, - "t_cell_population" : 272, - "monocyte_population" : 727 - }, - "bdm::OptimizationParam": { - "algorithm" : "ParticleSwarm", - "params" : [ - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::t_cell_walkspeed", - "lower_bound" : 2, - "upper_bound" : 6, - "initial_value" : 2 - } - ] - } -} diff --git a/demo/binding_cells/run.sh b/demo/binding_cells/run.sh deleted file mode 100755 index eb6a4ca88..000000000 --- a/demo/binding_cells/run.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -mpirun -n 2 -use-hwthread-cpus build/binding_cells --config=params.json diff --git a/demo/binding_cells/src/agents/monocyte.h b/demo/binding_cells/src/agents/monocyte.h deleted file mode 100644 index 271780ac5..000000000 --- a/demo/binding_cells/src/agents/monocyte.h +++ /dev/null @@ -1,74 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef MONOCYTE_H_ -#define MONOCYTE_H_ - -#include "agents/t_cell.h" -#include "core/agent/cell.h" - -namespace bdm { - -/// Define Monocyte cell type -class Monocyte : public Cell { - BDM_AGENT_HEADER(Monocyte, Cell, 1); - - public: - Monocyte() {} - explicit Monocyte(const Real3& position, real_t diameter, size_t color) - : Base(position), color_(color) { - this->SetDiameter(diameter); - } - - void ConnectTo(AgentPointer agent) { - if (connected_cells_.empty()) { - color_ = 2; - } - connected_cells_.push_back(agent); - } - - std::vector> GetConnectedCells() const { - return connected_cells_; - } - - void SetMaximumNumberOfSynapses(size_t num) { max_connections_ = num; } - - void StickToWellBottom() { at_bottom_ = true; } - - bool AtBottom() { return at_bottom_; } - - bool IsInhibited() const { return inhibited_; } - - void Inhibit() { inhibited_ = true; } - - bool IsOccupied() const { - return connected_cells_.size() == max_connections_; - } - - private: - // The cells that are connected to this Monocyte - std::vector> connected_cells_; - // The maximum number of connections allowed to this Monocyte - size_t max_connections_ = 1; - // Is the monocyte at the bottom of the cell well? - bool at_bottom_ = false; - // The color that will be used for visualization purposes - size_t color_ = 0; - // Is this T-Cell inhibited (i.e. due to PD-1 <-> PD-L1 interaction) - bool inhibited_ = false; -}; - -} // namespace bdm - -#endif // MONOCYTE_H_ diff --git a/demo/binding_cells/src/agents/t_cell.h b/demo/binding_cells/src/agents/t_cell.h deleted file mode 100644 index 320b3a18d..000000000 --- a/demo/binding_cells/src/agents/t_cell.h +++ /dev/null @@ -1,101 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef T_CELL_H_ -#define T_CELL_H_ - -#include "TH2I.h" - -#include "core/agent/cell.h" -#include "core/scheduler.h" - -namespace bdm { - -class Monocyte; - -/// Define T-Cell type -class TCell : public Cell { - BDM_AGENT_HEADER(TCell, Cell, 1); - - public: - TCell() {} - explicit TCell(const Real3& position, real_t diameter, size_t color, int t) - : Base(position), color_(color) { - activation_histo_ = TH2I("", "", 30, 0, 49, 30, 0, t - 1); - this->SetDiameter(diameter); - } - - void IncreaseActivationIntensity(real_t val) { - if (val > 0) { - activation_intensity_ += val; - } - } - - void Activate() { - auto* r = Simulation::GetActive()->GetRandom(); - auto val = r->Gaus(10 * mean_, 3 * sigma_); - IncreaseActivationIntensity(val); - is_activated_ = true; - auto t = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps(); - activation_histo_.Fill(activation_intensity_, t); - } - - void Deactivate() { is_activated_ = false; } - - void ConnectTo(AgentPointer agent) { - connected_cell_ = agent; - color_ = 2; - } - - // Set the initial activation energy. Initially the T-Cell is not activated - // and has therefore a low value, following a normal distribution - void SetInitialActivationIntensity(real_t mean, real_t sigma) { - mean_ = mean; - sigma_ = sigma; - auto* r = Simulation::GetActive()->GetRandom(); - auto val = r->Gaus(mean, sigma); - IncreaseActivationIntensity(val); - } - - TH2I* GetActivationHistogram() { return &activation_histo_; } - - size_t GetActivationIntensity() { return activation_intensity_; } - - bool IsActivated() { return is_activated_; } - - bool IsConnected() { return connected_cell_ != nullptr; } - - AgentPointer GetConnectedCell() const { return connected_cell_; } - - private: - // Is this T-Cell connected to a Monocyte - bool is_connected_ = false; - // The cell this T-Cell is connected to - AgentPointer connected_cell_; - // Is this T-Cell activated? - bool is_activated_ = false; - // The activation intensity (represents the number of PD-1 receptors) - size_t activation_intensity_ = 0; - // The color that will be used for visualization purposes - size_t color_ = 1; - // Mean for the normal distribution of the initial activation intensity - real_t mean_ = 3; - // Sigma for the normal distribution of the initial activation intensity - real_t sigma_ = 1; - TH2I activation_histo_; -}; - -} // namespace bdm - -#endif // T_CELL_H_ diff --git a/demo/binding_cells/src/binding_cells.cc b/demo/binding_cells/src/binding_cells.cc deleted file mode 100644 index 974eaa890..000000000 --- a/demo/binding_cells/src/binding_cells.cc +++ /dev/null @@ -1,27 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "binding_cells.h" -#include "core/multi_simulation/multi_simulation.h" -#include "core/param/param_group.h" - -using namespace bdm; - -const ParamGroupUid SimParam::kUid = ParamGroupUidGenerator::Get()->NewUid(); - -int main(int argc, const char** argv) { - Param::RegisterParamGroup(new SimParam()); - bdm::experimental::MultiSimulation pe(argc, argv); - return pe.Execute(Simulate); -} diff --git a/demo/binding_cells/src/binding_cells.h b/demo/binding_cells/src/binding_cells.h deleted file mode 100644 index e72cd8be9..000000000 --- a/demo/binding_cells/src/binding_cells.h +++ /dev/null @@ -1,172 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef BINDING_CELLS_H_ -#define BINDING_CELLS_H_ - -#include "agents/monocyte.h" -#include "agents/t_cell.h" -#include "biodynamo.h" -#include "biology_modules/connect_within_radius_module.h" -#include "biology_modules/constant_displacement_module.h" -#include "biology_modules/inhibitation_module.h" -#include "biology_modules/physical_bond_module.h" -#include "biology_modules/random_walk_module.h" -#include "biology_modules/spring_force_module.h" -#include "biology_modules/stokes_velocity_module.h" -#include "core/analysis/time_series.h" -#include "core/operation/operation.h" -#include "core/operation/operation_registry.h" -#include "core/operation/reduction_op.h" -#include "core/substance_initializers.h" -#include "core/util/io.h" - -#include "TH2I.h" -#include "TROOT.h" - -namespace bdm { - -using experimental::TimeSeries; - -enum CellType { kMonocyte, kTCell }; -enum Substances { kAntibody }; - -// Parameters specific for this simulation -struct SimParam : public ParamGroup { - BDM_PARAM_GROUP_HEADER(SimParam, 1); - - // World parameters - int timesteps = 40; - real_t min_space = 0; - real_t max_space = 20; - - // T-Cell parameters - int t_cell_population = 272; - real_t t_cell_diameter = 0.9; - real_t t_cell_walkspeed = 5; - real_t t_cell_density = 1.077; - real_t t_cell_init_mean = 3; - real_t t_cell_init_sigma = 1; - - // Monocyte parameters - int monocyte_population = 727; - real_t monocyte_diameter = 1.5; - real_t monocyte_density = 1.067; - - // Antibody (substance) parameters - real_t apd_amount = 10; - real_t diff_rate = 0; - real_t decay_rate = 0; - real_t res = 10; - - // Inhibition module parameters - real_t inhib_sigma = 1; - real_t inhib_mu = -8.5; - - // StokesVelocity module parameters - real_t stokes_u = .089; - real_t stokes_pf = .997; -}; - -inline void Simulate(int argc, const char** argv, TimeSeries* result, - Param* final_params = nullptr) { - auto set_param = [&](Param* param) { - param->Restore(std::move(*final_params)); - }; - Simulation simulation(argc, argv, set_param); - - // Get a pointer to an instance of SimParam - auto* sparam = simulation.GetParam()->Get(); - - // T-Cells contain a TH2I histogram object that is not thread-safe by default, - // agent we need to enable ROOT's implicit multithreading awareness - ROOT::EnableImplicitMT(); - - ////////////////////////////////////////////////////////////////////////////// - // Create and initialize Monocytes - ////////////////////////////////////////////////////////////////////////////// - auto mc_builder = [&](Real3 pos) { - Monocyte* mc = - new Monocyte(pos, sparam->monocyte_diameter, CellType::kMonocyte); - mc->SetDensity(sparam->monocyte_density); - mc->SetMaximumNumberOfSynapses(3); - mc->AddBehavior(new RandomWalk(sparam->monocyte_diameter / 2)); - mc->AddBehavior(new StokesVelocity(sparam->stokes_u, sparam->stokes_pf)); - mc->AddBehavior(new Inhibitation(sparam->inhib_sigma, sparam->inhib_mu)); - return mc; - }; - ModelInitializer::CreateAgentsRandom(sparam->min_space, sparam->max_space, - sparam->monocyte_population, mc_builder); - - ////////////////////////////////////////////////////////////////////////////// - // Create and initialize T-Cells - ////////////////////////////////////////////////////////////////////////////// - auto tc_builder = [&](Real3 pos) { - TCell* tc = new TCell(pos, sparam->t_cell_diameter, CellType::kTCell, - sparam->timesteps); - tc->SetDensity(sparam->t_cell_density); - tc->SetInitialActivationIntensity(sparam->t_cell_init_mean, - sparam->t_cell_init_sigma); - tc->AddBehavior(new RandomWalk(sparam->t_cell_walkspeed)); - tc->AddBehavior(new StokesVelocity(sparam->stokes_u, sparam->stokes_pf)); - tc->AddBehavior(new ConnectWithinRadius( - (0.75 * (sparam->t_cell_diameter + sparam->monocyte_diameter)))); - tc->AddBehavior(new PhysicalBond()); - return tc; - }; - ModelInitializer::CreateAgentsRandom(sparam->min_space, sparam->max_space, - sparam->t_cell_population, tc_builder); - - ////////////////////////////////////////////////////////////////////////////// - // Create and initialize Anti-PD-1 substance - ////////////////////////////////////////////////////////////////////////////// - ModelInitializer::DefineSubstance(Substances::kAntibody, "Antibody", - sparam->diff_rate, sparam->decay_rate, - sparam->res); - ModelInitializer::InitializeSubstance( - Substances::kAntibody, Uniform(sparam->min_space, sparam->max_space, - sparam->apd_amount, Axis::kZAxis)); - - ////////////////////////////////////////////////////////////////////////////// - // Collect results of interest - ////////////////////////////////////////////////////////////////////////////// - auto* ts = simulation.GetTimeSeries(); - auto activated = [](Simulation* sim) { - auto condition = L2F([](Agent* a) { - if (auto tcell = dynamic_cast(a)) { - return tcell->IsActivated(); - } - return false; - }); - auto result = static_cast(bdm::experimental::Count(sim, condition)); - auto num_agents = sim->GetResourceManager()->GetNumAgents(); - return result / static_cast(num_agents); - }; - ts->AddCollector("activated", activated); - - ////////////////////////////////////////////////////////////////////////////// - // Run the simulation - ////////////////////////////////////////////////////////////////////////////// - simulation.Simulate(sparam->timesteps); - - std::cout << "Simulation completed successfully!" << std::endl; - - ////////////////////////////////////////////////////////////////////////////// - // Return simulation results - ////////////////////////////////////////////////////////////////////////////// - *result = *simulation.GetTimeSeries(); -} - -} // namespace bdm - -#endif // BINDING_CELLS_H_ diff --git a/demo/binding_cells/src/biology_modules/connect_within_radius_module.h b/demo/binding_cells/src/biology_modules/connect_within_radius_module.h deleted file mode 100644 index 0b891f56a..000000000 --- a/demo/binding_cells/src/biology_modules/connect_within_radius_module.h +++ /dev/null @@ -1,95 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef CONNECT_WITHIN_RADIUS_MODULE_H_ -#define CONNECT_WITHIN_RADIUS_MODULE_H_ - -#include "agents/monocyte.h" -#include "agents/t_cell.h" -#include "biology_modules/constant_displacement_module.h" -#include "core/behavior/behavior.h" -#include "core/environment/uniform_grid_environment.h" - -namespace bdm { - -struct ConnectWithinRadius : public Behavior { - BDM_BEHAVIOR_HEADER(ConnectWithinRadius, Behavior, 1); - - public: - ConnectWithinRadius(real_t radius = 1) : squared_radius_(radius * radius) { - AlwaysCopyToNew(); - } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (ConnectWithinRadius* gdbm = dynamic_cast(other)) { - squared_radius_ = gdbm->squared_radius_; - } else { - Log::Fatal("ConnectWithinRadius::EventConstructor", - "other was not of type ConnectWithinRadius"); - } - } - - void Run(Agent* agent) override { - if (auto* this_cell = static_cast(agent)) { - // Prune if we are already connected to a monocyte - if (this_cell->IsConnected()) { - return; - } - - AgentPointer cell_to_connect_to; // nullptr initially - real_t smallest_distance = Math::kInfinity; - auto find_closest_cell = L2F([&](Agent* neighbor, - real_t squared_distance) { - if (auto* neighbor_cell = dynamic_cast(neighbor)) { - // T-Cells are activated if they are in close vicinity of monocytes - if (!this_cell->IsActivated() || !this_cell->IsConnected()) { - this_cell->Activate(); - } - - // We can only form an immune synapse with a monocyte if there is - // physically enough room and if the pathway is not inhibited - if (!neighbor_cell->IsOccupied() && !neighbor_cell->IsInhibited()) { - real_t distance = SquaredEuclideanDistance( - neighbor_cell->GetPosition(), this_cell->GetPosition()); - if (distance < smallest_distance) { - smallest_distance = distance; - cell_to_connect_to = - AgentPointer(neighbor_cell->GetUid()); - } - } - } - }); - auto* ctxt = Simulation::GetActive()->GetExecutionContext(); - ctxt->ForEachNeighbor(find_closest_cell, *this_cell, squared_radius_); - - // If we found an available monocyte then we connect this cell and the - // monocyte with each other, forming an immune synapse - if (cell_to_connect_to != nullptr) { - this_cell->ConnectTo(cell_to_connect_to); - AgentPointer soptr(this_cell->GetUid()); - cell_to_connect_to->ConnectTo(soptr); - // A T-Cell is considered not activated when it formed an immune synapse - this_cell->Deactivate(); - } - } - } - - private: - real_t squared_radius_; -}; - -} // namespace bdm - -#endif // CONNECT_WITHIN_RADIUS_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/constant_displacement_module.h b/demo/binding_cells/src/biology_modules/constant_displacement_module.h deleted file mode 100644 index fd5b8a4a3..000000000 --- a/demo/binding_cells/src/biology_modules/constant_displacement_module.h +++ /dev/null @@ -1,92 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef CONSTANT_DISPLACEMENT_MODULE_H_ -#define CONSTANT_DISPLACEMENT_MODULE_H_ - -#include "agents/monocyte.h" -#include "core/behavior/behavior.h" - -namespace bdm { - -/// @brief Calculates the squared euclidean distance between two points -/// in 3D -/// -/// @param[in] pos1 Position of the first point -/// @param[in] pos2 Position of the second point -/// -/// @return The distance between the two points -/// -inline real_t SquaredEuclideanDistance(const Real3& pos1, const Real3& pos2) { - const real_t dx = pos2[0] - pos1[0]; - const real_t dy = pos2[1] - pos1[1]; - const real_t dz = pos2[2] - pos1[2]; - return (dx * dx + dy * dy + dz * dz); -} - -/// Make a simulation object move at a constant velocity towards the direction -struct ConstantDisplace : public Behavior { - BDM_BEHAVIOR_HEADER(ConstantDisplace, Behavior, 1); - - public: - ConstantDisplace(real_t v = 1, Real3 goal_position = {0, 0, 0}) - : velocity_(v), goal_position_(goal_position) { - AlwaysCopyToNew(); - } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (ConstantDisplace* gdbm = dynamic_cast(other)) { - velocity_ = gdbm->velocity_; - } else { - Log::Fatal("ConstantDisplace::EventConstructor", - "other was not of type ConstantDisplace"); - } - } - - void SetGoalPosition(Real3 new_goal) { - goal_position_ = new_goal; - reached_goal_ = false; - } - - void Run(Agent* agent) override { - if (!reached_goal_) { - if (auto* cell = dynamic_cast(agent)) { - auto sq_distance = - SquaredEuclideanDistance(agent->GetPosition(), goal_position_); - if (sq_distance > eps_) { - Real3 direction = goal_position_ - cell->GetPosition(); - direction.Normalize(); - Real3 vel = direction * velocity_; - Real3 movement = vel * dt_; - cell->UpdatePosition(movement); - } else { // move the last remaining bit - cell->SetPosition(goal_position_); - reached_goal_ = true; - } - } - } - } - - private: - const real_t dt_ = 1; // TODO: should be parameterized - const real_t eps_ = 5; - bool reached_goal_ = false; - real_t velocity_; - Real3 goal_position_; -}; - -} // namespace bdm - -#endif // CONSTANT_DISPLACEMENT_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/inhibitation_module.h b/demo/binding_cells/src/biology_modules/inhibitation_module.h deleted file mode 100644 index 24bc57526..000000000 --- a/demo/binding_cells/src/biology_modules/inhibitation_module.h +++ /dev/null @@ -1,72 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef INHIBITATION_MODULE_H_ -#define INHIBITATION_MODULE_H_ - -#include "agents/t_cell.h" -#include "core/behavior/behavior.h" - -#include "Math/DistFunc.h" - -namespace bdm { - -/// Inhibits Monocytes from forming an immune synapse with T-Cells -struct Inhibitation : public Behavior { - BDM_BEHAVIOR_HEADER(Inhibitation, Behavior, 1); - - public: - Inhibitation() { AlwaysCopyToNew(); } - - Inhibitation(real_t s, real_t m) : sigma_(s), mu_(m) { AlwaysCopyToNew(); } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (Inhibitation* gdbm = dynamic_cast(other)) { - sigma_ = gdbm->sigma_; - mu_ = gdbm->mu_; - } else { - Log::Fatal("Inhibitation::EventConstructor", - "other was not of type Inhibitation"); - } - } - - void Run(Agent* agent) override { - if (auto* monocyte = static_cast(agent)) { - // If this monocyte is already inhibited, we can prune this function - if (monocyte->IsInhibited()) { - return; - } - auto* rm = Simulation::GetActive()->GetResourceManager(); - auto* dgrid = rm->GetDiffusionGrid(0); - real_t conc = dgrid->GetValue(monocyte->GetPosition()); - - // With certain probability, depending on concentration value, we - // inhibit the monocyte from forming immune synapses - auto* r = Simulation::GetActive()->GetRandom(); - if (r->Uniform(0, 1) < - ROOT::Math::normal_cdf(std::log(conc) / std::log(10), sigma_, mu_)) { - monocyte->Inhibit(); - } - } - } - - private: - real_t sigma_ = 1; - real_t mu_ = 0; -}; - -} // namespace bdm - -#endif // INHIBITATION_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/physical_bond_module.h b/demo/binding_cells/src/biology_modules/physical_bond_module.h deleted file mode 100644 index 12e11ead4..000000000 --- a/demo/binding_cells/src/biology_modules/physical_bond_module.h +++ /dev/null @@ -1,60 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef PHYSICAL_BOND_MODULE_H_ -#define PHYSICAL_BOND_MODULE_H_ - -#include "agents/monocyte.h" -#include "core/behavior/behavior.h" - -namespace bdm { - -/// If a cell A establishes a PhysicalBond with another cell B, cell A -/// attaches itself to B. Any displacement of cell B will result in cell A -/// moving next to cell B. This effectively disables cell A from being able to -/// move by itself. -struct PhysicalBond : public Behavior { - BDM_BEHAVIOR_HEADER(PhysicalBond, Behavior, 1); - - public: - PhysicalBond() { AlwaysCopyToNew(); } - - // NB: works only for spherical shaped cells - // Simple implementation of connecting `cell_a` to `cell_b`. We displace - // `cell_a` with a distance such that the edges of the spheres stay connected - void Connect(TCell* cell_a, AgentPointer cell_b) { - Real3 distance = cell_b->GetPosition() - cell_a->GetPosition(); - Real3 distance_copy = distance; - distance_copy.Normalize(); - auto radius_a = cell_a->GetDiameter() / 2; - auto radius_b = cell_b->GetDiameter() / 2; - Real3 displacement = distance - (distance_copy * (radius_a + radius_b)); - cell_a->UpdatePosition(displacement); - // if (Simulation::GetActive()->GetScheduler()->GetSimulatedSteps() == 1) { - // Log::Error("PhysicalBond", "Displacement: ", displacement); - // } - } - - void Run(Agent* agent) override { - if (auto* this_cell = static_cast(agent)) { - if (this_cell->IsConnected()) { - auto other_cell = this_cell->GetConnectedCell(); - Connect(this_cell, other_cell); - } - } - } -}; - -} // namespace bdm - -#endif // PHYSICAL_BOND_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/random_walk_module.h b/demo/binding_cells/src/biology_modules/random_walk_module.h deleted file mode 100644 index 27a45fa47..000000000 --- a/demo/binding_cells/src/biology_modules/random_walk_module.h +++ /dev/null @@ -1,107 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef RANDOM_WALK_MODULE_H_ -#define RANDOM_WALK_MODULE_H_ - -#include "core/behavior/behavior.h" - -namespace bdm { - -/// Make a simulation object move at a constant velocity towards the direction -struct RandomWalk : public Behavior { - BDM_BEHAVIOR_HEADER(RandomWalk, Behavior, 1); - - public: - RandomWalk(real_t v = 1) : velocity_(v) { AlwaysCopyToNew(); } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (RandomWalk* gdbm = dynamic_cast(other)) { - velocity_ = gdbm->velocity_; - } else { - Log::Fatal("RandomWalk::EventConstructor", - "other was not of type RandomWalk"); - } - } - - Real3 GetRandomDirection() { - auto* r = Simulation::GetActive()->GetRandom(); - Real3 random_vector = r->UniformArray<3>(-1, 1); - random_vector.Normalize(); - return random_vector; - } - - void Run(Agent* agent) override { - if (auto* monocyte = dynamic_cast(agent)) { - if (monocyte->AtBottom()) { - return; - } - } - if (auto* cell = dynamic_cast(agent)) { - Real3 direction = GetRandomDirection(); - Real3 vel = direction * velocity_; - auto dt = Simulation::GetActive()->GetParam()->simulation_time_step; - cell->UpdatePosition(vel * dt); - } - } - - private: - real_t velocity_; -}; - -/// Make a simulation object move at a constant velocity towards the direction -struct RandomWalkXY : public Behavior { - BDM_BEHAVIOR_HEADER(RandomWalkXY, Behavior, 1); - - public: - RandomWalkXY(real_t v = 1) : velocity_(v) { AlwaysCopyToNew(); } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (RandomWalkXY* gdbm = dynamic_cast(other)) { - velocity_ = gdbm->velocity_; - } else { - Log::Fatal("RandomWalkXY::EventConstructor", - "other was not of type RandomWalkXY"); - } - } - - Real3 GetRandomDirection() { - auto* r = Simulation::GetActive()->GetRandom(); - Real3 random_vector; - random_vector[0] = r->Uniform(-1, 1); - random_vector[1] = r->Uniform(-1, 1); - random_vector[2] = 0; - random_vector.Normalize(); - return random_vector; - } - - void Run(Agent* agent) override { - if (auto* cell = dynamic_cast(agent)) { - Real3 direction = GetRandomDirection(); - Real3 vel = direction * velocity_; - auto dt = Simulation::GetActive()->GetParam()->simulation_time_step; - cell->UpdatePosition(vel * dt); - } - } - - private: - real_t velocity_; -}; - -} // namespace bdm - -#endif // RANDOM_WALK_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/spring_force_module.h b/demo/binding_cells/src/biology_modules/spring_force_module.h deleted file mode 100644 index 23323ea6c..000000000 --- a/demo/binding_cells/src/biology_modules/spring_force_module.h +++ /dev/null @@ -1,72 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef SPRING_FORCE_MODULE_H_ -#define SPRING_FORCE_MODULE_H_ - -#include "agents/monocyte.h" -#include "agents/t_cell.h" -#include "core/behavior/behavior.h" - -namespace bdm { - -// Define displacement behavior: -// Cells move along the diffusion gradient (from low concentration to high) -struct SpringForce : public Behavior { - BDM_BEHAVIOR_HEADER(SpringForce, Behavior, 1); - - public: - SpringForce(real_t spring_constant = 1) : spring_constant_(spring_constant) { - AlwaysCopyToNew(); - } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (SpringForce* gdbm = dynamic_cast(other)) { - spring_constant_ = gdbm->spring_constant_; - } else { - Log::Fatal("SpringForce::EventConstructor", - "other was not of type SpringForce"); - } - } - - // Displacement calculated in the direction of ap2 - Real3 CalculateSpringForceDisplacement(TCell* ap1, - AgentPointer ap2) { - Real3 pos1 = ap1->GetPosition(); - Real3 pos2 = ap2->GetPosition(); - Real3 force = (pos1 - pos2) * (-spring_constant_); - auto dt = Simulation::GetActive()->GetParam()->simulation_time_step; - Real3 displacement = force * dt * dt; - return displacement; - } - - void Run(Agent* agent) override { - if (auto* this_cell = dynamic_cast(agent)) { - if (this_cell->IsConnected()) { - auto other_cell = this_cell->GetConnectedCell(); - auto displacement = - CalculateSpringForceDisplacement(this_cell, other_cell); - this_cell->UpdatePosition(displacement); - } - } - } - - private: - real_t spring_constant_; -}; - -} // namespace bdm - -#endif // SPRING_FORCE_MODULE_H_ diff --git a/demo/binding_cells/src/biology_modules/stokes_velocity_module.h b/demo/binding_cells/src/biology_modules/stokes_velocity_module.h deleted file mode 100644 index 510fd9c5a..000000000 --- a/demo/binding_cells/src/biology_modules/stokes_velocity_module.h +++ /dev/null @@ -1,91 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef STOKES_VELOCITY_MODULE_H_ -#define STOKES_VELOCITY_MODULE_H_ - -#include "agents/t_cell.h" -#include "core/behavior/behavior.h" - -namespace bdm { - -/// Modeling of Stokes' law of terminal velocity of sphere falling in a fluid -/// Source: https://en.wikipedia.org/wiki/Stokes%27_law -struct StokesVelocity : public Behavior { - BDM_BEHAVIOR_HEADER(StokesVelocity, Behavior, 1); - - public: - StokesVelocity() { AlwaysCopyToNew(); } - - StokesVelocity(real_t u, real_t pf) : u_(u), pf_(pf) { - AlwaysCopyToNew(); - if (std::abs(u) < 1e-9) { - Log::Fatal("StokesVelocity::Run()", - "u_ was found to be (very close to) zero!"); - } - } - - void Initialize(const NewAgentEvent& event) override { - Base::Initialize(event); - auto* other = event.existing_behavior; - if (StokesVelocity* gdbm = dynamic_cast(other)) { - u_ = gdbm->u_; - pf_ = gdbm->pf_; - } else { - Log::Fatal("StokesVelocity::EventConstructor", - "other was not of type StokesVelocity"); - } - } - - static constexpr real_t kG = -9.81; - - template - real_t CalculateStokesDisplacement(T* cell) { - auto R = cell->GetDiameter() / 2; - auto pp = cell->GetDensity(); - auto dt = Simulation::GetActive()->GetParam()->simulation_time_step; - auto vel = (4.5) * ((pp - pf_) / u_) * kG * (R * R); - return vel * dt; - } - - void Run(Agent* agent) override { - if (auto* tcell = dynamic_cast(agent)) { - // Ignore if connected to another cell; it should follow the movements of - // that cell instead - if (!tcell->IsConnected()) { - auto displacement = CalculateStokesDisplacement(tcell); - tcell->UpdatePosition({0, 0, displacement}); - } - } else if (auto* monocyte = dynamic_cast(agent)) { - if (monocyte->AtBottom()) { - return; - } - // If a monocyte reaches the bottom of the well, we make it stick to there - auto min = Simulation::GetActive()->GetParam()->min_bound; - if (monocyte->GetPosition()[2] < (min + 1)) { - monocyte->StickToWellBottom(); - } else { - auto displacement = CalculateStokesDisplacement(monocyte); - monocyte->UpdatePosition({0, 0, displacement}); - } - } - } - - private: - real_t u_ = 1; - real_t pf_ = 1; -}; - -} // namespace bdm - -#endif // STOKES_VELOCITY_MODULE_H_ diff --git a/demo/binding_cells/src/macro.C b/demo/binding_cells/src/macro.C deleted file mode 100644 index 3a960257b..000000000 --- a/demo/binding_cells/src/macro.C +++ /dev/null @@ -1,10 +0,0 @@ -{ - TFile *f = TFile::Open("results.root"); - TTree *t = nullptr; - f->GetObject("binding_cells", t); - t->Print(); - t->Show(0); - - TTreeReader reader("binding_cells", f); - TTreeReaderValue> veca(reader, "activity"); -} diff --git a/demo/binding_cells/src/plot_graph.h b/demo/binding_cells/src/plot_graph.h deleted file mode 100644 index dc9b32b45..000000000 --- a/demo/binding_cells/src/plot_graph.h +++ /dev/null @@ -1,49 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef PLOT_GRAPH_H_ -#define PLOT_GRAPH_H_ - -#include -#include -#include -#include - -#include -#include - -template -static void PlotGraph(std::vector x, std::vector y, std::string name) { - assert(x.size() == y.size()); - int n = x.size(); - - TCanvas *c = new TCanvas("c", name.c_str(), 200, 10, 700, 500); - c->SetGrid(); - - TGraph *gr = new TGraph(n, x.data(), y.data()); - gr->SetLineColor(2); - gr->SetLineWidth(4); - gr->SetTitle(name.c_str()); - gr->GetXaxis()->SetTitle("Timestep"); - gr->GetYaxis()->SetTitle("Activity"); - gr->Draw("ACP"); - - // TCanvas::Update() draws the frame, after which one can change it - c->Update(); - c->GetFrame()->SetBorderSize(12); - c->Modified(); - c->SaveAs((name + ".jpg").c_str()); -} - -#endif // PLOT_GRAPH_H_ diff --git a/demo/epidemiology/CMakeLists.txt b/demo/epidemiology/CMakeLists.txt deleted file mode 100644 index 10d9f1bf9..000000000 --- a/demo/epidemiology/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -# ----------------------------------------------------------------------------- -# -# Copyright (C) Lukas Breitwieser. -# All Rights Reserved. -# -# ----------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.19.3) - -project(epidemiology) - -find_package(BioDynaMo REQUIRED) -include(${BDM_USE_FILE}) -include_directories("src") - -find_package(GSL REQUIRED) -include_directories(${GSL_INCLUDE_DIR}) - -file(GLOB_RECURSE HEADERS src/*.h) -file(GLOB_RECURSE SOURCES src/*.cc) - -bdm_add_executable(epidemiology - HEADERS ${HEADERS} - SOURCES ${SOURCES} - LIBRARIES ${BDM_REQUIRED_LIBRARIES} GSL::gsl GSL::gslcblas optim) - diff --git a/demo/epidemiology/measles.json b/demo/epidemiology/measles.json deleted file mode 100644 index 53b61d6e5..000000000 --- a/demo/epidemiology/measles.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "bdm::Param": { - "remove_output_dir_contents": true, - "statistics": false, - "simulation_time_step": 1, - "bound_space": 2, - "min_bound": 0, - "max_bound": 100, - "visualization_export_generate_pvsm":false, - "visualize_agents": { - "Person": [ "state_" ] - } - }, - "bdm::SimParam": { - "beta" : 0.06719, - "gamma" : 0.00521, - "agent_diameter": 2, - "agent_speed": 5.7859, - "infection_probablity": 0.2850, - "infection_radius": 10.5092, - "initial_population_infected": 10, - "initial_population_susceptible": 2000, - "moving_agents_ratio": 1, - "number_of_iterations": 1000, - "recovery_probability": 0.00521 - } -} diff --git a/demo/epidemiology/optim.json b/demo/epidemiology/optim.json deleted file mode 100644 index 4599e91fb..000000000 --- a/demo/epidemiology/optim.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "bdm::OptimizationParam": { - "algorithm" : "ParticleSwarm", - "repetition" : 10, - "params" : [ - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::infection_probablity", - "lower_bound" : 0.001, - "upper_bound" : 1, - "initial_value" : 0.001 - }, - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::infection_radius", - "lower_bound" : 5, - "upper_bound" : 50, - "initial_value" : 5 - }, - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::agent_speed", - "lower_bound" : 2, - "upper_bound" : 50, - "initial_value" : 2 - } - ] - } -} diff --git a/demo/epidemiology/plot-style.json b/demo/epidemiology/plot-style.json deleted file mode 100644 index 0fe96af9e..000000000 --- a/demo/epidemiology/plot-style.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "bdm::SimParam": { - "root_style": { - "fFrameBorderSize": 12, - "fLegendTextSize": 0.06, - "fTitleFontSize": 0.1, - "fPadLeftMargin": 0.2, - "fPadRightMargin": 0.05, - "fPadTopMargin": 0.04, - "fPadBottomMargin": 0.2, - "fXaxis": { - "_typename": "TAttAxis", - "fNdivisions": 8, - "fLabelOffset": 0.005, - "fLabelSize": 0.09, - "fTickLength": 0.02, - "fTitleOffset": 1, - "fTitleSize": 0.09 - }, - "fYaxis": { - "_typename": "TAttAxis", - "fNdivisions": 5, - "fLabelOffset": 0.005, - "fLabelSize": 0.09, - "fTickLength": 0.02, - "fTitleOffset": 1, - "fTitleSize": 0.09 - } - } - } -} diff --git a/demo/epidemiology/render.py b/demo/epidemiology/render.py deleted file mode 100755 index d53b1613c..000000000 --- a/demo/epidemiology/render.py +++ /dev/null @@ -1,136 +0,0 @@ -import argparse -import os -import sys -from paraview.simple import * -from paraview import coprocessing - -def ExtendDefaultPipeline(renderview, coprocessor, datadescription, script_args): - parser = argparse.ArgumentParser(description='BDM-PV-Params') - parser.add_argument('--raytracing', action='store_true') - parser.add_argument('--screenshots', action='store_true') - parser.add_argument('--name', action='store', dest="name") - params = parser.parse_args(script_args) - print(script_args) - print(params) - print(params.raytracing) - # find source - persons = FindSource('Persons') - - # set active source - SetActiveSource(persons) - - # get active view - renderView1 = renderview - # uncomment following to set a specific view size - # renderView1.ViewSize = [3150, 1350] - - # create a new 'Threshold' to filter out agent that was created as a UniformGridEnvironement bug workaround - threshold1 = Threshold(Input=persons) - threshold1.Scalars = ['POINTS', 'diameter_'] - pm = paraview.servermanager.vtkSMProxyManager - if pm.GetVersionMajor() == 5 and pm.GetVersionMinor() < 10: - threshold1.ThresholdRange = [2.0, 2.0] - else: - threshold1.LowerThreshold = 2.0 - threshold1.UpperThreshold = 2.0 - threshold1.ThresholdMethod = "Between" - SetActiveSource(threshold1) - Hide(persons) - - # get layout - layout1 = GetLayout() - - # get display properties - agentsDisplay = GetDisplayProperties(threshold1, view=renderView1) - - # set scalar coloring - ColorBy(agentsDisplay, ('POINTS', 'state_')) - - # rescale color and/or opacity maps used to include current data range - agentsDisplay.RescaleTransferFunctionToDataRange(True, False) - - # show color bar/color legend - agentsDisplay.SetScalarBarVisibility(renderView1, True) - - # get color transfer function/color map for 'state_' - state_LUT = GetColorTransferFunction('state_') - state_LUT.ScalarRangeInitialized = 1.0 - - # get opacity transfer function/opacity map for 'state_' - state_PWF = GetOpacityTransferFunction('state_') - state_PWF.ScalarRangeInitialized = 1 - - # rescale color and/or opacity maps used to exactly fit the current data range - agentsDisplay.RescaleTransferFunctionToDataRange(False, True) - - # Rescale transfer function - state_LUT.RescaleTransferFunction(0.0, 2.0) - - # Rescale transfer function - state_PWF.RescaleTransferFunction(0.0, 2.0) - - # Properties modified on state_LUT - state_LUT.RGBPoints = [0.0, 0.6470588235294118, 0.37254901960784315, 0.09019607843137255, 1.0, 0.865003, 0.865003, 0.865003, 2.0, 0.705882, 0.0156863, 0.14902] - - # Properties modified on state_LUT - state_LUT.RGBPoints = [0.0, 0.6470588235294118, 0.37254901960784315, 0.09019607843137255, 1.0, 0.7568627450980392, 0.18823529411764706, 0.1803921568627451, 2.0, 0.705882, 0.0156863, 0.14902] - - # Properties modified on state_LUT - state_LUT.RGBPoints = [0.0, 0.6470588235294118, 0.37254901960784315, 0.09019607843137255, 1.0, 0.7568627450980392, 0.18823529411764706, 0.1803921568627451, 2.0, 0.0392156862745098, 0.48627450980392156, 0.5882352941176471] - - # Properties modified on state_LUT - state_LUT.RGBPoints = [0.0, 0.4392156862745098, 0.43137254901960786, 0.43529411764705883, 1.0, 0.7568627450980392, 0.18823529411764706, 0.1803921568627451, 2.0, 0.0392156862745098, 0.48627450980392156, 0.5882352941176471] - - # Properties modified on state_LUT - state_LUT.RGBPoints = [0.0, 1.0, 1.0, 1.0, 1.0, 0.7568627450980392, 0.18823529411764706, 0.1803921568627451, 2.0, 0.0392156862745098, 0.48627450980392156, 0.5882352941176471] - - if params.raytracing: - renderView1.EnableRayTracing = 1 - renderView1.BackEnd = 'OSPRay pathtracer' - renderView1.Denoise = 1 - renderView1.SamplesPerPixel = 10 - - renderView1.Background = [0.14901960784313725, 0.14901960784313725, 0.14901960784313725] - - # Hide orientation axes - renderView1.OrientationAxesVisibility = 0 - - # hide color bar/color legend - agentsDisplay.SetScalarBarVisibility(renderView1, False) - - renderView1.CameraPosition = [145.5451553636775, 185.21878354571766, 348.0277030120568] - renderView1.CameraFocalPoint = [50.21011908104193, 43.8733056934362, 52.84622954370056] - renderView1.CameraViewUp = [-0.14570586437890107, 0.9098135966908945, -0.38859879099397066] - renderView1.CameraParallelScale = 88.22632763603929 - # - # renderView1.ResetCamera() - timesteps = GetAnimationScene().TimeKeeper.TimestepValues - - # SaveScreenshot('epidemiology.png', renderView1, ImageResolution=[2000, 2000], - # FontScaling='Scale fonts proportionally', - # OverrideColorPalette='', - # StereoMode='No change', - # # PNG options - # CompressionLevel='5') - SaveAnimation("{}.png".format(params.name), renderView1, ImageResolution=[1024, 1024], - FontScaling='Scale fonts proportionally', - OverrideColorPalette='', - StereoMode='No change', - TransparentBackground=0, - FrameRate=1, - FrameWindow=[0, int(timesteps[-1])], - # PNG options - CompressionLevel='5', - SuffixFormat='.%04d') - print("Images ({}.*.png) created in directory: {}".format(params.name, os.getcwd())) - - -# Entry point for export visualization -if __name__ == "__main__": - #### disable automatic camera reset on 'Show' - paraview.simple._DisableFirstRenderCameraReset() - sys.path.insert(0, "{0}/include/core/visualization/paraview".format(os.environ['BDMSYS'])) - from generate_pv_state import BuildDefaultPipeline - BuildDefaultPipeline('output/epidemiology1/simulation_info.json') - ExtendDefaultPipeline(GetActiveViewOrCreate('RenderView'), None, None, sys.argv[2:]) - diff --git a/demo/epidemiology/run.sh b/demo/epidemiology/run.sh deleted file mode 100755 index 4868758fc..000000000 --- a/demo/epidemiology/run.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -BDM_SCRIPT_DIR=$(readlink -e $(dirname "${BASH_SOURCE[0]}")) - -cd $BDM_SCRIPT_DIR -biodynamo build -cd build - -./epidemiology --config ../measles.json --config ../plot-style.json -cp output/result.svg output/measles.svg - diff --git a/demo/epidemiology/src/analytical-solution.cc b/demo/epidemiology/src/analytical-solution.cc deleted file mode 100644 index 6ba9fc178..000000000 --- a/demo/epidemiology/src/analytical-solution.cc +++ /dev/null @@ -1,71 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#include "analytical-solution.h" -#include -#include -#include - -namespace bdm { - -int Odes(double t, const double y[], double f[], void* params) { - auto* dparams = static_cast(params); - double beta = dparams[0]; - double gamma = dparams[1]; - double n = dparams[2]; - - double s = y[0]; - double i = y[1]; - - // dsdt - f[0] = -beta * i * s / n; - // didt - f[1] = beta * i * s / n - gamma * i; - // drdt - f[2] = gamma * i; - return GSL_SUCCESS; -} - -void CalculateAnalyticalSolution(TimeSeries* result, real_t beta, real_t gamma, - real_t susceptible, real_t infected, - real_t tstart, real_t tend, real_t step_size) { - double n = susceptible + infected; - double params[3] = {beta, gamma, n}; - gsl_odeiv2_system sys = {Odes, nullptr, 3, params}; - - gsl_odeiv2_driver* d = - gsl_odeiv2_driver_alloc_y_new(&sys, gsl_odeiv2_step_rk2, 1e-6, 1e-6, 0.0); - double y[3] = {susceptible, infected, 0.0}; - - std::vector timevec; - std::vector susceptiblevec; - std::vector infectedvec; - std::vector recoveredvec; - - double tstart_d = static_cast(tstart); - for (double t = tstart_d; t < tend; t += step_size) { - int status = gsl_odeiv2_driver_apply(d, &tstart_d, t, y); - - if (status != GSL_SUCCESS) { - printf("error, return value=%d\n", status); - break; - } - - timevec.push_back(t); - susceptiblevec.push_back(y[0] / n); - infectedvec.push_back(y[1] / n); - recoveredvec.push_back(y[2] / n); - } - - gsl_odeiv2_driver_free(d); - - result->Add("susceptible", timevec, susceptiblevec); - result->Add("infected", timevec, infectedvec); - result->Add("recovered", timevec, recoveredvec); -} - -} // namespace bdm diff --git a/demo/epidemiology/src/analytical-solution.h b/demo/epidemiology/src/analytical-solution.h deleted file mode 100644 index 3d80361ab..000000000 --- a/demo/epidemiology/src/analytical-solution.h +++ /dev/null @@ -1,21 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef ANALYTICAL_SOLUTION_H_ -#define ANALYTICAL_SOLUTION_H_ - -#include "evaluate.h" - -namespace bdm { - -void CalculateAnalyticalSolution(TimeSeries* result, real_t beta, real_t gamma, - real_t susceptible, real_t infected, - real_t tstart, real_t tend, real_t step_size); - -} // namespace bdm - -#endif // ANALYTICAL_SOLUTION_H_ diff --git a/demo/epidemiology/src/behavior.h b/demo/epidemiology/src/behavior.h deleted file mode 100644 index 685d49619..000000000 --- a/demo/epidemiology/src/behavior.h +++ /dev/null @@ -1,90 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef BEHAVIOR_H_ -#define BEHAVIOR_H_ - -#include "core/behavior/behavior.h" - -#include "person.h" -#include "sim-param.h" - -namespace bdm { - -// ----------------------------------------------------------------------------- -struct Infection : public Behavior { - BDM_BEHAVIOR_HEADER(Infection, Behavior, 1); - - Infection() {} - virtual ~Infection() {} - - void Run(Agent* a) override { - auto* sim = Simulation::GetActive(); - auto* random = sim->GetRandom(); - auto* param = sim->GetParam(); - auto* sparam = param->Get(); - - auto* person = bdm_static_cast(a); - if (person->state_ == kSusceptible && - random->Uniform(0, 1) <= sparam->infection_probablity) { - auto* ctxt = sim->GetExecutionContext(); - auto check_surrounding = - L2F([&](Agent* neighbor, real_t squared_distance) { - auto* other = bdm_static_cast(neighbor); - if (other->state_ == State::kInfected) { - person->state_ = State::kInfected; - } - }); - ctxt->ForEachNeighbor(check_surrounding, *person, - sparam->infection_radius); - } - } -}; - -// ----------------------------------------------------------------------------- -struct Recovery : public Behavior { - BDM_BEHAVIOR_HEADER(Recovery, Behavior, 1); - - Recovery() {} - virtual ~Recovery() {} - - void Run(Agent* a) override { - auto* person = bdm_static_cast(a); - if (person->state_ == kInfected) { - auto* sim = Simulation::GetActive(); - auto* random = sim->GetRandom(); - auto* sparam = sim->GetParam()->Get(); - if (random->Uniform(0, 1) <= sparam->recovery_probability) { - person->state_ = State::kRecovered; - } - } - } -}; - -// ----------------------------------------------------------------------------- -struct RandomMovement : public Behavior { - BDM_BEHAVIOR_HEADER(RandomMovement, Behavior, 1); - - RandomMovement() {} - virtual ~RandomMovement() {} - - void Run(Agent* agent) override { - auto* sim = Simulation::GetActive(); - auto* random = sim->GetRandom(); - auto* sparam = sim->GetParam()->Get(); - - const auto& position = agent->GetPosition(); - auto rand_movement = random->UniformArray<3>(-1, 1); - rand_movement.Normalize(); - auto new_pos = position + rand_movement * sparam->agent_speed; - agent->SetPosition(new_pos); - } -}; - -} // namespace bdm - -#endif // BEHAVIOR_H_ diff --git a/demo/epidemiology/src/epidemiology.cc b/demo/epidemiology/src/epidemiology.cc deleted file mode 100644 index 5e82c3683..000000000 --- a/demo/epidemiology/src/epidemiology.cc +++ /dev/null @@ -1,78 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#include "epidemiology.h" -#include "analytical-solution.h" -#include "sim-param.h" - -#include "core/multi_simulation/database.h" -#include "core/multi_simulation/experiment.h" -#include "core/multi_simulation/multi_simulation.h" - -using namespace bdm; -using bdm::experimental::MultiSimulation; - -const ParamGroupUid SimParam::kUid = ParamGroupUidGenerator::Get()->NewUid(); - -TimeSeries GetAnalyticalResults(const Param* param) { - // Create simulation object just to obtain parameter values - auto* sparam = param->Get(); - - // analytical solution - real_t beta = sparam->beta; - real_t gamma = sparam->gamma; - TimeSeries analytical; - CalculateAnalyticalSolution( - &analytical, beta, gamma, sparam->initial_population_susceptible, - sparam->initial_population_infected, 0, sparam->number_of_iterations, 1); - return analytical; -} - -void ExperimentSimAndAnalytical(int argc, const char** argv, const Param* param, - uint64_t repeat) { - auto analytical = GetAnalyticalResults(param); - - auto sim_wrapper = L2F([&](Param* param, TimeSeries* result) { - Simulate(argc, argv, result, param); - }); - - auto plot = L2F([&](const std::vector& results, - const TimeSeries& mean, const TimeSeries& analytical) { - auto* sparam = param->Get(); - PlotResults(&analytical, &mean, results, sparam->root_style, "output", - !sparam->no_legend, sparam->result_plot); - }); - - real_t mse = Experiment(sim_wrapper, repeat, param, &analytical, &plot); - std::cout << " MSE " << mse << std::endl; -} - -int main(int argc, const char** argv) { - // register parameters that are specific for this simulation - Param::RegisterParamGroup(new SimParam()); - Simulation simulation(argc, argv); - auto* param = simulation.GetParam(); - auto* sparam = param->Get(); - - auto repeat = sparam->repeat; - - std::cout << "Mode: " << sparam->mode << std::endl; - - // Run the simulation once and compute the error against the analytical - // solution - if (sparam->mode == "sim-and-analytical") { - ExperimentSimAndAnalytical(argc, argv, param, repeat); - std::cout << "Simulation completed successfully!" << std::endl; - return 0; - } else { // Run the multi-simulation fitting routine - // Generate the analytical data - auto analytical = GetAnalyticalResults(param); - MultiSimulation pe(argc, argv, &analytical); - std::cout << "Simulation completed successfully!" << std::endl; - return pe.Execute(Simulate); - } -} diff --git a/demo/epidemiology/src/epidemiology.h b/demo/epidemiology/src/epidemiology.h deleted file mode 100644 index a5b65310d..000000000 --- a/demo/epidemiology/src/epidemiology.h +++ /dev/null @@ -1,95 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef EPIDEMIOLOGY_H_ -#define EPIDEMIOLOGY_H_ - -#include "biodynamo.h" -#include "core/environment/uniform_grid_environment.h" - -#include "analytical-solution.h" -#include "behavior.h" -#include "evaluate.h" -#include "person.h" -#include "sim-param.h" - -namespace bdm { - -// This is the main simulation function -inline int Simulate(int argc, const char** argv, TimeSeries* result, - Param* final_params = nullptr) { - // Overwrite the parameters with the `final_params` we obtain from the obtain - // from `bdm::Experiment` - auto set_param = [&](Param* param) { - param->Restore(std::move(*final_params)); - param->random_seed = 0; - param->simulation_time_step = 1; - param->bound_space = Param::BoundSpaceMode::kTorus; - }; - - // Create simulation object - Simulation sim(argc, argv, set_param); - - // Get pointers to important objects - auto* param = sim.GetParam(); - auto* sparam = param->Get(); - auto* random = sim.GetRandom(); - auto* env = dynamic_cast(sim.GetEnvironment()); - - auto state = State::kSusceptible; - // Lambda that creates a new person at specific position in space - auto person_creator = [&](const Real3& position) { - auto* person = new Person(position); - // Set the data members of the new person - person->SetDiameter(sparam->agent_diameter); - person->state_ = state; - // Define the persons behavior - person->AddBehavior(new Infection()); - person->AddBehavior(new Recovery()); - if (random->Uniform() < sparam->moving_agents_ratio) { - person->AddBehavior(new RandomMovement()); - } - return person; - }; - - // Create an initial population of susceptible persons. - // Person will be randomly distributed. - ModelInitializer::CreateAgentsRandom(param->min_bound, param->max_bound, - sparam->initial_population_susceptible, - person_creator); - - // Create an initial population of infected persons. - // Person will be randomly distributed. - state = State::kInfected; - ModelInitializer::CreateAgentsRandom(param->min_bound, param->max_bound, - sparam->initial_population_infected, - person_creator); - - SetupResultCollection(&sim); - - // Set the box length to the infection radius - env->SetBoxLength(sparam->infection_radius); - - // Now we finished defining the initial simulation state. - - auto* scheduler = sim.GetScheduler(); - scheduler->UnscheduleOp(scheduler->GetOps("mechanical forces")[0]); - - // Simulate for SimParam::number_of_iterations steps - { - Timing timer("RUNTIME"); - scheduler->Simulate(sparam->number_of_iterations); - } - // move time series data from simulation to result - *result = std::move(*sim.GetTimeSeries()); - - return 0; -} - -} // namespace bdm - -#endif // EPIDEMIOLOGY_H_ diff --git a/demo/epidemiology/src/evaluate.h b/demo/epidemiology/src/evaluate.h deleted file mode 100644 index 9533dd93b..000000000 --- a/demo/epidemiology/src/evaluate.h +++ /dev/null @@ -1,107 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef EVALUATE_H_ -#define EVALUATE_H_ - -#include -#include -#include -#include -#include -#include "biodynamo.h" -#include "person.h" - -using namespace bdm::experimental; - -namespace bdm { - -// --------------------------------------------------------------------------- -inline void SetupResultCollection(Simulation* sim) { - auto* ts = sim->GetTimeSeries(); - auto susceptible = [](Agent* a) { - return bdm_static_cast(a)->state_ == State::kSusceptible; - }; - auto infected = [](Agent* a) { - return bdm_static_cast(a)->state_ == State::kInfected; - }; - auto recovered = [](Agent* a) { - return bdm_static_cast(a)->state_ == State::kRecovered; - }; - auto post_process = [](real_t count) { - auto* rm = Simulation::GetActive()->GetResourceManager(); - auto num_agents = rm->GetNumAgents(); - return count / static_cast(num_agents); - }; - ts->AddCollector("susceptible", - new Counter(susceptible, post_process)); - ts->AddCollector("infected", new Counter(infected, post_process)); - ts->AddCollector("recovered", new Counter(recovered, post_process)); -} - -// --------------------------------------------------------------------------- -inline void PlotResults(const TimeSeries* analytical, const TimeSeries* mean, - const std::vector& individual_rd, - const experimental::Style& style, - const std::string& folder, - const bool plot_legend = true, - const std::string& filename = "result") { - TimeSeries allts; - if (mean) { - allts.Add(*mean, "mean"); - } - if (analytical) { - allts.Add(*analytical, "analytical"); - } - int i = 0; - for (auto& ind_ts : individual_rd) { - allts.Add(ind_ts, Concat("i", i++)); - } - LineGraph lg(&allts, "", "Time [h]", "Population Fraction", plot_legend, - style, 350, 250); - if (analytical) { - lg.Add("susceptible-analytical", " ", "L", kBlue, 1.0, kDashed, 2, kBlue, - 1.0, 1, 1, 0, 1.0, 0); - lg.Add("infected-analytical", " ", "L", kRed, 1.0, kDashed, 2, kRed, 1.0, 1, - 1, 0, 1.0, 0); - lg.Add("recovered-analytical", "SIR analytical", "L", kGreen, 1.0, kDashed, - 2, kGreen, 1.0, 1, 1, 0, 1.0, 0); - } - if (mean) { - lg.Add("susceptible-mean", " ", "L", kBlue, 1.0, kSolid, 2, kBlue, 1.0, 1, - 1, 0, 1.0, 0); - lg.Add("infected-mean", " ", "L", kRed, 1.0, kSolid, 2, kRed, 1.0, 1, 1, 0, - 1.0, 0); - lg.Add("recovered-mean", "SIR sim mean", "L", kGreen, 1.0, kSolid, 2, - kGreen, 1.0, 1, 1, 0, 1.0, 0); - } - - for (uint64_t i = 0; i < individual_rd.size(); ++i) { - lg.Add(Concat("susceptible-i", i), " ", "L", kBlue, 0.2, kSolid, 1, kBlue, - 0.2); - lg.Add(Concat("infected-i", i), " ", "L", kRed, 0.2, kSolid, 1, kRed, 0.2); - lg.Add(Concat("recovered-i", i), "SIR single sim", "L", kGreen, 0.2, kSolid, - 1, kGreen, 0.2); - } - - if (plot_legend) { - // Keep only the first 4 entries of the legend - lg.SetLegendPosNDC(0.5482955, 0.3799213, 0.9261364, 0.7224409); - auto* legend = lg.GetTLegend(); - auto list = legend->GetListOfPrimitives(); - for (uint64_t i = 0; i < individual_rd.size() * 3; i++) { - list->Remove(list->At(9)); - } - } - - lg.GetTMultiGraph()->SetMaximum(1.); - lg.SaveAs(Concat(folder, "/", filename), {".svg", ".root", ".C"}); -} - -} // namespace bdm - -#endif // EVALUATE_H_ diff --git a/demo/epidemiology/src/person.h b/demo/epidemiology/src/person.h deleted file mode 100644 index 921b24c01..000000000 --- a/demo/epidemiology/src/person.h +++ /dev/null @@ -1,32 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef PERSON_H_ -#define PERSON_H_ - -#include "core/agent/cell.h" - -namespace bdm { - -/// Possible Person states. -enum State { kSusceptible, kInfected, kRecovered }; - -class Person : public SphericalAgent { - BDM_AGENT_HEADER(Person, SphericalAgent, 1); - - public: - Person() {} - explicit Person(const Real3& position) : Base(position) {} - virtual ~Person() {} - - /// This data member stores the current state of the person. - int state_ = State::kSusceptible; -}; - -} // namespace bdm - -#endif // PERSON_H_ diff --git a/demo/epidemiology/src/sim-param.h b/demo/epidemiology/src/sim-param.h deleted file mode 100644 index 9de45a722..000000000 --- a/demo/epidemiology/src/sim-param.h +++ /dev/null @@ -1,42 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) Lukas Breitwieser. -// All Rights Reserved. -// -// ----------------------------------------------------------------------------- - -#ifndef SIM_PARAM_H_ -#define SIM_PARAM_H_ - -#include -#include "core/param/param_group.h" - -namespace bdm { - -/// This class defines parameters that are specific to this simulation. -/// The default values are set to simulate a measles outbreak. -struct SimParam : public ParamGroup { - BDM_PARAM_GROUP_HEADER(SimParam, 1); - - std::string mode = "sim-and-analytical"; - real_t beta = 0.06719; - real_t gamma = 0.00521; - uint64_t repeat = 10; - bool no_legend = false; - - std::string result_plot = "result"; - uint64_t number_of_iterations = 1000; - uint64_t initial_population_susceptible = 2000; - uint64_t initial_population_infected = 10; - real_t infection_radius = 10.5092197414493; - real_t moving_agents_ratio = 1.0; - real_t recovery_probability = 0.00521; - real_t agent_diameter = 2.0; - real_t agent_speed = 5.78594372145249; - real_t infection_probablity = 0.285097276954021; - experimental::Style root_style; -}; - -} // namespace bdm - -#endif // SIM_PARAM_H_ diff --git a/demo/epidemiology/test.sh b/demo/epidemiology/test.sh deleted file mode 100644 index 5ec0e765d..000000000 --- a/demo/epidemiology/test.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -source ~/biodynamo/build/bin/thisbdm.sh -./epidemiology --inline-config '{ "bdm::OptimizationParam" : { "algorithm" : "ParticleSwarm" } }' diff --git a/demo/epidemiology/visualize.sh b/demo/epidemiology/visualize.sh deleted file mode 100755 index a1db802b6..000000000 --- a/demo/epidemiology/visualize.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash - -BDM_SCRIPT_DIR=$(readlink -e $(dirname "${BASH_SOURCE[0]}")) - -cd $BDM_SCRIPT_DIR -biodynamo build -cd build - -./epidemiology --config ../measles.json --inline-config="{ \"bdm::Param\": { \"visualization_interval\": 100, \"export_visualization\": true }}" --repeat=1 - -echo "Start rendering..." -pvbatch $BDM_SCRIPT_DIR/render.py --screenshots --raytracing --name measles - diff --git a/demo/makefile_project/Makefile b/demo/makefile_project/Makefile index 7f765062f..6084a3175 100644 --- a/demo/makefile_project/Makefile +++ b/demo/makefile_project/Makefile @@ -22,24 +22,15 @@ BDM_CONFIG=bdm-config $(BUILD_TYPE) CXXFLAGS=`$(BDM_CONFIG) --cxxflags` LINKFLAGS=`$(BDM_CONFIG) --ldflags --libs` -HEADER=src/makefile_project.h - all: makefile_project -# BioDynaMo generate code: pass all headers that contain BioDynaMo code to the -# code generator -bdm_generated_code.cc: $(HEADER) - bdm-code-generation $@ "$(BDM_CONFIG)" -i "$(pwd)/src" -h $? - # Compile all source files -bdm_generated_code.o: bdm_generated_code.cc - $(CXX) $(CXXFLAGS) -c $? makefile_project.o: src/makefile_project.cc $(CXX) $(CXXFLAGS) -c $? # Generate binary (link object files and libraries) -makefile_project: bdm_generated_code.o makefile_project.o +makefile_project: makefile_project.o $(CXX) $? -o $@ $(LINKFLAGS) clean: - rm -rf *o bdm_generated_code.cc *_rdict.pcm makefile_project + rm -f *.o makefile_project diff --git a/demo/makefile_project/README.md b/demo/makefile_project/README.md index b51439810..a7a62e267 100644 --- a/demo/makefile_project/README.md +++ b/demo/makefile_project/README.md @@ -14,8 +14,6 @@ If everything was successful, the final output should be: Simulation completed successfully! -The solution uses two helper scripts `bdm-config` and `bdm-code-generation`. +The solution uses the `bdm-config` helper script. `bdm-config` provides the compiler and linker options that are required to build the simulation. -`bdm-code-generation` is performing the code generation step that is usually -taken care of by CMake. BioDynaMo relies on code generation to support reflection. diff --git a/demo/multiple_simulations/src/multiple_simulations.h b/demo/multiple_simulations/src/multiple_simulations.h index 3d2b30eb1..b0fa7e66a 100644 --- a/demo/multiple_simulations/src/multiple_simulations.h +++ b/demo/multiple_simulations/src/multiple_simulations.h @@ -22,7 +22,7 @@ namespace bdm { // Behavior that divides the agent at each time step struct Divide : Behavior { - BDM_BEHAVIOR_HEADER(Divide, Behavior, 1); + BDM_BEHAVIOR_HEADER(Divide, Behavior); Divide() {} diff --git a/doc/dev_guide/build.md b/doc/dev_guide/build.md index 74cdd4a09..caf5e0cd5 100644 --- a/doc/dev_guide/build.md +++ b/doc/dev_guide/build.md @@ -65,7 +65,7 @@ git checkout -b [edit the files] -# clean the previous build but keep the third party libraries, typically ROOT and ParaView +# clean the previous build cd build ninja cleanbuild @@ -116,8 +116,7 @@ If you change the value of these switches, you might have to delete `CMakeCache. | Option | Default Value | Description | | ---------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | | `test` | `on` | build the test executables; precondition for e.g. `valgrind` and `coverage` | -| `dict` | `on` | build ROOT dictionaries. These are compulsory to use backups. Turning them off reduces compilation time. | -| `paraview` | `on` | Enable visualization using ParaView. Visualization cannot be used if this switch is turned off. | +| `paraview` | `off` | Enable visualization using an installed ParaView package. | | `libgit2` | `off` | Enable automatic git tracking for executed simulations (e.g. last commits and `git diff` outputs; not available on `CentOS`.). | | `cuda` | `off` | enable CUDA code generation for GPU acceleration | | `opencl` | `off` | enable OpenCL code generation for GPU acceleration | @@ -197,51 +196,21 @@ export C=/opt/local/bin/clang++-mp-8.0 ./install.sh ``` -#### Use a Specific ROOT / ParaView Installation +#### Use a Specific ParaView Installation -When you want to inform BioDynaMo of a specific installation of ROOT and /or ParaView on your system, -you will need to perform the following instructions prior to installation. +Pass the installation prefix through CMake's standard package search path: ```bash git clone https://github.com/BioDynaMo/biodynamo.git cd biodynamo - -# For ROOT -source /bin/thisroot.sh - -# For ParaView -export ParaView_DIR=/lib/cmake/paraview-5.8 -export Qt5_DIR=/lib/cmake/Qt5 - -./install.sh -``` - -

Note

- -If you specify `ParaView_DIR`, then you will need to provide also the `Qt5_DIR` variable as well. -This is because ParaView implicitly relies on the Qt5 installation. - - -#### Speed Up Installation Tests with a Local BioDynaMo-LFS Copy - -The installation scripts fetch large precompiled dependencies like ROOT or ParaView -from biodynamo's large file storage (LFS). To enable faster builds you can download the whole -LFS and tell BioDynaMo to access the local version instead. This is done with the -environmental flag `BDM_LOCAL_LFS`. Use an absolute path to the directory -that contains the local copy. - -``` bash -export BDM_LOCAL_LFS=/path/to/local/lfs +cmake -S . -B build -Dparaview=ON \ + -DCMAKE_PREFIX_PATH= +cmake --build build --parallel ``` -If you want to download the files from remote LFS again execute: +Ubuntu's ParaView development package requires its public development +dependencies when BioDynaMo builds the visualization plugin: -``` bash -unset BDM_LOCAL_LFS +```bash +sudo apt-get install paraview paraview-dev libdouble-conversion-dev libutfcpp-dev ``` - - -

Warning

- -At the moment there is no check if the local copy is in synch with remote. -You have to ensure that yourself! diff --git a/doc/sidebars/userguide.yaml b/doc/sidebars/userguide.yaml index edadf7bc0..e1a971073 100644 --- a/doc/sidebars/userguide.yaml +++ b/doc/sidebars/userguide.yaml @@ -37,12 +37,8 @@ link: /docs/userguide/substance_initializers/ - title: GPU Acceleration link: /docs/userguide/gpu_acceleration/ - - title: Notebook - link: /docs/userguide/notebook/ - title: Adding documentation webpage link: /docs/userguide/add_page/ - - title: Multi simulation runtime - link: /docs/userguide/multi_simulation - title: Floating-point precision link: /docs/userguide/fp-precision - group: Troubleshooting diff --git a/doc/user_guide/Singularity.md b/doc/user_guide/Singularity.md index ca3350275..533e3149e 100644 --- a/doc/user_guide/Singularity.md +++ b/doc/user_guide/Singularity.md @@ -52,10 +52,7 @@ singularity run --cleanenv Singularity.sif ``` where the ``--cleanenv`` option clears out all the environment variables set in the host machine to avoid conflicts. -Once the container is running we can source Root and the BioDynaMo environment: -```bash -source /biodynamo/build/third_party/root/bin/thisroot.sh -``` +Once the container is running we can source the BioDynaMo environment: ```bash source /biodynamo/build/bin/thisbdm.sh ``` @@ -79,10 +76,7 @@ singularity run --cleanenv Singularity.sif ``` where the ``--cleanenv`` option clears out all the environment variables set in the host machine to avoid conflicts. -Once the container is running we can source Root and the BioDynaMo environment: -```bash -source /biodynamo/build/third_party/root/bin/thisroot.sh -``` +Once the container is running we can source the BioDynaMo environment: ```bash source /biodynamo/build/bin/thisbdm.sh ``` @@ -92,7 +86,7 @@ complex use cases. ## Exporting visualisations on HPC's -By default, BioDynaMo uses ParaView for visualization, which needs an X-display server to function. Since the Singularity image does not provide a graphical desktop environment and hence no X-server, there are two workarounds. +ParaView visualization requires an X display unless the installed ParaView uses a headless rendering backend. Since the Singularity image does not provide a graphical desktop environment, there are two approaches. ### Option 1: Using xvfb ```xvfb``` stands for X virtual frame buffer and emulates the required display server. Start a virtual frame buffer with: @@ -103,9 +97,5 @@ The buffer can be managed with the arguments ```start```|```stop```|```restart`` Note: Some systems may require display forwarding **before** starting the frame buffer. This can be achived through ```export DISPLAY=0```. -### Option 2: Setting Paraview to work in a headless mode using the CMAKE flag -Paraview with the osmesa or EGL backend does not require an X-server. To change the backend, you have to edit the cmake options in [1], build paraview, and replace the ParaView version that BioDynaMo installs. See also [2]. - -[1] https://github.com/BioDynaMo/biodynamo/blob/HPC-documentation/util/build-third-party/paraview/build.sh - -[2] https://discourse.paraview.org/t/pvpython-offscreen-rendering-segfault/246/3 +### Option 2: Install a headless ParaView build +ParaView with an OSMesa or EGL backend does not require an X server. Install a ParaView build configured for one of those backends and configure BioDynaMo with `-Dparaview=ON`. diff --git a/doc/user_guide/docs/notebooks.md b/doc/user_guide/docs/notebooks.md deleted file mode 100644 index 279393baa..000000000 --- a/doc/user_guide/docs/notebooks.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "BioDynaMo Notebooks" -date: "2019-11-11" -path: "/docs/userguide/notebook/" -meta_title: "BioDynaMo Dev Guide" -meta_description: "Information about BioDynaMo Notebooks" -toc: true -image: "" -next: - url: "/docs/userguide/add_page/" - title: "Adding documentation webpage" - description: "Information about adding documentation to the BioDynaMo website." -sidebar: "userguide" -keywords: - -notebooks - -jupyter - -web-app ---- - -BioDynaMo supports the use of Jupyter Notebooks to create, run and visualize -simulations in. This is a more user-friendly interface to BioDynaMo, and is -intended mostly for educational and demonstrative purposes, as the performance -capabilities are limited. - -## What is a Notebook? - -Jupyter Notebook is a web application that allows you to interactively work with -code snippets. It allows you to write text (in Markdown and/or HTML format) to -give information about the contents of code snippets, or to give context. -Besides code snippets, you can embed visualizations (e.g. BioDynaMo visualizations), -and other forms of media (e.g. images, videos, etc.). A Notebook is composed of -"cells" with certain contents. There are different type of cells to contain -different types of content (e.g. code snippets, text). - -You can use Notebooks to play around interactively with code snippets -(e.g. to test code, or to quickly change parameters). Another great use is -to create tutorials that can be presented to others for demonstrative or -educational purposes. You can embed the visualization to bring across certain -points about your simulation in an effective manner. - -Notebooks in BioDynaMo are supported by the ROOT framework. Since simulations -in BioDynaMo are currently written in C++, we make use of 'ROOT Notebooks' to -get the same functionalities one would expect in regular (Python-based) Jupyter -Notebooks. - -## How to open a Notebook - -After you have installed BioDynaMo, there are a couple of Notebooks already -available to play around with. They can be found in `$BDMSYS/notebooks`, and -are in the file format `.ipynb`. You can open them by executing the following -command in a terminal (where `thisbdm.sh` is sourced): - -``` sh -root --notebook -``` - -This will automatically open up the Notebook web application in your default -browser. It should show a list of directories. Browse to your specific notebook, -and click on the `.ipynb` file. This should open the notebook. - -## How to interact with a Notebook - -The way to interact with a Notebook in BioDynaMo is almost exactly the same as -with regular Jupyter notebooks. - -You can execute the context of a cell by selecting a cell by simply clicking on -it. Then from the menu bar open the "Cell" drop down menu and click on "Run Cells", -or simply "Ctrl + Enter" on your keyboard. If you wish to go through the cells -without having to select them individually you can also select the "Run Cells and Select Below" -option from the "Cell" drop down menu, or "Shift + Enter" on your keyboard. - -If you wish to execute the entire notebook at once you can click on "Restart & Run All" -from the "Kernel" dropdown menu. - - -
-

Tip

-

You can find a list of common shortcuts in the "command palette" by clicking - on the keyboard icon in the menu bar -

-
-
- -## How to create a Notebook - -If you are in the file browsing view of ROOT Notebooks, you can create a new -notebook by pressing the "New" button on the right top corner, and selecting -"ROOT C++". If you have already an existing Notebook open, you can achieve the -same with "File" >> "New Notebook" >> "ROOT C++". diff --git a/doc/user_guide/installation.md b/doc/user_guide/installation.md index 96a738102..614840ddc 100644 --- a/doc/user_guide/installation.md +++ b/doc/user_guide/installation.md @@ -22,7 +22,7 @@ To install and update BioDynaMo execute the following command. curl https://biodynamo.github.io/install | bash ``` -This will also install all prerequisites, including ROOT, ParaView and Qt5. +This also installs the required toolchain and libraries. ParaView remains an optional system dependency. By default the installation directory is set to `$HOME/biodynamo-vX.Y.Z`, where X.Y.Z is the version number.
diff --git a/doc/user_guide/multi_simulation.md b/doc/user_guide/multi_simulation.md deleted file mode 100644 index fef0ee719..000000000 --- a/doc/user_guide/multi_simulation.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: "BioDynaMo Multi Simulation" -date: "2021-11-18" -path: "/docs/userguide/multi_simulation/" -meta_title: "BioDynaMo User Guide" -meta_description: "Information about BioDynaMo Multi Simulation runtime" -toc: true -image: "" -sidebar: "userguide" -keywords: - -multi - -simulation - -multi-simulation ---- - -# Multi Simulation: What and Why? - -With BioDynaMo it is possible to run multiple simulations in parallel, as -separate processes. We refer to this as "Multi Simulation". This can be a -useful feature when you want to repeat a certain simulation multiple times; -possibly with different runtime parameters. Instead of running the simulations -consecutively, with Multi Simulation it is possible to run multiple instances simultaneously, on one or more machines. This allows you to explore a parameter -space and obtain results at a much faster pace. The more computing resources are -available, the faster the simulations are completed. -BioDynaMo offers a couple of default algorithms on exploring a parameter space (e.g. parameter sweep, particle swarm). -The algorithms benefit from Multi Simulation by running each iteration in a separate process. - -## MPI -Multi Simulation uses MPI to spawn different processes and schedule the -simulations on your system(s). - - If you work with more than one machine, you are required to have the - same OpenMPI versions installed on all the machines in order for Multi Simulation to work properly. - - Furthermore, MPI requires you to have a passwordless SSH login to the other machines. - -## How to use Multi Simulation - -In order to run a simulation in Multi Simulation mode, you need to make a few changes. - -### Main function -In the `main` function of your simulation you need to call the `MultiSimulation` wrapper -around your regular `Simulate` call: - -```c++ -int main(int argc, const char** argv) { - bdm::experimental::MultiSimulation pe(argc, argv); - return pe.Execute(Simulate); -} -``` - -### Simulate function - -Your `Simulate` function also should conform to the following signature in order to use Multi Simulation: - -```c++ -void Simulate(int argc, const char** argv, TimeSeries* result, - Param* final_params = nullptr) { -auto set_param = [&](Param* param) { - param->Restore(std::move(*final_params)); -}; -Simulation simulation(argc, argv, set_param); - -// Your simulation code... -} -``` - -`result ` is a `TimeSeries` object that can be populated with results that are of interest in your simulation. -For some optimization algorithms, like ParticleSwarm, this *must* be populated with such results to be able to minimize the error between simulated data and real-life data. - -`final_params` are the unique set of parameters that a simulation instance receives from the Multi Simulation runtime. You must therefore configure your simulation with these parameters *before* you define your simulation using the `Restore` functionality. - -### Optimization parameters - -The Multi Simulation runtime expects you to define which parameter space exploration algorithm you want to use. -This can be done by defining a `OptimizationParam` in your parameter configuration: - -```json -{ - "bdm::OptimizationParam": { - "algorithm" : "", - "params" : [ - { - "_typename": "", - "param_name" : "", - ... - } - ] - } -} - -``` -* The `algorithm` should be the name of the algorithm you wish to use (e.g. "ParameterSweep", "ParticleSwarm") -* The `params` should be a list of simulation parameters you wish to explore. In the code block above, there is only one parameter block, but this can be a comma-separated list of multiple parameter blocks. - * The `_typename` should be the type of parameter it concerns (e.g. a uniform range of parameters, a set of parameters). See "core/multi\_simulation/optimization\_param_type" for a list of available parameter types - * The `param_name` should be the name of the parameter in your simulation, including any namespace identifiers (e.g. "bdm::SimParam::my_param") - * Each parameter type has a number of extra fields that need to be filled in. For example, for a RangeParam (a uniform range of values), you would also need to specify the `lower_bound`, `upper_bound` and `stride` in its parameter block. - -### Command line execution -Since Multi Simulation relies on MPI, we must use the `mpirun` binary to run the simulation with - -``` sh -$ mpirun -np --config=param.json -``` - -`param.json` contains the optimization parameter information as described earlier (this can also instead be inlined with the `inline-config` command line argument). - -This command spawns `N-1` number of processes that each will start a -simulation (`N-1` because one process is always reserved as the managing process). The number of simulations that will eventually be performed depends -on your optimization algorithm: the more parameters you would like to explore, -the higher the number of simulations that need to be executed. - -It is very likely that the total number of simulations will be greater than `N-1`. Since -there can only be at most `N-1` simulation running at any given point in time, -the other simulations are queued, and scheduled to be executed whenever -computing resources become available. - -If you wish to run your simulations on multiple machines (e.g. a cluster, or cloud instances), it -can simply be done as follows: - -``` sh -$ mpirun -np --hostfile --config=param.json -``` - -The `hostfile` should contain the names (e.g. IP addresses) of the machines in -your cluster. For detailed information on how to create a hostfile, please check -out the OpenMPI docs [^1]. - - [^1]: https://www.open-mpi.org/faq/?category=running#mpirun-hostfile - -### Performance tuning - -Since we rely on MPI to distribute the simulation workloads over a specified -number of processes, we are able to finetune the performance through the many -options that come with the MPI implementation. Important for the performance of -multi-threaded applications is being able to tweak the number of threads that -each process is able to spawn, the thread affinity, and other related -parameters. These parameters are conveniently described online [^3]. - - [^3]: https://www.open-mpi.org/doc/v3.0/man1/mpirun.1.php - - - diff --git a/doc/user_guide/parameter.md b/doc/user_guide/parameter.md index a46812201..bb07f2e33 100644 --- a/doc/user_guide/parameter.md +++ b/doc/user_guide/parameter.md @@ -3,7 +3,7 @@ title: "Parameter" date: "2019-01-01" path: "/docs/userguide/parameter/" meta_title: "BioDynaMo User Guide" -meta_description: "This is the parameter page." +meta_description: "Configure BioDynaMo simulations." toc: true image: "" sidebar: "userguide" @@ -14,153 +14,75 @@ keywords: -setup --- -Parameters are used to tailor BioDynaMo to your specific simulation. +Parameters tailor BioDynaMo to a simulation. Core parameters are documented in +the [`Param` API](/api/structbdm_1_1Param.html). Simulations and modules can add +their own `ParamGroup` implementations. -The majority of parameters are defined in the [core engine](/api/structbdm_1_1Param.html). -Each simulation or module can define its own [`Param` class](/api/structbdm_1_1neuroscience_1_1Param.html) to add additional parameters. +### Read parameters -There are three ways to set the value of a parameter: - -1. TOML/JSON configuration file -2. Command line argument -3. Assignment in the source code. - -
- -
-

Note

-

Higher index takes precedence. E.g. If you define the backup_file in the TOML/JSON file and the - command line parameter, the command line version will be used. -

-
-
- -The documentation of each parameter contains a description of the -parameter, its default value and how to set it in the TOML file ([example](/api/structbdm_1_1Param.html#a13d24f045335b7ac62a091f56c6fe166)) - -The following code snippet shows how to access a parameter in your -simulation. +The active simulation owns the effective parameter set: ```cpp const auto* param = Simulation::GetActive()->GetParam(); std::cout << param->simulation_time_step << std::endl; std::cout << param->Get()->neurite_max_length_ << std::endl; - ``` +### TOML configuration -### Configuration File - -This is the recommended way to set runtime variables. -BioDynaMo supports configuration files in [TOML](https://toml.io/en/) -or [JSON merge patch](https://tools.ietf.org/html/rfc7386) format. - -Here you can find a tutorial about the usage of [simulation parameters](/docs/userguide/simulation_parameter_tutorial) - -#### TOML - -Create a file `bdm.toml` -in the working directory and add your configuration. You can find a sample below: +Place `bdm.toml` in the working directory or its parent directory. BioDynaMo +loads it automatically. The following file changes the time step and enables +exported visualization: ```toml +[simulation] +time_step = 0.1 + [visualization] export = true [[visualize_agent]] name = "Cell" -additional_data_members = [ "density_" ] +additional_data_members = ["density_"] ``` -#### JSON +Required visualization members supplied by an agent are available +automatically. A custom name in `additional_data_members` also requires the +agent to override `GetVisualizationData` and return a `std::vector`, +`std::vector`, or `std::vector` for that name. -Create a file `bdm.json` -in the working directory and add your configuration. You can find a sample below: +Pass a different file with `-c FILE` or `--config FILE`. Repeat the option to +load several files in order. A simulation can also supply configuration files +to its constructor: -```json -{ - "bdm::Param": { - "export_visualization": true, - "visualize_agents": { - "Cell": ["density_"] - } - } -} +```cpp +Simulation simulation(argc, argv, {"experiment.toml"}); ``` -### Command Line Options +Custom parameter groups implement `AssignFromConfig` and read their values from +the parsed TOML table. -Some parameter can be set as command line argument when you start the simulation. -For a complete list execute the binary with the `--help` switch. e.g. `./cell_division --help`. +### Command line options -Sample output: -``` --- BioDynaMo command line options - -Usage: - ./cell_division [OPTION...] - - Core options: - -h, --help Print this help message. - --version Print version number of BioDynaMo. - --opencl Enable GPU acceleration through OpenCL. - --cuda Enable GPU acceleration through CUDA. - -v, --verbose Verbose mode. Causes BioDynaMo to print - debugging messages. Multiple -v options increases - the verbosity. The maximum is 3. - -r, --restore FILE Restores the simulation from the checkpoint - found in FILE and continues simulation from - that point. (default: ) - -b, --backup FILE Periodically create full simulation backup to - the specified file. NOTA BENE: File will be - overridden if it exists. (default: ) - -c, --config FILE The TOML or JSON configuration that should be - used. The JSON file must be in JSON merge - patch format - (https://tools.ietf.org/html/rfc7386) (default: ) - --inline-config JSON_STRING - JSON configuration string passed directly on - the command line. Overwrites values specified - in config file. The JSON string must be in - JSON merge patch format - (https://tools.ietf.org/html/rfc7386) (default: ) - --output-default-json Prints a JSON string with all parameters and - their default values and exits. - --toml-to-json TOML_FILE Converts a TOML file to a JSON patch. After - printing the JSON patch the application will - exit. (default: ) -``` +Run a simulation with `--help` to list its options. Core options cover compute +targets, visualization, verbosity, and TOML configuration. -You can append your own command line options as following (e.g. `num-cells` as -show in the sample above): +Add a simulation-specific option before constructing `Simulation`: ```cpp -auto opts = CommandLineOptions(argc, argv); -opts.AddOption("n, num-cells", "The total number of cells", "10"); - -// You will need to pass this object to the main Simulation object as follows: -Simulation simulation(opts); - -// To retrieve the values from the command line in your simulation code -auto parser = opts.Parse(); -uint64_t num_cells = parser.Get("num-cells"); +CommandLineOptions options(argc, argv); +options.AddOption("n, num-cells", "10", + "The total number of cells"); +Simulation simulation(options); +auto num_cells = options.Get("num-cells"); ``` -The `AddOption` function can be broken down as follows: The template parameter -(`uint64_t`) specifies what value type your option should be. The first function -parameter is for the flag abbreviation (in this case -n and --num-cells) The -second parameter is the name of your command line option The third parameter is -the description (as shown in the help dialogue) The fourth parameter is the -default value of the command line option (i.e. when you do not specify the -flag). - -### Assignment in the Source Code +### Source configuration -You can also set a runtime parameter in the source code. You have to recompile -your simulation though. +Use a constructor callback for values fixed by the simulation source: ```cpp auto set_param = [](Param* param) { - // Create an artificial bound for the simulation space param->bound_space = Param::BoundSpaceMode::kClosed; param->min_bound = 0; param->max_bound = 250; @@ -169,6 +91,4 @@ auto set_param = [](Param* param) { Simulation simulation(argc, argv, set_param); ``` -You have to create a lambda and pass it to the constructor of `Simulation`. -Afterwards, `Simulation` only returns a const pointer to the parameters. Thus, -they cannot be modified. +The simulation exposes parameters as read-only state after initialization. diff --git a/doc/user_guide/prerequisites.md b/doc/user_guide/prerequisites.md index 24cc54a82..2fba14b2a 100644 --- a/doc/user_guide/prerequisites.md +++ b/doc/user_guide/prerequisites.md @@ -234,8 +234,6 @@ Requirements to build on macOS are: * **cmake**: Set of tools for automate building, testing of software * **ninja**: Ninja is a small build system with a focus on speed * **bash**: Recent version of bash shell - * **tbb**: Rich and complete approach to parallelism in C++ (needed by ROOT on Apple M1) - * **qt@5**: Library used by ParaView ### Optional Packages @@ -244,6 +242,7 @@ Requirements to build on macOS are: * **kcov**: Code coverage testing tool * **gsl**: GNU Scientific Library (GSL) -- development package * **libgit2**: C library for git + * **paraview**: Scientific visualization and in situ analysis ### Installation @@ -251,12 +250,11 @@ Requirements to build on macOS are: ```bash brew update; brew upgrade -brew install libomp open-mpi python@3.9 wget cmake ninja bash tbb qt@5 +brew install libomp open-mpi python@3.9 wget cmake ninja bash ``` #### Optional Packages ```bash -brew install doxygen graphviz kcov gsl libgit2 -python3 -m pip install markupsafe==2.0.1 nbformat jupyter metakernel jupyterlab jinja2==3.0 +brew install doxygen graphviz kcov gsl libgit2 paraview ``` diff --git a/doc/user_guide/simulation_parameter_tutorial.md b/doc/user_guide/simulation_parameter_tutorial.md index f925268a1..0cf30e4c7 100644 --- a/doc/user_guide/simulation_parameter_tutorial.md +++ b/doc/user_guide/simulation_parameter_tutorial.md @@ -3,392 +3,114 @@ title: "Simulation Parameter Tutorial" date: "2020-09-08" path: "/docs/userguide/simulation_parameter_tutorial/" meta_title: "BioDynaMo User Guide" -meta_description: "This page explains simulation parameters." +meta_description: "Define and configure simulation parameters with TOML." toc: true image: "" sidebar: "userguide" keywords: -parameter - -json + -toml --- -This tutorial demonstrates the usage of simulation parameters using the JSON format. +This tutorial uses the installed `parameters` demo to define a custom parameter +group and configure it with TOML. -### Copy the demo code - -`parameters` is one of many installed demos in BioDynaMo. It can be copied out -with `biodynamo demo`. +### Copy and inspect the demo ```bash biodynamo demo parameters +cd parameters ``` -### Inspect the code - -Go into the `parameters` directory and open the files `src/parameters.h` -and `src/parameters.cc` in your -favorite editor and inspect the code. -We can note the following things from its content: - -#### 1. Add simulation specific parameters - -We add the simulation specific parameters `foo` and `bar`. -Therefore, we create a new struct called `SimParam`, which inherits -from `ParamGroup`. -To reduce the amount of boilerplate code, BioDynaMo provides the macro -`BDM_PARAM_GROUP_HEADER`. +`src/parameters.h` defines two simulation-specific values: ```cpp -// Parameters specific for this simulation struct SimParam : public ParamGroup { BDM_PARAM_GROUP_HEADER(SimParam, 1); real_t foo = 3.14; int bar = -42; + + protected: + void AssignFromConfig( + const std::shared_ptr& config) override { + BDM_ASSIGN_CONFIG_VALUE(foo, "parameters.foo"); + BDM_ASSIGN_CONFIG_VALUE(bar, "parameters.bar"); + } }; ``` -#### 2. Initialize ParamGroupUid - -Every ParamGroup must have a unique identifier. -Definition of `SimParam::kUid` must be done in a source file (`src/parameters.cc`). +`src/parameters.cc` defines the group's unique identifier: ```cpp const ParamGroupUid SimParam::kUid = ParamGroupUidGenerator::Get()->NewUid(); ``` -#### 3. Register new parameters - -Before we create a simulation, we have to tell BioDynaMo about the new parameters. +The simulation registers the group before creating `Simulation`, then reads the +effective values from the simulation-owned parameter set: ```cpp Param::RegisterParamGroup(new SimParam()); - -``` - -#### 4. Create simulation - -We create a new simulation and pass the command line arguments to it. - -```cpp Simulation simulation(argc, argv); +const auto* param = simulation.GetParam(); +const auto* simulation_param = param->Get(); ``` -#### 5. Print parameters - -We obtain pointers to the core and our simulation specific parameters -and print out a few values. - -```cpp -// get a pointer to the param object -auto* param = simulation.GetParam(); -// get a pointer to an instance of SimParam -auto* sparam = param->Get(); - -std::cout << "Value of simulation time step " << param->simulation_time_step << std::endl; -std::cout << "Value of foo " << sparam->foo << std::endl; -std::cout << "Value of bar " << sparam->bar << std::endl; -``` - -NB: If you don't have a pointer to `bdm::Simulation` inside e.g. a behavior, you can -obtain it by calling `Simulation::GetActive()`. - -### Build the simulation - -In this tutorial, we use `cmake` and `make` directly instead of `biodynamo build` or `biodynamo run`. +### Build and run ```bash -mkdir build -cd build -cmake .. -make -j4 +cmake -S . -B build +cmake --build build --parallel +./build/parameters ``` -These commands create a binary called `parameters` - -### Run the simulation +The initial output contains the defaults: -Execute `./parameters` in your build directory. -You should see the following output. - -``` +```text Value of simulation time step 0.01 Value of foo 3.14 Value of bar -42 Simulation completed successfully! ``` -These three parameters are set to their default values. - -### Explore available parameters - -BioDynaMo comes with a command line option to print all available simulation parameters. -Execute `./parameters --output-default-json`. - -You should see output similar to this: - -```json -Below you can find a JSON string with all available parameters and their default values. -Have a look at https://biodynamo.org/bioapi/ for more details about each parameter. -{ - "bdm::Param": { - "_typename": "bdm::Param", - "backup_file": "", - "backup_interval": 1800, - "bound_space": 0, - "cache_neighbors": false, - "calculate_gradients": true, - "compute_target": "cpu", - "debug_numa": false, - "detect_static_agents": false, - "diffusion_method": "euler", - "export_visualization": false, - "diffusion_boundary_condition": "open", - "max_bound": 100, - "mem_mgr_aligned_pages_shift": 8, - "mem_mgr_growth_rate": 1.1, - "mem_mgr_max_mem_per_thread_factor": 1, - "min_bound": 0, - "minimize_memory_while_rebalancing": true, - "numerical_ode_solver": 1, - "opencl_debug": false, - "output_dir": "output", - "preferred_gpu": 0, - "restore_file": "", - "root_visualization": false, - "scheduling_batch_size": 1000, - "show_simulation_step": 0, - "simulation_max_displacement": 3, - "simulation_time_step": 0.01, - "statistics": false, - "thread_safety_mechanism": 1, - "use_bdm_mem_mgr": true, - "visualization_engine": "paraview", - "visualization_export_generate_pvsm": true, - "visualize_diffusion": [], - "visualize_agents": { - "_typename": "map >" - } - }, - "bdm::SimParam": { - "_typename": "bdm::SimParam", - "bar": -42, - "foo": 3.14 - } -} - -``` - -NB: You can ignore keys with name `_typename` +### Configure the simulation -### Create a JSON config file +Create `bdm.toml` in the demo directory: -Now let's create a JSON config file. The output from the previous step can serve as a good -starting point. +```toml +[simulation] +time_step = 1.0 -Create a new file `bdm.json` in the project root directory with the following content. - -```json -{ - "bdm::Param": { - "simulation_time_step": 1.0 - }, - "bdm::SimParam": { - "bar": 84 - } -} +[parameters] +foo = 6.28 +bar = 84 ``` -Execute `./parameters` in your build directory. -You should see the following output. +Run the binary again. BioDynaMo finds `bdm.toml` in the parent of the build +directory and prints the configured values: -``` +```text Value of simulation time step 1 -Value of foo 3.14 -Value of bar 84 -Simulation completed successfully! -``` - -BioDynaMo automatically picked up the configuration file and parsed its content. -BioDynaMo looks for a file with the name `bdm.json` in the current working directory and -it's parent directory. If it finds one it automatically uses it. - -### Use specific JSON config file - -Rename the file `bdm.json` from the previous step to `config.json`. - -If you execute `./parameters` again, you get the same output as running [without config file](#run-the-simulation). - -BioDynaMo has different methods to choose a specific configuration file. -This allows us to have multiple configuration files in the same project. - -Execute `./parameters --config ../config.json` from within the build directory. -You should see the following output. - -``` -Value of simulation time step 1 -Value of foo 3.14 -Value of bar 84 -Simulation completed successfully! -``` - -There is another way to tell BioDynaMo to use a specific configuration file. You can pass a config file parameter as an argument to the `bdm::Simulation` constructor. - -Therefore, in file `src/parameters.h` replace `Simulation simulation(argc, argv)` -with `Simulation simulation(argc, argv, {"../config.json"})`. -Since we changed the code, we have to recompile it before we can execute it. - -``` -make -j4 -./parameters -``` - -Although we didn't specify any command line argument, BioDynaMo still picks up our `config.json` configuration file. - -``` -Value of simulation time step 1 -Value of foo 3.14 -Value of bar 84 -Simulation completed successfully! -``` - -### Use inline config command line parameter - -In addition to a configuration file, BioDynaMo offers the functionality to specify the JSON string on the command line using the -`inline-config` option. - - -Execute the following command to change the `foo` parameter on the command line. -```bash -./parameters --inline-config '{ "bdm::SimParam": { "foo": 6.28 } }' -``` - -You should see the following output. - -``` -Value of simulation time step 1 Value of foo 6.28 Value of bar 84 Simulation completed successfully! ``` -We can see that parameter `foo` was correctly updated to `6.28`. The other parameters are set to the values in `config.json`. -If the same value is set in the configuration file and the `inline-config` parameter, the `inline-config` value takes precedence. - -### Output used simulation parameters +### Select a configuration explicitly -BioDynaMo offers the functionality to output simulation metadata at the end of the simulation. -This contains a list of all parameters with their values. +Rename the file and pass it on the command line: -To turn it on update the file `config.json`: - -```json -{ - "bdm::Param": { - "statistics": true, - "simulation_time_step": 1.0 - }, - "bdm::SimParam": { - "bar": 84 - } -} +```bash +mv bdm.toml experiment.toml +./build/parameters --config experiment.toml ``` -Once more, execute `./parameters --inline-config '{ "bdm::SimParam": { "foo": 6.28 } }'`. -You should see output similar to this: - -```json -Value of simulation time step 1 -Value of foo 6.28 -Value of bar 84 -Simulation completed successfully! - -*********************************************** -*********************************************** -Simulation Metadata: -*********************************************** - -General -Command : ./parameters --inline-config { "bdm::SimParam": { "foo": 6.28 } } -Simulation name : parameters -Number of iterations executed : 0 -Number of agents : 0 -Output directory : output/parameters - size : 4.0K - -*********************************************** - -No statistics were gathered! - -*********************************************** - -Thread Info -max_threads : 4 -num_numa nodes : 1 -thread to numa mapping : 0 0 0 0 -thread id in numa node : 0 1 2 3 -num threads per numa : 4 - -*********************************************** - -Agents per numa node -numa node 0 -> size: 0 - -*********************************************** - -Parameters -{ - "bdm::Param": { - "_typename": "bdm::Param", - "backup_file": "", - "backup_interval": 1800, - "bound_space": 0, - "cache_neighbors": false, - "calculate_gradients": true, - "compute_target": "cpu", - "debug_numa": false, - "detect_static_agents": false, - "diffusion_method": "euler", - "export_visualization": false, - "diffusion_boundary_condition": "open", - "max_bound": 100, - "mem_mgr_aligned_pages_shift": 8, - "mem_mgr_growth_rate": 1.1, - "mem_mgr_max_mem_per_thread_factor": 1, - "min_bound": 0, - "minimize_memory_while_rebalancing": true, - "numerical_ode_solver": 1, - "opencl_debug": false, - "output_dir": "output", - "preferred_gpu": 0, - "restore_file": "", - "root_visualization": false, - "scheduling_batch_size": 1000, - "show_simulation_step": 0, - "simulation_max_displacement": 3, - "simulation_time_step": 1, - "statistics": true, - "thread_safety_mechanism": 1, - "use_bdm_mem_mgr": true, - "visualization_engine": "paraview", - "visualization_export_generate_pvsm": true, - "visualize_diffusion": [], - "visualize_agents": { - "_typename": "map >" - } - }, - "bdm::SimParam": { - "_typename": "bdm::SimParam", - "bar": 84, - "foo": 6.28 - } -} -*********************************************** -*********************************************** +The constructor can select the same file in source code: +```cpp +Simulation simulation(argc, argv, {"experiment.toml"}); ``` -The values in the parameter list are the final values that were used in the simulation. -This includes applying a config file, command line arguments, or hardcoded parameters in the source code. - +Command line configuration is convenient for choosing experiments. Constructor +configuration keeps a simulation tied to an explicit configuration set. diff --git a/etc/bdm.rootrc b/etc/bdm.rootrc deleted file mode 100644 index 1ea0b8615..000000000 --- a/etc/bdm.rootrc +++ /dev/null @@ -1,4 +0,0 @@ -Unix.*.Root.PluginPath: $(ROOTSYS)/etc/plugins:$(BDMSYS)/etc/plugins -Unix.*.Root.DynamicPath: .:$(ROOTSYS)/lib:$(BDMSYS)/lib - -#Root.ErrorIgnoreLevel: Info diff --git a/notebook/ST01-model-initializer.ipynb b/notebook/ST01-model-initializer.ipynb deleted file mode 100644 index 5f95ba03e..000000000 --- a/notebook/ST01-model-initializer.ipynb +++ /dev/null @@ -1,348 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d08f4bda", - "metadata": {}, - "source": [ - "# Create agents in 3D space\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we want to demonstrate different functions to initialize agents in space." - ] - }, - { - "cell_type": "markdown", - "id": "afc9e8fc", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5df86ed1", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "290f8c07", - "metadata": {}, - "source": [ - "We use `SphericalAgent`s with $diameter = 10$ for all consecutive examples." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5fcbd149", - "metadata": {}, - "outputs": [], - "source": [ - "auto create_agent = [](const Real3& position) {\n", - " auto* agent = new SphericalAgent(position);\n", - " agent->SetDiameter(10);\n", - " return agent;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "3c4a8bec", - "metadata": {}, - "source": [ - "We define the number of agents that should be created for functions that require this parameter." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "013e187f", - "metadata": {}, - "outputs": [], - "source": [ - "uint64_t num_agents = 300;" - ] - }, - { - "cell_type": "markdown", - "id": "c1253a31", - "metadata": {}, - "source": [ - "We define two helper functions that reset the simulation to the empty state and one to visualize the result." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cdd9589c", - "metadata": {}, - "outputs": [], - "source": [ - "void Clear() {\n", - " simulation.GetResourceManager()->ClearAgents();\n", - "}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "48fb01d3", - "metadata": {}, - "outputs": [], - "source": [ - "void Vis() {\n", - " simulation.GetScheduler()->FinalizeInitialization();\n", - " VisualizeInNotebook();\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "0f2c9fa2", - "metadata": {}, - "source": [ - "### Create agents randomly inside a 3D cube \n", - "Cube: $x_{min} = y_{min} = z_{min} = -200$ and $x_{max} = y_{max} = z_{max} = 200$
\n", - "By default a uniform random number distribution is used." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4602b092", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "ModelInitializer::CreateAgentsRandom(-200, 200, num_agents, create_agent);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "5b0ff08f", - "metadata": {}, - "source": [ - "
" - ] - }, - { - "cell_type": "markdown", - "id": "be46b17d", - "metadata": {}, - "source": [ - "### Create agents randomly inside a 3D cube using a gaussian distribution\n", - "Cube: $x_{min} = y_{min} = z_{min} = -200$ and $x_{max} = y_{max} = z_{max} = 200$
\n", - "Gaussian: $\\mu = 0$, $\\sigma = 20$
\n", - "Note the extra parameter $rng$ passed to `CreateAgentsRandom`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b47d15fe", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "auto rng = simulation.GetRandom()->GetGausRng(0, 20);\n", - "ModelInitializer::CreateAgentsRandom(-200, 200, num_agents, create_agent, &rng);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "bffeec23", - "metadata": {}, - "source": [ - "### Create agents randomly inside a 3D cube using an exponential distribution\n", - "Cube: $x_{min} = y_{min} = z_{min} = -200$ and $x_{max} = y_{max} = z_{max} = 200$
\n", - "Exponential: $\\tau = 100$
\n", - "Note the extra parameter $rng$ passed to `CreateAgentsRandom`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3b00519a", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "auto rng = simulation.GetRandom()->GetExpRng(100);\n", - "ModelInitializer::CreateAgentsRandom(-200, 200, num_agents, create_agent, &rng);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "da3fcfc5", - "metadata": {}, - "source": [ - "### Create agents randomly inside a 3D cube using a 3D gaussian distribution\n", - "Cube: $x_{min} = y_{min} = z_{min} = -200$ and $x_{max} = y_{max} = z_{max} = 200$
\n", - "3D gaussian: $\\mu_x = \\mu_y = \\mu_z = 0$, $\\sigma_x = 100$, $\\sigma_y = 50$, $\\sigma_z = 20$
\n", - "The gaussian distribution we used earlier in this tutorial used the same parameters $\\mu$ and $\\sigma$ for all three dimensions. In this example we want to use different values for $\\sigma$ in each dimension. Therefore we have to use a 3D gaussian.\n", - "Since BioDynaMo does not have a predefined 3D gaussian, we have to define the function ourselves." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "67e5df83", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "auto gaus3d = [](const real_t* x, const real_t* params) {\n", - " auto mx = params[0];\n", - " auto my = params[2];\n", - " auto mz = params[4];\n", - " auto sx = params[1];\n", - " auto sy = params[3];\n", - " auto sz = params[5];\n", - " auto ret = (1.0/(sx * sy * sz *std::pow(2.0*Math::kPi, 3.0/2.0))) * \n", - " std::exp(-std::pow(x[0] - mx, 2.0)/std::pow(sx, 2.0) - \n", - " std::pow(x[1] - my, 2.0)/std::pow(sy, 2.0) - \n", - " std::pow(x[2] - mz, 2.0)/std::pow(sz, 2.0));\n", - " return ret;\n", - "};\n", - "auto* random = simulation.GetRandom();\n", - "auto rng = random->GetUserDefinedDistRng3D(gaus3d, {0, 100, 0, 50, 0, 20}, \n", - " -200, 200, -200, 200, -200, 200);\n", - "ModelInitializer::CreateAgentsRandom(-200, 200, num_agents, create_agent, &rng);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "2bfcf14b", - "metadata": {}, - "source": [ - "### Create agents randomly on a sphere\n", - "Center of the sphere ${0, 0, 0}$
\n", - "Radius: 100" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8ef1a886", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "ModelInitializer::CreateAgentsOnSphereRndm({0, 0, 0}, 100, num_agents, \n", - " create_agent);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "4498618b", - "metadata": {}, - "source": [ - "### Create 3D grid of agents\n", - "Number of agents per dimension: 10
\n", - "Space between agents: 20
\n", - "With this parameters `Grid3D` will create 1000 agents." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f3d6c1a0", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "uint64_t agents_per_dim = 10;\n", - "real_t space_between_agents = 20;\n", - "ModelInitializer::Grid3D(10, 20, create_agent);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "55175666", - "metadata": {}, - "source": [ - "### Create agents on a surface\n", - "\n", - "We create agents between $x_{min} = y_{min} = -100$ and $x_{max} = y_{max} = 100$ with spacing of 10 between agents.\n", - "The $z$-coordinate is defined by the function $f(x, y) = 10 * sin(x/20) + 10 * sin(y/20)$
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "956872a1", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "auto f = [](const real_t* x, const real_t* params) {\n", - " return 10 * std::sin(x[0] / 20.) + 10 * std::sin(x[1] / 20.0);\n", - "};\n", - "ModelInitializer::CreateAgentsOnSurface(f, {}, -100, 100, 10, -100, 100, 10, \n", - " create_agent);\n", - "Vis();" - ] - }, - { - "cell_type": "markdown", - "id": "343cbc87", - "metadata": {}, - "source": [ - "### Create agents on a surface randomly\n", - "\n", - "We use the same parameters as in the example before, but this time we want to place agents randomly on this surface.\n", - "Therefore, $x$, and $y$ coordinate are sampled from a uniform distribution between $x_{min} = y_{min} = -100$ and $x_{max} = y_{max} = 100$." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "97d760cf", - "metadata": {}, - "outputs": [], - "source": [ - "Clear();\n", - "ModelInitializer::CreateAgentsOnSurfaceRndm(f, {}, -100, 100, -100, 100, num_agents, \n", - " create_agent);\n", - "Vis();" - ] - } - ], - "metadata": { - "ipub": { - "titlepage": { - "author": "Lukas Breitwieser", - "email": "lukas.breitwieser@cern.ch", - "subtitle": "Sub-Title", - "tagline": "A tagline for the report.", - "title": "Main-Title" - } - }, - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST02-user-defined-random-number-distribution.ipynb b/notebook/ST02-user-defined-random-number-distribution.ipynb deleted file mode 100644 index 92c5648cb..000000000 --- a/notebook/ST02-user-defined-random-number-distribution.ipynb +++ /dev/null @@ -1,164 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "261afc2b", - "metadata": {}, - "source": [ - "# Generate random samples from a user-defined distribution\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we demonstrate how to create a random number generator that draws samples from a user-defined distribution." - ] - }, - { - "cell_type": "markdown", - "id": "16390b36", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e115ba78", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "78266042", - "metadata": {}, - "source": [ - "We have to create a `TCanvas` object to draw results in this notebook." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9789c3da", - "metadata": {}, - "outputs": [], - "source": [ - "TCanvas c(\"\", \"\", 400, 300);\n", - "c.SetGrid();" - ] - }, - { - "cell_type": "markdown", - "id": "e3e7f610", - "metadata": {}, - "source": [ - "Let's assume that we want to generate random numbers from a student-t distribution.
\n", - "Class [`Random`](https://biodynamo.org/api/classbdm_1_1Random.html) does not provide a direct function for that.
\n", - "Therefore, we use the user-defined distribution feature `Random::GetUserDefinedDistRng1D`.
\n", - "Fortunately, ROOT already provides a function called `tdistribution_pdf` that we can use.
\n", - "Have a look at the following two links for more math functions: [TMath](https://root.cern/doc/master/namespaceTMath.html) and [statistical functions](https://root.cern/doc/master/group__StatFunc.html)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b17664b7", - "metadata": {}, - "outputs": [], - "source": [ - "auto* random = simulation.GetRandom();\n", - "auto distribution = [](const double* x, const double* param) { \n", - " return ROOT::Math::tdistribution_pdf(*x, 1.0); \n", - "};\n", - "auto udd_rng = random->GetUserDefinedDistRng1D(distribution, {}, -5, 10);" - ] - }, - { - "cell_type": "markdown", - "id": "b0cbec82", - "metadata": {}, - "source": [ - "The returned random number generator has a function to draw the distribution." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1705dca2", - "metadata": {}, - "outputs": [], - "source": [ - "udd_rng.Draw();\n", - "c.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "e162d7fd", - "metadata": {}, - "source": [ - "In the next step we want to verify that the created random number generator follows the specified distribution.
\n", - "Therefore, we create a histogram with 100 bins in the range \\[-5, 10\\] and fill it with 10000 samples." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e81c5664", - "metadata": {}, - "outputs": [], - "source": [ - "TH1F h(\"\",\"\", 100, -5, 10);\n", - "for (int i = 0; i < 10000; ++i){\n", - " auto rndm_sample = udd_rng.Sample();\n", - " h.Fill(rndm_sample);\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "bb0e6242", - "metadata": {}, - "source": [ - "Let's draw the result:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6b77f1f", - "metadata": {}, - "outputs": [], - "source": [ - "h.SetFillColor(kBlue-10);\n", - "h.Draw();\n", - "c.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "026336df", - "metadata": {}, - "source": [ - "As we can see from the last figure the samples from our random number generator fit our distribution." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST03-agent-reproduction-mortality.ipynb b/notebook/ST03-agent-reproduction-mortality.ipynb deleted file mode 100644 index 4d7334a05..000000000 --- a/notebook/ST03-agent-reproduction-mortality.ipynb +++ /dev/null @@ -1,204 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "71c33bc3", - "metadata": {}, - "source": [ - "# Agent reproduction and mortality\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we want to demonstrate how to add and remove agents from the simulation." - ] - }, - { - "cell_type": "markdown", - "id": "3a265f99", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "628dae37", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "99248da3", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "auto* scheduler = simulation.GetScheduler();\n", - "auto* rm = simulation.GetResourceManager();" - ] - }, - { - "cell_type": "markdown", - "id": "ad387f12", - "metadata": {}, - "source": [ - "Let's define our initial model: One cell at origin.
\n", - "We also create an agent pointer for our cell, because raw pointers might be invalidated after a call to `Scheduler::Simulate`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71ea49a5", - "metadata": {}, - "outputs": [], - "source": [ - "auto* cell = new Cell();\n", - "ctxt->AddAgent(cell);\n", - "auto cell_aptr = cell->GetAgentPtr();\n", - "scheduler->FinalizeInitialization();\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "09d9c6a9", - "metadata": {}, - "source": [ - "Adding an agent to the simulation is as easy as constructing one and adding it to the execution context.
\n", - "Our default execution context will add the new agent to the simulation at the end of the iteration.
\n", - "Therefore, the visualization still shows only one agent." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "06f1e6cf", - "metadata": {}, - "outputs": [], - "source": [ - "ctxt->AddAgent(new SphericalAgent({3, 0, 0}));\n", - "VisualizeInNotebook()" - ] - }, - { - "cell_type": "markdown", - "id": "fd025d7f", - "metadata": {}, - "source": [ - "Let's simulate one time step and see what happens." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6839f0e", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);\n", - "VisualizeInNotebook()" - ] - }, - { - "cell_type": "markdown", - "id": "3271ff63", - "metadata": {}, - "source": [ - "Our new agent has been added to the simulation.
\n", - "Usually, new agents will be created based on some process, e.g. cell division, neurite extension from soma, neurite branching, etc.\n", - "The following example shows cell division. We specify the division axis." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3131f214", - "metadata": {}, - "outputs": [], - "source": [ - "cell_aptr->Divide({1, 0, 0});\n", - "VisualizeInNotebook()" - ] - }, - { - "cell_type": "markdown", - "id": "4825d277", - "metadata": {}, - "source": [ - "Again, the new cell is not visible yet. We have to finish one iteration." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45f93c49", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);\n", - "VisualizeInNotebook()" - ] - }, - { - "cell_type": "markdown", - "id": "3a6103ed", - "metadata": {}, - "source": [ - "Removing agents from the simulation works similarly.
\n", - "The default execution context will remove it at the end of the iteration." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "77d63217", - "metadata": {}, - "outputs": [], - "source": [ - "cell_aptr->RemoveFromSimulation();\n", - "rm->GetNumAgents();\n", - "VisualizeInNotebook()" - ] - }, - { - "cell_type": "markdown", - "id": "23ea7e00", - "metadata": {}, - "source": [ - "We expect that after the `Simulate` call only 2 agents are shown in the visualization." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f585c671", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);\n", - "VisualizeInNotebook()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST04-agent-reproduction-with-behaviors.ipynb b/notebook/ST04-agent-reproduction-with-behaviors.ipynb deleted file mode 100644 index e88f1cd67..000000000 --- a/notebook/ST04-agent-reproduction-with-behaviors.ipynb +++ /dev/null @@ -1,218 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "fe622041", - "metadata": {}, - "source": [ - "# Agent reproduction with behaviors\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In tutorial `ST3-agent-reproduction-mortality` we have explored how to add and remove agents from the simulation.\n", - "In this tutorial we want to explore different behavior options to control if a new agent gets a behavior from the original agent, and if a behavior will be removed from the original one." - ] - }, - { - "cell_type": "markdown", - "id": "5f0b34a5", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "628dae37", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "f1b6d8d3", - "metadata": {}, - "source": [ - "We define a simple behavior which prints `has print behavior`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dd7a38db", - "metadata": {}, - "outputs": [], - "source": [ - "StatelessBehavior print_behavior([](Agent* agent) {\n", - " std::cout << \" has print behavior\" << std::endl;\n", - "});" - ] - }, - { - "cell_type": "markdown", - "id": "a54cef7c", - "metadata": {}, - "source": [ - "We define the following experiment which we will run with different options of the `print_behavior`.
\n", - "We create a cell, add a copy of the `print_behavior`, and run all behaviors. \n", - "We expect that the following output is created.\n", - "```\n", - "mother: \n", - " has print behavior\n", - "```\n", - "Afterwards we print a separator `-------` to indicate cell division, divide the mother cell and run the behaviors of daughter 1 and daughter 2.\n", - "By definition the original mother cell turns into daughter 1 and the new agent becomes daughter 2." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71ea49a5", - "metadata": {}, - "outputs": [], - "source": [ - "void Experiment() {\n", - " Simulation sim(\"my-simulation\");\n", - " auto* mother = new Cell();\n", - " mother->AddBehavior(print_behavior.NewCopy());\n", - " std::cout << \"mother: \" << std::endl;\n", - " mother->RunBehaviors();\n", - " std::cout << \"---------------------\" << std::endl;\n", - " auto* daughter2 = mother->Divide();\n", - " std::cout << \"mother = daughter 1: \" << std::endl;\n", - " mother->RunBehaviors(); // mother = daughter 1\n", - " std::cout << \"daughter 2: \" << std::endl;\n", - " daughter2->RunBehaviors();\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "90413d31", - "metadata": {}, - "source": [ - "Let's run the experiment with default parameters and see what happens." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e6839f0e", - "metadata": {}, - "outputs": [], - "source": [ - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "05f00e5b", - "metadata": {}, - "source": [ - "The `print_behavior` was **not copied** to the daughter 2 cell and was **not removed** from the mother cell.\n", - "\n", - "---\n", - "\n", - "Let's try to copy the behavior from the mother cell to daughter 2." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "09e6d449", - "metadata": {}, - "outputs": [], - "source": [ - "print_behavior.AlwaysCopyToNew();\n", - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "a429d714", - "metadata": {}, - "source": [ - "Now the `print_behavior` **was copied** to the daughter 2 cell and was **not removed** from the mother cell.\n", - "\n", - "---\n", - "\n", - "Let's try to remove the behavior from the mother cell." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3131f214", - "metadata": {}, - "outputs": [], - "source": [ - "print_behavior.AlwaysCopyToNew();\n", - "print_behavior.AlwaysRemoveFromExisting();\n", - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "49235127", - "metadata": {}, - "source": [ - "Now the `print_behavior` **was copied** to the daughter 2 cell and **was removed** from the mother cell.\n", - "\n", - "---\n", - "\n", - "Let's reset the values to the default." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45f93c49", - "metadata": {}, - "outputs": [], - "source": [ - "print_behavior.NeverCopyToNew();\n", - "print_behavior.NeverRemoveFromExisting();\n", - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "0de424e4", - "metadata": {}, - "source": [ - "Behaviors provide also more fine-grained distinction. Some agents support multiple [new agent events](https://biodynamo.org/docs/userguide/new_agent_event/): neurite branching, neurite bifurcation, side neurite extension, etc.\n", - "For each event we can specify if the behavior should be copied to the new, or removed from the existing agent." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "77d63217", - "metadata": {}, - "outputs": [], - "source": [ - "print_behavior.CopyToNewIf({CellDivisionEvent::kUid});\n", - "print_behavior.RemoveFromExistingIf({CellDivisionEvent::kUid});\n", - "Experiment();" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST05-agent-reproduction-advanced.ipynb b/notebook/ST05-agent-reproduction-advanced.ipynb deleted file mode 100644 index 6c5764da6..000000000 --- a/notebook/ST05-agent-reproduction-advanced.ipynb +++ /dev/null @@ -1,380 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "cfece0db", - "metadata": {}, - "source": [ - "# Agent reproduction advanced\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In the tutorials so far we used `Cell::Divide` to create new agents.\n", - "In this demo we want to show how to define your own \"process\" that creates a new agent.\n", - "Furthermore, we will explain the purpose of the functions `Agent::Initialize` and `Agent::Update`.\n", - "\n", - "Assume that we want to create a new agent type `Human` which should be able to `GiveBirth`." - ] - }, - { - "cell_type": "markdown", - "id": "7050c0c6", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6a3a1fa6", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27ce5b1f", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "auto* scheduler = simulation.GetScheduler();" - ] - }, - { - "cell_type": "markdown", - "id": "c11074ec", - "metadata": {}, - "source": [ - "Let's start by creating the `ChildBirthEvent`.\n", - "In this example we do not need any attributes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "459c519c", - "metadata": {}, - "outputs": [], - "source": [ - "struct ChildBirthEvent : public NewAgentEvent {\n", - " ChildBirthEvent() {}\n", - " virtual ~ChildBirthEvent() {}\n", - " NewAgentEventUid GetUid() const override { \n", - " static NewAgentEventUid kUid = \n", - " NewAgentEventUidGenerator::GetInstance()->GenerateUid();\n", - " return kUid; \n", - " }\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "a53261d2", - "metadata": {}, - "source": [ - "We continue by defining the class `Human` which derives from `SphericalAgent`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71c326cd", - "metadata": {}, - "outputs": [], - "source": [ - "class Human : public SphericalAgent {\n", - " BDM_AGENT_HEADER(Human, SphericalAgent, 1);\n", - "\n", - " public:\n", - " Human() {}\n", - " explicit Human(const Real3& position) : Base(position) {}\n", - " virtual ~Human() {}\n", - "\n", - " void GiveBirth();\n", - " void Initialize(const NewAgentEvent& event) override;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "0fcf5d2b", - "metadata": {}, - "source": [ - "The implementation of `GiveBirth` only requires two lines of code.
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "99ad043e", - "metadata": {}, - "outputs": [], - "source": [ - "void Human::GiveBirth() {\n", - " ChildBirthEvent event;\n", - " CreateNewAgents(event, {this});\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "07dec17c", - "metadata": {}, - "source": [ - "First, creating an instance of the event.
\n", - "Second, invoking `CreateNewAgents` function which is defined in class `Agent`.\n", - "\n", - "The first parameter of `CreateNewAgents` takes an event object, and the second a vector of agent prototypes.\n", - "The size of this vector determines how many new agents will be created. \n", - "In our case: one. If twins should be born we could change it to `CreateNewAgents(event, {this, this});`.\n", - "\n", - "But why do we have to pass a list of agent pointers to the function?\n", - "\n", - "The answer is simple: we have to tell `CreateNewAgents` which agent type it should create. \n", - "In our use case we want to create another instance of class `Human`. Therefore, we pass the `this` pointer.\n", - "\n", - "The only part missing is to tell BioDynaMo how to initialize the attributes of the new child.\n", - "This decision is encapsulated in the `Initialize` function which we override from the base class.\n", - "Don't forget to also call the implementation of the base class using `Base::Initialize(event)`.\n", - "Otherwise the initialization of the base class is skipped.\n", - "\n", - "In our example we define that the child should be created next to the mother in 3D space. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e0cb0aa4", - "metadata": {}, - "outputs": [], - "source": [ - "void Human::Initialize(const NewAgentEvent& event) {\n", - " Base::Initialize(event);\n", - " auto* mother = bdm_static_cast(event.existing_agent);\n", - " SetPosition(mother->GetPosition() + Real3{2, 0, 0});\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "51d74f7d", - "metadata": {}, - "source": [ - "This concludes all required building blocks. Let's try it out!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8eb0fea1", - "metadata": {}, - "outputs": [], - "source": [ - "auto* human = new Human();\n", - "ctxt->AddAgent(human);" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8dea1e59", - "metadata": {}, - "outputs": [], - "source": [ - "human->GiveBirth();" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "044c370a", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "66a018d2", - "metadata": {}, - "source": [ - "As expected the simulation consists of two \"humans\".\n", - "\n", - "----\n", - "\n", - "Let's take this one step further.\n", - "Let's assume that class `Human` was provided in a library that we don't want to modify.\n", - "However, we want to add two more attributes: \n", - "* the number of offsprings\n", - "* the mitochondiral dna (Note: the mitochondrial dna is inherited solely from the mother)\n", - "\n", - "Let's create a new class called `MyHuman` which derives from `Human` and which adds these two attributes." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1bdfdd23", - "metadata": {}, - "outputs": [], - "source": [ - "using MitochondrialDNA = int;" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b4d66427", - "metadata": {}, - "outputs": [], - "source": [ - "class MyHuman : public Human {\n", - " BDM_AGENT_HEADER(MyHuman, Human, 1);\n", - "\n", - " public:\n", - " MyHuman() {}\n", - " explicit MyHuman(const Real3& position) : Base(position) {}\n", - " virtual ~MyHuman() {}\n", - "\n", - " void Initialize(const NewAgentEvent& event) override;\n", - " void Update(const NewAgentEvent& event) override;\n", - "\n", - " int num_offsprings_ = 0;\n", - " MitochondrialDNA mdna_;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "496ee37f", - "metadata": {}, - "source": [ - "As in the example above, the `Initialize` method is used to set the attributes during new agent events.\n", - "In this example, we have to set the mitochondrial dna of the child to the value from the mother.\n", - "The following function definition does exactly that and prints out the value." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b6b5c460", - "metadata": {}, - "outputs": [], - "source": [ - "void MyHuman::Initialize(const NewAgentEvent& event) {\n", - " Base::Initialize(event);\n", - " auto* mother = bdm_static_cast(event.existing_agent);\n", - " mdna_ = mother->mdna_;\n", - " std::cout << \"Initialize child attributes: mitochondrial dna set to \"\n", - " << mdna_ << std::endl;\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "3672e873", - "metadata": {}, - "source": [ - "The only task left is to update the attributes of the mother. This is done by overriding the `Update` method.\n", - "Again, do not forget to call the implementation of the base class for correctness.\n", - "We increment the `num_offsprings_` attribute by the number of newly created agents.\n", - "Although we could just have incremented the attribute by one, the solution below is generic enough to handle e.g. twin births." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6f9c863b", - "metadata": {}, - "outputs": [], - "source": [ - "void MyHuman::Update(const NewAgentEvent& event) {\n", - " Base::Update(event);\n", - " num_offsprings_ += event.new_agents.size();\n", - " std::cout << \"Update mother attributes: num_offsprings incremented to \"\n", - " << num_offsprings_ << std::endl;\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "1c1529d1", - "metadata": {}, - "source": [ - "Let's create a new `MyHuman`, set its mitochondrial dna to `123` and output the current value of `num_offsprings_`, which we expect to be `0`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "522e3ee8", - "metadata": {}, - "outputs": [], - "source": [ - "auto* my_human = new MyHuman();\n", - "my_human->mdna_ = 123;\n", - "my_human->num_offsprings_" - ] - }, - { - "cell_type": "markdown", - "id": "a3b9d99a", - "metadata": {}, - "source": [ - "Now we can call `GiveBirth` again. We expect the output of two lines.\n", - "* The first coming from the child informing us about the initialization of its `mdna_` attribute\n", - "* and the second from the mother telling us about the update of `num_offsprings_`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e430fb7b", - "metadata": {}, - "outputs": [], - "source": [ - "my_human->GiveBirth();" - ] - }, - { - "cell_type": "markdown", - "id": "a8dbeaae", - "metadata": {}, - "source": [ - "To real_t check, let's output the value of `num_offsprings`, which we expect to be 1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "64620dde", - "metadata": {}, - "outputs": [], - "source": [ - "my_human->num_offsprings_" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST06-environment-search.ipynb b/notebook/ST06-environment-search.ipynb deleted file mode 100644 index d8933c81d..000000000 --- a/notebook/ST06-environment-search.ipynb +++ /dev/null @@ -1,179 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "35b1e478", - "metadata": {}, - "source": [ - "# Environment search\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we will show how to execute a function for each neighbor of an agent." - ] - }, - { - "cell_type": "markdown", - "id": "2082b703", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "11ca5e41", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "4c86850d", - "metadata": {}, - "source": [ - "We create three agents in a row along the x-axis with identical y and z values." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2401012a", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "\n", - "auto* a0 = new SphericalAgent({10, 0, 0});\n", - "auto* a1 = new SphericalAgent({20, 0, 0});\n", - "auto* a2 = new SphericalAgent({30, 0, 0});\n", - "\n", - "a0->SetDiameter(11);\n", - "a1->SetDiameter(11);\n", - "a2->SetDiameter(11);\n", - "\n", - "ctxt->AddAgent(a0);\n", - "ctxt->AddAgent(a1);\n", - "ctxt->AddAgent(a2);" - ] - }, - { - "cell_type": "markdown", - "id": "3ab3a953", - "metadata": {}, - "source": [ - "We finalize the initialization and update the environment so it can be used later.\n", - "Please not that this is usually done automatically inside `Scheduler::Simulate`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8f0d4544", - "metadata": {}, - "outputs": [], - "source": [ - "simulation.GetScheduler()->FinalizeInitialization();\n", - "simulation.GetEnvironment()->Update();\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "282ea396", - "metadata": {}, - "source": [ - "Let's define the function that we want to execute for each neighbor. It prints the unique id of the neighbor and its distance from the querying agent." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a4da75e5", - "metadata": {}, - "outputs": [], - "source": [ - "auto print_id_distance = L2F([](Agent* a, real_t squared_distance) {\n", - " std::cout << \"Neighbor \" << a->GetUid() << \" with distance: \" \n", - " << std::sqrt(squared_distance) << std::endl;\n", - "});" - ] - }, - { - "cell_type": "markdown", - "id": "62da5578", - "metadata": {}, - "source": [ - "The agents have the following ids (in order of increasing x-value)\n", - "0-0, 1-0, 2-0\n", - "\n", - "We start by executing print_id_distance for the first agent. We ask for all neighbors within distance 101.\n", - "Therefore the function should be executed for the agent in the middle with id 1-0" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "eb14d94e", - "metadata": {}, - "outputs": [], - "source": [ - "ctxt->ForEachNeighbor(print_id_distance, *a0, 101);" - ] - }, - { - "cell_type": "markdown", - "id": "6e8096bb", - "metadata": {}, - "source": [ - "Let's repeat the experiment for the middle agent. We expect to see two lines for the left and right neighbor." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "22ba95a1", - "metadata": {}, - "outputs": [], - "source": [ - "ctxt->ForEachNeighbor(print_id_distance, *a1, 101);" - ] - }, - { - "cell_type": "markdown", - "id": "10639340", - "metadata": {}, - "source": [ - "Lastly, we want to execute the function `print_id_distance` for all neighbors of the righ-most agent. We expect to see one line printing the middle agent as neighbor (1-0)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f8e1ec99", - "metadata": {}, - "outputs": [], - "source": [ - "ctxt->ForEachNeighbor(print_id_distance, *a2, 101);" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST07-multi-scale-simulation.ipynb b/notebook/ST07-multi-scale-simulation.ipynb deleted file mode 100644 index c248753fa..000000000 --- a/notebook/ST07-multi-scale-simulation.ipynb +++ /dev/null @@ -1,179 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "bb375e54", - "metadata": {}, - "source": [ - "# Multi-scale simulations\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we will show how BioDynaMo support multi-scale simulations. \n", - "Multi-scale simulation means that simulated processes happen in different time-scales---e.g. substance diffusion and neurite growth." - ] - }, - { - "cell_type": "markdown", - "id": "d2e32028", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3654007a", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "7b63e9cb", - "metadata": {}, - "source": [ - "We define a new [standalone operation](https://biodynamo.org/docs/userguide/operation/) which only task is to print the current simulation time step if it is executed." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f336788b", - "metadata": {}, - "outputs": [], - "source": [ - "struct TestOp : public StandaloneOperationImpl {\n", - " BDM_OP_HEADER(TestOp);\n", - " void operator()() override {\n", - " auto* scheduler = Simulation::GetActive()->GetScheduler();\n", - " auto* param = Simulation::GetActive()->GetParam();\n", - " std::cout << \"Processing iteration \" \n", - " << scheduler->GetSimulatedSteps() \n", - " << \" simulation time \"\n", - " << scheduler->GetSimulatedSteps() * param->simulation_time_step\n", - " << std::endl; \n", - " }\n", - "};\n", - "OperationRegistry::GetInstance()->AddOperationImpl(\n", - " \"test_op\", OpComputeTarget::kCpu, new TestOp());" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b6187081", - "metadata": {}, - "outputs": [], - "source": [ - "auto set_param = [](Param * param) {\n", - " param->simulation_time_step = 2;\n", - "};\n", - "Simulation simulation(\"my-simulation\", set_param);" - ] - }, - { - "cell_type": "markdown", - "id": "ab605e19", - "metadata": {}, - "source": [ - "Our initial model consists of one agent at origin." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8bc5851d", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "ctxt->AddAgent(new SphericalAgent());" - ] - }, - { - "cell_type": "markdown", - "id": "5b395ab8", - "metadata": {}, - "source": [ - "Let's create a new instance of our class `TestOp` and add it to the scheduler." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d74d3d77", - "metadata": {}, - "outputs": [], - "source": [ - "auto* op1 = NewOperation(\"test_op\");\n", - "auto* scheduler = simulation.GetScheduler();\n", - "scheduler->ScheduleOp(op1);" - ] - }, - { - "cell_type": "markdown", - "id": "72100a54", - "metadata": {}, - "source": [ - "Let's simulate 9 steps. We expect that `op1` will be called each time step." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fb044c02", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(9);" - ] - }, - { - "cell_type": "markdown", - "id": "1e9571e0", - "metadata": {}, - "source": [ - "Operations have a frequency attribute which specifies how often it will be executed.\n", - "An operation with frequency one will be executed at every time step; an operation with frequency two every second, and so on." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "71568cbb", - "metadata": {}, - "outputs": [], - "source": [ - "op1->frequency_= 3;\n", - "scheduler->Simulate(9);" - ] - }, - { - "cell_type": "markdown", - "id": "b55860a3", - "metadata": {}, - "source": [ - "This functionality can be used to set the frequency of different processes in an agent-based model." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST08-histograms.ipynb b/notebook/ST08-histograms.ipynb deleted file mode 100644 index 7220a93c0..000000000 --- a/notebook/ST08-histograms.ipynb +++ /dev/null @@ -1,164 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "59a444f2", - "metadata": {}, - "source": [ - "# Create a histogram of agent attributes\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we will show how to create a histogram of all agent diameters in the simulation and fit a function to the data." - ] - }, - { - "cell_type": "markdown", - "id": "b2c4e70d", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "96f8df86", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "4826bcd8", - "metadata": {}, - "source": [ - "We want to define a function that creates a cell at a certain position with diameters drawn from a gaussian distribution with $\\mu=20$ and $\\sigma=5$.\n", - "The smallest diameter should be larger then $2.0$." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55d54a85", - "metadata": {}, - "outputs": [], - "source": [ - "simulation.GetResourceManager()->ClearAgents();\n", - "auto rng = simulation.GetRandom()->GetGausRng(20, 5);\n", - "auto create_cell = [&](const Real3& position) {\n", - " Cell* cell = new Cell(position);\n", - " real_t diameter = std::max(2.0, rng.Sample());\n", - " cell->SetDiameter(diameter);\n", - " return cell;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "b75a38d5", - "metadata": {}, - "source": [ - "Now that we defined `create_cell` we can use it to create 400 cells on a plane with $z = 0$, $xmin = ymin = -200$, $xmax = ymax = 200$, and spacing = 20 in both dimensions." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16dfac9d", - "metadata": {}, - "outputs": [], - "source": [ - "auto f = [](const real_t* x, const real_t* params) { return 0.0; };\n", - "ModelInitializer::CreateAgentsOnSurface(f, {}, -200, 200, 20, -200, 200, 20, \n", - " create_cell);\n", - "simulation.GetScheduler()->FinalizeInitialization();\n", - "VisualizeInNotebook(300, 300);" - ] - }, - { - "cell_type": "markdown", - "id": "e39ad15d", - "metadata": {}, - "source": [ - "The next step is to create a histogram object with 100 bins in the interval [2, 40].
\n", - "The second line creates a function which fills the histogram with the diameter of the given agent.
\n", - "The third line calls the function `fill` for each agent, thus adding all diameters to the histogram." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1b668a6f", - "metadata": {}, - "outputs": [], - "source": [ - "TH1F h(\"myHisto\",\"Agent Diameter Histogram;Diameter;Count\", 100, 2, 40);\n", - "auto fill = L2F([&](Agent* a, AgentHandle){ h.Fill(a->GetDiameter()); });\n", - "simulation.GetResourceManager()->ForEachAgent(fill);" - ] - }, - { - "cell_type": "markdown", - "id": "f72003ca", - "metadata": {}, - "source": [ - "Let's draw the final histogram.
\n", - "Before we have to create a `TCanvas` object in order to display the result in this notebook.
\n", - "We also modify the default color and create a grid." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "922bdaff", - "metadata": {}, - "outputs": [], - "source": [ - "TCanvas c(\"\", \"\", 400, 300);\n", - "h.SetFillColor(kBlue - 10);\n", - "c.SetGrid();\n", - "h.Draw();\n", - "c.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "66975011", - "metadata": {}, - "source": [ - "Finally, we can try to fit a function to the data in the histogram.
\n", - "Since we drew samples from a gaussian random number generator when we created our cells, we expect that a gaussian will fit our data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a5692df4", - "metadata": {}, - "outputs": [], - "source": [ - "h.Fit(\"gaus\", \"S\");\n", - "h.Draw();\n", - "c.Draw();" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST09-timeseries-plotting-basic.ipynb b/notebook/ST09-timeseries-plotting-basic.ipynb deleted file mode 100644 index f920553fa..000000000 --- a/notebook/ST09-timeseries-plotting-basic.ipynb +++ /dev/null @@ -1,209 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "27e05215", - "metadata": {}, - "source": [ - "# Simulation time series plotting (basics)\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we show how to collect data during the simulation and plot it at the end.
\n", - "To this extent, we create a simulation where cells divide rapidly leading to exponential growth." - ] - }, - { - "cell_type": "markdown", - "id": "61e7a91d", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef7edf86", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "46333689", - "metadata": {}, - "outputs": [], - "source": [ - "using namespace bdm::experimental;" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6921b944", - "metadata": {}, - "outputs": [], - "source": [ - "auto set_param = [](Param* param) {\n", - " param->simulation_time_step = 1.0;\n", - "};\n", - "Simulation simulation(\"MySimulation\", set_param);" - ] - }, - { - "cell_type": "markdown", - "id": "81271f84", - "metadata": {}, - "source": [ - "Let's create a behavior which divides cells with $10\\%$ probability in each time step.
\n", - "New cells should also get this behavior.
\n", - "Therefore, we have to call `AlwaysCopyToNew()`.
\n", - "Otherwise, we would only see linear growth." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55a9d0bd", - "metadata": {}, - "outputs": [], - "source": [ - "StatelessBehavior rapid_division([](Agent* agent) {\n", - " if (Simulation::GetActive()->GetRandom()->Uniform() < 0.1) {\n", - " bdm_static_cast(agent)->Divide();\n", - " }\n", - "});\n", - "rapid_division.AlwaysCopyToNew();" - ] - }, - { - "cell_type": "markdown", - "id": "efac4965", - "metadata": {}, - "source": [ - "Let's create a function that creates a cell at a specific position, with diameter = 10, and the `rapid_division` behavior." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a50d084a", - "metadata": {}, - "outputs": [], - "source": [ - "auto create_cell = [](const Real3& position) {\n", - " Cell* cell = new Cell(position);\n", - " cell->SetDiameter(10);\n", - " cell->AddBehavior(rapid_division.NewCopy());\n", - " return cell;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "f7738e8f", - "metadata": {}, - "source": [ - "As starting condition we want to create 100 cells randomly distributed in a cube with $min = 0, max = 200$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bac61f01", - "metadata": {}, - "outputs": [], - "source": [ - "simulation.GetResourceManager()->ClearAgents();\n", - "ModelInitializer::CreateAgentsRandom(0, 200, 100, create_cell);\n", - "simulation.GetScheduler()->FinalizeInitialization();\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "273d7037", - "metadata": {}, - "source": [ - "Before we start the simulation, we have to tell BioDynaMo which data to collect.
\n", - "We can do this with the `TimeSeries::AddCollector` function.\n", - "In this example we are interested in the number of agents.
" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b3d62c1", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ts = simulation.GetTimeSeries();\n", - "auto get_num_agents = [](Simulation* sim) {\n", - " return static_cast(sim->GetResourceManager()->GetNumAgents());\n", - "};\n", - "ts->AddCollector(\"num-agents\", get_num_agents);" - ] - }, - { - "cell_type": "markdown", - "id": "f3f4783d", - "metadata": {}, - "source": [ - "Now let's simulate until there are 4000 agents in the simulation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ce235bb", - "metadata": {}, - "outputs": [], - "source": [ - "auto exit_condition = [](){\n", - " auto* rm = Simulation::GetActive()->GetResourceManager();\n", - " return rm->GetNumAgents() > 4000;\n", - "};\n", - "simulation.GetScheduler()->SimulateUntil(exit_condition);" - ] - }, - { - "cell_type": "markdown", - "id": "b9a24d69", - "metadata": {}, - "source": [ - "Now we can plot how the number of agents (in this case cells) evolved over time." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a7e92b2b", - "metadata": {}, - "outputs": [], - "source": [ - "LineGraph g(ts, \"My result\", \"Time\", \"Number of agents\", true, nullptr, 500, 300);\n", - "g.Add(\"num-agents\", \"Number of Agents\");\n", - "g.Draw();" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST10-timeseries-plotting-and-analysis.ipynb b/notebook/ST10-timeseries-plotting-and-analysis.ipynb deleted file mode 100644 index 4c64f2192..000000000 --- a/notebook/ST10-timeseries-plotting-and-analysis.ipynb +++ /dev/null @@ -1,296 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "32a23b2c", - "metadata": {}, - "source": [ - "# Simulation time series plotting and analysis\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we show how to collect data during the simulation, and plot and analyse it at the end.
\n", - "To this extent, we create a simulation where cells divide rapidly leading to exponential growth." - ] - }, - { - "cell_type": "markdown", - "id": "f05fc59b", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef7edf86", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38f30ea8", - "metadata": {}, - "outputs": [], - "source": [ - "using namespace bdm::experimental;" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3b033786", - "metadata": {}, - "outputs": [], - "source": [ - "auto set_param = [](Param* param) {\n", - " param->simulation_time_step = 1.0;\n", - "};\n", - "Simulation simulation(\"MySimulation\", set_param);" - ] - }, - { - "cell_type": "markdown", - "id": "f9dac184", - "metadata": {}, - "source": [ - "Let's create a behavior which divides cells with $5\\%$ probability in each time step.
\n", - "New cells should also get this behavior.
\n", - "Therefore, we have to call `AlwaysCopyToNew()`.
\n", - "Otherwise, we would only see linear growth." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55a9d0bd", - "metadata": {}, - "outputs": [], - "source": [ - "StatelessBehavior rapid_division([](Agent* agent) {\n", - " if (Simulation::GetActive()->GetRandom()->Uniform() < 0.05) {\n", - " bdm_static_cast(agent)->Divide();\n", - " }\n", - "});\n", - "rapid_division.AlwaysCopyToNew();" - ] - }, - { - "cell_type": "markdown", - "id": "d55bc904", - "metadata": {}, - "source": [ - "Let's create a function that creates a cell at a specific position, with diameter = 10, and the `rapid_division` behavior." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a50d084a", - "metadata": {}, - "outputs": [], - "source": [ - "auto create_cell = [](const Real3& position) {\n", - " Cell* cell = new Cell(position);\n", - " cell->SetDiameter(10);\n", - " cell->AddBehavior(rapid_division.NewCopy());\n", - " return cell;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "306f90b8", - "metadata": {}, - "source": [ - "As starting condition we want to create 100 cells randomly distributed in a cube with $min = 0, max = 200$" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bac61f01", - "metadata": {}, - "outputs": [], - "source": [ - "simulation.GetResourceManager()->ClearAgents();\n", - "ModelInitializer::CreateAgentsRandom(0, 200, 100, create_cell);\n", - "simulation.GetScheduler()->FinalizeInitialization();\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "c35e0f44", - "metadata": {}, - "source": [ - "Before we start the simulation, we have to tell BioDynaMo which data to collect.
\n", - "We can do this with the TimeSeries::AddCollector function.
\n", - "In this example we are interested in the number of agents ..." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8b3d62c1", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ts = simulation.GetTimeSeries();\n", - "auto get_num_agents = [](Simulation* sim) {\n", - " return static_cast(sim->GetResourceManager()->GetNumAgents());\n", - "};\n", - "ts->AddCollector(\"num-agents\", get_num_agents);" - ] - }, - { - "cell_type": "markdown", - "id": "7b6353cd", - "metadata": {}, - "source": [ - "... and the number agents with $diameter < 5$.
\n", - "We create a condition `cond` and pass it to an instance of `Counter` which calculates the number of agents for which `cond(agent)` evaluates to true." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fe964505", - "metadata": {}, - "outputs": [], - "source": [ - "auto cond = [](Agent* a) { return a->GetDiameter() < 5; };\n", - "ts->AddCollector(\"agents_lt_5\", new bdm::experimental::Counter(cond));" - ] - }, - { - "cell_type": "markdown", - "id": "e014efbf", - "metadata": {}, - "source": [ - "Now let's simulate 40 iterations" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1ce235bb", - "metadata": {}, - "outputs": [], - "source": [ - "simulation.GetScheduler()->Simulate(40);" - ] - }, - { - "cell_type": "markdown", - "id": "1718298b", - "metadata": {}, - "source": [ - "Now we can plot how the number of agents (in this case cells) and the number of agents with $diameter < 5$ evolved over time." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a7e92b2b", - "metadata": {}, - "outputs": [], - "source": [ - "LineGraph g(ts, \"my result\", \"Time\", \"Number of agents\", \n", - " true, nullptr, 500, 300);\n", - "g.Add(\"num-agents\", \"Number of Agents\", \"L\", kBlue);\n", - "g.Add(\"agents_lt_5\", \"Number of Agents diam < 5\", \"L\", kGreen);\n", - "g.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "74fcca1f", - "metadata": {}, - "source": [ - "Let's try to fit an exponential function to verify our assumption that the cells grew exponentially.
\n", - "Please visit the [ROOT user-guide](https://root.cern.ch/root/htmldoc/guides/users-guide/FittingHistograms.html) for more information regarding fitting " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "7aa6ad92", - "metadata": {}, - "outputs": [], - "source": [ - "auto fitresult = g.GetTGraphs(\"num-agents\")[0]->Fit(\"expo\", \"S\");\n", - "g.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "6b395b71", - "metadata": {}, - "source": [ - "Indeed, the number of agents follow an exponential function $$y = \\exp(slope * x + constant)$$ with constant = 4.6 and slope = 0.049\n", - "This corresponds to the division probability of $0.05$ " - ] - }, - { - "cell_type": "markdown", - "id": "3f2b70b1", - "metadata": {}, - "source": [ - "This is how to change the color after the creation of `g`.
\n", - "Also the position of the legend can be optimized." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1c53fe3e", - "metadata": {}, - "outputs": [], - "source": [ - "g.GetTGraphs(\"num-agents\")[0]->SetLineColor(kBlack);\n", - "g.SetLegendPos(1, 500, 20, 700);\n", - "g.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "64245848", - "metadata": {}, - "source": [ - "Let's save these results in multiple formats" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "92d716a1", - "metadata": {}, - "outputs": [], - "source": [ - "g.SaveAs(Concat(simulation.GetOutputDir(), \"/line-graph\"), \n", - " {\".root\", \".svg\", \".png\", \".C\"});" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST11-multiple-experiments-statistical-analysis.ipynb b/notebook/ST11-multiple-experiments-statistical-analysis.ipynb deleted file mode 100644 index a68005f61..000000000 --- a/notebook/ST11-multiple-experiments-statistical-analysis.ipynb +++ /dev/null @@ -1,217 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "27e05215", - "metadata": {}, - "source": [ - "# Multiple experiments and statistical analysis\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we show how to collect and analyse data from multiple experiments.
\n", - "To this extent, we create a simulation where cells divide rapidly leading to exponential growth." - ] - }, - { - "cell_type": "markdown", - "id": "302c3309", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ef7edf86", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c5d8d40b", - "metadata": {}, - "outputs": [], - "source": [ - "using namespace bdm::experimental;" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "adc6bce5", - "metadata": {}, - "outputs": [], - "source": [ - "real_t gDivProb = 0.05;" - ] - }, - { - "cell_type": "markdown", - "id": "102c177f", - "metadata": {}, - "source": [ - "We use the same simulation as in `ST09-timeseries-plotting-basic`. \n", - "It is a simulation were agents divide with a specific division probability in each time step leading to exponential growth. We collect the number of agents in each time step.\n", - "Have a look at `ST09-timeseries-plotting-basic` for more information. \n", - "\n", - "We wrap the required simulation code in a function called `Experiment` which takes two parameters:\n", - "* the collected result data from a single invocation (output param)\n", - "* the division probability parameter " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b5c3f40", - "metadata": {}, - "outputs": [], - "source": [ - "void Experiment(TimeSeries* result, real_t division_probability) {\n", - " gDivProb = division_probability;\n", - " \n", - " auto set_param = [](Param* param) {\n", - " param->simulation_time_step = 1.0;\n", - " };\n", - " Simulation simulation(\"MySimulation\", set_param);\n", - " \n", - " StatelessBehavior rapid_division([](Agent* agent) {\n", - " if (Simulation::GetActive()->GetRandom()->Uniform() < gDivProb) {\n", - " bdm_static_cast(agent)->Divide();\n", - " }\n", - " });\n", - " rapid_division.AlwaysCopyToNew();\n", - " \n", - " auto create_cell = [&](const Real3& position) {\n", - " Cell* cell = new Cell(position);\n", - " cell->SetDiameter(10);\n", - " cell->AddBehavior(rapid_division.NewCopy());\n", - " return cell;\n", - " };\n", - " \n", - " simulation.GetResourceManager()->ClearAgents();\n", - " ModelInitializer::CreateAgentsRandom(0, 200, 100, create_cell);\n", - " simulation.GetScheduler()->FinalizeInitialization();\n", - " \n", - " auto* ts = simulation.GetTimeSeries();\n", - " auto get_num_agents = [](Simulation* sim) {\n", - " return static_cast(sim->GetResourceManager()->GetNumAgents());\n", - " };\n", - " ts->AddCollector(\"num-agents\", get_num_agents);\n", - " \n", - " simulation.GetScheduler()->Simulate(40);\n", - " \n", - " // move collected time series data from simulation to object result\n", - " *result = std::move(*simulation.GetTimeSeries());\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "f4f7b3b8", - "metadata": {}, - "source": [ - "We want to run our experiment for 10 times with a different division probability parameter.\n", - "We choose the division probability randomly between 0.04 and 0.06" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c115283f", - "metadata": {}, - "outputs": [], - "source": [ - "std::vector individual_results(10);\n", - "Random rnd;\n", - "for(auto& ir : individual_results) {\n", - " Experiment(&ir, rnd.Uniform(0.04, 0.06));\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "d78ace15", - "metadata": {}, - "source": [ - "In the next step we want to combine the individual results. Therefore we calculate the mean, and min (error low), and max (error high) and store it in a merged `TimeSeries` object." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "52af58c2", - "metadata": {}, - "outputs": [], - "source": [ - "TimeSeries merged;\n", - "auto merger = [](const std::vector& all_ys, \n", - " real_t* y, real_t* eh, real_t* el) {\n", - " *y = TMath::Mean(all_ys.begin(), all_ys.end());\n", - " *el = *y - *TMath::LocMin(all_ys.begin(), all_ys.end());\n", - " *eh = *TMath::LocMax(all_ys.begin(), all_ys.end()) - *y;\n", - "};\n", - "TimeSeries::Merge(&merged, individual_results, merger);" - ] - }, - { - "cell_type": "markdown", - "id": "7fbecc45", - "metadata": {}, - "source": [ - "Now we can print the merged results and see how the simulations evolved over time, and how they differed from each other." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ebd013ea", - "metadata": {}, - "outputs": [], - "source": [ - "LineGraph g(&merged, \"My result\", \"Time\", \"Number of agents\", false, nullptr, 500, 300);\n", - "g.Add(\"num-agents\", \"Number of Agents\", \"LP\", kBlue);\n", - "g.Draw();" - ] - }, - { - "cell_type": "markdown", - "id": "cb193f1d", - "metadata": {}, - "source": [ - "Finally, let's fit an exponential function to the data." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "130bb51e", - "metadata": {}, - "outputs": [], - "source": [ - "g.GetTMultiGraph()->Fit(\"expo\", \"S\");\n", - "g.Draw()" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST12-hierarchical-model.ipynb b/notebook/ST12-hierarchical-model.ipynb deleted file mode 100644 index 08dbae8f5..000000000 --- a/notebook/ST12-hierarchical-model.ipynb +++ /dev/null @@ -1,253 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "cf421e00", - "metadata": {}, - "source": [ - "# Hierarchical model support\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "Some models require to update certain agents before others.\n", - "In this tutorial we show how to execute operations first for large agents and afterwards for small ones.\n", - "Lastly, we demonstrate how to run a different set of operations for large and for small agents." - ] - }, - { - "cell_type": "markdown", - "id": "700c09a6", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "3654007a", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "4ae01b7f", - "metadata": {}, - "source": [ - "To make this demo easier to understand, we turn off multi-threading and load balancing. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "78277bc9", - "metadata": {}, - "outputs": [], - "source": [ - "omp_set_num_threads(1);\n", - "ThreadInfo::GetInstance()->Renew();\n", - "auto* scheduler = simulation.GetScheduler();\n", - "scheduler->UnscheduleOp(scheduler->GetOps(\"load balancing\")[0]);" - ] - }, - { - "cell_type": "markdown", - "id": "2c6850fe", - "metadata": {}, - "source": [ - "We create a new agent operation which prints out its name and the diameter of the agent it is processing" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f336788b", - "metadata": {}, - "outputs": [], - "source": [ - "struct TestOp : public AgentOperationImpl {\n", - " BDM_OP_HEADER(TestOp);\n", - " void operator()(Agent* agent) override {\n", - " std::cout << name << \" processing agent with diameter \" \n", - " << agent->GetDiameter() << endl; \n", - " }\n", - " std::string name = \"\";\n", - "};\n", - "OperationRegistry::GetInstance()->AddOperationImpl(\n", - " \"test_op\", OpComputeTarget::kCpu, new TestOp());" - ] - }, - { - "cell_type": "markdown", - "id": "79e02ac2", - "metadata": {}, - "source": [ - "We create four agents with diameter `{20, 10, 20, 10}`" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8bc5851d", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "for (int i = 0; i < 4; ++i) {\n", - " real_t diameter = i % 2 == 0 ? 20 : 10;\n", - " ctxt->AddAgent(new SphericalAgent(diameter));\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "01f04ed6", - "metadata": {}, - "source": [ - "We add the new operation to the simulation" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d74d3d77", - "metadata": {}, - "outputs": [], - "source": [ - "auto* op1 = NewOperation(\"test_op\");\n", - "scheduler->ScheduleOp(op1);" - ] - }, - { - "cell_type": "markdown", - "id": "4aca92f2", - "metadata": {}, - "source": [ - "Let's simulate one time step and observe the default behavior of BioDynaMo.\n", - "We expect that the agents are processed in the order they were added (`{20, 10, 20, 10}`)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "fb044c02", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "45ad99d6", - "metadata": {}, - "source": [ - "Now we want to define the group of large and small agents and tell BioDynaMo that large agents should be processed before small ones. \n", - "\n", - "This can be done with the following three lines of code." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "ad4b226b", - "metadata": {}, - "outputs": [], - "source": [ - "auto small_filter = L2F([](Agent* a) { return a->GetDiameter() < 15; });\n", - "auto large_filter = L2F([](Agent* a) { return a->GetDiameter() >= 15; });\n", - "scheduler->SetAgentFilters({&large_filter, &small_filter});" - ] - }, - { - "cell_type": "markdown", - "id": "25366858", - "metadata": {}, - "source": [ - "Let's observe if the output has changed. We expect to see first the large agents `{20, 20}`, followed by the small ones `{10, 10}`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d0858e54", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "72e2980e", - "metadata": {}, - "source": [ - "Let's create two more instances of our `TestOp`.\n", - "We define that:\n", - "* `op1` should be run for all agents (large and small).\n", - "* `op2` only for small agents\n", - "* `op3` only for large agents" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6761123", - "metadata": {}, - "outputs": [], - "source": [ - "auto* op2 = NewOperation(\"test_op\");\n", - "auto* op3 = NewOperation(\"test_op\");\n", - "\n", - "op1->GetImplementation()->name = \"OpAll \";\n", - "op2->GetImplementation()->name = \"OpOnlySmall\";\n", - "op3->GetImplementation()->name = \"OpOnlyLarge\";\n", - "\n", - "op2->SetExcludeFilters({&large_filter});\n", - "op3->SetExcludeFilters({&small_filter});\n", - "\n", - "scheduler->ScheduleOp(op2);\n", - "scheduler->ScheduleOp(op3);" - ] - }, - { - "cell_type": "markdown", - "id": "73aeefb9", - "metadata": {}, - "source": [ - "Now we want to execute another time step with the updated model. We expect that for each agent two operations will be executed. \n", - "\n", - "For large agents `OpAll` and `OpOnlyLarge` and for small agents `OpAll` and `OpOnlySmall`.\n", - "As before, we expect that first all large agents are executed, followed by all small agents." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b13e0354", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST13-dynamic-scheduling.ipynb b/notebook/ST13-dynamic-scheduling.ipynb deleted file mode 100644 index 552bcd7cf..000000000 --- a/notebook/ST13-dynamic-scheduling.ipynb +++ /dev/null @@ -1,322 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "a81151f9", - "metadata": {}, - "source": [ - "# Dynamic scheduling\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "This tutorial demonstrates that behaviors and operations can be added and removed during the simulation.\n", - "This feature provides maximum flexibility to control which functions will be executed during the lifetime of a simulation." - ] - }, - { - "cell_type": "markdown", - "id": "ef10be44", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "201082b4", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d1d5fdc4", - "metadata": {}, - "outputs": [], - "source": [ - "auto* ctxt = simulation.GetExecutionContext();\n", - "auto* scheduler = simulation.GetScheduler();" - ] - }, - { - "cell_type": "markdown", - "id": "09c18d30", - "metadata": {}, - "source": [ - "Define a helper variable" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c39d7149", - "metadata": {}, - "outputs": [], - "source": [ - "int test_op_id = 0;" - ] - }, - { - "cell_type": "markdown", - "id": "f0506762", - "metadata": {}, - "source": [ - "We define a standalone operation `TestOp` which prints out that it got executed and which removes itself from the list of scheduled operations afterwards. The same principles apply also for agent operations." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d650b370", - "metadata": {}, - "outputs": [], - "source": [ - "struct TestOp : public StandaloneOperationImpl {\n", - " BDM_OP_HEADER(TestOp);\n", - " void operator()() override {\n", - " auto* scheduler = Simulation::GetActive()->GetScheduler();\n", - " std::cout << name << \" processing iteration \" \n", - " << scheduler->GetSimulatedSteps() \n", - " << std::endl; \n", - "\n", - " auto* op = scheduler->GetOps(\"test_op\")[test_op_id++];\n", - " scheduler->UnscheduleOp(op);\n", - " \n", - " std::cout << \" \" << name \n", - " << \" removed itself from the simulation \" << std::endl;\n", - " }\n", - " std::string name = \"\";\n", - "};\n", - "OperationRegistry::GetInstance()->AddOperationImpl(\n", - " \"test_op\", OpComputeTarget::kCpu, new TestOp());" - ] - }, - { - "cell_type": "markdown", - "id": "08de84e8", - "metadata": {}, - "source": [ - "Let's define a little helper function which creates a new instance of `TestOp` and adds it to the list of scheduled operations." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "59162209", - "metadata": {}, - "outputs": [], - "source": [ - "void AddNewTestOpToSim(const std::string& name) {\n", - " auto* op = NewOperation(\"test_op\");\n", - " op->GetImplementation()->name = name;\n", - " scheduler->ScheduleOp(op);\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "5301eb93", - "metadata": {}, - "source": [ - "Let's define a new behavior `b2` which prints out when it gets executed and which adds a new operation with name `OP2` to the simulation if a condition is met.\n", - "\n", - "In this scenario the condition is defined as `simulation time step == 1`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "62f14b53", - "metadata": {}, - "outputs": [], - "source": [ - "StatelessBehavior b2([](Agent* agent) {\n", - " std::cout << \"B2 \" << agent->GetUid() << std::endl;\n", - " if (simulation.GetScheduler()->GetSimulatedSteps() == 1) {\n", - " AddNewTestOpToSim(\"OP2\");\n", - " std::cout << \" B2 added OP2 to the simulation\" << std::endl;\n", - " }\n", - "});" - ] - }, - { - "cell_type": "markdown", - "id": "1f724a55", - "metadata": {}, - "source": [ - "We define another behavior `b1` which prints out when it gets executed, removes itself from the agent, and which adds behavior `b2` to the agent." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "af44d774", - "metadata": {}, - "outputs": [], - "source": [ - "StatelessBehavior b1([](Agent* agent) {\n", - " std::cout << \"B1 \" << agent->GetUid() << std::endl;\n", - " agent->RemoveBehavior(agent->GetAllBehaviors()[0]);\n", - " std::cout << \" B1 removed itself from agent \" << agent->GetUid() << std::endl;\n", - " agent->AddBehavior(b2.NewCopy());\n", - " std::cout << \" B1 added B2 to agent \" << agent->GetUid() << std::endl;\n", - "});" - ] - }, - { - "cell_type": "markdown", - "id": "de61161c", - "metadata": {}, - "source": [ - "Now all required building blocks are ready. Let's define the initial model: a single agent with behavior `b1`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8d36312f", - "metadata": {}, - "outputs": [], - "source": [ - "auto* agent = new SphericalAgent();\n", - "agent->AddBehavior(b1.NewCopy());\n", - "ctxt->AddAgent(agent);" - ] - }, - { - "cell_type": "markdown", - "id": "af9d3f69", - "metadata": {}, - "source": [ - "We also add a new operation to the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c7a1189f", - "metadata": {}, - "outputs": [], - "source": [ - "AddNewTestOpToSim(\"OP1\");" - ] - }, - { - "cell_type": "markdown", - "id": "3e7b7086", - "metadata": {}, - "source": [ - "Let's simulate one iteration and think about the expected output.\n", - "* Since we initialized our only agent with behavior `b1`, we expect to see a line `B1 0-0`\n", - "* Furthermore, `b1` will print a line to inform us that it removed itself from the agent, and that it added behavior `b2` to the agent.\n", - "* Because changes are applied immediately (using the default `InPlaceExecCtxt`) also `B2` will be executed. However the condition inside `b2` is not met.\n", - "* Next we expect an output from `OP1` telling us that it got executed.\n", - "* Lastly, we expect an output from `OP1` to tell is that it removed itself from the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e78cf8b9", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "f5f7837a", - "metadata": {}, - "source": [ - "Let's simulate another iteration.
\n", - "This time we only expect output from `B2`.\n", - "Remember that `B1` and `OP1` have been removed in the last iteration.\n", - "\n", - "This time the condition in `B2` is met and we expect to see an output line to tell us that a new instance of `TestOp` with name `OP2` has been added to the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "be462af4", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "8803ce5e", - "metadata": {}, - "source": [ - "Let's simulate another iteration.\n", - "This time we expect an output from `B2` whose condition is not met in this iterations, and from `OP2` that it got executed and removed from the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0943f9aa", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "b21667f1", - "metadata": {}, - "source": [ - "Let's simulate one last iteration.\n", - "`OP2` removed itself in the last iteration. Therefore, only `B2` should be left. The condition of `B2` is not met. " - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "325eb8a5", - "metadata": {}, - "outputs": [], - "source": [ - "scheduler->Simulate(1);" - ] - }, - { - "cell_type": "markdown", - "id": "4fd1e20c", - "metadata": {}, - "source": [ - "In summary: \n", - "We initialized the simulation with `B1` and `OP1`.\n", - "\n", - "In iteration:\n", - "\n", - "0. B1 removed, B2 added, OP1 removed\n", - "1. OP2 added\n", - "2. OP2 removed" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST14-randomize-iteration-order.ipynb b/notebook/ST14-randomize-iteration-order.ipynb deleted file mode 100644 index 3429e13d7..000000000 --- a/notebook/ST14-randomize-iteration-order.ipynb +++ /dev/null @@ -1,164 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "d82aa08c", - "metadata": {}, - "source": [ - "# Randomize iteration order\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "In this tutorial we show how to randomize the order that BioDynaMo uses in each iteration to process the agents." - ] - }, - { - "cell_type": "markdown", - "id": "0f2eccf9", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e78c1565", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "markdown", - "id": "73bfe0f7", - "metadata": {}, - "source": [ - "Let's create two helper functions:\n", - "* `AddAgents` to add four agents to the simulation\n", - "* `print_uid` which prints the uid of the given agent" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d6280097", - "metadata": {}, - "outputs": [], - "source": [ - "void AddAgents(ResourceManager* rm) {\n", - " for (int i = 0; i < 4; ++i) {\n", - " rm->AddAgent(new SphericalAgent());\n", - " }\n", - "}\n", - "auto print_uid = [](Agent* a) { \n", - " std::cout << a->GetUid() << std::endl;\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "7124c420", - "metadata": {}, - "source": [ - "We define an experiment which \n", - "1. takes a simulation object as input\n", - "2. adds four agents\n", - "3. calls `print_uid` for each agent\n", - "4. print a separator so we can distinguish the output of the two different time steps\n", - "4. advances to the next time step\n", - "5. calls `print_uid` for each agent again" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e15b1ee4", - "metadata": {}, - "outputs": [], - "source": [ - "void Experiment(Simulation* sim) {\n", - " auto* rm = sim->GetResourceManager();\n", - " AddAgents(rm);\n", - " \n", - " rm->ForEachAgent(print_uid);\n", - " rm->EndOfIteration();\n", - " std::cout << \"-----------------\" << std::endl;\n", - " rm->ForEachAgent(print_uid);\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "1ac0256b", - "metadata": {}, - "source": [ - "The default behavior of BioDynaMo is to iterate over the agents in the order they were added (not taking multi-threading and load balancing into account). Therefore, we expect to see the same order twice." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a50ec22e", - "metadata": {}, - "outputs": [], - "source": [ - "Experiment(&simulation)" - ] - }, - { - "cell_type": "markdown", - "id": "77e55b34", - "metadata": {}, - "source": [ - "BioDynaMo also provides a wrapper called `RandomizedRm`, which, as the name suggests, randomizes the iteration order after each iteration. It just takes two lines to add this functionality to the simulation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "08de3470", - "metadata": {}, - "outputs": [], - "source": [ - "Simulation simulation(\"my-sim\");\n", - "auto* rand_rm = new RandomizedRm();\n", - "simulation.SetResourceManager(rand_rm);" - ] - }, - { - "cell_type": "markdown", - "id": "619abd2d", - "metadata": {}, - "source": [ - "Let's run our experiment again. This time with the simulation which has a randomized resource manager. We expect two different orders." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "710d474f", - "metadata": {}, - "outputs": [], - "source": [ - "Experiment(&simulation)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebook/ST15-replace-interaction-force.ipynb b/notebook/ST15-replace-interaction-force.ipynb deleted file mode 100644 index 692be224b..000000000 --- a/notebook/ST15-replace-interaction-force.ipynb +++ /dev/null @@ -1,246 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "744e5067", - "metadata": {}, - "source": [ - "# Replace mechanical interaction force\n", - "\n", - "**Author: Lukas Breitwieser**
\n", - "This tutorial demonstrates how to replace BioDynaMo's default interaction force with a user-defined one.\n", - "The interaction force is used to calculate forces between agent pairs that are in physical contact with each other." - ] - }, - { - "cell_type": "markdown", - "id": "220dbe96", - "metadata": {}, - "source": [ - "Let's start by setting up BioDynaMo notebooks." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "cc6fcee9", - "metadata": {}, - "outputs": [], - "source": [ - "%jsroot on\n", - "gROOT->LoadMacro(\"${BDMSYS}/etc/rootlogon.C\");" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0e1fdc1a", - "metadata": {}, - "outputs": [], - "source": [ - "#include \"core/operation/mechanical_forces_op.h\"" - ] - }, - { - "cell_type": "markdown", - "id": "821c1990", - "metadata": {}, - "source": [ - "We modify the `simulation_max_displacement` parameter to better visualize the difference of the user-defined force that we will add." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "0dd52b08", - "metadata": {}, - "outputs": [], - "source": [ - "auto set_param = [](Param* p) {\n", - " p->simulation_max_displacement = 50;\n", - "};\n", - "Simulation simulation(\"my-simulation\", set_param);" - ] - }, - { - "cell_type": "markdown", - "id": "4a798834", - "metadata": {}, - "source": [ - "In our experiment we create two overlapping cells and visualize the starting condition." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38207a67", - "metadata": {}, - "outputs": [], - "source": [ - "void Experiment() {\n", - " simulation.GetResourceManager()->ClearAgents();\n", - " auto* ctxt = simulation.GetExecutionContext();\n", - " auto* scheduler = simulation.GetScheduler();\n", - " \n", - " auto* cell1 = new Cell({0, 0, 0});\n", - " auto* cell2 = new Cell({10, 0, 0});\n", - " cell1->SetDiameter(20);\n", - " cell2->SetDiameter(20);\n", - " cell1->SetMass(0.1);\n", - " cell2->SetMass(0.1);\n", - "\n", - " ctxt->AddAgent(cell1);\n", - " ctxt->AddAgent(cell2);\n", - " \n", - " scheduler->FinalizeInitialization();\n", - " VisualizeInNotebook();\n", - "}" - ] - }, - { - "cell_type": "markdown", - "id": "4c558d1e", - "metadata": {}, - "source": [ - "Let's run our experiment and have a look at the visualization." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b8b6889c", - "metadata": {}, - "outputs": [], - "source": [ - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "e4b46995", - "metadata": {}, - "source": [ - "We continue by simulating 10 iterations and observe how the mechanical force pushed the two cells away from each other, until they don't overlap anymore." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "e3e20ef1", - "metadata": {}, - "outputs": [], - "source": [ - "auto* scheduler = simulation.GetScheduler();\n", - "scheduler->Simulate(10);\n", - "VisualizeInNotebook();" - ] - }, - { - "cell_type": "markdown", - "id": "f28bf2eb", - "metadata": {}, - "source": [ - "Now we want to add our user-defined force implementation. \n", - "First, we have to subclass `InteractionForce` and implement our force. \n", - "In this case, it is an extremely simple (and unrealistic) implementation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a123cee0", - "metadata": {}, - "outputs": [], - "source": [ - "class MyInteractionForce : public InteractionForce {\n", - " public:\n", - " MyInteractionForce() {}\n", - " virtual ~MyInteractionForce() {}\n", - " \n", - " Real4 Calculate(const Agent* lhs, const Agent* rhs) const override {\n", - " if (lhs < rhs) {\n", - " return {100, 0, 0, 0};\n", - " } else {\n", - " return {-100, 0, 0, 0};\n", - " }\n", - " }\n", - " \n", - " InteractionForce* NewCopy() const override { return new MyInteractionForce(); }\n", - "};" - ] - }, - { - "cell_type": "markdown", - "id": "b141ec01", - "metadata": {}, - "source": [ - "With the following three lines we instruct BioDynaMo to use our new `MyInteractionForce` instead of the default implementation." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d2b6d8e8", - "metadata": {}, - "outputs": [], - "source": [ - "auto* myforce = new MyInteractionForce();\n", - "auto* op = scheduler->GetOps(\"mechanical forces\")[0];\n", - "op->GetImplementation()->SetInteractionForce(myforce);" - ] - }, - { - "cell_type": "markdown", - "id": "938d808b", - "metadata": {}, - "source": [ - "We create the same starting condition as before." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6f1d4b1e", - "metadata": {}, - "outputs": [], - "source": [ - "Experiment();" - ] - }, - { - "cell_type": "markdown", - "id": "d5e4f1af", - "metadata": {}, - "source": [ - "Because `myforce` is so strong, it is sufficient to simulate only one iteration to clearly see its impact." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "597840f2", - "metadata": {}, - "outputs": [], - "source": [ - "auto* scheduler = simulation.GetScheduler();\n", - "scheduler->Simulate(1);\n", - "VisualizeInNotebook();" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/src/biodynamo.h b/src/biodynamo.h index 51ba49c8d..1936535b2 100644 --- a/src/biodynamo.h +++ b/src/biodynamo.h @@ -22,9 +22,7 @@ #include "core/agent/cell_division_event.h" #include "core/agent/new_agent_event.h" #include "core/agent/spherical_agent.h" -#include "core/analysis/line_graph.h" #include "core/analysis/reduce.h" -#include "core/analysis/style.h" #include "core/analysis/time_series.h" #include "core/behavior/behavior.h" #include "core/behavior/chemotaxis.h" @@ -44,9 +42,7 @@ #include "core/shape.h" #include "core/substance_initializers.h" #include "core/util/filesystem.h" -#include "core/util/root.h" #include "core/util/timing.h" #include "core/util/vtune.h" -#include "core/visualization/root/notebook_util.h" #endif // BIODYNAMO_H_ diff --git a/src/core/analysis/line_graph.cc b/src/core/analysis/line_graph.cc deleted file mode 100644 index 1984c624f..000000000 --- a/src/core/analysis/line_graph.cc +++ /dev/null @@ -1,200 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/analysis/line_graph.h" -#include -#include -#include -#include -#include -#include -#include -#include "core/analysis/time_series.h" -#include "core/util/log.h" -#include "core/util/string.h" - -namespace bdm { -namespace experimental { - -// ----------------------------------------------------------------------------- -LineGraph::LineGraph(const TimeSeries* ts, const std::string& title, - const std::string& xaxis_title, - const std::string& yaxis_title, bool legend, TStyle* style, - int width, int height) - : ts_(ts), s_(style) { - if (s_) { - s_->cd(); - } - c_ = new TCanvas(); - mg_ = new TMultiGraph(); - c_->SetCanvasSize(width, height); - c_->SetGrid(); - mg_->SetTitle(Concat(title, ";", xaxis_title, ";", yaxis_title).c_str()); - if (legend) { - l_ = new TLegend(); - } -} - -// ----------------------------------------------------------------------------- -LineGraph::~LineGraph() { - delete c_; - delete mg_; - if (l_) { - delete l_; - } -} - -// ----------------------------------------------------------------------------- -TGraph* LineGraph::Add(const std::string& ts_name, - const std::string& legend_label, - const char* add_mg_options, short line_color, - float line_color_alpha, short line_style, - short line_width, short marker_color, - float marker_color_alpha, short marker_style, - float marker_size, short fill_color, - float fill_color_alpha, short fill_style) { - if (s_) { - s_->cd(); - } - - if (!ts_->Contains(ts_name)) { - Log::Warning("LineGraph::Add", - "The time series stored in this line graph does not contain " - "an entry for (", - ts_name, "). Operation aborted."); - return nullptr; - } - const auto& xvals = ts_->GetXValues(ts_name); - const auto& yvals = ts_->GetYValues(ts_name); - const auto& el = ts_->GetYErrorLow(ts_name); - const auto& eh = ts_->GetYErrorHigh(ts_name); - TGraph* gr = nullptr; - if (el.size() == 0) { - gr = new TGraph(xvals.size(), xvals.data(), yvals.data()); - } else { - gr = new TGraphAsymmErrors(xvals.size(), xvals.data(), yvals.data(), - nullptr, nullptr, el.data(), eh.data()); - } - gr->SetTitle(legend_label.c_str()); - gr->InvertBit(TGraph::EStatusBits::kNotEditable); - gr->SetLineColorAlpha(line_color, line_color_alpha); - gr->SetLineStyle(line_style); - gr->SetLineWidth(line_width); - gr->SetMarkerColorAlpha(marker_color, marker_color_alpha); - gr->SetMarkerStyle(marker_style); - gr->SetMarkerSize(marker_size); - gr->SetFillColorAlpha(fill_color, fill_color_alpha); - gr->SetFillStyle(fill_style); - - mg_->Add(gr, add_mg_options); - if (l_ && legend_label != "") { - l_->AddEntry(gr, legend_label.c_str()); - } - id_tgraphs_map_[ts_name].push_back(gr); - return gr; -} - -// ----------------------------------------------------------------------------- -void LineGraph::Draw(const char* canvas_draw_option) { - Update(); - c_->Draw(canvas_draw_option); -} - -// ----------------------------------------------------------------------------- -void LineGraph::SetLegendPos(real_t x1, real_t y1, real_t x2, real_t y2) { - if (l_) { - Update(); - l_->SetX1(x1); - l_->SetY1(y1); - l_->SetX2(x2); - l_->SetY2(y2); - } else { - Log::Warning( - "LineGraph::SetLegendPos", - "This LineGraph was created without legend. Operation aborted."); - } -} - -// ----------------------------------------------------------------------------- -void LineGraph::SetLegendPosNDC(real_t x1, real_t y1, real_t x2, real_t y2) { - if (l_) { - Update(); - l_->SetX1NDC(x1); - l_->SetY1NDC(y1); - l_->SetX2NDC(x2); - l_->SetY2NDC(y2); - } else { - Log::Warning( - "LineGraph::SetLegendPosNDC", - "This LineGraph was created without legend. Operation aborted."); - } -} - -// ----------------------------------------------------------------------------- -void LineGraph::SaveAs(const std::string& filenpath_wo_extension, - const std::vector& extensions) { - Update(); - for (auto& ext : extensions) { - auto full_path = Concat(filenpath_wo_extension, ext); - Log::Info("LineGraph::SaveAs", "Saved LineGraph at: ", full_path); - c_->SaveAs(full_path.c_str()); - } -} - -// ----------------------------------------------------------------------------- -void LineGraph::SetMultiGraphDrawOption(const std::string& s) { - mg_draw_option_ = s; -} - -// ----------------------------------------------------------------------------- -TCanvas* LineGraph::GetTCanvas() { return c_; } - -// ----------------------------------------------------------------------------- -TMultiGraph* LineGraph::GetTMultiGraph() { return mg_; } - -// ----------------------------------------------------------------------------- -TLegend* LineGraph::GetTLegend() { return l_; } - -// ----------------------------------------------------------------------------- -const std::vector& LineGraph::GetTGraphs( - const std::string& ts_name) const { - auto it = id_tgraphs_map_.find(ts_name); - if (it == id_tgraphs_map_.end()) { - static std::vector kEmpty; - return kEmpty; - } - return it->second; -} - -// ----------------------------------------------------------------------------- -TStyle* LineGraph::GetTStyle() { return s_; } - -// ----------------------------------------------------------------------------- -void LineGraph::Update() { - if (s_) { - s_->cd(); - } - mg_->Draw(mg_draw_option_.c_str()); - if (l_) { - l_->Draw(); - } - c_->Update(); - gPad->Modified(); - gPad->Update(); - c_->Modified(); - c_->cd(0); -} - -} // namespace experimental -} // namespace bdm diff --git a/src/core/analysis/line_graph.h b/src/core/analysis/line_graph.h deleted file mode 100644 index 71def94dc..000000000 --- a/src/core/analysis/line_graph.h +++ /dev/null @@ -1,95 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef CORE_ANALYSIS_LINE_GRAPH_H_ -#define CORE_ANALYSIS_LINE_GRAPH_H_ - -#include -#include -#include -#include "core/real_t.h" -#include "core/util/root.h" - -class TCanvas; -class TMultiGraph; -class TLegend; -class TGraph; -class TStyle; - -namespace bdm { -namespace experimental { - -class TimeSeries; - -/// This class simplifies the creation of line graphs using data from -/// `TimeSeries`. -class LineGraph { - public: - /// \param style This class does not take ownership of style - LineGraph(const TimeSeries* ts, const std::string& title = "", - const std::string& xaxis_title = "", - const std::string& yaxis_title = "", bool legend = true, - TStyle* style = nullptr, int width = 700, int height = 500); - - ~LineGraph(); - - /// Add a new graph to the plot - /// The following links provide further information for line, marker, and fill - /// parameters: \see https://root.cern/doc/master/classTAttLine.html \see - /// https://root.cern/doc/master/classTAttMarker.html \see - /// https://root.cern/doc/master/classTAttFill.html - TGraph* Add(const std::string& ts_name, const std::string& legend_name = "", - const char* add_mg_options = "L", short line_color = 1, - float line_color_alpha = 1.0, short line_style = 1, - short line_width = 1, short marker_color = 1, - float marker_color_alpha = 1.0, short marker_style = 1, - float marker_size = 1, short fill_color = 0, - float fill_color_alpha = 1.0, short fill_style = 1000); - - void SetLegendPos(real_t x1, real_t y1, real_t x2, real_t y2); - /// NDC coordinates are a % of the canvas size: - /// (0.5,0.5) is the middle of the canvas. (1,1) upper right corner, - /// (0,0) bottom left corner. - /// \ref - /// https://root-forum.cern.ch/t/how-to-imagine-ndc-normalized-coord/24202 - void SetLegendPosNDC(real_t x1, real_t y1, real_t x2, real_t y2); - - void SetMultiGraphDrawOption(const std::string& s); - - void Draw(const char* canvas_draw_option = ""); - - void SaveAs(const std::string& filenpath_wo_extension, - const std::vector& extensions); - - void Update(); - - TCanvas* GetTCanvas(); - TMultiGraph* GetTMultiGraph(); - TLegend* GetTLegend(); - const std::vector& GetTGraphs(const std::string& ts_name) const; - TStyle* GetTStyle(); - - private: - const TimeSeries* ts_ = nullptr; - std::string mg_draw_option_ = "A"; - TCanvas* c_ = nullptr; - TMultiGraph* mg_ = nullptr; - TLegend* l_ = nullptr; - TStyle* s_ = nullptr; - std::unordered_map> id_tgraphs_map_; -}; - -} // namespace experimental -} // namespace bdm - -#endif // CORE_ANALYSIS_TIME_SERIES_H_ diff --git a/src/core/analysis/style.cc b/src/core/analysis/style.cc deleted file mode 100644 index 881af408a..000000000 --- a/src/core/analysis/style.cc +++ /dev/null @@ -1,335 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/analysis/style.h" - -namespace bdm { -namespace experimental { - -// ----------------------------------------------------------------------------- -Style::Style() : TNamed(), TAttLine(), TAttFill(), TAttMarker(), TAttText() { - FromTStyle(gStyle); -} - -// ----------------------------------------------------------------------------- -Style::~Style() { - if (tstyle_) { - delete tstyle_; - } -} - -// ----------------------------------------------------------------------------- -TStyle* Style::GetTStyle() const { - if (!tstyle_) { - tstyle_ = new TStyle(); - ToTStyle(); - } - return tstyle_; -} - -// ----------------------------------------------------------------------------- -Style::operator TStyle*() const { return GetTStyle(); } - -// ----------------------------------------------------------------------------- -void Style::ToTStyle() const { - // delete gROOT->GetStyle("Modern"); - auto set_axis = [this](const TAttAxis& axis, Option_t* o) { - this->tstyle_->SetNdivisions(axis.GetNdivisions(), o); - this->tstyle_->SetAxisColor(axis.GetAxisColor(), o); - this->tstyle_->SetLabelColor(axis.GetLabelColor(), o); - this->tstyle_->SetLabelFont(axis.GetLabelFont(), o); - this->tstyle_->SetLabelOffset(axis.GetLabelOffset(), o); - this->tstyle_->SetLabelSize(axis.GetLabelSize(), o); - this->tstyle_->SetTickLength(axis.GetTickLength(), o); - this->tstyle_->SetTitleOffset(axis.GetTitleOffset(), o); - this->tstyle_->SetTitleSize(axis.GetTitleSize(), o); - this->tstyle_->SetTitleColor(axis.GetTitleColor(), o); - this->tstyle_->SetTitleFont(axis.GetTitleFont(), o); - }; - set_axis(fXaxis, "x"); - set_axis(fYaxis, "y"); - set_axis(fZaxis, "z"); - - tstyle_->SetBarWidth(fBarWidth); - tstyle_->SetBarOffset(fBarOffset); - tstyle_->SetColorModelPS(fColorModelPS); - tstyle_->SetDrawBorder(fDrawBorder); - tstyle_->SetOptLogx(fOptLogx); - tstyle_->SetOptLogy(fOptLogy); - tstyle_->SetOptLogz(fOptLogz); - tstyle_->SetOptDate(fOptDate); - tstyle_->SetOptStat(fOptStat); - tstyle_->SetOptTitle(fOptTitle); - tstyle_->SetOptFile(fOptFile); - tstyle_->SetOptFit(fOptFit); - tstyle_->SetNumberContours(fNumberContours); - if (fShowEventStatus != tstyle_->GetShowEventStatus()) { - tstyle_->ToggleEventStatus(); - } - if (fShowEditor != tstyle_->GetShowEditor()) { - tstyle_->ToggleEditor(); - } - if (fShowToolBar != tstyle_->GetShowToolBar()) { - tstyle_->ToggleToolBar(); - } - tstyle_->GetAttDate()->SetTextFont(fAttDate.GetTextFont()); - tstyle_->GetAttDate()->SetTextSize(fAttDate.GetTextSize()); - tstyle_->GetAttDate()->SetTextAngle(fAttDate.GetTextAngle()); - tstyle_->GetAttDate()->SetTextAlign(fAttDate.GetTextAlign()); - tstyle_->GetAttDate()->SetTextColor(fAttDate.GetTextColor()); - tstyle_->SetDateX(fDateX); - tstyle_->SetDateY(fDateY); - tstyle_->SetEndErrorSize(fEndErrorSize); - tstyle_->SetErrorX(fErrorX); - tstyle_->SetFuncColor(fFuncColor); - tstyle_->SetFuncStyle(fFuncStyle); - tstyle_->SetFuncWidth(fFuncWidth); - tstyle_->SetGridColor(fGridColor); - tstyle_->SetGridStyle(fGridStyle); - tstyle_->SetGridWidth(fGridWidth); - tstyle_->SetLegendBorderSize(fLegendBorderSize); - tstyle_->SetLegendFillColor(fLegendFillColor); - tstyle_->SetLegendFont(fLegendFont); - tstyle_->SetLegendTextSize(fLegendTextSize); - tstyle_->SetHatchesLineWidth(fHatchesLineWidth); - tstyle_->SetHatchesSpacing(fHatchesSpacing); - tstyle_->SetFrameFillColor(fFrameFillColor); - tstyle_->SetFrameLineColor(fFrameLineColor); - tstyle_->SetFrameFillStyle(fFrameFillStyle); - tstyle_->SetFrameLineStyle(fFrameLineStyle); - tstyle_->SetFrameLineWidth(fFrameLineWidth); - tstyle_->SetFrameBorderSize(fFrameBorderSize); - tstyle_->SetFrameBorderMode(fFrameBorderMode); - tstyle_->SetHistFillColor(fHistFillColor); - tstyle_->SetHistLineColor(fHistLineColor); - tstyle_->SetHistFillStyle(fHistFillStyle); - tstyle_->SetHistLineStyle(fHistLineStyle); - tstyle_->SetHistLineWidth(fHistLineWidth); - tstyle_->SetHistMinimumZero(fHistMinimumZero); - tstyle_->SetHistTopMargin(fHistTopMargin); - tstyle_->SetCanvasPreferGL(fCanvasPreferGL); - tstyle_->SetCanvasColor(fCanvasColor); - tstyle_->SetCanvasBorderSize(fCanvasBorderSize); - tstyle_->SetCanvasBorderMode(fCanvasBorderMode); - tstyle_->SetCanvasDefH(fCanvasDefH); - tstyle_->SetCanvasDefW(fCanvasDefW); - tstyle_->SetCanvasDefX(fCanvasDefX); - tstyle_->SetCanvasDefY(fCanvasDefY); - tstyle_->SetPadColor(fPadColor); - tstyle_->SetPadBorderSize(fPadBorderSize); - tstyle_->SetPadBorderMode(fPadBorderMode); - tstyle_->SetPadBottomMargin(fPadBottomMargin); - tstyle_->SetPadTopMargin(fPadTopMargin); - tstyle_->SetPadLeftMargin(fPadLeftMargin); - tstyle_->SetPadRightMargin(fPadRightMargin); - tstyle_->SetPadGridX(fPadGridX); - tstyle_->SetPadGridY(fPadGridY); - tstyle_->SetPadTickX(fPadTickX); - tstyle_->SetPadTickY(fPadTickY); - tstyle_->SetPaperSize(fPaperSizeX, fPaperSizeY); - tstyle_->SetScreenFactor(fScreenFactor); - tstyle_->SetStatColor(fStatColor); - tstyle_->SetStatTextColor(fStatTextColor); - tstyle_->SetStatBorderSize(fStatBorderSize); - tstyle_->SetStatFont(fStatFont); - tstyle_->SetStatFontSize(fStatFontSize); - tstyle_->SetStatStyle(fStatStyle); - tstyle_->SetStatFormat(fStatFormat); - tstyle_->SetStatX(fStatX); - tstyle_->SetStatY(fStatY); - tstyle_->SetStatW(fStatW); - tstyle_->SetStatH(fStatH); - tstyle_->SetStripDecimals(fStripDecimals); - tstyle_->SetTitleAlign(fTitleAlign); - tstyle_->SetTitleColor(fTitleColor); - tstyle_->SetTitleTextColor(fTitleTextColor); - tstyle_->SetTitleBorderSize(fTitleBorderSize); - tstyle_->SetTitleFont(fTitleFont); - tstyle_->SetTitleFontSize(fTitleFontSize); - tstyle_->SetTitleStyle(fTitleStyle); - tstyle_->SetTitleX(fTitleX); - tstyle_->SetTitleY(fTitleY); - tstyle_->SetTitleW(fTitleW); - tstyle_->SetTitleH(fTitleH); - tstyle_->SetLegoInnerR(fLegoInnerR); - - tstyle_->SetHeaderPS(fHeaderPS); - tstyle_->SetTitlePS(fTitlePS); - tstyle_->SetFitFormat(fFitFormat); - tstyle_->SetPaintTextFormat(fPaintTextFormat); - tstyle_->SetLineScalePS(fLineScalePS); - tstyle_->SetJoinLinePS(fJoinLinePS); - tstyle_->SetCapLinePS(fCapLinePS); - tstyle_->SetColorModelPS(fColorModelPS); - tstyle_->SetTimeOffset(fTimeOffset); - tstyle_->SetImageScaling(fImageScaling); - - tstyle_->SetLineColor(fLineColor); - tstyle_->SetLineStyle(fLineStyle); - tstyle_->SetLineWidth(GetLineWidth()); - tstyle_->SetFillColor(GetFillColor()); - tstyle_->SetFillStyle(GetFillStyle()); - tstyle_->SetMarkerColor(GetMarkerColor()); - tstyle_->SetMarkerSize(GetMarkerSize()); - tstyle_->SetMarkerStyle(GetMarkerStyle()); - tstyle_->SetTextAlign(GetTextAlign()); - tstyle_->SetTextAngle(GetTextAngle()); - tstyle_->SetTextColor(GetTextColor()); - tstyle_->SetTextFont(GetTextFont()); - tstyle_->SetTextSize(GetTextSize()); -} - -// ----------------------------------------------------------------------------- -void Style::FromTStyle(TStyle* style) { - auto set_axis = [style](TAttAxis& axis, Option_t* o) { - axis.SetNdivisions(style->GetNdivisions(o)); - axis.SetAxisColor(style->GetAxisColor(o)); - axis.SetLabelColor(style->GetLabelColor(o)); - axis.SetLabelFont(style->GetLabelFont(o)); - axis.SetLabelOffset(style->GetLabelOffset(o)); - axis.SetTickLength(style->GetTickLength(o)); - axis.SetTitleOffset(style->GetTitleOffset(o)); - axis.SetTitleSize(style->GetTitleSize(o)); - axis.SetTitleColor(style->GetTitleColor(o)); - axis.SetTitleFont(style->GetTitleFont(o)); - }; - set_axis(fXaxis, "x"); - set_axis(fYaxis, "y"); - set_axis(fZaxis, "z"); - - fBarWidth = style->GetBarWidth(); - fBarOffset = style->GetBarOffset(); - fColorModelPS = style->GetColorModelPS(); - fDrawBorder = style->GetDrawBorder(); - fOptLogx = style->GetOptLogx(); - fOptLogy = style->GetOptLogy(); - fOptLogz = style->GetOptLogz(); - fOptDate = style->GetOptDate(); - fOptStat = style->GetOptStat(); - fOptTitle = style->GetOptTitle(); - fOptFile = style->GetOptFile(); - fOptFit = style->GetOptFit(); - fShowEventStatus = style->GetShowEventStatus(); - fShowEditor = style->GetShowEditor(); - fShowToolBar = style->GetShowToolBar(); - fNumberContours = style->GetNumberContours(); - fAttDate.SetTextFont(style->GetAttDate()->GetTextFont()); - fAttDate.SetTextSize(style->GetAttDate()->GetTextSize()); - fAttDate.SetTextAngle(style->GetAttDate()->GetTextAngle()); - fAttDate.SetTextAlign(style->GetAttDate()->GetTextAlign()); - fAttDate.SetTextColor(style->GetAttDate()->GetTextColor()); - fDateX = style->GetDateX(); - fDateY = style->GetDateY(); - fEndErrorSize = style->GetEndErrorSize(); - fErrorX = style->GetErrorX(); - fFuncColor = style->GetFuncColor(); - fFuncStyle = style->GetFuncStyle(); - fFuncWidth = style->GetFuncWidth(); - fGridColor = style->GetGridColor(); - fGridStyle = style->GetGridStyle(); - fGridWidth = style->GetGridWidth(); - fLegendBorderSize = style->GetLegendBorderSize(); - fLegendFillColor = style->GetLegendFillColor(); - fLegendFont = style->GetLegendFont(); - fLegendTextSize = style->GetLegendTextSize(); - fHatchesLineWidth = style->GetHatchesLineWidth(); - fHatchesSpacing = style->GetHatchesSpacing(); - fFrameFillColor = style->GetFrameFillColor(); - fFrameLineColor = style->GetFrameLineColor(); - fFrameFillStyle = style->GetFrameFillStyle(); - fFrameLineStyle = style->GetFrameLineStyle(); - fFrameLineWidth = style->GetFrameLineWidth(); - fFrameBorderSize = style->GetFrameBorderSize(); - fFrameBorderMode = style->GetFrameBorderMode(); - fHistFillColor = style->GetHistFillColor(); - fHistLineColor = style->GetHistLineColor(); - fHistFillStyle = style->GetHistFillStyle(); - fHistLineStyle = style->GetHistLineStyle(); - fHistLineWidth = style->GetHistLineWidth(); - fHistMinimumZero = style->GetHistMinimumZero(); - fHistTopMargin = style->GetHistTopMargin(); - fCanvasPreferGL = style->GetCanvasPreferGL(); - fCanvasColor = style->GetCanvasColor(); - fCanvasBorderSize = style->GetCanvasBorderSize(); - fCanvasBorderMode = style->GetCanvasBorderMode(); - fCanvasDefH = style->GetCanvasDefH(); - fCanvasDefW = style->GetCanvasDefW(); - fCanvasDefX = style->GetCanvasDefX(); - fCanvasDefY = style->GetCanvasDefY(); - fPadColor = style->GetPadColor(); - fPadBorderSize = style->GetPadBorderSize(); - fPadBorderMode = style->GetPadBorderMode(); - fPadBottomMargin = style->GetPadBottomMargin(); - fPadTopMargin = style->GetPadTopMargin(); - fPadLeftMargin = style->GetPadLeftMargin(); - fPadRightMargin = style->GetPadRightMargin(); - fPadGridX = style->GetPadGridX(); - fPadGridY = style->GetPadGridY(); - fPadTickX = style->GetPadTickX(); - fPadTickY = style->GetPadTickY(); - style->GetPaperSize(fPaperSizeX, fPaperSizeY); - fScreenFactor = style->GetScreenFactor(); - fStatColor = style->GetStatColor(); - fStatTextColor = style->GetStatTextColor(); - fStatBorderSize = style->GetStatBorderSize(); - fStatFont = style->GetStatFont(); - fStatFontSize = style->GetStatFontSize(); - fStatStyle = style->GetStatStyle(); - fStatFormat = style->GetStatFormat(); - fStatX = style->GetStatX(); - fStatY = style->GetStatY(); - fStatW = style->GetStatW(); - fStatH = style->GetStatH(); - fStripDecimals = style->GetStripDecimals(); - fTitleAlign = style->GetTitleAlign(); - fTitleColor = style->GetTitleColor(); - fTitleTextColor = style->GetTitleTextColor(); - fTitleBorderSize = style->GetTitleBorderSize(); - fTitleFont = style->GetTitleFont(); - fTitleFontSize = style->GetTitleFontSize(); - fTitleStyle = style->GetTitleStyle(); - fTitleX = style->GetTitleX(); - fTitleY = style->GetTitleY(); - fTitleW = style->GetTitleW(); - fTitleH = style->GetTitleH(); - fLegoInnerR = style->GetLegoInnerR(); - - fHeaderPS = style->GetHeaderPS(); - fTitlePS = style->GetTitlePS(); - fFitFormat = style->GetFitFormat(); - fPaintTextFormat = style->GetPaintTextFormat(); - fLineScalePS = style->GetLineScalePS(); - fJoinLinePS = style->GetJoinLinePS(); - fCapLinePS = style->GetCapLinePS(); - fColorModelPS = style->GetColorModelPS(); - fTimeOffset = style->GetTimeOffset(); - fImageScaling = style->GetImageScaling(); - - fLineColor = style->GetLineColor(); - fLineStyle = style->GetLineStyle(); - SetLineWidth(style->GetLineWidth()); - SetFillColor(style->GetFillColor()); - SetFillStyle(style->GetFillStyle()); - SetMarkerColor(style->GetMarkerColor()); - SetMarkerSize(style->GetMarkerSize()); - SetMarkerStyle(style->GetMarkerStyle()); - SetTextAlign(style->GetTextAlign()); - SetTextAngle(style->GetTextAngle()); - SetTextColor(style->GetTextColor()); - SetTextFont(style->GetTextFont()); - SetTextSize(style->GetTextSize()); -} - -} // namespace experimental -} // namespace bdm diff --git a/src/core/analysis/style.h b/src/core/analysis/style.h deleted file mode 100644 index 40a3006ab..000000000 --- a/src/core/analysis/style.h +++ /dev/null @@ -1,169 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_ANALYSIS_STYLE_H_ -#define CORE_ANALYSIS_STYLE_H_ - -#include "TStyle.h" - -namespace bdm { -namespace experimental { - -/// This is just a replacement for TStyle until a bug related to JSON -/// deserialization is resolved. -/// \see https://root-forum.cern.ch/t/error-restoring-tstyle-from-json/44879 -class Style : public TNamed, - public TAttLine, - public TAttFill, - public TAttMarker, - public TAttText { - public: - Style(); - ~Style(); - operator TStyle*() const; - TStyle* GetTStyle() const; - - private: - mutable TStyle* tstyle_ = nullptr; //! - - // The following attributes were copied from TStyle - - TAttAxis fXaxis; ///< X axis attributes - TAttAxis fYaxis; ///< Y axis attributes - TAttAxis fZaxis; ///< Z axis attributes - Float_t fBarWidth; ///< Width of bar for graphs - Float_t fBarOffset; ///< Offset of bar for graphs - Int_t fColorModelPS; ///< PostScript color model: 0 = RGB, 1 = CMYK - Int_t fDrawBorder; ///< Flag to draw border(=1) or not (0) - Int_t fOptLogx; ///< True if log scale in X - Int_t fOptLogy; ///< True if log scale in y - Int_t fOptLogz; ///< True if log scale in z - Int_t fOptDate; ///< True if date option is selected - Int_t fOptStat; ///< True if option Stat is selected - Int_t fOptTitle; ///< True if option Title is selected - Int_t fOptFile; ///< True if option File is selected - Int_t fOptFit; ///< True if option Fit is selected - Int_t fShowEventStatus; ///< Show event status panel - Int_t fShowEditor; ///< Show pad editor - Int_t fShowToolBar; ///< Show toolbar - - Int_t fNumberContours; ///< Default number of contours for 2-d plots - TAttText fAttDate; ///< Canvas date attribute - Float_t fDateX; ///< X position of the date in the canvas (in NDC) - Float_t fDateY; ///< Y position of the date in the canvas (in NDC) - Float_t fEndErrorSize; ///< Size of lines at the end of error bars - Float_t fErrorX; ///< Per cent of bin width for errors along X - Color_t fFuncColor; ///< Function color - Style_t fFuncStyle; ///< Function style - Width_t fFuncWidth; ///< Function line width - Color_t fGridColor; ///< Grid line color (if 0 use axis line color) - Style_t fGridStyle; ///< Grid line style - Width_t fGridWidth; ///< Grid line width - Width_t fLegendBorderSize; ///< Legend box border size - Color_t fLegendFillColor; ///< Legend fill color - Style_t fLegendFont; ///< Legend font style - Double_t fLegendTextSize; ///< Legend text size. If 0 the size is computed - ///< automatically - Int_t fHatchesLineWidth; ///< Hatches line width for hatch styles > 3100 - Double_t fHatchesSpacing; ///< Hatches spacing for hatch styles > 3100 - Color_t fFrameFillColor; ///< Pad frame fill color - Color_t fFrameLineColor; ///< Pad frame line color - Style_t fFrameFillStyle; ///< Pad frame fill style - Style_t fFrameLineStyle; ///< Pad frame line style - Width_t fFrameLineWidth; ///< Pad frame line width - Width_t fFrameBorderSize; ///< Pad frame border size - Int_t fFrameBorderMode; ///< Pad frame border mode - Color_t fHistFillColor; ///< Histogram fill color - Color_t fHistLineColor; ///< Histogram line color - Style_t fHistFillStyle; ///< Histogram fill style - Style_t fHistLineStyle; ///< Histogram line style - Width_t fHistLineWidth; ///< Histogram line width - Bool_t fHistMinimumZero; ///< True if default minimum is 0, false if minimum - ///< is automatic - Double_t fHistTopMargin; ///< Margin between histogram's top and pad's top - Bool_t fCanvasPreferGL; ///< If true, rendering in canvas is with GL - Color_t fCanvasColor; ///< Canvas color - Width_t fCanvasBorderSize; ///< Canvas border size - Int_t fCanvasBorderMode; ///< Canvas border mode - Int_t fCanvasDefH; ///< Default canvas height - Int_t fCanvasDefW; ///< Default canvas width - Int_t fCanvasDefX; ///< Default canvas top X position - Int_t fCanvasDefY; ///< Default canvas top Y position - Color_t fPadColor; ///< Pad color - Width_t fPadBorderSize; ///< Pad border size - Int_t fPadBorderMode; ///< Pad border mode - Float_t fPadBottomMargin; ///< Pad bottom margin - Float_t fPadTopMargin; ///< Pad top margin - Float_t fPadLeftMargin; ///< Pad left margin - Float_t fPadRightMargin; ///< Pad right margin - Bool_t fPadGridX; ///< True to get the grid along X - Bool_t fPadGridY; ///< True to get the grid along Y - Int_t fPadTickX; ///< True to set special pad ticks along X - Int_t fPadTickY; ///< True to set special pad ticks along Y - Float_t fPaperSizeX; ///< PostScript paper size along X - Float_t fPaperSizeY; ///< PostScript paper size along Y - Float_t - fScreenFactor; ///< Multiplication factor for canvas size and position - Color_t fStatColor; ///< Stat fill area color - Color_t fStatTextColor; ///< Stat text color - Width_t fStatBorderSize; ///< Border size of Stats PaveLabel - Style_t fStatFont; ///< Font style of Stats PaveLabel - Float_t - fStatFontSize; ///< Font size in pixels for fonts with precision type 3 - Style_t fStatStyle; ///< Fill area style of Stats PaveLabel - TString fStatFormat; ///< Printing format for stats - Float_t fStatX; ///< X position of top right corner of stat box - Float_t fStatY; ///< Y position of top right corner of stat box - Float_t fStatW; ///< Width of stat box - Float_t fStatH; ///< Height of stat box - Bool_t fStripDecimals; ///< Strip decimals in axis labels - Int_t fTitleAlign; ///< Title box alignment - Color_t fTitleColor; ///< Title fill area color - Color_t fTitleTextColor; ///< Title text color - Width_t fTitleBorderSize; ///< Border size of Title PavelLabel - Style_t fTitleFont; ///< Font style of Title PaveLabel - Float_t - fTitleFontSize; ///< Font size in pixels for fonts with precision type 3 - Style_t fTitleStyle; ///< Fill area style of title PaveLabel - Float_t fTitleX; ///< X position of top left corner of title box - Float_t fTitleY; ///< Y position of top left corner of title box - Float_t fTitleW; ///< Width of title box - Float_t fTitleH; ///< Height of title box - Float_t fLegoInnerR; ///< Inner radius for cylindrical legos - // This is the attribute that causes problems - // TString fLineStyle[30]; ///< String describing line style i (for - // postScript) - TString fHeaderPS; ///< User defined additional Postscript header - TString fTitlePS; ///< User defined Postscript file title - TString fFitFormat; ///< Printing format for fit parameters - TString fPaintTextFormat; ///< Printing format for TH2::PaintText - Float_t fLineScalePS; ///< Line scale factor when drawing lines on Postscript - Int_t fJoinLinePS; ///< Determines the appearance of joining lines on - ///< PostScript, PDF and SVG - Int_t fCapLinePS; ///< Determines the appearance of line caps on PostScript, - ///< PDF and SVG - Double_t fTimeOffset; ///< Time offset to the beginning of an axis - Float_t fImageScaling; ///< Image scaling to produce high definition bitmap - ///< images - - void ToTStyle() const; - void FromTStyle(TStyle* style); - - ClassDefNV(Style, 1); -}; - -} // namespace experimental -} // namespace bdm - -#endif // CORE_ANALYSIS_STYLE_H_ diff --git a/src/core/analysis/time_series.cc b/src/core/analysis/time_series.cc index 11132f5d1..40e6c8bc6 100644 --- a/src/core/analysis/time_series.cc +++ b/src/core/analysis/time_series.cc @@ -13,12 +13,10 @@ // ----------------------------------------------------------------------------- #include "core/analysis/time_series.h" -#include #include #include "core/analysis/reduce.h" #include "core/scheduler.h" #include "core/simulation.h" -#include "core/util/io.h" #include "core/util/log.h" namespace bdm { @@ -189,11 +187,6 @@ real_t TimeSeries::ComputeError(const TimeSeries& ts1, const TimeSeries& ts2) { return error; } -// ----------------------------------------------------------------------------- -void TimeSeries::Load(const std::string& full_filepath, TimeSeries** restored) { - GetPersistentObject(full_filepath.c_str(), "TimeSeries", *restored); -} - // ----------------------------------------------------------------------------- void TimeSeries::Merge( TimeSeries* merged, const std::vector& time_series, @@ -531,15 +524,5 @@ void TimeSeries::ListEntries() const { } } -// ----------------------------------------------------------------------------- -void TimeSeries::Save(const std::string& full_filepath) const { - WritePersistentObject(full_filepath.c_str(), "TimeSeries", *this, "recreate"); -} - -// ----------------------------------------------------------------------------- -void TimeSeries::SaveJson(const std::string& full_filepath) const { - TBufferJSON::ExportToFile(full_filepath.c_str(), this, Class()); -} - } // namespace experimental } // namespace bdm diff --git a/src/core/analysis/time_series.h b/src/core/analysis/time_series.h index ceed0e0bb..815537595 100644 --- a/src/core/analysis/time_series.h +++ b/src/core/analysis/time_series.h @@ -19,7 +19,6 @@ #include #include "core/analysis/reduce.h" #include "core/real_t.h" -#include "core/util/root.h" namespace bdm { @@ -50,8 +49,6 @@ class DataTransformer { virtual void TransformYErrorHigh( const std::vector& old_y_error_high, std::vector& new_y_error_high) const = 0; - - BDM_CLASS_DEF(DataTransformer, 1); }; /// This class implements a linear transformation of the data of a time series. @@ -113,8 +110,6 @@ class LinearTransformer : public DataTransformer { real_t y_error_low_intercept_ = 0.0; real_t y_error_high_slope_ = 1.0; real_t y_error_high_intercept_ = 0.0; - - BDM_CLASS_DEF_OVERRIDE(LinearTransformer, 1); }; /// This class simplifies the collection of time series data during a @@ -133,23 +128,14 @@ class TimeSeries { Data& operator=(const Data& other); Reducer* y_reducer_collector = nullptr; - real_t (*ycollector)(Simulation*) = nullptr; //! - real_t (*xcollector)(Simulation*) = nullptr; //! + real_t (*ycollector)(Simulation*) = nullptr; + real_t (*xcollector)(Simulation*) = nullptr; std::vector x_values; std::vector y_values; std::vector y_error_low; std::vector y_error_high; - BDM_CLASS_DEF_NV(Data, 1); }; - /// Restore a saved TimeSeries object. - /// Usage example: - /// \code - /// TimeSeries* ts_restored; - /// TimeSeries::Load("path/ts.root", &ts_restored); - /// \endcode - static void Load(const std::string& full_filepath, TimeSeries** restored); - /// This function combines several time series into one. /// All time series in parameter `time_series` must have the same entries. /// All entries must have the exact same x values. @@ -167,12 +153,7 @@ class TimeSeries { /// TimeSeries merged; /// TimeSeries::Merge( /// &merged, tss, - /// [](const std::vector& all_y_values, real_t* y, real_t* el, - /// real_t* eh) { - /// *y = TMath::Median(all_y_values.size(), all_y_values.data()); - /// *el = *y - *TMath::LocMin(all_y_values.begin(), all_y_values.end()); - /// *eh = *TMath::LocMax(all_y_values.begin(), all_y_values.end()) - *y; - /// }); + /// merger); /// \endcode /// After these operations, `merged` will contain one entry with id "entry-0" /// with the following arrays: \n @@ -181,7 +162,6 @@ class TimeSeries { /// `y-error-low: {1, 3}` \n /// `y-error-high: {2, 5}` \n /// Of course any other merger can be used too: e.g. mean + stddev - /// \see https://root.cern/doc/master/namespaceTMath.html static void Merge( TimeSeries* merged, const std::vector& time_series, const std::function&, real_t*, real_t*, @@ -241,7 +221,7 @@ class TimeSeries { /// Add new entry with data that is not collected during a simulation. /// This function can for example be used to add experimental data /// which can be later plotted together with the simulation results - /// using a `LineGraph`. + /// using an analysis tool. /// \code /// time_series.Add("experimental-data", {0, 1, 2}, {3, 4, 5}); /// \endcode @@ -287,43 +267,10 @@ class TimeSeries { /// Print all time series entry names to stdout void ListEntries() const; - /// Saves a root file to disk. - void Save(const std::string& full_filepath) const; - - /// Saves a json representation to disk - void SaveJson(const std::string& full_filepath) const; - private: std::unordered_map data_; - - BDM_CLASS_DEF_NV(TimeSeries, 1); }; -// The following custom streamer should be visible to rootcling for dictionary -// generation, but not to the interpreter! -#if (!defined(__CLING__) || defined(__ROOTCLING__)) && defined(USE_DICT) - -// The custom streamer is needed because ROOT can't stream function pointers -// by default. -inline void TimeSeries::Data::Streamer(TBuffer& R__b) { - if (R__b.IsReading()) { - R__b.ReadClassBuffer(TimeSeries::Data::Class(), this); - Long64_t l; - R__b.ReadLong64(l); - this->ycollector = reinterpret_cast(l); - R__b.ReadLong64(l); - this->xcollector = reinterpret_cast(l); - } else { - R__b.WriteClassBuffer(TimeSeries::Data::Class(), this); - Long64_t l = reinterpret_cast(this->ycollector); - R__b.WriteLong64(l); - l = reinterpret_cast(this->xcollector); - R__b.WriteLong64(l); - } -} - -#endif // !defined(__CLING__) || defined(__ROOTCLING__) - } // namespace experimental } // namespace bdm diff --git a/src/core/multi_simulation/algorithm/algorithm.h b/src/core/multi_simulation/algorithm/algorithm.h deleted file mode 100644 index 5b3055bec..000000000 --- a/src/core/multi_simulation/algorithm/algorithm.h +++ /dev/null @@ -1,41 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_H_ -#define CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_H_ - -#include - -#include "core/analysis/time_series.h" -#include "core/functor.h" -#include "core/param/param.h" - -namespace bdm { -namespace experimental { - -using experimental::TimeSeries; - -/// An interface for creating new optimization algorithms -struct Algorithm { - virtual ~Algorithm() = default; - - virtual void operator()( - Functor& dispatch_experiment, - Param* default_param) = 0; -}; - -} // namespace experimental -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_H_ diff --git a/src/core/multi_simulation/algorithm/algorithm_registry.cc b/src/core/multi_simulation/algorithm/algorithm_registry.cc deleted file mode 100644 index 67ccd1cc6..000000000 --- a/src/core/multi_simulation/algorithm/algorithm_registry.cc +++ /dev/null @@ -1,59 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "core/util/log.h" - -namespace bdm { -namespace experimental { - -AlgorithmRegistry::~AlgorithmRegistry() { - for (auto &pair : algorithms_) { - delete pair.second; - } -} - -AlgorithmRegistry *AlgorithmRegistry::GetInstance() { - static AlgorithmRegistry algorithm_registry; - return &algorithm_registry; -} - -Algorithm *AlgorithmRegistry::GetAlgorithm(const std::string &algo_name) { - if (algo_name.empty()) { - Log::Warning("AlgorithmRegistry::GetAlgorithm", - "No algorithm name defined in parameter configuration."); - return nullptr; - } - auto search = algorithms_.find(algo_name); - if (search == algorithms_.end()) { - std::string msg = "Algorithm not found in registry: " + algo_name; - Log::Fatal("AlgorithmRegistry::GetAlgorithm", msg); - } - return search->second; -} - -bool AlgorithmRegistry::AddAlgorithm(const std::string &algo_name, - Algorithm *algo) { - auto algo_it = algorithms_.find(algo_name); - // If algorithm doesn't exist yet, register the new algorithm under given name - if (algo_it == algorithms_.end()) { - algorithms_.insert(std::make_pair(algo_name, algo)); - } - return true; -} - -AlgorithmRegistry::AlgorithmRegistry() = default; - -} // namespace experimental -} // namespace bdm diff --git a/src/core/multi_simulation/algorithm/algorithm_registry.h b/src/core/multi_simulation/algorithm/algorithm_registry.h deleted file mode 100644 index 9afacd4c8..000000000 --- a/src/core/multi_simulation/algorithm/algorithm_registry.h +++ /dev/null @@ -1,84 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_REGISTRY_H_ -#define CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_REGISTRY_H_ - -#include - -#include "core/multi_simulation/algorithm/algorithm.h" -#include "core/multi_simulation/optimization_param.h" -#include "core/param/param.h" - -namespace bdm { -namespace experimental { - -class MultiSimulationManager; - -/// Registry of all optimization algorithms -struct AlgorithmRegistry { - /// Singleton class - returns the static instance - static AlgorithmRegistry *GetInstance(); - - /// Gets the algorithm - /// - /// @param[in] algo_name The algorithm's name - /// - /// @return The algorithm pointer - /// - Algorithm *GetAlgorithm(const std::string &algo_name); - - /// Adds an algorithm to the registry - /// - /// @param[in] algo_name The algorithm's name - /// @param algo The algorithm - /// - /// @return Returns true when the algorithm is successfully added to - /// registry - /// - bool AddAlgorithm(const std::string &algo_name, Algorithm *algo); - - private: - /// The map containing the algorithms; accessible by their name - std::unordered_map algorithms_; - - AlgorithmRegistry(); - ~AlgorithmRegistry(); -}; - -#define BDM_REGISTER_ALGO(op) \ - bool op::registered_ = \ - AlgorithmRegistry::GetInstance()->AddAlgorithm(#op, new op()); - -/// A convenient macro to hide some of the boilerplate code from the user in -/// implementing new algorithms -#define BDM_ALGO_HEADER() \ - private: \ - static bool registered_; - -// Get Optimization Algorithm from registry -inline Algorithm *CreateOptimizationAlgorithm(OptimizationParam *opt_params) { - // Check if the parameters are initialized correctly - for (auto param : opt_params->params) { - param->Validate(); - } - auto ret = - AlgorithmRegistry::GetInstance()->GetAlgorithm(opt_params->algorithm); - return ret; -} - -} // namespace experimental -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_ALGORITHM_ALGORITHM_REGISTRY_H_ diff --git a/src/core/multi_simulation/algorithm/parameter_sweep.cc b/src/core/multi_simulation/algorithm/parameter_sweep.cc deleted file mode 100644 index 08b860473..000000000 --- a/src/core/multi_simulation/algorithm/parameter_sweep.cc +++ /dev/null @@ -1,63 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/algorithm/algorithm.h" -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "core/multi_simulation/dynamic_loop.h" -#include "core/multi_simulation/mpi_helper.h" -#include "core/multi_simulation/optimization_param.h" -#include "core/simulation.h" - -using nlohmann::json; - -namespace bdm { -namespace experimental { - -/// Perform an exhaustive sweep across specified parameters -struct ParameterSweep : public Algorithm { - BDM_ALGO_HEADER(); - - void operator()(Functor& dispatch_experiment, - Param* default_params) override { - auto sweeping_params = default_params->Get()->params; - - if (sweeping_params.empty()) { - Log::Error("ParameterSweep", "No sweeping parameters found!"); - return; - } - - DynamicNestedLoop(sweeping_params, [&](const std::vector& slots) { - json j_patch; - - int i = 0; - for (auto* param : sweeping_params) { - j_patch[param->GetGroupName()][param->GetParamName()] = - param->GetValue(slots[i]); - i++; - } - - Param final_params = *default_params; - final_params.MergeJsonPatch(j_patch.dump()); - - dispatch_experiment(&final_params, nullptr); - }); - }; -}; - -BDM_REGISTER_ALGO(ParameterSweep); - -} // namespace experimental -} // namespace bdm diff --git a/src/core/multi_simulation/algorithm/particle_swarm.cc b/src/core/multi_simulation/algorithm/particle_swarm.cc deleted file mode 100644 index cfff23b2d..000000000 --- a/src/core/multi_simulation/algorithm/particle_swarm.cc +++ /dev/null @@ -1,146 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include -#include "optim.hpp" - -#include "core/multi_simulation/algorithm/algorithm.h" -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "core/multi_simulation/dynamic_loop.h" -#include "core/multi_simulation/experiment.h" -#include "core/multi_simulation/multi_simulation_manager.h" -#include "core/multi_simulation/optimization_param_type/particle_swarm_param.h" -#include "core/util/spinlock.h" - -using nlohmann::json; - -namespace bdm { -namespace experimental { - -/// Implements the particle swarm optimization algorithm -/// For more info: https://www.kthohr.com/optimlib_docs_pso.html -struct ParticleSwarm : public Algorithm { - BDM_ALGO_HEADER(); - - void operator()(Functor& dispatch_experiment, - Param* default_params) override { - OptimizationParam* opt_params = default_params->Get(); - - // The number of times to run an experiment - int repetition = opt_params->repetition; - - // Initial values and the bounds of the free parameters that we want to - // optimize - std::vector param_names; - std::vector init_vals; - std::vector lower_bounds; - std::vector upper_bounds; - - if (opt_params->params.empty()) { - Log::Fatal("ParticleSwarm::operator()", - "No optimization parameters were selected. Please check your " - "parameter configuration."); - } - - for (auto* el : opt_params->params) { - auto* opt_param = dynamic_cast(el); - if (!opt_param) { - Log::Error( - "ParticleSwarm::operator()", - "Encountered non-ParticleSwarmParam type optimization parameter: ", - el->GetParamName()); - continue; - } - param_names.push_back(opt_param->GetParamName()); - init_vals.push_back(opt_param->initial_value); - lower_bounds.push_back(opt_param->lower_bound); - upper_bounds.push_back(opt_param->upper_bound); - } - arma::vec inout(init_vals); - optim::algo_settings_t settings; - settings.vals_bound = true; - settings.lower_bounds = arma::vec(lower_bounds); - settings.upper_bounds = arma::vec(upper_bounds); - settings.pso_n_gen = opt_params->max_iterations; - - auto max_it = settings.pso_n_gen; - int iteration = 0; - real_t min_mse = 1e9; - json best_params; - real_t prev_mse = 1.0; - Spinlock lock; - - // The fitting function (i.e. calling a simulation with a paramset) - // Anything inside this function should be thread-safe - auto fit = [=, &dispatch_experiment, &iteration, &prev_mse, &min_mse, - &best_params, &lock](const arma::vec& free_params, - arma::vec* grad_out, void* opt_data) { - Param new_param = *default_params; - - std::cout << "iteration (" << iteration << "/" << max_it << ")" - << std::endl; - - // Bug: on the rare occasion that we get NaN values back from optim:pso, - // we should ignore it and return the previously obtained error - for (auto& p : free_params) { - if (std::isnan(p)) { - return prev_mse + static_cast(0.005); - } - } - - // Merge the free param values into the Param object that will be sent to - // the worker - json j_patch; - int i = 0; - std::cout << "FP: " << free_params << std::endl; - for (auto* opt_param : opt_params->params) { - j_patch[opt_param->GetGroupName()][opt_param->GetParamName()] = - free_params[i]; - i++; - } - - std::cout << j_patch << std::endl; - - new_param.MergeJsonPatch(j_patch.dump()); - - real_t mse = Experiment(dispatch_experiment, repetition, &new_param); - std::cout << " MSE " << mse << " inout " << free_params << std::endl; - { - std::lock_guard lock_guard(lock); - iteration++; - prev_mse = mse; - // Check if the current error is smaller than the previously smallest - // error If it is, then we save the corresponding parameters as the next - // best set of parameters - if (mse < min_mse) { - min_mse = mse; - best_params = j_patch; - } - } - return mse; - }; - - // Call the optimization routine - if (!optim::pso(inout, fit, nullptr, settings)) { - Log::Fatal("", "Optimization algorithm didn't complete successfully."); - } - - std::cout << "Best params = " << best_params << std::endl; - }; -}; - -BDM_REGISTER_ALGO(ParticleSwarm); - -} // namespace experimental -} // namespace bdm diff --git a/src/core/multi_simulation/database.h b/src/core/multi_simulation/database.h deleted file mode 100644 index 60fe0ea2f..000000000 --- a/src/core/multi_simulation/database.h +++ /dev/null @@ -1,43 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_DATABASE_H_ -#define CORE_MULTI_SIMULATION_DATABASE_H_ - -#include "core/analysis/time_series.h" - -namespace bdm { -namespace experimental { - -using experimental::TimeSeries; - -/// A singleton for storing real-life data in the form of a `TimeSeries` object -/// for the purpose of parameter optimization -class Database { - public: - TimeSeries* data_ = nullptr; - - static Database* GetInstance() { - static Database kDatabase; - return &kDatabase; - } - - private: - Database() = default; -}; - -} // namespace experimental -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_DATABASE_H_ diff --git a/src/core/multi_simulation/dynamic_loop.h b/src/core/multi_simulation/dynamic_loop.h deleted file mode 100644 index fcdf243a3..000000000 --- a/src/core/multi_simulation/dynamic_loop.h +++ /dev/null @@ -1,66 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_DYNAMIC_LOOP_H_ -#define CORE_MULTI_SIMULATION_DYNAMIC_LOOP_H_ - -#include -#include -#include - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" - -namespace bdm { -namespace experimental { - -// Emulates dynamic nested loops. The `action` gets back a vector of integers -// that represent the iteration of each respective `OptimizationParamType` -template -inline void DynamicNestedLoop( - const std::vector& containers, - const Lambda& action) { - // Initialize the slots to hold the iterator value for each depth - auto depth = containers.size(); - if (depth == 0) { - return; - } - std::vector slots(depth, 0); - - // The depth index - size_t index = 0; - while (true) { - action(slots); - - // Increment iterator over outer-most loop - slots[0]++; - - // Carry - while (slots[index] == containers[index]->GetNumElements()) { - // Overflow, we're done - if (index == depth - 1) { - return; - } - - slots[index++] = 0; - slots[index]++; - } - - index = 0; - } -} - -} // namespace experimental -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_DYNAMIC_LOOP_H_ diff --git a/src/core/multi_simulation/experiment.h b/src/core/multi_simulation/experiment.h deleted file mode 100644 index 000bfc808..000000000 --- a/src/core/multi_simulation/experiment.h +++ /dev/null @@ -1,87 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_EXPERIMENT_H_ -#define CORE_MULTI_SIMULATION_EXPERIMENT_H_ - -#include -#include - -#include "TMath.h" - -#include "core/analysis/time_series.h" -#include "core/functor.h" -#include "core/multi_simulation/database.h" -#include "core/param/param.h" -#include "core/real_t.h" - -namespace bdm { -namespace experimental { - -// Runs the given `simulation` for `iterations` amount of times` and computes -// the mean of the simulated results. If a real (experimental / analytical) -// dataset is presented (either as the argument or through a database), we -// compute the average error and return it -inline real_t Experiment( - Functor& simulation, size_t iterations, - const Param* param, TimeSeries* real_ts = nullptr, - Functor&, const TimeSeries&, - const TimeSeries&>* post_simulation = nullptr) { - // If no experimental / analytical data is given, we try to extract it from - // the database - bool use_real_data = true; - if (!real_ts) { - real_ts = Database::GetInstance()->data_; - // If also no real data is present in the database, we just run the - // simulation - if (!real_ts) { - use_real_data = false; - } - } - - // Run the simulation with the input parameters for N iterations - std::vector results(iterations); - for (size_t i = 0; i < iterations; i++) { - Param param_copy = *param; - simulation(¶m_copy, &results[i]); - } - - // Compute the mean result values of the N iterations - TimeSeries simulated; - TimeSeries::Merge(&simulated, results, - [](const std::vector all_y_values, real_t* y, - real_t* eh, real_t* el) { - *y = - TMath::Mean(all_y_values.begin(), all_y_values.end()); - }); - - // Execute post-simulation lambda (e.g. plotting or exporting of simulated - // data) - if (post_simulation) { - (*post_simulation)(results, simulated, *real_ts); - } - - if (use_real_data) { - // Compute and return the error between the real and simulated data - real_t err = TimeSeries::ComputeError(*real_ts, simulated); - - return err; - } - return 0.0; -} - -} // namespace experimental -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_EXPERIMENT_H_ diff --git a/src/core/multi_simulation/mpi_helper.h b/src/core/multi_simulation/mpi_helper.h deleted file mode 100644 index b071e73db..000000000 --- a/src/core/multi_simulation/mpi_helper.h +++ /dev/null @@ -1,84 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_MPI_HELPER_H_ -#define CORE_MULTI_SIMULATION_MPI_HELPER_H_ - -#include -#include -#include - -#include - -// Hide MPI headers from Cling -#if (!defined(__CLING__) && !defined(__ROOTCLING__)) -#include "mpi.h" -#endif // __ROOTCLING__ - -#include "core/util/log.h" -#include "core/util/root.h" - -namespace bdm { -namespace experimental { - -#ifdef USE_MPI - -/// Need this class to assign a buffer to TMessage. TMessage constructor -/// is protected. TMessage::SetBuffer doesn't do what we want. So we use this. -class MPIObject : public TMessage { - public: - MPIObject() = default; - ~MPIObject() override = default; - MPIObject(void* buf, Int_t len) : TMessage(buf, len) {} - - private: - BDM_CLASS_DEF_OVERRIDE(MPIObject, 1); -}; - -// Hide MPI functions from Cling -#if (!defined(__CLING__) && !defined(__ROOTCLING__)) -/// Send object to worker using ROOT Serialization -template -int MPI_Send_Obj_ROOT(T* obj, int dest, int tag, - MPI_Status* status = MPI_STATUS_IGNORE) { - MPIObject mpio; - mpio.WriteObject(obj); - int size = mpio.Length(); - // First send the size of the buffer - MPI_Send(&size, 1, MPI_INT, dest, tag, MPI_COMM_WORLD); - // Then send the buffer - return MPI_Send(mpio.Buffer(), size, MPI_BYTE, dest, tag, MPI_COMM_WORLD); -} - -/// Receive object from master using ROOT Serialization -template -T* MPI_Recv_Obj_ROOT(int size, int source, int tag, - MPI_Status* status = MPI_STATUS_IGNORE) { - char* buf = (char*)malloc(size); - // Then receive the buffer - MPI_Recv(buf, size, MPI_BYTE, source, tag, MPI_COMM_WORLD, status); - MPIObject* mpio = new MPIObject(buf, size); - T* obj = (T*)(mpio->ReadObject(mpio->GetClass())); - free(buf); - return obj; -} - -#endif // __ROOTCLING__ - -} // namespace experimental -} // namespace bdm - -#endif // USE_MPI - -#endif // CORE_MULTI_SIMULATION_MPI_HELPER_H_ diff --git a/src/core/multi_simulation/multi_simulation.cc b/src/core/multi_simulation/multi_simulation.cc deleted file mode 100644 index 748b819d7..000000000 --- a/src/core/multi_simulation/multi_simulation.cc +++ /dev/null @@ -1,103 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifdef USE_MPI - -#include "mpi.h" - -#include "TROOT.h" -#include "TSystem.h" - -#include -#include - -#include "core/analysis/time_series.h" -#include "core/multi_simulation/database.h" -#include "core/multi_simulation/multi_simulation.h" -#include "core/multi_simulation/multi_simulation_manager.h" -#include "core/multi_simulation/optimization_param.h" -#include "core/param/command_line_options.h" - -namespace bdm { -namespace experimental { - -MultiSimulation::MultiSimulation(int argc, const char** argv) - : argc_(argc), argv_(argv) { - // MPI_Init needs a non-const version of argv, so we make a deep copy - argv_copy_ = (char**)malloc((argc_ + 1) * sizeof(char*)); - for (int i = 0; i < argc_; ++i) { - size_t length = strlen(argv_[i]) + 1; - argv_copy_[i] = (char*)malloc(length); - memcpy(argv_copy_[i], argv_[i], length); - } - argv_copy_[argc_] = nullptr; -} - -MultiSimulation::MultiSimulation(int argc, const char** argv, TimeSeries* real) - : MultiSimulation(argc, argv) { - // Register the real data to the database - auto* db = Database::GetInstance(); - db->data_ = real; -} - -MultiSimulation::~MultiSimulation() { - for (int i = 0; i < argc_; ++i) { - free(argv_copy_[i]); - } - free(argv_copy_); -} - -int MultiSimulation::Execute(const TSimulate& simulate_call) { - int worldsize, provided, myrank; - MPI_Init_thread(&argc_, &argv_copy_, MPI_THREAD_MULTIPLE, &provided); - if (provided < MPI_THREAD_MULTIPLE) { - Log::Error("MPI_Init_thread", - "The threading support level is lesser than that demanded."); - MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE); - } - MPI_Comm_size(MPI_COMM_WORLD, &worldsize); - MPI_Comm_rank(MPI_COMM_WORLD, &myrank); - - ROOT::EnableThreadSafety(); - - int status; - if (myrank == 0) { - // Make a copy of the default parameters - Simulation simulation(argc_, argv_); - Param default_params = *(simulation.GetParam()); - - // Start the Master routine - MultiSimulationManager pem( - worldsize, &default_params, [&](Param* params, TimeSeries* result) { - return simulate_call(argc_, argv_, result, params); - }); - - status = pem.Start(); - } else { - omp_set_num_threads(2); - // Start the Worker routine (`params` to be received by Master) - Worker w(myrank, [&](Param* params, TimeSeries* result) { - return simulate_call(argc_, argv_, result, params); - }); - status = w.Start(); - } - - MPI_Finalize(); - return status; -} - -} // namespace experimental -} // namespace bdm - -#endif // USE_MPI diff --git a/src/core/multi_simulation/multi_simulation.h b/src/core/multi_simulation/multi_simulation.h deleted file mode 100644 index 424ec64e6..000000000 --- a/src/core/multi_simulation/multi_simulation.h +++ /dev/null @@ -1,59 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_MULTI_SIMULATION_H_ -#define CORE_MULTI_SIMULATION_MULTI_SIMULATION_H_ - -#ifdef USE_MPI - -#include -#include - -#include "core/analysis/time_series.h" -#include "core/param/param.h" - -namespace bdm { -namespace experimental { - -using experimental::TimeSeries; - -// Signature of the Simulate() call -using TSimulate = std::function; - -class MultiSimulation { - public: - MultiSimulation(int argc, const char** argv); - - MultiSimulation(int argc, const char** argv, TimeSeries* real); - - ~MultiSimulation(); - - void DeleteResultFiles(const std::string& dir); - - void MergeResultFiles(const std::string& dir); - - int Execute(const TSimulate& simulate_call); - - private: - int argc_ = 0; - const char** argv_ = nullptr; - char** argv_copy_ = nullptr; -}; - -} // namespace experimental -} // namespace bdm - -#endif // USE_MPI - -#endif // CORE_MULTI_SIMULATION_MULTI_SIMULATION_H_ diff --git a/src/core/multi_simulation/multi_simulation_manager.cc b/src/core/multi_simulation/multi_simulation_manager.cc deleted file mode 100644 index 34a58ef34..000000000 --- a/src/core/multi_simulation/multi_simulation_manager.cc +++ /dev/null @@ -1,283 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifdef USE_MPI - -#include - -#include "mpi.h" - -#include "core/functor.h" -#include "core/multi_simulation/mpi_helper.h" -#include "core/multi_simulation/multi_simulation_manager.h" -#include "core/multi_simulation/optimization_param.h" -#include "core/scheduler.h" -#include "core/util/timing.h" - -using std::cout; -using std::endl; -using std::string; -using std::to_string; -using std::vector; - -namespace bdm { -namespace experimental { - -/// The Master in a Master-Worker design pattern. Maintains the status of all -/// the workers in the MPI runtime. -void MultiSimulationManager::Log(string s) { - Log::Info("MultiSimulationManager", "[M]: ", s); -} - -MultiSimulationManager::MultiSimulationManager( - int ws, Param *default_params, - std::function simulate) - : worldsize_(ws), default_params_(default_params), simulate_(simulate) { - Log("Started Master process"); - availability_.resize(ws); - timings_.resize(ws); -} - -void MultiSimulationManager::WriteTimingsToFile() { - std::ofstream myfile; - myfile.open("timing_results.csv"); - int worker = 0; - myfile << "worker_id,simulation_runtime,mpi_runtime" << std::endl; - for (auto &t : timings_) { - myfile << worker << ","; - myfile << t["SIMULATE"] << ","; - myfile << t["MPI_CALL"] << std::endl; - worker++; - } - myfile.close(); - Log("Timing results of all workers have been written to " - "timing_results.csv."); -} - -MultiSimulationManager::~MultiSimulationManager() { - Log("Completed all tasks"); -} - -void MultiSimulationManager::IngestData(const std::string &data_file) {} - -// Copy the timing results of the specified worker -void MultiSimulationManager::RecordTiming(int worker, TimingAggregator *agg) { - timings_[worker] = *agg; -} - -// Send kill message to all workers -void MultiSimulationManager::KillAllWorkers() { - ForAllWorkers([&](int worker) { - { - Timing t_mpi("MPI_CALL", &ta_); - MPI_Send(nullptr, 0, MPI_INT, worker, Tag::kKill, MPI_COMM_WORLD); - } - }); -} - -// Receive timing objects of all workers -void MultiSimulationManager::GetTimingsFromWorkers() { - ForAllWorkers([&](int worker) { - int size; - MPI_Status status; - { - Timing t_mpi("MPI_CALL", &ta_); - MPI_Recv(&size, 1, MPI_INT, MPI_ANY_SOURCE, Tag::kKill, MPI_COMM_WORLD, - &status); - } - TimingAggregator *agg = MPI_Recv_Obj_ROOT( - size, status.MPI_SOURCE, Tag::kKill); - RecordTiming(status.MPI_SOURCE, agg); - }); -} - -int MultiSimulationManager::Start() { - { - Timing t_tot("TOTAL", &ta_); - - // Wait for all workers to reach this barrier - MPI_Barrier(MPI_COMM_WORLD); - - // Change status of all workers to 'available' after barrier has been - // reached - ForAllWorkers( - [&](int worker) { ChangeStatusWorker(worker, Status::kAvail); }); - - auto dispatch_experiment = - L2F([&](Param *final_params, TimeSeries *result) { - // If there is only one MPI process, the master performs the - // simulation - if (worldsize_ == 1) { - simulate_(final_params, result); - } else { // Otherwise we dispatch the work to the worker(s) - auto worker = GetFirstAvailableWorker(); - - // If there is no available worker, wait for one to finish - while (worker == -1) { - std::this_thread::sleep_for(std::chrono::milliseconds(100)); - worker = GetFirstAvailableWorker(); - } - - // Send parameters to worker - { - Timing t_mpi("MPI_CALL", &ta_); - MPI_Send_Obj_ROOT(final_params, worker, Tag::kTask); - } - - // Wait for results - MPI_Status status; - { - int size; - MPI_Recv(&size, 1, MPI_INT, worker, Tag::kResult, MPI_COMM_WORLD, - &status); - string msg = "Receiving results from worker " + - to_string(status.MPI_SOURCE); - Log(msg); - Timing t_mpi("MPI_CALL", &ta_); - TimeSeries *tmp_result = - MPI_Recv_Obj_ROOT(size, worker, Tag::kResult); - msg = "Successfully received results from worker " + - to_string(status.MPI_SOURCE); - Log(msg); - *result = *tmp_result; - delete tmp_result; - } - - ChangeStatusWorker(status.MPI_SOURCE, Status::kAvail); - } - }); - - // From default_params read out the OptimizationParam section to - // determine the algorithm type: e.g. ParameterSweep, Differential - // Evolution, Particle Swarm Optimization - OptimizationParam *opt_params = default_params_->Get(); - auto algorithm = CreateOptimizationAlgorithm(opt_params); - - if (algorithm) { - (*algorithm)(dispatch_experiment, default_params_); - } else { - dispatch_experiment(default_params_, new TimeSeries()); - } - - KillAllWorkers(); - GetTimingsFromWorkers(); - } - - // Record master's timing - RecordTiming(kMaster, &ta_); - - // Write all timing info to file - WriteTimingsToFile(); - - return 0; -} - -// Returns the ID of the first available worker in the list. Returns -1 if -// there is no available worker. -int MultiSimulationManager::GetFirstAvailableWorker() { - int ret = -1; -#pragma omp critical - { - auto it = std::find(begin(availability_), end(availability_), true); - if (it != end(availability_)) { - ret = std::distance(begin(availability_), it); - ChangeStatusWorker(ret, Status::kBusy); - } - } - return ret; -} - -// Changes the status of a worker -void MultiSimulationManager::ChangeStatusWorker(int worker, Status s) { - std::stringstream msg; - msg << "Changing status of [W" << worker << "] to " << s; - Log(msg.str()); - availability_[worker] = s; -} - -// Executes the specified function for all workers. Starting from index 1, -// because 0 is the master's ID. -void MultiSimulationManager::ForAllWorkers( - const std::function &lambda) { - for (int i = 1; i < worldsize_; i++) { - lambda(i); - } -} - -/// The Worker class in a Master-Worker design pattern. -Worker::Worker(int myrank, std::function simulate) - : myrank_(myrank), simulate_(simulate) { - Log("Started"); -} - -Worker::~Worker() { - string msg = "Stopped (Completed " + to_string(task_count_) + " tasks)"; - Log(msg); -} - -int Worker::Start() { - Timing tot("TOTAL", &ta_); - - // Wait for all MPI processes to reach this barrier - MPI_Barrier(MPI_COMM_WORLD); - - while (true) { - MPI_Status status; - int size; - // Receive the command type. If the command is a task, we use the `size` - // argument as the size of the object we're about to receive - { - Timing t("MPI_CALL", &ta_); - MPI_Recv(&size, 1, MPI_INT, kMaster, MPI_ANY_TAG, MPI_COMM_WORLD, - &status); - } - - // The tag tells us what kind of message we received from Master - switch (status.MPI_TAG) { - case Tag::kTask: { - Param *params = nullptr; - { - Timing t("MPI_CALL", &ta_); - params = MPI_Recv_Obj_ROOT(size, kMaster, Tag::kTask); - } - TimeSeries result; - { - Timing sim("SIMULATE", &ta_); - simulate_(params, &result); - } - IncrementTaskCount(); - { - Timing t("MPI_CALL", &ta_); - Log("Sending back results"); - MPI_Send_Obj_ROOT(&result, kMaster, Tag::kResult); - } - break; - } - case Tag::kKill: - // Send back the timing results to the master for writing to file - MPI_Send_Obj_ROOT(&ta_, kMaster, Tag::kKill); - return 0; - default: - Log("Received unknown message tag. Stopping..."); - return 1; - } - } -} - -void Worker::IncrementTaskCount() { task_count_++; } - -} // namespace experimental -} // namespace bdm - -#endif // USE_MPI diff --git a/src/core/multi_simulation/multi_simulation_manager.h b/src/core/multi_simulation/multi_simulation_manager.h deleted file mode 100644 index 6b8deb332..000000000 --- a/src/core/multi_simulation/multi_simulation_manager.h +++ /dev/null @@ -1,125 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_MULTI_SIMULATION_MANAGER_H_ -#define CORE_MULTI_SIMULATION_MULTI_SIMULATION_MANAGER_H_ - -#ifdef USE_MPI - -#include -#include -#include -#include -#include -#include -#include - -#include "core/analysis/time_series.h" -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "core/multi_simulation/dynamic_loop.h" -#include "core/util/timing_aggregator.h" - -using std::cout; -using std::endl; -using std::string; -using std::to_string; -using std::vector; - -namespace bdm { -namespace experimental { - -static const unsigned int kMaster = 0; - -enum Status { kBusy, kAvail }; -enum Tag { kReady, kResult, kTask, kKill }; - -/// The Master in a Master-Worker design pattern. Maintains the status of all -/// the workers in the multi-simulation runtime. -class MultiSimulationManager { - public: - void Log(string s); - - explicit MultiSimulationManager( - int ws, Param *default_params, - std::function simulate); - - void WriteTimingsToFile(); - - void IngestData(const std::string &data_file); - - ~MultiSimulationManager(); - - // Copy the timing results of the specified worker - void RecordTiming(int worker, TimingAggregator *agg); - - // Send kill message to all workers - void KillAllWorkers(); - - // Receive timing objects of all workers - void GetTimingsFromWorkers(); - - int Start(); - - private: - friend struct ParticleSwarm; - // Returns the ID of the first available worker in the list. Returns -1 if - // there is no available worker. - int GetFirstAvailableWorker(); - - // Changes the status - void ChangeStatusWorker(int worker, Status s); - - // Executes the specified function for all workers. Starting from index 1, - // because 0 is the master's ID. - void ForAllWorkers(const std::function &lambda); - - vector availability_; - int worldsize_; - TimingAggregator ta_; - Param *default_params_; - std::function simulate_; - std::vector timings_; -}; - -/// The Worker class in a Master-Worker design pattern of the multi-simulation -/// runtime -class Worker { - public: - explicit Worker(int myrank, - std::function simulate); - - template - void Log(T s) { - Log::Info("MultiSimulationManager", "[W", myrank_, "]: ", s); - } - - ~Worker(); - - int Start(); - - private: - void IncrementTaskCount(); - - int myrank_; - unsigned int task_count_ = 0; - std::function simulate_; - TimingAggregator ta_; -}; - -} // namespace experimental -} // namespace bdm - -#endif // USE_MPI - -#endif // CORE_MULTI_SIMULATION_MULTI_SIMULATION_MANAGER_H_ diff --git a/src/core/multi_simulation/optimization_param.h b/src/core/multi_simulation/optimization_param.h deleted file mode 100644 index 7f306f835..000000000 --- a/src/core/multi_simulation/optimization_param.h +++ /dev/null @@ -1,48 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_H_ - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" -#include "core/param/param.h" -#include "core/param/param_group.h" - -namespace bdm { - -struct OptimizationParam : public ParamGroup { - BDM_PARAM_GROUP_HEADER(OptimizationParam, 1); - - OptimizationParam(const OptimizationParam& other) { - this->params.resize(other.params.size()); - int i = 0; - for (auto* param : other.params) { - this->params[i] = param->GetCopy(); - i++; - } - this->algorithm = other.algorithm; - this->repetition = other.repetition; - } - - std::string algorithm; - std::vector params; - // Number of times to repeat an experiment - size_t repetition = 1; - // Maximum number of optimization iterations - size_t max_iterations = 100; -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_H_ diff --git a/src/core/multi_simulation/optimization_param_type/log_range_param.h b/src/core/multi_simulation/optimization_param_type/log_range_param.h deleted file mode 100644 index ee56361d3..000000000 --- a/src/core/multi_simulation/optimization_param_type/log_range_param.h +++ /dev/null @@ -1,77 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_LOG_RANGE_PARAM_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_LOG_RANGE_PARAM_H_ - -#include -#include - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" -#include "core/util/log.h" - -namespace bdm { - -/// A uniform range of logarithmically scaled values (e.g. 1, 10, 100, 1000) -struct LogRangeParam : public OptimizationParamType { - LogRangeParam() = default; - LogRangeParam(const std::string& n, real_t base, real_t min, real_t max, - real_t stride) - : OptimizationParamType(n), - base(base), - lower_bound(min), - upper_bound(max), - stride(stride) { - Validate(); - }; - - void Validate() const override { - if (lower_bound > upper_bound) { - Log::Fatal("LogRangeParam", "Tried to initialize parameter '", param_name, - "' with a lower_bound value higher than upper_bound: ", - lower_bound, " > ", upper_bound); - } - } - - OptimizationParamType* GetCopy() const override { - return new LogRangeParam(*this); - } - - // Get the nth value - real_t GetValue(int n) const override { - real_t exp = lower_bound + n * stride; - return exp > upper_bound ? std::pow(base, upper_bound) - : std::pow(base, exp); - } - - // Returns the number of discrete values that this range contains (including - // the `lower_bound` and `upper_bound` values) - uint32_t GetNumElements() const override { - return std::round(((upper_bound - lower_bound) + stride) / stride); - } - - // The base value - real_t base = 10; - // The minimum value - real_t lower_bound = 0; - // THe maximum value - real_t upper_bound = 0; - // The stride - real_t stride = 1; - BDM_CLASS_DEF_OVERRIDE(LogRangeParam, 1); -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_LOG_RANGE_PARAM_H_ diff --git a/src/core/multi_simulation/optimization_param_type/optimization_param_type.h b/src/core/multi_simulation/optimization_param_type/optimization_param_type.h deleted file mode 100644 index 6bd873888..000000000 --- a/src/core/multi_simulation/optimization_param_type/optimization_param_type.h +++ /dev/null @@ -1,58 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_OPTIMIZATION_PARAM_TYPE_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_OPTIMIZATION_PARAM_TYPE_H_ - -#include -#include - -#include "core/real_t.h" -#include "core/util/io.h" - -namespace bdm { - -/// An interface for creating different types of optimization parameters -struct OptimizationParamType { - OptimizationParamType() = default; - explicit OptimizationParamType(const std::string& name) : param_name(name) {} - virtual ~OptimizationParamType() = default; - - virtual OptimizationParamType* GetCopy() const = 0; - - virtual uint32_t GetNumElements() const = 0; - virtual real_t GetValue(int n) const = 0; - virtual void Validate() const {}; - - // Return the substring before the last "::", which should be - // bdm:: - std::string GetGroupName() { - size_t found = param_name.find_last_of("::"); - return param_name.substr(0, found - 1); - } - - // Return the substring after the last "::", which should be - std::string GetParamName() { - size_t found = param_name.find_last_of("::"); - return param_name.substr(found + 1); - } - - // Must be in format bdm:::: - std::string param_name; - BDM_CLASS_DEF(OptimizationParamType, 1); -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_OPTIMIZATION_PARAM_TYPE_H_ diff --git a/src/core/multi_simulation/optimization_param_type/particle_swarm_param.h b/src/core/multi_simulation/optimization_param_type/particle_swarm_param.h deleted file mode 100644 index 572c8113f..000000000 --- a/src/core/multi_simulation/optimization_param_type/particle_swarm_param.h +++ /dev/null @@ -1,73 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_PARTICLE_SWARM_PARAM_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_PARTICLE_SWARM_PARAM_H_ - -#include - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" -#include "core/util/log.h" - -namespace bdm { - -/// A parameter type exclusively used for the Particle Swarm optimization -/// algorithm Defines an initial value, and the lower and upper bound -struct ParticleSwarmParam : public OptimizationParamType { - ParticleSwarmParam() = default; - ParticleSwarmParam(const std::string& name, real_t min, real_t max, real_t iv) - : OptimizationParamType(name), - lower_bound(min), - upper_bound(max), - initial_value(iv) { - Validate(); - }; - - void Validate() const override { - if (lower_bound > upper_bound) { - Log::Fatal( - "ParticleSwarmParam", "Tried to initialize parameter '", param_name, - "' with a lower_bound value higher than upper_bound: ", lower_bound, - " > ", upper_bound); - } - } - - OptimizationParamType* GetCopy() const override { - return new ParticleSwarmParam(*this); - } - - real_t GetValue(int n) const override { - Log::Fatal("ParticleSwarmParam::GetValue", - "Invalid operation! Values are obtained through the " - "optimization library."); - return 0.0; - } - - uint32_t GetNumElements() const override { - Log::Fatal("ParticleSwarmParam::GetValue", "Invalid operation!"); - return 0.0; - } - - // The minimum value - real_t lower_bound = 0; - // THe maximum value - real_t upper_bound = 0; - // The stride - real_t initial_value = 1; - BDM_CLASS_DEF_OVERRIDE(ParticleSwarmParam, 1); -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_PARTICLE_SWARM_PARAM_H_ diff --git a/src/core/multi_simulation/optimization_param_type/range_param.h b/src/core/multi_simulation/optimization_param_type/range_param.h deleted file mode 100644 index 5fff57356..000000000 --- a/src/core/multi_simulation/optimization_param_type/range_param.h +++ /dev/null @@ -1,73 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_RANGE_PARAM_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_RANGE_PARAM_H_ - -#include -#include - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" -#include "core/util/log.h" - -namespace bdm { - -/// A uniform range of values (e.g. [1,2,3,4,5]) -/// All values are interpreted as real_t precision floating point types -struct RangeParam : public OptimizationParamType { - RangeParam() = default; - RangeParam(const std::string& name, real_t min, real_t max, real_t stride) - : OptimizationParamType(name), - lower_bound(min), - upper_bound(max), - stride(stride) { - Validate(); - }; - - void Validate() const override { - if (lower_bound > upper_bound) { - Log::Fatal("RangeParam", "Tried to initialize parameter '", param_name, - "' with a lower_bound value higher than upper_bound: ", - lower_bound, " > ", upper_bound); - } - } - - OptimizationParamType* GetCopy() const override { - return new RangeParam(*this); - } - - // Get the nth value - real_t GetValue(int n) const override { - real_t curr = lower_bound + n * stride; - return curr > upper_bound ? upper_bound : curr; - } - - // Returns the number of discrete values that this range contains (including - // the `lower_bound` and `upper_bound` values) - uint32_t GetNumElements() const override { - return std::round(((upper_bound - lower_bound) + stride) / stride); - } - - // The minimum value - real_t lower_bound = 0; - // THe maximum value - real_t upper_bound = 0; - // The stride - real_t stride = 1; - BDM_CLASS_DEF_OVERRIDE(RangeParam, 1); -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_RANGE_PARAM_H_ diff --git a/src/core/multi_simulation/optimization_param_type/set_param.h b/src/core/multi_simulation/optimization_param_type/set_param.h deleted file mode 100644 index f6fad7bd6..000000000 --- a/src/core/multi_simulation/optimization_param_type/set_param.h +++ /dev/null @@ -1,48 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_SET_PARAM_H_ -#define CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_SET_PARAM_H_ - -#include -#include - -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" - -namespace bdm { - -/// A set of values (e.g. [-12, 3.2, 43, 98]) -/// All values are interpreted as real_t precision floating point types -struct SetParam : public OptimizationParamType { - SetParam() = default; - SetParam(const std::string& name, const std::vector v) - : OptimizationParamType(name), values(v) {} - - OptimizationParamType* GetCopy() const override { - return new SetParam(*this); - } - - size_t size() const { return values.size(); } - real_t at(size_t n) const { return values.at(n); } - - uint32_t GetNumElements() const override { return this->size(); } - real_t GetValue(int n) const override { return this->at(n); } - - std::vector values; - BDM_CLASS_DEF_OVERRIDE(SetParam, 1); -}; - -} // namespace bdm - -#endif // CORE_MULTI_SIMULATION_OPTIMIZATION_PARAM_TYPE_SET_PARAM_H_ diff --git a/src/core/param/command_line_options.cc b/src/core/param/command_line_options.cc index 6d7c6b9e1..bb3e837e5 100644 --- a/src/core/param/command_line_options.cc +++ b/src/core/param/command_line_options.cc @@ -13,10 +13,7 @@ // ----------------------------------------------------------------------------- #include "core/param/command_line_options.h" -#include #include -#include "core/param/param.h" -#include "core/util/io.h" #include "core/util/log.h" namespace bdm { @@ -32,13 +29,6 @@ CommandLineOptions::CommandLineOptions(int argc, const char** argv) ExtractSimulationName(argv[0]); } -CommandLineOptions::~CommandLineOptions() { - if (parser_) { - delete parser_; - parser_ = nullptr; - } -} - cxxopts::OptionAdder CommandLineOptions::AddOption(string group) { if (parser_ != nullptr) { Log::Fatal("CommandLineOptions::AddOption", @@ -52,24 +42,26 @@ std::string CommandLineOptions::GetSimulationName() const { return sim_name_; } /// Parse the given command line arguments void CommandLineOptions::Parse() { - // Make a non-const deep copy of argv - char** argv_copy = (char**)malloc((argc_ + 1) * sizeof(char*)); - int argc_copy = argc_; + std::vector arguments; + arguments.reserve(argc_); for (int i = 0; i < argc_; ++i) { - size_t length = strlen(argv_[i]) + 1; - argv_copy[i] = (char*)malloc(length); - memcpy(argv_copy[i], argv_[i], length); + arguments.emplace_back(argv_[i]); } - argv_copy[argc_] = nullptr; - // Perform parsing (consumes argc_copy and argv_copy) - if (parser_) { - delete parser_; - parser_ = nullptr; + std::vector argument_pointers; + argument_pointers.reserve(arguments.size() + 1); + for (auto& argument : arguments) { + argument_pointers.push_back(argument.data()); } + argument_pointers.push_back(nullptr); + + int argc_copy = argc_; + char** argv_copy = argument_pointers.data(); + parser_.reset(); try { - parser_ = new cxxopts::ParseResult(options_.parse(argc_copy, argv_copy)); + parser_ = std::make_unique( + options_.parse(argc_copy, argv_copy)); } catch (const cxxopts::option_not_exists_exception& option) { Log::Fatal("CommandLineOptions::ParseResult", option.what(), " Perhaps you are constructing multiple Simulation objects with " @@ -81,12 +73,6 @@ void CommandLineOptions::Parse() { HandleCoreOptions(); first_parse_ = false; } - - // free memory - for (int i = 0; i < argc_; ++i) { - free(argv_copy[i]); - } - free(argv_copy); } bool CommandLineOptions::IsSet(std::string option) { @@ -107,14 +93,7 @@ void CommandLineOptions::AddCoreOptions() { ("vis-frequency", "Set the frequency of exporting the visualization.", value()->default_value("10"), "FREQ") ("v, verbose", "Verbose mode. Causes BioDynaMo to print debugging messages. Multiple " "-v options increases the verbosity. The maximum is 3.", value()) - ("r, restore", "Restores the simulation from the checkpoint found in FILE and " - "continues simulation from that point.", value()->default_value(""), "FILE") - ("b, backup", "Periodically create full simulation backup to the specified file. " - "NOTA BENE: File will be overridden if it exists.", value()->default_value(""), "FILE") - ("c, config", "The TOML or JSON configuration that should be used. The JSON file must be in JSON merge patch format (https://tools.ietf.org/html/rfc7386). This option can be used multiple times.", value>()->default_value(""), "FILE") - ("inline-config", "JSON configuration string passed directly on the command line. Overwrites values specified in config file. The JSON string must be in JSON merge patch format (https://tools.ietf.org/html/rfc7386). This option can be used multiple times.", value>()->default_value(""), "JSON_STRING") - ("output-default-json", "Prints a JSON string with all parameters and their default values and exits.") - ("toml-to-json", "Converts a TOML file to a JSON patch. After printing the JSON patch the application will exit.", value()->default_value(""), "TOML_FILE"); + ("c, config", "The TOML configuration that should be used. This option can be used multiple times.", value>()->default_value(""), "FILE"); } // clang-format on @@ -143,70 +122,20 @@ void CommandLineOptions::HandleCoreOptions() { exit(0); } - // Handle "verbose" argument - // If set in etc/bdm.rootrc use that value, command line argument will - // override it - Int_t ll = kWarning; - TString slevel = "Warning"; - TEnvRec* rec = gEnv->Lookup("Root.ErrorIgnoreLevel"); - if (rec) { - if (rec->GetLevel() == kEnvUser) - slevel = rec->GetValue(); - } - if (!slevel.CompareTo("Print", TString::kIgnoreCase)) - ll = kPrint; - else if (!slevel.CompareTo("Info", TString::kIgnoreCase)) - ll = kInfo; - else if (!slevel.CompareTo("Warning", TString::kIgnoreCase)) - ll = kWarning; - else if (!slevel.CompareTo("Error", TString::kIgnoreCase)) - ll = kError; - if (IsSet("verbose")) { auto verbosity = parser_->count("verbose"); - switch (verbosity) { - // case 0 can never occur; we wouldn't go into this if statement case 1: - ll = kWarning; + Log::SetLevel(Log::Level::kWarning); break; case 2: - ll = kInfo; - break; - case 3: - ll = kPrint; + Log::SetLevel(Log::Level::kInfo); break; default: - ll = kPrint; + Log::SetLevel(Log::Level::kDebug); break; } } - // Global variable of ROOT that determines verbosity of logging functions - gErrorIgnoreLevel = ll; - - if (parser_->count("output-default-json")) { - Param param; - std::cout << "Below you can find a JSON string with all available " - "parameters and their default values.\n" - << "Have a look at https://biodynamo.org/bioapi/ for more " - "details about each parameter." - << std::endl; - std::cout << param.ToJsonString() << std::endl; - exit(0); - } - - auto toml_file = (*parser_)["toml-to-json"].as(); - if (toml_file != "") { - if (!FileExists(toml_file)) { - Log::Fatal("CommandLineOptions::HandleCoreOptions", - "Specified TOML file (", toml_file, ") does not exist."); - } - auto toml = cpptoml::parse_file(toml_file); - Param param; - param.AssignFromConfig(toml); - std::cout << param.ToJsonString() << std::endl; - exit(0); - } } std::ostream& operator<<(std::ostream& os, const CommandLineOptions& clo) { diff --git a/src/core/param/command_line_options.h b/src/core/param/command_line_options.h index 19838efc2..54877bbd4 100644 --- a/src/core/param/command_line_options.h +++ b/src/core/param/command_line_options.h @@ -15,18 +15,16 @@ #ifndef CORE_PARAM_COMMAND_LINE_OPTIONS_H_ #define CORE_PARAM_COMMAND_LINE_OPTIONS_H_ -/// Don't split at ',' if options are repeated -/// This would split { "bdm::Param": "option1": 123, "option2": 123}} -/// into two strings: "{ "bdm::Param": "option1": 123" and ""option2": 123}}" #define CXXOPTS_VECTOR_DELIMITER '\n' -#include #include #include #include +#include #include #include #include +#include #include "bdm_version.h" #include "core/simulation.h" @@ -38,7 +36,7 @@ class CommandLineOptions { public: CommandLineOptions(int argc, const char** argv); - ~CommandLineOptions(); + ~CommandLineOptions() = default; /// Add an extra command line option template @@ -92,7 +90,7 @@ class CommandLineOptions { // Flag to determine if new options were added bool first_parse_ = true; cxxopts::Options options_; - cxxopts::ParseResult* parser_ = nullptr; + std::unique_ptr parser_; }; } // namespace bdm diff --git a/src/core/param/param.cc b/src/core/param/param.cc index bdcecb7dc..24bfc9077 100644 --- a/src/core/param/param.cc +++ b/src/core/param/param.cc @@ -12,24 +12,15 @@ // // ----------------------------------------------------------------------------- -#include -#include - #include #include -#include "core/multi_simulation/optimization_param.h" #include "core/param/param.h" #include "core/util/cpptoml.h" #include "core/util/log.h" -using nlohmann::json; - namespace bdm { -const bdm::ParamGroupUid bdm::OptimizationParam::kUid = - bdm::ParamGroupUidGenerator::Get()->NewUid(); - std::unordered_map> Param::registered_groups_; @@ -40,7 +31,6 @@ void Param::RegisterParamGroup(ParamGroup* param) { // ----------------------------------------------------------------------------- Param::Param() { - RegisterParamGroup(new OptimizationParam()); for (auto& el : registered_groups_) { groups_[el.first] = el.second->NewCopy(); } @@ -53,15 +43,6 @@ Param::~Param() { } } -// ----------------------------------------------------------------------------- -void Param::Restore(Param&& other) { - for (auto& el : groups_) { - delete el.second; - } - *this = other; - other.groups_.clear(); -} - Param::Param(const Param& other) { *this = other; for (auto el : other.groups_) { @@ -69,82 +50,6 @@ Param::Param(const Param& other) { } } -// ----------------------------------------------------------------------------- -json FlattenGroups(const json& j_document) { - json j_copy = j_document; - j_copy.erase("groups_"); - - json j_new; - j_new["bdm::Param"] = j_copy; - - // iterator over all group parameters - auto j_groups = j_document["groups_"]; - for (json::iterator it = j_groups.begin(); it != j_groups.end(); ++it) { - j_new[(*it)["second"]["_typename"].get()] = (*it)["second"]; - } - return j_new; -} - -// ----------------------------------------------------------------------------- -json UnflattenGroups(const json& j_flattened, const json& j_original) { - json j_return = j_flattened["bdm::Param"]; - j_return["groups_"] = {}; - auto& j_groups = j_return["groups_"]; - - auto j_original_groups = j_original["groups_"]; - for (json::iterator it = j_original_groups.begin(); - it != j_original_groups.end(); ++it) { - json j_param_group; - j_param_group["$pair"] = (*it)["$pair"]; - j_param_group["first"] = (*it)["first"]; - j_param_group["second"] = - j_flattened[(*it)["second"]["_typename"].get()]; - j_groups.push_back(j_param_group); - } - return j_return; -} - -// ----------------------------------------------------------------------------- -std::string Param::ToJsonString() const { - // If you segfault here, try running the unit tests to find the root cause - std::string current_json_str( - TBufferJSON::ToJSON(this, TBufferJSON::kMapAsObject).Data()); - // Flatten groups_ to simplify json patches in rfc7386 format. - try { - json j_document = json::parse(current_json_str); - auto j_flattened = FlattenGroups(j_document); - return j_flattened.dump(4); - } catch (std::exception& e) { - Log::Fatal("Param::ToJsonString", - Concat("Couldn't parse `Param` parameters.\n", e.what(), "\n", - current_json_str)); - return std::string(); - } -} - -// ----------------------------------------------------------------------------- -void Param::MergeJsonPatch(const std::string& patch) { - // If you segfault here, try running the unit tests to find the root cause - std::string json_str( - TBufferJSON::ToJSON(this, TBufferJSON::kMapAsObject).Data()); - json j_param = json::parse(json_str); - auto j_flattened = FlattenGroups(j_param); - - auto j_patch = json::parse(patch); - try { - j_flattened.merge_patch(j_patch); - } catch (std::exception& e) { - Log::Fatal("Param::MergeJsonPatch", - Concat("Couldn't merge the given json parameters.\n", e.what(), - "\n", j_patch)); - } - - auto j_unflattened = UnflattenGroups(j_flattened, j_param); - Param* restored = nullptr; - TBufferJSON::FromJSON(restored, j_unflattened.dump().c_str()); - Restore(std::move(*restored)); -} - // ----------------------------------------------------------------------------- void AssignThreadSafetyMechanism(const std::shared_ptr& config, Param* param) { @@ -166,32 +71,6 @@ void AssignThreadSafetyMechanism(const std::shared_ptr& config, } } -// ----------------------------------------------------------------------------- -void AssignMappedDataArrayMode(const std::shared_ptr& config, - Param* param) { - const std::string config_key = "performance.mapped_data_array_mode"; - if (config->contains_qualified(config_key)) { - auto value = config->get_qualified_as(config_key); - if (!value) { - return; - } - auto str_value = *value; - if (str_value == "zero-copy") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kZeroCopy; - } else if (str_value == "cache") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kCache; - } else if (str_value == "copy") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kCopy; - } else { - Log::Fatal( - "Param", - Concat( - "Parameter mapped_data_array_mode was set to an invalid value (", - str_value, ").")); - } - } -} - // ----------------------------------------------------------------------------- void AssignBoundSpaceMode(const std::shared_ptr& config, Param* param) { @@ -203,11 +82,11 @@ void AssignBoundSpaceMode(const std::shared_ptr& config, } auto str_value = *value; if (str_value == "open") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kZeroCopy; + param->bound_space = Param::BoundSpaceMode::kOpen; } else if (str_value == "closed") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kCache; + param->bound_space = Param::BoundSpaceMode::kClosed; } else if (str_value == "torus") { - param->mapped_data_array_mode = Param::MappedDataArrayMode::kCopy; + param->bound_space = Param::BoundSpaceMode::kTorus; } else { Log::Fatal("Param", Concat("Parameter bound_space was set to an invalid value (", @@ -229,9 +108,6 @@ void Param::AssignFromConfig(const std::shared_ptr& config) { BDM_ASSIGN_CONFIG_VALUE(environment, "simulation.environment"); BDM_ASSIGN_CONFIG_VALUE(nanoflann_depth, "simulation.nanoflann_depth"); BDM_ASSIGN_CONFIG_VALUE(unibn_bucketsize, "simulation.unibn_bucketsize"); - BDM_ASSIGN_CONFIG_VALUE(backup_file, "simulation.backup_file"); - BDM_ASSIGN_CONFIG_VALUE(restore_file, "simulation.restore_file"); - BDM_ASSIGN_CONFIG_VALUE(backup_interval, "simulation.backup_interval"); BDM_ASSIGN_CONFIG_VALUE(simulation_time_step, "simulation.time_step"); BDM_ASSIGN_CONFIG_VALUE(simulation_max_displacement, "simulation.max_displacement"); @@ -252,7 +128,6 @@ void Param::AssignFromConfig(const std::shared_ptr& config) { "visualization.pv_insitu_pipeline"); BDM_ASSIGN_CONFIG_VALUE(pv_insitu_pipelinearguments, "visualization.pv_insitu_pipelinearguments"); - BDM_ASSIGN_CONFIG_VALUE(root_visualization, "visualization.root"); BDM_ASSIGN_CONFIG_VALUE(export_visualization, "visualization.export"); BDM_ASSIGN_CONFIG_VALUE(visualization_interval, "visualization.interval"); BDM_ASSIGN_CONFIG_VALUE(visualization_export_generate_pvsm, @@ -350,8 +225,6 @@ void Param::AssignFromConfig(const std::shared_ptr& config) { "performance.mem_mgr_max_mem_per_thread_factor"); BDM_ASSIGN_CONFIG_VALUE(minimize_memory_while_rebalancing, "performance.minimize_memory_while_rebalancing"); - AssignMappedDataArrayMode(config, this); - // development group BDM_ASSIGN_CONFIG_VALUE(statistics, "development.statistics"); BDM_ASSIGN_CONFIG_VALUE(debug_numa, "development.debug_numa"); diff --git a/src/core/param/param.h b/src/core/param/param.h index f1d394ede..b838e85b5 100644 --- a/src/core/param/param.h +++ b/src/core/param/param.h @@ -22,10 +22,8 @@ #include #include #include -#include "core/analysis/style.h" #include "core/param/param_group.h" #include "core/real_t.h" -#include "core/util/root.h" #include "core/util/type.h" namespace bdm { @@ -41,20 +39,6 @@ struct Param { Param(const Param& other); - void Restore(Param&& other); - - /// Returns a Json representation of this parameter and all - /// ParamGroupeter. - /// The groups_ data member has been flattened to simplify - /// JSON merge patches (https://tools.ietf.org/html/rfc7386). - std::string ToJsonString() const; - - /// Applies a JSON merge patch (https://tools.ietf.org/html/rfc7386) - /// to this parameter and ParamGroupeter. - /// The groups_ data member must be flattened. See output of - /// `ToJsonString()`. - void MergeJsonPatch(const std::string& patch); - template const TParamGroup* Get() const { if (groups_.find(TParamGroup::kUid) != groups_.end()) { @@ -148,34 +132,6 @@ struct Param { /// inevitably use more disk space with this option. bool remove_output_dir_contents = true; - /// Backup file name for full simulation backups\n - /// Path is relative to working directory.\n - /// Default value: `""` (no backups will be made)\n - /// TOML config file: - /// - /// [simulation] - /// backup_file = /.root - /// Command line argument: `-b, --backup` - std::string backup_file = ""; - - /// File name to restore simulation from\n - /// Path is relative to working directory.\n - /// Default value: `""` (no restore will be made)\n - /// TOML config file: - /// - /// [simulation] - /// restore_file = /.root - /// Command line argument: `-r, --restore` - std::string restore_file = ""; - - /// Specifies the interval (in seconds) in which backups will be performed.\n - /// Default Value: `1800` (every half an hour)\n - /// TOML config file: - /// - /// [simulation] - /// backup_interval = 1800 # backup every half an hour - uint32_t backup_interval = 1800; - /// Time between two simulation steps, in hours. /// Default value: `0.01`\n /// TOML config file: @@ -311,14 +267,6 @@ struct Param { /// export = false bool export_visualization = false; - /// Use ROOT for enable visualization.\n - /// Default value: `false`\n - /// TOML config file: - /// - /// [visualization] - /// root = false - bool root_visualization = false; - /// Enable insitu visualization with a custom python pipeline /// Default value: /// `"/include/core/visualization/paraview/default_insitu_pipeline.py"`\n @@ -365,9 +313,10 @@ struct Param { /// Every agent defines the minimum set of data members which /// are required to visualize it. (e.g. Cell: `position_` and `diameter_`).\n /// With this parameter it is also possible to extend the number of data - /// members that are sent to the visualization engine. + /// members that are sent to the visualization engine. Each additional + /// member must be exposed by the agent's `GetVisualizationData` override as + /// `std::vector`, `std::vector`, or `std::vector`. /// Default value: empty (no agent will be visualized)\n - /// NB: This data member is not backed up, due to a ROOT error. /// TOML config file: /// /// [visualization] @@ -382,8 +331,7 @@ struct Param { /// # The former block can be repeated for further agents /// [[visualize_agent]] /// name = "Neurite" - std::map> - visualize_agents; ///< JSON_object + std::map> visualize_agents; struct VisualizeDiffusion { std::string name; @@ -535,26 +483,6 @@ struct Param { /// minimize_memory_while_rebalancing = true bool minimize_memory_while_rebalancing = true; - /// MappedDataArrayMode options: - /// `kZeroCopy`: access agent data directly only if it is - /// requested. \n - /// `kCache`: Like `kZeroCopy` but stores the results in contiguous - /// array, to speed up access if it is used again.\n - /// `kCopy`: Copy all data elements to a contiguous array at - /// initialization time. Serves requests from the cache. - enum MappedDataArrayMode { kZeroCopy = 0, kCopy, kCache }; - - /// This parameter sets the operation mode in `bdm::MappedDataArray`.\n - /// Allowed values are defined in `MappedDataArrayMode`\n - /// Possible values: zero-copy, cache, copy\n - /// Default value: `zero-copy`\n - /// TOML config file: - /// - /// [performance] - /// mapped_data_array_mode = "zero-copy" - Param::MappedDataArrayMode mapped_data_array_mode = - MappedDataArrayMode::kZeroCopy; - // development values -------------------------------------------------------- /// Statistics of profiling data; keeps track of the execution time of each /// operation at every timestep.\n @@ -642,7 +570,6 @@ struct Param { /// Determines if agents' memory layout plots should be generated /// during load balancing. - bool plot_memory_layout = false; /// Assign values from config file to variables void AssignFromConfig(const std::shared_ptr&); @@ -652,7 +579,6 @@ struct Param { static std::unordered_map> registered_groups_; std::unordered_map groups_; - BDM_CLASS_DEF_NV(Param, 1); }; } // namespace bdm diff --git a/src/core/param/param_group.h b/src/core/param/param_group.h index 082842df0..f30a2077d 100644 --- a/src/core/param/param_group.h +++ b/src/core/param/param_group.h @@ -15,8 +15,9 @@ #ifndef CORE_PARAM_PARAM_GROUP_H_ #define CORE_PARAM_PARAM_GROUP_H_ +#include +#include #include -#include "core/util/root.h" #include "cpptoml/cpptoml.h" namespace bdm { @@ -56,7 +57,6 @@ struct ParamGroup { private: friend struct Param; - BDM_CLASS_DEF(ParamGroup, 1); }; #define BDM_PARAM_GROUP_HEADER(name, version_id) \ @@ -66,9 +66,6 @@ struct ParamGroup { ParamGroup* NewCopy() const override { return new name(*this); } \ ParamGroupUid GetUid() const override { return kUid; } \ \ - private: \ - BDM_CLASS_DEF_OVERRIDE(name, version_id); \ - \ public: } // namespace bdm diff --git a/src/core/scheduler.cc b/src/core/scheduler.cc index 507544306..c5ce8ddda 100644 --- a/src/core/scheduler.cc +++ b/src/core/scheduler.cc @@ -13,7 +13,6 @@ // ----------------------------------------------------------------------------- #include "core/scheduler.h" -#include #include #include #include @@ -27,20 +26,11 @@ #include "core/param/param.h" #include "core/resource_manager.h" #include "core/simulation.h" -#include "core/simulation_backup.h" #include "core/util/log.h" -#include "core/visualization/root/adaptor.h" namespace bdm { Scheduler::Scheduler() { - auto* param = Simulation::GetActive()->GetParam(); - backup_ = new SimulationBackup(param->backup_file, param->restore_file); - if (backup_->RestoreEnabled()) { - restore_point_ = backup_->GetSimulationStepsFromBackup(); - } - root_visualization_ = new RootAdaptor(); - // Operations are scheduled in the following order (sub categorated by their // operation implementation type, so that actual order may vary) std::vector default_op_names = { @@ -71,8 +61,8 @@ Scheduler::Scheduler() { "update environment", "tear down iteration"}; - auto disabled_op_names = - Simulation::GetActive()->GetParam()->unschedule_default_operations; + auto* param = Simulation::GetActive()->GetParam(); + auto disabled_op_names = param->unschedule_default_operations; if (!param->detect_static_agents) { disabled_op_names.push_back("propagate staticness"); disabled_op_names.push_back("propagate staticness agentop"); @@ -122,22 +112,15 @@ Scheduler::~Scheduler() { for (auto* op : all_ops_) { delete op; } - delete backup_; - delete root_visualization_; delete progress_bar_; } void Scheduler::Simulate(uint64_t steps) { - if (Restore(&steps)) { - return; - } - Initialize(steps); for (unsigned step = 0; step < steps; step++) { Execute(); total_steps_++; UpdateSimulatedTime(); - Backup(); } } @@ -371,8 +354,7 @@ void Scheduler::Execute() { void Scheduler::PrintInfo(std::ostream& out) const { out << "\n" << std::string(80, '-') << "\n\n"; out << "Scheduler information:\n"; - out << std::setw(80) << "frequency" - << "\n"; + out << std::setw(80) << "frequency" << "\n"; out << "Pre-scheduled operations:\n"; // pre-scheduled ops for (auto* pre_op : pre_scheduled_ops_) { @@ -417,37 +399,6 @@ void Scheduler::PrintInfo(std::ostream& out) const { out << "\n" << std::string(80, '-') << "\n"; } -void Scheduler::Backup() { - using std::chrono::duration_cast; - using std::chrono::seconds; - auto* param = Simulation::GetActive()->GetParam(); - if (backup_->BackupEnabled() && - duration_cast(Clock::now() - last_backup_).count() >= - param->backup_interval) { - last_backup_ = Clock::now(); - backup_->Backup(total_steps_); - } -} - -/// Restore the simulation if requested at the right time -/// @param steps number of simulation steps for a `Simulate` call -/// @return if `Simulate` should return early -bool Scheduler::Restore(uint64_t* steps) { - if (backup_->RestoreEnabled() && restore_point_ > total_steps_ + *steps) { - total_steps_ += *steps; - // restore requested, but not last backup was not done during this call to - // Simulate. Therefore, we skip it. - return true; - } else if (backup_->RestoreEnabled() && restore_point_ > total_steps_ && - restore_point_ < total_steps_ + *steps) { - // Restore - backup_->Restore(); - *steps = total_steps_ + *steps - restore_point_; - total_steps_ = restore_point_; - } - return false; -} - void Scheduler::UpdateSimulatedTime() { simulated_time_ += Simulation::GetActive()->GetParam()->simulation_time_step; } diff --git a/src/core/scheduler.h b/src/core/scheduler.h index 0367c995c..1ab2d6104 100644 --- a/src/core/scheduler.h +++ b/src/core/scheduler.h @@ -33,9 +33,7 @@ namespace bdm { class SchedulerTest; class Agent; -class SimulationBackup; class VisualizationAdaptor; -class RootAdaptor; struct BoundSpace; class MechanicalForcesOp; class DiffusionOp; @@ -44,8 +42,6 @@ enum OpType { kSchedule, kPreSchedule, kPostSchedule }; class Scheduler { public: - using Clock = std::chrono::high_resolution_clock; - Scheduler(); virtual ~Scheduler(); @@ -62,8 +58,6 @@ class Scheduler { /// return rm->GetNumAgents() >= 1000; /// }); /// - /// NB: Automated backups and restores are not yet supported - /// if the simulation uses this simulate function. TODO(lukas) void SimulateUntil(const std::function& exit_condition); /// Finalize simulation initialization or manual changes between @@ -99,8 +93,6 @@ class Scheduler { const std::vector*>& GetAgentFilters() const; - RootAdaptor* GetRootVisualization() { return root_visualization_; } - TimingAggregator* GetOpTimes(); /// Prints an overview of all pre-scheduled, agent, standalone, and @@ -120,30 +112,26 @@ class Scheduler { virtual void Execute(); private: - friend void RunAgentsTest(Param::MappedDataArrayMode, uint64_t, bool, bool); + friend void RunAgentsTest(uint64_t, bool, bool); friend SchedulerTest; - SimulationBackup* backup_ = nullptr; - uint64_t restore_point_; - std::chrono::time_point last_backup_ = Clock::now(); - RootAdaptor* root_visualization_ = nullptr; //! ProgressBar* progress_bar_ = nullptr; /// List of all operations that have been add either as default /// or by a call to Scheduler::ScheduleOp. /// Scheduler::UnscheduleOp doesn't remove the operation from this /// list. - std::vector all_ops_; //! + std::vector all_ops_; /// List of operations that are to be added in the upcoming timestep - std::vector> schedule_ops_; //! + std::vector> schedule_ops_; /// List of operations that are to be removed in the upcoming timestep - std::vector unschedule_ops_; //! + std::vector unschedule_ops_; /// List of operations will be executed as a stand-alone operation - std::vector scheduled_standalone_ops_; //! + std::vector scheduled_standalone_ops_; /// List of operations will be executed on all agents - std::vector scheduled_agent_ops_; //! + std::vector scheduled_agent_ops_; /// List of operations that cannot be affected by the user - std::vector protected_op_names_; //! + std::vector protected_op_names_; // Operations that are run before setting up, running and tearing down // scheduled operations std::vector pre_scheduled_ops_; @@ -156,15 +144,7 @@ class Scheduler { /// Agent operations are executed for each filter in agent_filters_.\n /// By default no filter is specified which means that all /// agent operations will be executed for each agents in the simulation. - std::vector*> agent_filters_; //! - - /// Backup the simulation. Backup interval based on `Param::backup_interval` - void Backup(); - - /// Restore the simulation if requested at the right time - /// @param steps number of simulation steps for a `Simulate` call - /// @return if `Simulate` should return early - bool Restore(uint64_t* steps); + std::vector*> agent_filters_; void UpdateSimulatedTime(); diff --git a/src/core/simulation.cc b/src/core/simulation.cc index 3eab3bd9a..ae608c5e2 100644 --- a/src/core/simulation.cc +++ b/src/core/simulation.cc @@ -47,17 +47,17 @@ #include "core/util/string.h" #include "core/util/thread_info.h" #include "core/util/timing.h" -#include "core/visualization/root/adaptor.h" #include "memory_usage.h" #ifdef USE_LIBGIT2 #include "core/util/git_tracker.h" #endif // USE_LIBGIT2 -#include -#include - namespace bdm { +namespace { +constexpr double kBytesPerMebibyte = 1024.0 * 1024.0; +} // namespace + /// Implementation for `Simulation`: /// It must be separate to avoid circular dependencies. @@ -67,22 +67,17 @@ Simulation* Simulation::active_ = nullptr; Simulation* Simulation::GetActive() { return active_; } -Simulation::Simulation(TRootIOCtor* p) {} - Simulation::Simulation(int argc, const char** argv, const std::vector& config_files) - : Simulation( - argc, argv, [](auto* param) {}, config_files) {} + : Simulation(argc, argv, [](auto* param) {}, config_files) {} Simulation::Simulation(const std::string& simulation_name, const std::vector& config_files) - : Simulation( - simulation_name, [](auto* param) {}, config_files) {} + : Simulation(simulation_name, [](auto* param) {}, config_files) {} Simulation::Simulation(CommandLineOptions* clo, const std::vector& config_files) { - Initialize( - clo, [](auto* param) {}, config_files); + Initialize(clo, [](auto* param) {}, config_files); } Simulation::Simulation(CommandLineOptions* clo, @@ -106,35 +101,6 @@ Simulation::Simulation(const std::string& simulation_name, Initialize(&options, set_param, config_files); } -void Simulation::Restore(Simulation&& restored) { - // random_ - if (random_.size() != restored.random_.size()) { - Log::Warning("Simulation", "The restore file (", param_->restore_file, - ") was run with a different number of threads. Can't restore " - "complete random number generator state."); - uint64_t min = std::min(random_.size(), restored.random_.size()); - for (uint64_t i = 0; i < min; i++) { - *(random_[i]) = *(restored.random_[i]); - } - } else { - for (uint64_t i = 0; i < random_.size(); i++) { - *(random_[i]) = *(restored.random_[i]); - } - } - - // param and rm - param_->Restore(std::move(*restored.param_)); - restored.param_ = nullptr; - *rm_ = std::move(*restored.rm_); - restored.rm_ = nullptr; - - *time_series_ = std::move(*restored.time_series_); - - // name_ and unique_name_ - InitializeUniqueName(restored.name_); - InitializeOutputDir(); -} - std::ostream& operator<<(std::ostream& os, Simulation& sim) { os << std::endl; @@ -150,7 +116,7 @@ std::ostream& operator<<(std::ostream& os, Simulation& sim) { os << "Simulation name\t\t\t: " << sim.GetUniqueName() << std::endl; os << "Total simulation runtime\t: " << (sim.dtor_ts_ - sim.ctor_ts_) << " ms" << std::endl; - os << "Peak memory usage (MB)\t\t: " << (getPeakRSS() / 1048576.0) + os << "Peak memory usage (MB)\t\t: " << (getPeakRSS() / kBytesPerMebibyte) << std::endl; os << "Number of iterations executed\t: " << sim.scheduler_->GetSimulatedSteps() << std::endl; @@ -159,10 +125,6 @@ std::ostream& operator<<(std::ostream& os, Simulation& sim) { sim.rm_->ForEachDiffusionGrid([&os](auto* dgrid) { dgrid->PrintInfo(os); }); os << "Output directory\t\t: " << sim.GetOutputDir() << std::endl; - os << " size\t\t\t\t: " - << gSystem->GetFromPipe( - Concat("du -sh ", sim.GetOutputDir(), " | cut -f1").c_str()) - << std::endl; os << "BioDynaMo version:\t\t: " << Version::String() << std::endl; os << "BioDynaMo real type:\t\t: " << kRealtName << std::endl; os << std::endl; @@ -179,10 +141,6 @@ std::ostream& operator<<(std::ostream& os, Simulation& sim) { os << std::endl; os << "***********************************************" << std::endl; os << std::endl; - os << "\033[1mParameters\033[0m" << std::endl; - os << sim.param_->ToJsonString(); - os << std::endl; - os << "***********************************************" << std::endl; os << "***********************************************" << std::endl; return os; @@ -294,10 +252,6 @@ void Simulation::ReplaceScheduler(Scheduler* scheduler) { void Simulation::Initialize(CommandLineOptions* clo, const std::function& set_param, const std::vector& config_files) { - // Initialize a thread-safe ROOT instance - TROOT(name_.c_str(), "BioDynaMo"); - ROOT::EnableThreadSafety(); - ctor_ts_ = bdm::Timing::Timestamp(); id_ = counter_++; Activate(); @@ -399,34 +353,10 @@ void Simulation::InitializeRuntimeParams( "command."); } - static bool read_env = false; - if (!read_env) { - // Read, only once, bdm.rootrc to set BioDynaMo-related settings for ROOT - std::stringstream os; - os << std::getenv("BDMSYS") << "/etc/bdm.rootrc"; - gEnv->ReadFile(os.str().c_str(), kEnvUser); - read_env = true; - } - // Process `--config` arguments LoadConfigFiles(ctor_config_files, clo->Get>("config")); - // Process `--inline-config` arguments - auto inline_configs = clo->Get>("inline-config"); - if (inline_configs.size()) { - for (auto& inline_config : inline_configs) { - param_->MergeJsonPatch(inline_config); - } - } - - if (clo->Get("backup") != "") { - param_->backup_file = clo->Get("backup"); - } - if (clo->Get("restore") != "") { - param_->restore_file = clo->Get("restore"); - } - // Handle "cuda" and "opencl" arguments if (clo->Get("cuda")) { param_->compute_target = "cuda"; @@ -450,9 +380,6 @@ void Simulation::InitializeRuntimeParams( is_gpu_environment_initialized_ = true; } - // Removing this line causes an unexplainable segfault due to setting the - // gErrorIngoreLevel global parameter of ROOT. We need to log at least one - // thing before setting that parameter. Log::Info("", "Initialize new simulation using BioDynaMo ", Version::String()); } @@ -460,9 +387,7 @@ void Simulation::InitializeRuntimeParams( void Simulation::LoadConfigFiles(const std::vector& ctor_configs, const std::vector& cli_configs) { constexpr auto kTomlConfigFile = "bdm.toml"; - constexpr auto kJsonConfigFile = "bdm.json"; constexpr auto kTomlConfigFileParentDir = "../bdm.toml"; - constexpr auto kJsonConfigFileParentDir = "../bdm.json"; // find config file std::vector configs = {}; if (ctor_configs.size()) { @@ -496,10 +421,6 @@ void Simulation::LoadConfigFiles(const std::vector& ctor_configs, configs.push_back(kTomlConfigFile); } else if (FileExists(kTomlConfigFileParentDir)) { configs.push_back(kTomlConfigFileParentDir); - } else if (FileExists(kJsonConfigFile)) { - configs.push_back(kJsonConfigFile); - } else if (FileExists(kJsonConfigFileParentDir)) { - configs.push_back(kJsonConfigFileParentDir); } } @@ -509,18 +430,13 @@ void Simulation::LoadConfigFiles(const std::vector& ctor_configs, if (EndsWith(config, ".toml")) { auto toml = cpptoml::parse_file(config); param_->AssignFromConfig(toml); - } else if (EndsWith(config, ".json")) { - std::ifstream ifs(config); - std::stringstream buffer; - buffer << ifs.rdbuf(); - param_->MergeJsonPatch(buffer.str()); } Log::Info("Simulation::LoadConfigFiles", "Processed config file: ", config); } } else { Log::Info("Simulation::LoadConfigFiles", "Default config file ", - kTomlConfigFile, " or ", kJsonConfigFile, + kTomlConfigFile, " not found in `.` or `..` directory. No other config file was " "specified as command line parameter or passed to the " "constructor of bdm::Simulation."); diff --git a/src/core/simulation.h b/src/core/simulation.h index f7c5c8476..01af408cb 100644 --- a/src/core/simulation.h +++ b/src/core/simulation.h @@ -22,7 +22,6 @@ #include "core/gpu/opencl_state.h" #include "core/memory/memory_manager.h" #include "core/util/random.h" -#include "core/util/root.h" namespace bdm { @@ -52,7 +51,6 @@ class Simulation { /// This function returns the currently active Simulation simulation. static Simulation* GetActive(); - explicit Simulation(TRootIOCtor* p); /// Constructor that takes the arguments from `main` to parse command line /// arguments. The simulation name is extracted from the executable name. /// Creation of a new simulation automatically activates it. @@ -66,8 +64,7 @@ class Simulation { /// available, or if a different simulation name should be chosen. \n /// Command line arguments are not parsed!\n /// Creation of a new simulation automatically activates it. - /// \param config_file Use a different config file than the default bdm.toml - /// or bdm.json + /// \param config_file Use a different config file than the default bdm.toml. explicit Simulation(const std::string& simulation_name, const std::vector& config_files = {}); @@ -85,10 +82,6 @@ class Simulation { ~Simulation(); - /// Copies / moves values from a restored simulation into this object. - /// Thus, pointers to `rm_`, `param_`, ... are not invalidated. - void Restore(Simulation&& restored); - /// Activates this simulation. void Activate(); @@ -153,34 +146,34 @@ class Simulation { std::vector random_; /// Execution Context for each thread - std::vector exec_ctxt_; //! + std::vector exec_ctxt_; ResourceManager* rm_ = nullptr; Param* param_ = nullptr; - AgentUidGenerator* agent_uid_generator_ = nullptr; //! + AgentUidGenerator* agent_uid_generator_ = nullptr; std::string name_; - Environment* environment_ = nullptr; //! - Scheduler* scheduler_ = nullptr; //! - OpenCLState* ocl_state_ = nullptr; //! + Environment* environment_ = nullptr; + Scheduler* scheduler_ = nullptr; + OpenCLState* ocl_state_ = nullptr; bool is_gpu_environment_initialized_ = false; /// This id is unique for each simulation within the same process - uint64_t id_ = 0; //! + uint64_t id_ = 0; /// cached value where `id_` is appended to `name_` if `id_` is /// not zero.\n /// e.g. `name_ = "my-sim"` and `id_ = 0` -> "my-sim"\n /// e.g. `name_ = "my-sim"` and `id_ = 4` -> "my-sim4" - std::string unique_name_; //! + std::string unique_name_; /// cached value where `unique_name_` is appended to `Param::output_dir` - std::string output_dir_; //! + std::string output_dir_; /// Stores command line arguments if (argc,argv) or CommandLineOptions /// are passed to the constructor.\n - std::string command_line_parameter_str_; //! + std::string command_line_parameter_str_; /// BioDynaMo memory manager. If nullptr, default allocator will be used. - MemoryManager* mem_mgr_ = nullptr; //! + MemoryManager* mem_mgr_ = nullptr; /// Timestep when constructor was called - int64_t ctor_ts_ = 0; //! + int64_t ctor_ts_ = 0; /// Timestep when destructor was called - int64_t dtor_ts_ = 0; //! + int64_t dtor_ts_ = 0; /// Collects time series information during the simulation experimental::TimeSeries* time_series_ = nullptr; @@ -210,8 +203,6 @@ class Simulation { friend ParaviewAdaptorTest; friend class DiffusionTest_CopyOldData_Test; friend std::ostream& operator<<(std::ostream& os, Simulation& sim); - - BDM_CLASS_DEF_NV(Simulation, 1); }; } // namespace bdm diff --git a/src/core/simulation_backup.cc b/src/core/simulation_backup.cc deleted file mode 100644 index eeb0888cc..000000000 --- a/src/core/simulation_backup.cc +++ /dev/null @@ -1,71 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/simulation_backup.h" - -namespace bdm { - -SimulationBackup::SimulationBackup(const std::string& backup_file, - const std::string& restore_file) - : backup_file(backup_file), restore_file(restore_file) { - backup_ = true; - if (backup_file == "") { - backup_ = false; - Log::Info("SimulationBackup", - "No backup file name given. No backups will be made!"); - } else if (backup_file == restore_file) { - Log::Warning( - "SimulationBackup", - "Backup file is identical to restore file. Will be overridden after " - "restore."); - } - - if (restore_file == "") { - restore_ = false; - } else if (!FileExists(restore_file)) { - Log::Fatal("SimulationBackup", - "Given restore file does not exist: ", restore_file); - } -} - -size_t SimulationBackup::GetSimulationStepsFromBackup() const { - if (restore_) { - IntegralTypeWrapper* wrapper = nullptr; - bdm::GetPersistentObject(restore_file.c_str(), kSimulationStepName.c_str(), - wrapper); - if (wrapper != nullptr) { - return wrapper->Get(); - } else { - Log::Fatal("SimulationBackup", "Failed to retrieve SimulationSteps."); - return 0; - } - } else { - Log::Fatal("SimulationBackup", - "Requested to restore data, but no restore file given."); - return 0; - } -} - -bool SimulationBackup::BackupEnabled() const { return backup_; } - -bool SimulationBackup::RestoreEnabled() const { return restore_; } - -const std::string SimulationBackup::kSimulationName = "simulation"; -const std::string SimulationBackup::kSimulationStepName = - "completed_simulation_steps"; -const std::string SimulationBackup::kRuntimeVariableName = "runtime_variable"; - -std::vector> SimulationBackup::after_restore_event_ = {}; - -} // namespace bdm diff --git a/src/core/simulation_backup.h b/src/core/simulation_backup.h deleted file mode 100644 index 60ecc3ce4..000000000 --- a/src/core/simulation_backup.h +++ /dev/null @@ -1,126 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_SIMULATION_BACKUP_H_ -#define CORE_SIMULATION_BACKUP_H_ - -#include -#include -#include -#include -#include - -#include "core/simulation.h" - -#include "core/util/io.h" -#include "core/util/log.h" - -namespace bdm { - -/// SimulationBackup is responsible for backing up and restoring all relevant -/// simulation information. -class SimulationBackup { - public: - // object names for root file - static const std::string kSimulationName; - static const std::string kSimulationStepName; - static const std::string kRuntimeVariableName; - - /// If a whole simulation is restored from a ROOT file, the new - /// ResourceManager is not updated before the end. Consequently, during - /// restore, a custom streamer cannot access the new RessourceManager. - /// However, they can delay actions that rely on the new RessourceManager - /// by registering it to `after_restore_event_` and will be executed - /// after the restore has been finished and the ResourceManager has been - /// updated. - static std::vector> after_restore_event_; - - /// If `backup_file` is an empty string no backups will be made - /// If `restore_file` is an empty string no restore will be made - SimulationBackup(const std::string& backup_file, - const std::string& restore_file); - - void Backup(size_t completed_simulation_steps) const { - if (!backup_) { - Log::Fatal("SimulationBackup", - "Requested to backup data, but no backup file given."); - } - - // create temporary file - // if application crashes during backup; last backup is not corrupted - std::stringstream tmp_file; - tmp_file << "tmp_" << backup_file; - - // Backup - { - TFileRaii f(tmp_file.str(), "UPDATE"); - auto* simulation = Simulation::GetActive(); - f.Get()->WriteObject(simulation, kSimulationName.c_str()); - IntegralTypeWrapper wrapper(completed_simulation_steps); - f.Get()->WriteObject(&wrapper, kSimulationStepName.c_str()); - RuntimeVariables rv; - f.Get()->WriteObject(&rv, kRuntimeVariableName.c_str()); - // TODO(lukas) random number generator; all statistics (e.g. Param) - } - - // remove last backup file - remove(backup_file.c_str()); - // rename temporary file - rename(tmp_file.str().c_str(), backup_file.c_str()); - } - - void Restore() { - if (!restore_) { - Log::Fatal("SimulationBackup", - "Requested to restore data, but no restore file given."); - } - after_restore_event_.clear(); - - TFileRaii file(TFile::Open(restore_file.c_str())); - RuntimeVariables* restored_rv; - file.Get()->GetObject(kRuntimeVariableName.c_str(), restored_rv); - // check if runtime variables are the same - if (!(RuntimeVariables() == *restored_rv)) { - Log::Warning("SimulationBackup", - "Restoring simulation executed on a different system!"); - } - Simulation* restored_simulation = nullptr; - file.Get()->GetObject(kSimulationName.c_str(), restored_simulation); - Simulation::GetActive()->Restore(std::move(*restored_simulation)); - Log::Info("Scheduler", "Restored simulation from ", restore_file); - delete restored_simulation; - - // call all after restore events - for (auto&& event : after_restore_event_) { - event(); - } - after_restore_event_.clear(); - } - - size_t GetSimulationStepsFromBackup() const; - - bool BackupEnabled() const; - - bool RestoreEnabled() const; - - private: - bool backup_ = false; - bool restore_ = true; - std::string backup_file; - std::string restore_file; -}; - -} // namespace bdm - -#endif // CORE_SIMULATION_BACKUP_H_ diff --git a/src/core/util/io.cc b/src/core/util/io.cc index ad1e952b0..19db5baef 100644 --- a/src/core/util/io.cc +++ b/src/core/util/io.cc @@ -5,75 +5,17 @@ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// // See the LICENSE file distributed with this work for details. // See the NOTICE file distributed with this work for additional information // regarding copyright ownership. // // ----------------------------------------------------------------------------- -#include -#include - #include "core/util/io.h" -#include "core/util/log.h" - -namespace bdm { - -RuntimeVariables::RuntimeVariables() { gSystem->GetSysInfo(&sysinfo_); } -RuntimeVariables::RuntimeVariables(TRootIOCtor* io_ctor) {} - -SysInfo_t RuntimeVariables::GetSystemInfo() const { return sysinfo_; } - -void RuntimeVariables::SetSystemInfo(const SysInfo_t& other) { - sysinfo_ = other; -} - -void RuntimeVariables::PrintSystemInfo() const { - // clang-format off - Log::Info("RuntimeVariables", "OS:\t", sysinfo_.fOS, "\n", - "Model:\t", sysinfo_.fModel, "\n", - "Arch:\t", sysinfo_.fCpuType, "\n", - "#CPUs:\t", sysinfo_.fCpus, "\n", - "RAM:\t", sysinfo_.fPhysRam, "MB", "\n"); - // clang-format on -} - -bool RuntimeVariables::operator==(const RuntimeVariables& other) const { - if (sysinfo_.fOS != other.GetSystemInfo().fOS) { - return false; - } - if (sysinfo_.fModel != other.GetSystemInfo().fModel) { - return false; - } - if (sysinfo_.fCpuType != other.GetSystemInfo().fCpuType) { - return false; - } - if (sysinfo_.fCpus != other.GetSystemInfo().fCpus) { - return false; - } - if (sysinfo_.fPhysRam != other.GetSystemInfo().fPhysRam) { - return false; - } - return true; -} - -bool RuntimeVariables::operator!=(const RuntimeVariables& other) const { - return !(*this == other); -} - -TFileRaii::TFileRaii(const std::string& filename, const char* mode) - : file_(new TFile(filename.c_str(), mode)) {} - -TFileRaii::TFileRaii(TFile* file) : file_(file) {} - -TFileRaii::~TFileRaii() { - file_->Close(); - delete file_; -} +#include -TFile* TFileRaii::Get() { return file_; } +namespace bdm { bool FileExists(const std::string& file_name) { std::ifstream infile(file_name); @@ -83,7 +25,6 @@ bool FileExists(const std::string& file_name) { void WriteToFile(const std::string& filename, const std::string& content) { std::ofstream ofs(filename); ofs << content; - ofs.close(); } } // namespace bdm diff --git a/src/core/util/io.h b/src/core/util/io.h index a8d1c18de..b6a65a190 100644 --- a/src/core/util/io.h +++ b/src/core/util/io.h @@ -5,7 +5,6 @@ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// // See the LICENSE file distributed with this work for details. // See the NOTICE file distributed with this work for additional information // regarding copyright ownership. @@ -16,123 +15,12 @@ #define CORE_UTIL_IO_H_ #include -#include - -#include -#include -#include "core/util/root.h" namespace bdm { -/// This class stores the runtime variables of the system. This is useful for -/// check if the same system is used for continuing a simulation for example. -class RuntimeVariables { - public: - RuntimeVariables(); - // Constructor for ROOT I/O - explicit RuntimeVariables(TRootIOCtor* io_ctor); - - SysInfo_t GetSystemInfo() const; - void SetSystemInfo(const SysInfo_t& other); - - void PrintSystemInfo() const; - - bool operator==(const RuntimeVariables& other) const; - - bool operator!=(const RuntimeVariables& other) const; - - private: - SysInfo_t sysinfo_; - BDM_CLASS_DEF_NV(RuntimeVariables, 1); // NOLINT -}; - -/// Automatically close a TFile object using RAII pattern -class TFileRaii { - public: - TFileRaii(const std::string& filename, const char* mode); - explicit TFileRaii(TFile* file); - ~TFileRaii(); - TFile* Get(); - - private: - TFile* file_; -}; - -/// ROOT cannot write a single integral type (int, real_t, ...). Therefore, -/// this wrapper is needed -template -class IntegralTypeWrapper { - public: - explicit IntegralTypeWrapper(const T& data) : data_(data) {} - explicit IntegralTypeWrapper(TRootIOCtor* io_ctor) {} - const T& Get() const { return data_; } - - private: - T data_; - BDM_CLASS_DEF_NV(IntegralTypeWrapper, 1); -}; - -/// ROOT cannot write array of pointers. Therefore, this wrapper is needed. See -/// for example `InlineVector` for its usage -template -class VectorTypeWrapper { - public: - VectorTypeWrapper() = default; - - std::vector vector_; - ClassDefNV(VectorTypeWrapper, 1); -}; - bool FileExists(const std::string& file_name); - void WriteToFile(const std::string& filename, const std::string& content); -/// @brief Gets the persistent object from the specified ROOT file. -/// -/// @param[in] root_file The root file -/// @param[in] obj_name The object name -/// @param empty_obj The empty object -/// -/// @tparam T { The object class type } -/// -/// @return The persistent object. -/// -template -bool GetPersistentObject(const char* root_file, const char* obj_name, - T*& empty_obj) { // NOLINT - if (FileExists(root_file)) { - TFileRaii file(TFile::Open(root_file)); - file.Get()->GetObject(obj_name, empty_obj); - return true; - } - return false; -} - -// clang-format off -/// -/// @brief Writes a persistent object to the specified ROOT file. -/// -/// @param[in] root_file The root file -/// @param[in] obj_name The object name -/// @param pst_object The persistent object -/// @param[in] mode The mode -/// -/// @tparam T { The object class type } -/// -/// Option | Details -/// -------|-------- -/// new (default) | A new root file `root_file` is created. If file already exists, an error message is printed and the function returns. -/// recreate | If file does not exist, it is created (like in "new"). If file already exist, the existing file is deleted before creating the new file. -/// update | New classes are added to the existing directory. Existing classes with the same name are replaced by the new definition. If the directory dirname doest not exist, same effect as "new". -/// -// clang-format on -template -void WritePersistentObject(const char* root_file, const char* obj_name, - const T& pst_object, const char* mode = "new") { - TFileRaii file(root_file, mode); - file.Get()->WriteObject(&pst_object, obj_name); -} - } // namespace bdm #endif // CORE_UTIL_IO_H_ diff --git a/src/core/util/jit.cc b/src/core/util/jit.cc deleted file mode 100644 index 8af8cacbc..000000000 --- a/src/core/util/jit.cc +++ /dev/null @@ -1,212 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include -#include - -#include -#include -#include -#include -#include - -#include "core/util/jit.h" -#include "core/util/log.h" -#include "core/util/string.h" - -namespace bdm { - -// ----------------------------------------------------------------------------- -std::vector FindClassSlow(const std::string& class_name) { - bool cn_has_scope = class_name.find("::") != std::string::npos; - std::string cn_with_scope_prefix = std::string("::") + class_name; - char* current = 0; - uint64_t idx = 0; - std::vector tclasses; - while ((current = TClassTable::At(idx++)) != nullptr) { - std::string scurrent(current); - if (scurrent.find("::") == std::string::npos) { - // current does not contain a scope operator -> full match - if (std::string(current).compare(class_name) == 0) { - tclasses.push_back(TClassTable::GetDict(current)()); - } - } else { - if (cn_has_scope) { - if (EndsWith(scurrent, class_name)) { - tclasses.push_back(TClassTable::GetDict(current)()); - } - } else { - if (EndsWith(scurrent, cn_with_scope_prefix)) { - tclasses.push_back(TClassTable::GetDict(current)()); - } - } - } - } - return tclasses; -} - -// ----------------------------------------------------------------------------- -std::vector FindDataMemberSlow(TClass* tclass, - const std::string& data_member) { - std::vector ret_val; - - bool dm_has_scope = data_member.find("::") != std::string::npos; - std::string class_name = ""; - std::string dm_only_name = data_member; - if (dm_has_scope) { - auto idx = data_member.find_last_of("::"); - class_name = data_member.substr(0, idx - 1); - dm_only_name = data_member.substr(idx + 1, data_member.size()); - } - - std::stack tc_stack; - tc_stack.push(tclass); - - while (tc_stack.size() != 0) { - auto* current_tc = tc_stack.top(); - tc_stack.pop(); - for (const auto&& base : *current_tc->GetListOfBases()) { - auto get_dict_functor = TClassTable::GetDict(base->GetName()); - if (get_dict_functor != nullptr) { - tc_stack.push(get_dict_functor()); - } - } - - for (int i = 0; i < current_tc->GetListOfDataMembers()->GetSize(); ++i) { - auto* dm = - static_cast(current_tc->GetListOfDataMembers()->At(i)); - if (dm_has_scope) { - if (dm_only_name.compare(dm->GetName()) == 0 && - EndsWith(std::string(current_tc->GetName()), class_name)) { - ret_val.push_back(dm); - } - } else { - if (data_member.compare(dm->GetName()) == 0) { - ret_val.push_back(dm); - } - } - } - } - - return ret_val; -} - -// ----------------------------------------------------------------------------- -JitForEachDataMemberFunctor::JitForEachDataMemberFunctor( - TClass* tclass, const std::vector& dm_names, - const std::string& functor_name, - const std::function&)>& code_generator) - : functor_name_(Concat(functor_name, counter_++)), - code_generator_(code_generator) { - data_members_.reserve(dm_names.size()); - for (auto& dm : dm_names) { - auto candidates = FindDataMemberSlow(tclass, dm); - if (candidates.size() == 1) { - data_members_.push_back(candidates[0]); - } else if (candidates.size() == 0) { - Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor", - "Could not find data member ", dm); - } else { - Log::Fatal("JitForEachDataMemberFunctor::JitForEachDataMemberFunctor", - "Data member name (", dm, ") is ambiguous"); - } - } -} - -// ----------------------------------------------------------------------------- -void JitForEachDataMemberFunctor::Compile() const { - JitHeaders::IncludeIntoCling(); - gInterpreter->Declare(code_generator_(functor_name_, data_members_).c_str()); -} - -// ----------------------------------------------------------------------------- -void* JitForEachDataMemberFunctor::New(const std::string& parameter) { - auto cmd = Concat("#pragma cling optimize(3)\nnew bdm::", functor_name_, "(", - parameter, ")"); - return reinterpret_cast(gInterpreter->Calc(cmd.c_str())); -} - -// ----------------------------------------------------------------------------- -std::atomic JitForEachDataMemberFunctor::counter_; - -// ----------------------------------------------------------------------------- -void JitHeaders::Register(const std::string& header) { - headers_.push_back(header); -} - -// ----------------------------------------------------------------------------- -namespace { - -bool ExistsInIncludePath(const std::string& header) { - // "-I"/path/1 -I"/path/2" - std::string inc_dir_flags = gInterpreter->GetIncludePath(); - // remove leading `-I"`, trailing `""` and split into separate tokens - auto include_dirs = - Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\""); - // postprocess - std::string slash_header = Concat("/", header); - for (auto& dir : include_dirs) { - std::filesystem::path hpath = dir; - hpath += slash_header; - if (std::filesystem::exists(hpath)) { - return true; - } - } - return false; -} - -std::string GetIncludePaths() { - std::string inc_dir_flags = gInterpreter->GetIncludePath(); - auto dirs = - Split(inc_dir_flags.substr(3, inc_dir_flags.length() - 4), "\" -I\""); - std::stringstream sstr; - for (auto& dir : dirs) { - sstr << dir << std::endl; - } - return sstr.str(); -} - -} // namespace - -// ----------------------------------------------------------------------------- -void JitHeaders::IncludeIntoCling() { - for (auto& header : headers_) { - std::filesystem::path hpath = header; - if (hpath.is_absolute()) { - if (std::filesystem::exists(hpath)) { - gInterpreter->Declare(Concat("#include \"", header, "\"").c_str()); - } else { - Log::Fatal("JitHeaders::Declare", - Concat("Header file ", header, " does not exist.")); - } - } else { - if (ExistsInIncludePath(header)) { - gInterpreter->Declare(Concat("#include \"", header, "\"").c_str()); - } else { - Log::Fatal("JitHeaders::Declare", - Concat("Header file ", header, - " does not exist in any of the following include " - "directories.\n\n", - GetIncludePaths())); - } - } - } - headers_.clear(); -} - -// ----------------------------------------------------------------------------- -std::vector JitHeaders::headers_; - -} // namespace bdm diff --git a/src/core/util/jit.h b/src/core/util/jit.h deleted file mode 100644 index 045e0c988..000000000 --- a/src/core/util/jit.h +++ /dev/null @@ -1,93 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_UTIL_JIT_H_ -#define CORE_UTIL_JIT_H_ - -#include -#include -#include - -#include -#include - -namespace bdm { - -class Agent; - -/// Iterates over all entries in `TClassTable` and returns a vector of candidate -/// TClass* that match the given class name. -/// \param class_name does not have to be fully qualified -/// (e.g. `Cell` instead of `bdm::Cell`). \n -/// However, `Cell` will also match e.g "bdm::foo::Cell" -/// \return multiple values if class_name is ambiguous and multiple classes -/// were found in different namespaces -std::vector FindClassSlow(const std::string& class_name); - -/// Iterates over all data members of `tclass` and its base classes and returns -/// TClass* that match the given class name. -/// \param tclass TClass for which the data members should be determined -/// \param data_member name of the data_member -/// (e.g. `position_` or `bdm::Cell::position_`). \n -/// \return multiple values if data_member name is ambiguous and multiple -/// instances were found in `tclass` and its base classes -std::vector FindDataMemberSlow(TClass* tclass, - const std::string& data_member); - -// ----------------------------------------------------------------------------- -class JitForEachDataMemberFunctor { - public: - JitForEachDataMemberFunctor( - TClass* tclass, const std::vector& dm_names, - const std::string& functor_name, - const std::function&)>& - code_generation); - - void Compile() const; - - void* New(const std::string& parameter = ""); - - template - TFunctor* New(const std::string& parameter = "") { - return static_cast(New(parameter)); - } - - private: - /// The counter value is appended to the functor_name to obtain unique names - static std::atomic counter_; - std::string functor_name_; - std::vector data_members_; - std::function&)> - code_generator_; -}; - -// ----------------------------------------------------------------------------- -class JitHeaders { - public: - /// Header must be an absolute path or relative to one of the include - /// directories known to cling. - static void Register(const std::string& header); - /// Include headers from `JitHeaders::headers_` into cling and - /// removes them from the vector. - static void IncludeIntoCling(); - - private: - static std::vector headers_; -}; - -} // namespace bdm - -#endif // CORE_UTIL_JIT_H_ diff --git a/src/core/util/plot_memory_layout.cc b/src/core/util/plot_memory_layout.cc deleted file mode 100644 index 6ff258b9b..000000000 --- a/src/core/util/plot_memory_layout.cc +++ /dev/null @@ -1,190 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/util/plot_memory_layout.h" - -#include -#include -#include -// ROOT -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -// BioDynaMo -#include "core/agent/agent.h" -#include "core/environment/environment.h" -#include "core/scheduler.h" -#include "core/simulation.h" - -namespace bdm { - -// ----------------------------------------------------------------------------- -void PlotMemoryLayout(const std::vector& agents, int numa_node) { - TCanvas c; - c.SetCanvasSize(1920, 1200); - std::vector x(agents.size()); - std::vector y(agents.size()); - - uint64_t min = std::numeric_limits::max(); - for (uint64_t i = 0; i < agents.size(); ++i) { - auto val = reinterpret_cast(agents[i]); - if (val < min) { - min = val; - } - } - for (uint64_t i = 1; i < agents.size(); ++i) { - x[i] = i; - y[i] = reinterpret_cast(agents[i]) - min; - } - TGraph graph(agents.size(), x.data(), y.data()); - graph.SetTitle(";Agent element index; Virtual memory address"); - graph.Draw("ap"); - - c.Update(); - gPad->Modified(); - gPad->Update(); - c.Modified(); - c.cd(0); - auto steps = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps(); - auto dir = Simulation::GetActive()->GetOutputDir(); - c.SaveAs(Concat(dir, "/mem-layout-", steps, "-", numa_node, ".png").c_str()); -} - -// ----------------------------------------------------------------------------- -void PlotMemoryHistogram(const std::vector& agents, int numa_node) { - TCanvas c; - c.SetCanvasSize(1920, 1200); - - TH1F hist("", "", 100, 1, 10000); - hist.SetTitle(";#Delta bytes; Count"); - for (uint64_t i = 1; i < agents.size(); ++i) { - float val = 0; - auto t = reinterpret_cast(agents[i]); - auto l = reinterpret_cast(agents[i - 1]); - if (t > l) { - val = t - l; - } else { - val = l - t; - } - val = std::min(val, 10000.f - 1); - hist.Fill(val); - } - hist.Draw(); - - c.Update(); - gPad->SetLogy(); - gPad->Modified(); - gPad->Update(); - c.Modified(); - c.cd(0); - auto steps = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps(); - auto dir = Simulation::GetActive()->GetOutputDir(); - c.SaveAs( - Concat(dir, "/mem-layout-hist-", steps, "-", numa_node, ".png").c_str()); -} - -// ----------------------------------------------------------------------------- -struct Fen : public Functor { - std::vector& diffs; - Agent* query; - Fen(std::vector& diffs, Agent* query) : diffs(diffs), query(query) {} - - void operator()(Agent* neighbor, real_t) override { - if (neighbor == query) { - return; - } - auto t = reinterpret_cast(query); - auto l = reinterpret_cast(neighbor); - diffs.push_back(t - l); - } -}; - -// ----------------------------------------------------------------------------- -struct Fea : public Functor { - std::vector& diffs; - explicit Fea(std::vector& diffs) : diffs(diffs) {} - - void operator()(Agent* agent, AgentHandle) override { - Fen fen(diffs, agent); - auto* sim = Simulation::GetActive(); - auto* env = sim->GetEnvironment(); - auto squared_radius = env->GetLargestAgentSizeSquared(); - sim->GetExecutionContext()->ForEachNeighbor(fen, *agent, squared_radius); - } -}; - -// ----------------------------------------------------------------------------- -void PlotNeighborMemoryHistogram(bool before) { - TCanvas c; - c.SetCanvasSize(1920, 1200); - auto* rm = Simulation::GetActive()->GetResourceManager(); - if (rm->GetNumAgents() == 0) { - return; - } - std::vector diffs; - diffs.reserve(rm->GetNumAgents() * 3); - if (!before) { - Simulation::GetActive()->GetEnvironment()->Update(); - } - Fea fea(diffs); - rm->ForEachAgent(fea); - auto min = std::numeric_limits::max(); - auto max = std::numeric_limits::min(); - for (uint64_t i = 0; i < diffs.size(); ++i) { - if (diffs[i] < min) { - min = diffs[i]; - } - if (diffs[i] > max) { - max = diffs[i]; - } - } - min--; - max++; - uint64_t nbins = std::max(static_cast(100u), - static_cast((max - min) / 20000)); - TH1F hist("", "", nbins, min, max); - hist.SetTitle(";#Delta bytes; Count"); - for (uint64_t i = 0; i < diffs.size(); ++i) { - hist.Fill(diffs[i]); - } - hist.Draw(); - - c.Update(); - gPad->SetLogy(); - gPad->Modified(); - gPad->Update(); - c.Modified(); - c.cd(0); - auto steps = Simulation::GetActive()->GetScheduler()->GetSimulatedSteps(); - auto dir = Simulation::GetActive()->GetOutputDir(); - std::string suffix = "-end"; - if (before) { - suffix = "-begin"; - } - c.SaveAs( - Concat(dir, "/mem-layout-neighbor-hist-", steps, suffix, ".png").c_str()); - c.SaveAs( - Concat(dir, "/mem-layout-neighbor-hist-", steps, suffix, ".C").c_str()); -} - -} // namespace bdm diff --git a/src/core/util/plot_memory_layout.h b/src/core/util/plot_memory_layout.h deleted file mode 100644 index b79febc56..000000000 --- a/src/core/util/plot_memory_layout.h +++ /dev/null @@ -1,35 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_UTIL_PLOT_MEMORY_LAYOUT_H_ -#define CORE_UTIL_PLOT_MEMORY_LAYOUT_H_ - -#include - -namespace bdm { - -class Agent; - -// ----------------------------------------------------------------------------- -void PlotMemoryLayout(const std::vector& agents, int numa_node); - -// ----------------------------------------------------------------------------- -void PlotMemoryHistogram(const std::vector& agents, int numa_node); - -// ----------------------------------------------------------------------------- -void PlotNeighborMemoryHistogram(bool before = false); - -} // namespace bdm - -#endif // CORE_UTIL_PLOT_MEMORY_LAYOUT_H_ diff --git a/src/core/util/root.cc b/src/core/util/root.cc deleted file mode 100644 index ff2e1691a..000000000 --- a/src/core/util/root.cc +++ /dev/null @@ -1,38 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/util/root.h" -#include -#include -#include -#include -#include - -namespace bdm { - -// ----------------------------------------------------------------------------- -void PrintDataMemberInfo(const std::string& class_name) { - auto* dm_list = - TClassTable::GetDict(class_name.c_str())()->GetListOfDataMembers(); - std::cout << std::setw(40) << "Data member name" - << "\tOffset\tSize\tType" << std::endl; - for (auto el : *dm_list) { - auto* dm = static_cast(el); - std::cout << std::setw(40) << dm->GetName() << "\t" << dm->GetOffset() - << "\t" << dm->GetUnitSize() << "\t" << dm->GetFullTypeName() - << std::endl; - } -} - -} // namespace bdm diff --git a/src/core/util/root.h b/src/core/util/root.h deleted file mode 100644 index b09599ebc..000000000 --- a/src/core/util/root.h +++ /dev/null @@ -1,215 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef CORE_UTIL_ROOT_H_ -#define CORE_UTIL_ROOT_H_ - -#if defined(USE_DICT) - -#include -#include - -#define BDM_CLASS_DEF(class_name, class_version_id) \ - ClassDef(class_name, class_version_id) -#define BDM_CLASS_DEF_NV(class_name, class_version_id) \ - ClassDefNV(class_name, class_version_id) -#define BDM_CLASS_DEF_OVERRIDE(class_name, class_version_id) \ - ClassDefOverride(class_name, class_version_id) - -// NOLINT - -// ----------------------------------------------------------------------------- -// ----------------------------------------------------------------------------- -#else - -#include -#include "core/util/log.h" - -#define BDM_DICT_ERROR_MSG \ - "You tried to use a ROOT dictionary function, but " \ - "compiled BioDynaMo without dictionary support. " \ - "Please configure with cmake -Ddict=on .. and recompile." - -/// Macro that inserts empty definitions of each function used for compilations -/// without dictionaries. \n -/// The compiler won't complain about missing functions. \n -/// However, if ROOT functions are used that rely on dictionaries (e.g. backup) -/// a runtime error will be thrown. -#define BDM_NULL_CLASS_DEF(class_name, class_version_id) \ - public: \ - static TClass* Class() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static const char* Class_Name() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static Version_t Class_Version() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return class_version_id; \ - } \ - static TClass* Dictionary() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - virtual TClass* IsA() const { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return class_name::Class(); \ - } \ - virtual void ShowMembers(TMemberInspector& insp) const { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - virtual void Streamer(TBuffer&) { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - void StreamerNVirtual(TBuffer& ClassDef_StreamerNVirtual_b) { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - static const char* DeclFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int ImplFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return -1; \ - } \ - static const char* ImplFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int DeclFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return __LINE__; \ - } \ - \ - private: -// NOLINT - -#define BDM_NULL_CLASS_DEF_NV(class_name, class_version_id) \ - public: \ - static TClass* Class() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static const char* Class_Name() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static Version_t Class_Version() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return class_version_id; \ - } \ - static TClass* Dictionary() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - TClass* IsA() const { return class_name::Class(); } \ - void ShowMembers(TMemberInspector& insp) const { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - void Streamer(TBuffer&) { Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); } \ - void StreamerNVirtual(TBuffer& ClassDef_StreamerNVirtual_b) { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - static const char* DeclFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int ImplFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return -1; \ - } \ - static const char* ImplFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int DeclFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return __LINE__; \ - } \ - \ - private: -// NOLINT - -#define BDM_NULL_CLASS_DEF_OVERRIDE(class_name, class_version_id) \ - public: \ - static TClass* Class() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static const char* Class_Name() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static Version_t Class_Version() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return class_version_id; \ - } \ - static TClass* Dictionary() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - TClass* IsA() const override { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return class_name::Class(); \ - } \ - void ShowMembers(TMemberInspector& insp) const override { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - void Streamer(TBuffer&) override { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - void StreamerNVirtual(TBuffer& ClassDef_StreamerNVirtual_b) { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - } \ - static const char* DeclFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int ImplFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return -1; \ - } \ - static const char* ImplFileName() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return nullptr; \ - } \ - static int DeclFileLine() { \ - Log::Fatal("Dictionary", BDM_DICT_ERROR_MSG); \ - return __LINE__; \ - } \ - \ - private: -// NOLINT - -/// Forward all calls to BDM_NULL_CLASS_DEF -#define BDM_CLASS_DEF(class_name, class_version_id) \ - BDM_NULL_CLASS_DEF(class_name, class_version_id) -#define BDM_CLASS_DEF_NV(class_name, class_version_id) \ - BDM_NULL_CLASS_DEF_NV(class_name, class_version_id) -#define BDM_CLASS_DEF_OVERRIDE(class_name, class_version_id) \ - BDM_NULL_CLASS_DEF_OVERRIDE(class_name, class_version_id) - -#endif // defined(USE_DICT) - -namespace bdm { - -// ----------------------------------------------------------------------------- -/// Writes information of each data member of a class to cout. -void PrintDataMemberInfo(const std::string& class_name); - -} // namespace bdm - -#endif // CORE_UTIL_ROOT_H_ diff --git a/src/core/visualization/root/adaptor.h b/src/core/visualization/root/adaptor.h deleted file mode 100644 index 859e1df2d..000000000 --- a/src/core/visualization/root/adaptor.h +++ /dev/null @@ -1,218 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef CORE_VISUALIZATION_ROOT_ADAPTOR_H_ -#define CORE_VISUALIZATION_ROOT_ADAPTOR_H_ - -#include - -#include -#include -#include -#include -#include -#include "Math/AxisAngle.h" -#include "Math/EulerAngles.h" - -#include "core/param/param.h" -#include "core/resource_manager.h" -#include "core/scheduler.h" -#include "core/shape.h" -#include "core/simulation.h" -#include "core/util/log.h" -#include "core/util/math.h" -#include "neuroscience/neurite_element.h" - -using bdm::neuroscience::NeuriteElement; -using ROOT::Math::AxisAngle; -using ROOT::Math::EulerAngles; - -namespace bdm { - -/// The class that bridges the simulation code with ROOT Visualization -class RootAdaptor { - public: - RootAdaptor() : initialized_(false), max_viz_nodes_(1e6) {} - - /// Visualize one timestep - void Visualize(uint64_t total_steps) { - if (!initialized_) { - Initialize(); - initialized_ = true; - } - - auto *param = Simulation::GetActive()->GetParam(); - if (total_steps % param->visualization_interval != 0) { - return; - } - - top_->ClearNodes(); - - auto *rm = Simulation::GetActive()->GetResourceManager(); - - rm->ForEachAgent([&](Agent *agent) { - auto container = new TGeoVolumeAssembly("A"); - this->AddBranch(agent, container); - top_->AddNode(container, top_->GetNdaughters()); - }); - - gSystem->ProcessEvents(); - gGeoManager->Export(outfile_.c_str(), "biodynamo"); - } - - void DrawInCanvas(size_t w = 300, size_t h = 300, std::string opt = "") { - canvas_->GetListOfPrimitives()->Clear(); - if (opt.empty()) { - canvas_->GetListOfPrimitives()->Add(gGeoManager->GetTopVolume(), "all"); - } else { - opt = "all;" + opt; - canvas_->GetListOfPrimitives()->Add(gGeoManager->GetTopVolume(), - opt.c_str()); - } - canvas_->SetCanvasSize(static_cast(w), static_cast(h)); - canvas_->Update(); - canvas_->Draw(); - } - - private: - void Initialize() { - gGeoManager = new TGeoManager("Visualization", "BioDynaMo"); - canvas_ = new TCanvas("BioDynaMo Canvas", "For ROOT Notebooks ", 300, 300); - - outfile_ = Simulation::GetActive()->GetUniqueName() + ".root"; - - // Set number of segments for approximating circles in drawing. - // Keep it low for better performance. - gGeoManager->SetNsegments(15); - - mat_empty_space_ = new TGeoMaterial("EmptySpace", 0, 0, 0); - mat_solid_ = new TGeoMaterial("Solid", .938, 1., 10000.); - med_empty_space_ = new TGeoMedium("Empty", 1, mat_empty_space_); - med_solid_ = new TGeoMedium("Solid", 1, mat_solid_); - - // Another way to make top volume for world. In this way it will be - // unbounded. - top_ = new TGeoVolumeAssembly("WORLD"); - - gGeoManager->SetTopVolume(top_); - gGeoManager->SetVisLevel(4); - - // Number of visualized nodes inside one volume. If you exceed this number, - // ROOT will draw nothing. - gGeoManager->SetMaxVisNodes(max_viz_nodes_); - - // Assign the gGeoManager to our canvas to enable resizing of the output - // display. The "all" option is necessary to prevent ROOT from hiding - // objects (which it does by default for performance reasons). - canvas_->GetListOfPrimitives()->Add(gGeoManager->GetTopVolume(), "all"); - - initialized_ = true; - } - - /// Recursively adds sphere and its daughters to the container. - void AddBranch(const Agent *agent, TGeoVolume *container) { - switch (agent->GetShape()) { - case Shape::kSphere: - AddSphere(agent, container); - break; - case Shape::kCylinder: - AddCylinder(agent, container); - break; - default: - Log::Error("RootAdaptor", - "Tried to add a shape to the Root visualization that's not " - "one of the supported types : ", - agent->GetShape()); - } - // to be extended for other object - } - - /// Adds a sphere object to the volume - void AddSphere(const Agent *agent, TGeoVolume *container) { - std::string name = agent->GetTypeName() + std::to_string(agent->GetUid()); - auto radius = agent->GetDiameter() / 2; - auto massLocation = agent->GetPosition(); - auto x = massLocation[0]; - auto y = massLocation[1]; - auto z = massLocation[2]; - auto position = new TGeoTranslation(x, y, z); - auto volume = gGeoManager->MakeSphere(name.c_str(), med_solid_, 0, radius); - volume->SetLineColor(kBlue); - container->AddNode(volume, container->GetNdaughters(), position); - } - - /// Adds a cylinder object to the volume - void AddCylinder(const Agent *agent, TGeoVolume *container) { - if (auto neurite = dynamic_cast(agent)) { - std::string name = agent->GetTypeName() + std::to_string(agent->GetUid()); - auto radius = neurite->GetDiameter() / 2; - auto half_length = neurite->GetLength() / 2; - auto massLocation = neurite->GetPosition(); - auto x = massLocation[0]; - auto y = massLocation[1]; - auto z = massLocation[2]; - auto trans = new TGeoTranslation(x, y, z); - - // The initial orientation of the cylinder - TVector3 orig(0, 0, 1); - - // The vector that we want to orient the cylinder to (symmetry axis - // aligns with this vector) - Real3 d = neurite->GetSpringAxis(); - TVector3 dir(d[0], d[1], d[2]); - dir = dir.Unit(); - - // Compute the Axis-Angle rotation representation - auto dot_product = dir.Dot(orig); - auto angle = std::acos(dot_product); - // TODO(ahmad): make sure it is `z x dir, and not `dir x z` - TVector3 n = dir.Cross(orig); - n = n.Unit(); - auto axis = AxisAngle::AxisVector(n[0], n[1], n[2]); - AxisAngle aa(axis, angle); - EulerAngles ea(aa); - TGeoRotation *rot = new TGeoRotation("rot", Math::ToDegree(ea.Phi()), - Math::ToDegree(ea.Theta()), - Math::ToDegree(ea.Psi())); - TGeoCombiTrans *transrot = new TGeoCombiTrans(*trans, *rot); - auto volume = gGeoManager->MakeTube(name.c_str(), med_solid_, 0, radius, - half_length); - volume->SetLineColor(kBlue); - container->AddNode(volume, container->GetNdaughters(), transrot); - } else { - Log::Error("RootAdaptor", "This is not a cylindrical shaped object!"); - } - } - - std::string outfile_; - - TCanvas *canvas_ = nullptr; - - /// Top volumes for TGeo and TEve (world) - TGeoVolume *top_; - - /// Eve materials and medium - TGeoMaterial *mat_empty_space_; - TGeoMaterial *mat_solid_; - TGeoMedium *med_empty_space_; - TGeoMedium *med_solid_; - - bool initialized_; - - /// Max visualized shapes per volume. - int max_viz_nodes_; -}; - -} // namespace bdm - -#endif // CORE_VISUALIZATION_ROOT_ADAPTOR_H_ diff --git a/src/core/visualization/root/notebook_util.h b/src/core/visualization/root/notebook_util.h deleted file mode 100644 index e2c756bcb..000000000 --- a/src/core/visualization/root/notebook_util.h +++ /dev/null @@ -1,39 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- -#ifndef CORE_VISUALIZATION_ROOT_NOTEBOOK_UTIL_H_ -#define CORE_VISUALIZATION_ROOT_NOTEBOOK_UTIL_H_ - -#include -#include - -#include "core/simulation.h" -#include "core/visualization/root/adaptor.h" - -namespace bdm { - -/// Visualize the agents in ROOT notebooks -inline void VisualizeInNotebook(size_t w = 300, size_t h = 300, - std::string opt = "") { - auto* sim = Simulation::GetActive(); - auto* param = sim->GetParam(); - // Force an update of the visualization engine - sim->GetScheduler()->GetRootVisualization()->Visualize( - param->visualization_interval); - sim->GetScheduler()->GetRootVisualization()->DrawInCanvas(w, h, - std::move(opt)); -} - -} // namespace bdm - -#endif // CORE_VISUALIZATION_ROOT_NOTEBOOK_UTIL_H_ diff --git a/test/installation-test.sh b/test/installation-test.sh index 03714df95..7e44d5504 100755 --- a/test/installation-test.sh +++ b/test/installation-test.sh @@ -37,15 +37,12 @@ cd $BDM_PROJECT_DIR BDM_OS=$(DetectOs) -NOTEBOOK_FLAG="-Dnotebooks=off" - # speed-up build by disabling tests and demos -# Currently SBML and notebooks is not supported on osx +# Currently SBML is not supported on osx if [ "$BDM_OS" != "osx" ]; then SBML_FLAG="-Dsbml=on" - NOTEBOOK_FLAG="-Dnotebooks=on" fi -export BDM_CMAKE_FLAGS="-Dtest=off ${NOTEBOOK_FLAG} ${SBML_FLAG}" +export BDM_CMAKE_FLAGS="-Dtest=off ${SBML_FLAG}" # Build BioDynaMo SILENT_INSTALL=1 $BDM_PROJECT_DIR/install.sh diff --git a/test/system/backup_restore.sh b/test/system/backup_restore.sh deleted file mode 100755 index 778eddf46..000000000 --- a/test/system/backup_restore.sh +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - - -# Pass DYLD_LIBRARY_PATH again due to OS X System Integrity Policy -if [ `uname` = "Darwin" ]; then - source $BDMSYS/bin/thisbdm.sh &> /dev/null -fi - -set -e -x - -SOURCE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -tmp_dir=$(mktemp -d) -trap "rm -rf \"${tmp_dir}\"" EXIT - -cd "${tmp_dir}" -cp -r "${SOURCE}/backup_restore" . -cd backup_restore - -cmake . -make -j4 - -BACKUP_RESTORE_FILE="backup_restore.root" - -# start simulation -./backup_restore -b $BACKUP_RESTORE_FILE & - -# simulate crash of simulation after 5 seconds -SIMULATION_PID=$! -sleep 5 -# wait longer if backup file has not been created yet -# check every second if backup file exists -for i in {0..5}; do - if [ -e "$BACKUP_RESTORE_FILE" ]; then - break - fi - sleep 1 -done -kill -9 $SIMULATION_PID -sleep 1 - -# restart after artificial crash -./backup_restore -r $BACKUP_RESTORE_FILE -RETURN_CODE=$? - -exit $RETURN_CODE diff --git a/test/system/backup_restore/CMakeLists.txt b/test/system/backup_restore/CMakeLists.txt deleted file mode 100644 index de6b86dae..000000000 --- a/test/system/backup_restore/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.19.3) - -project(backup_restore) - -find_package(BioDynaMo REQUIRED) -include("${BDM_USE_FILE}") -include_directories("src") - -file(GLOB_RECURSE HEADERS src/*.h) -file(GLOB_RECURSE SOURCES src/*.cc) - -bdm_add_executable(backup_restore - HEADERS "${HEADERS}" - SOURCES "${SOURCES}" - LIBRARIES "${BDM_REQUIRED_LIBRARIES}") diff --git a/test/system/backup_restore/src/backup_restore.cc b/test/system/backup_restore/src/backup_restore.cc deleted file mode 100644 index 4666ac78d..000000000 --- a/test/system/backup_restore/src/backup_restore.cc +++ /dev/null @@ -1,21 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "backup_restore.h" -#include - -int main(int argc, const char** argv) { - omp_set_num_threads(1); - return bdm::Simulate(argc, argv); -} diff --git a/test/system/backup_restore/src/backup_restore.h b/test/system/backup_restore/src/backup_restore.h deleted file mode 100644 index b1e12f306..000000000 --- a/test/system/backup_restore/src/backup_restore.h +++ /dev/null @@ -1,80 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef SYSTEM_BACKUP_RESTORE_SRC_BACKUP_RESTORE_H_ -#define SYSTEM_BACKUP_RESTORE_SRC_BACKUP_RESTORE_H_ - -#include -#include "biodynamo.h" - -namespace bdm { - -struct TestBehaviour : public Behavior { - BDM_BEHAVIOR_HEADER(TestBehaviour, Behavior, 1); - - TestBehaviour() { AlwaysCopyToNew(); } - - void Run(Agent* agent) override { - usleep(35000); // 35 ms -> one iteration will take 350 ms - agent->SetDiameter(agent->GetDiameter() + 1); - } -}; - -inline int Simulate(int argc, const char** argv) { - auto set_param = [](Param* param) { param->backup_interval = 1; }; - Simulation simulation(argc, argv, set_param); - auto* rm = simulation.GetResourceManager(); - - for (size_t i = 0; i < 10; i++) { - auto* cell = new Cell({real_t(100.0) * i, real_t(100.0) * i, - real_t(100.0) * i}); // no colliding cells - cell->SetDiameter(i); - cell->AddBehavior(new TestBehaviour()); - rm->AddAgent(cell); - } - - auto* scheduler = simulation.GetScheduler(); - - // will perform backup after iteration 3 - scheduler->Simulate(3); // 1050 ms - - // application crash will happen inside this call - scheduler->Simulate(11); // 3850 ms - - // another call to Simulate after recovery - scheduler->Simulate(2); - - // check result - int count = 0; - bool failed = 0; - rm->ForEachAgent([&](Agent* agent) { - if (agent->GetDiameter() != 16 + count) { - std::cerr << "Test failure: result incorrect" << std::endl; - std::cerr << " Diameter of cell " << count << " is " - << agent->GetDiameter() << " but should be 16" << std::endl; - failed = true; - return; - } - count++; - }); - if (failed) { - return 1; - } - std::cout << "Test finished successfully" << std::endl; - return 0; -} - -} // namespace bdm - -#endif // SYSTEM_BACKUP_RESTORE_SRC_BACKUP_RESTORE_H_ diff --git a/test/system/multi_simulation.sh b/test/system/multi_simulation.sh deleted file mode 100755 index 5eddc0e75..000000000 --- a/test/system/multi_simulation.sh +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & Newcastle University for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - - -# Pass DYLD_LIBRARY_PATH again due to OS X System Integrity Policy -if [ `uname` = "Darwin" ]; then - source $BDMSYS/bin/thisbdm.sh &> /dev/null -fi - -set -e -x - -SOURCE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - -tmp_dir=$(mktemp -d) - -cd "${tmp_dir}" -cp -r "${SOURCE}/multi_simulation" . -cd multi_simulation - -cmake . -make -j4 - -# Legacy code, CentOS no longer supported but kept for reference. -# CentOS Github Action runner uses a root user to execute the mpirun command -# below, giving a fatal warning. We understand this warning and allow mpirun to -# be executed as root -OS_ID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"') -if [ ! -z ${GITHUB_ACTIONS+x} ]; then - if [ ${OS_ID} = "centos" ]; then - GHA_CENTOS_ALLOW_ROOT="--allow-run-as-root" - fi -fi - -# start simulation -mpirun -np 2 $GHA_CENTOS_ALLOW_ROOT ./multi_simulation_test --config=optim.json - -RETURN_CODE=$? -exit $RETURN_CODE diff --git a/test/system/multi_simulation/CMakeLists.txt b/test/system/multi_simulation/CMakeLists.txt deleted file mode 100644 index 562919bc4..000000000 --- a/test/system/multi_simulation/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & Newcastle University for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -cmake_minimum_required(VERSION 3.19.3) - -project(multi_simulation_test) - -find_package(BioDynaMo REQUIRED) -include("${BDM_USE_FILE}") -include_directories("src") -include_directories("${BDMSYS}/include") - -file(GLOB_RECURSE HEADERS src/*.h) -file(GLOB_RECURSE SOURCES src/*.cc) - -bdm_add_executable(multi_simulation_test - HEADERS "${HEADERS}" - SOURCES "${SOURCES}" - LIBRARIES "${BDM_REQUIRED_LIBRARIES}") diff --git a/test/system/multi_simulation/optim.json b/test/system/multi_simulation/optim.json deleted file mode 100644 index 9d415a403..000000000 --- a/test/system/multi_simulation/optim.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "bdm::OptimizationParam": { - "algorithm" : "TestAlgorithm", - "params" : [ - { - "_typename": "bdm::RangeParam", - "param_name" : "bdm::SimParam::param1", - "lower_bound" : 1.0, - "upper_bound" : 3.0, - "stride" : 1 - }, - { - "_typename": "bdm::SetParam", - "param_name" : "bdm::SimParam::param2", - "values" : [0, 8, 13] - }, - { - "_typename": "bdm::LogRangeParam", - "param_name" : "bdm::SimParam::param3", - "base" : 10, - "lower_bound" : -2.0, - "upper_bound" : 1.0, - "stride" : 1 - } - ] - } -} diff --git a/test/system/multi_simulation/src/multi_simulation_test.cc b/test/system/multi_simulation/src/multi_simulation_test.cc deleted file mode 100644 index d6a6c740a..000000000 --- a/test/system/multi_simulation/src/multi_simulation_test.cc +++ /dev/null @@ -1,28 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/multi_simulation.h" -#include "multi_simulation_test.h" - -using namespace bdm; - -const ParamGroupUid SimParam::kUid = ParamGroupUidGenerator::Get()->NewUid(); - -int main(int argc, const char** argv) { - Param::RegisterParamGroup(new SimParam()); - experimental::MultiSimulation pe(argc, argv); - return pe.Execute(Simulate); -} diff --git a/test/system/multi_simulation/src/multi_simulation_test.h b/test/system/multi_simulation/src/multi_simulation_test.h deleted file mode 100644 index 2a28735d0..000000000 --- a/test/system/multi_simulation/src/multi_simulation_test.h +++ /dev/null @@ -1,62 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef SYSTEM_MULTI_SIMULATION_MULTI_SIMULATION_TEST_H_ -#define SYSTEM_MULTI_SIMULATION_MULTI_SIMULATION_TEST_H_ - -#include -#include -#include - -#include "biodynamo.h" - -namespace bdm { - -using namespace bdm::experimental; -using namespace std::chrono_literals; - -// Parameters specific for this simulation -struct SimParam : public ParamGroup { - BDM_PARAM_GROUP_HEADER(SimParam, 1); - - int param1 = 0; - int param2 = 0; - int param3 = 0; -}; - -inline int Simulate(int argc, const char** argv, TimeSeries* result, - Param* final_params = nullptr) { - // Set the optimization parameters - auto set_param = [&](Param* param) { - param->Restore(std::move(*final_params)); - }; - Simulation simulation(argc, argv, set_param); - - auto* sparam = simulation.GetParam()->Get(); - - // Emulate a simulation - std::this_thread::sleep_for(100ms); - - result->Add("param1", {0}, {static_cast(sparam->param1)}); - result->Add("param2", {0}, {static_cast(sparam->param2)}); - result->Add("param3", {0}, {static_cast(sparam->param3)}); - - std::cout << "Processing parameters: [" << sparam->param1 << ", " - << sparam->param2 << ", " << sparam->param3 << "]" << std::endl; - return 0; -} - -} // namespace bdm - -#endif // SYSTEM_MULTI_SIMULATION_MULTI_SIMULATION_TEST_H_ diff --git a/test/system/multi_simulation/src/test_algorithm.cc b/test/system/multi_simulation/src/test_algorithm.cc deleted file mode 100644 index 40eeabecc..000000000 --- a/test/system/multi_simulation/src/test_algorithm.cc +++ /dev/null @@ -1,86 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/algorithm/algorithm.h" -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "core/multi_simulation/dynamic_loop.h" -#include "core/multi_simulation/optimization_param.h" -#include "core/util/log.h" - -using nlohmann::json; - -namespace bdm { -namespace experimental { - -/// Perform an exhaustive sweep across specified parameters -struct TestAlgorithm : public Algorithm { - BDM_ALGO_HEADER(); - - void operator()(Functor& send_params_to_worker, - Param* default_params) override { - auto sweeping_params = default_params->Get()->params; - - if (sweeping_params.empty()) { - Log::Error("TestAlgorithm", "No sweeping parameters found!"); - return; - } - - DynamicNestedLoop(sweeping_params, [&](const std::vector& slots) { - TimeSeries expected_result; - TimeSeries obtained_result; - json j_patch; - - int i = 0; - for (auto* param : sweeping_params) { - expected_result.Add(param->GetParamName(), {0}, - {static_cast(param->GetValue(slots[i]))}); - j_patch[param->GetGroupName()][param->GetParamName()] = - param->GetValue(slots[i]); - i++; - } - - Param final_params = *default_params; - final_params.MergeJsonPatch(j_patch.dump()); - - send_params_to_worker(&final_params, &obtained_result); - - // Check results - int failed = 0; - if (std::abs(expected_result.GetXValues("param1")[0] - - obtained_result.GetXValues("param1")[0]) > 1e-9) { - failed = 1; - } - if (std::abs(expected_result.GetXValues("param2")[0] - - obtained_result.GetXValues("param2")[0]) > 1e-9) { - failed = 1; - } - if (std::abs(expected_result.GetXValues("param3")[0] - - obtained_result.GetXValues("param3")[0]) > 1e-9) { - failed = 1; - } - - if (failed) { - Log::Error("TestAlgorithm", "Test failed"); - exit(1); - } - }); - } -}; - -BDM_REGISTER_ALGO(TestAlgorithm); - -} // namespace experimental -} // namespace bdm diff --git a/test/unit/core/analysis/time_series_test.cc b/test/unit/core/analysis/time_series_test.cc index 11b6533d1..223035d39 100644 --- a/test/unit/core/analysis/time_series_test.cc +++ b/test/unit/core/analysis/time_series_test.cc @@ -12,10 +12,11 @@ // // ----------------------------------------------------------------------------- -#include "core/analysis/time_series.h" -#include +#include + #include #include "core/agent/cell.h" +#include "core/analysis/time_series.h" #include "core/behavior/behavior.h" #include "core/behavior/stateless_behavior.h" #include "core/resource_manager.h" @@ -301,77 +302,6 @@ TEST(TimeSeries, ReuseAddCollectorReducerResult) { EXPECT_NEAR(3.0, yvals[0], abs_error::value); } -// ----------------------------------------------------------------------------- -TEST(TimeSeries, StoreAndLoad) { - Simulation sim(TEST_NAME); - sim.GetResourceManager()->AddAgent(new Cell()); - sim.GetResourceManager()->AddAgent(new Cell()); - - TimeSeries ts; - auto ycollector = [](Simulation* sim) { return static_cast(4.0); }; - auto xcollector = [](Simulation* sim) { return static_cast(5.0); }; - ts.AddCollector("collect", ycollector, xcollector); - - auto d_gt_0 = [](Agent* a) { return a->GetDiameter() > 0; }; - auto* counter = new Counter(d_gt_0); - ts.AddCollector("collect1", counter, xcollector); - - ts.Add("my-entry", {1, 2}, {3, 4}); - ts.Save("ts.root"); - - TimeSeries* restored = nullptr; - - TimeSeries::Load("ts.root", &restored); - ASSERT_TRUE(restored != nullptr); - - EXPECT_EQ(3u, restored->Size()); - EXPECT_TRUE(restored->Contains("my-entry")); - EXPECT_TRUE(restored->Contains("collect")); - EXPECT_TRUE(restored->Contains("collect1")); - - const auto& xvals = restored->GetXValues("my-entry"); - EXPECT_EQ(2u, xvals.size()); - EXPECT_NEAR(1.0, xvals[0], abs_error::value); - EXPECT_NEAR(2.0, xvals[1], abs_error::value); - const auto& yvals = restored->GetYValues("my-entry"); - EXPECT_EQ(2u, yvals.size()); - EXPECT_NEAR(3.0, yvals[0], abs_error::value); - EXPECT_NEAR(4.0, yvals[1], abs_error::value); - - // check if collector has been restored correctly. - restored->Update(); - { - const auto& xvals1 = restored->GetXValues("collect"); - EXPECT_EQ(1u, xvals1.size()); - EXPECT_NEAR(5.0, xvals1[0], abs_error::value); - const auto& yvals1 = restored->GetYValues("collect"); - EXPECT_EQ(1u, yvals1.size()); - EXPECT_NEAR(4.0, yvals1[0], abs_error::value); - } - { - const auto& xvals1 = restored->GetXValues("collect1"); - EXPECT_EQ(1u, xvals1.size()); - EXPECT_NEAR(5.0, xvals1[0], abs_error::value); - const auto& yvals1 = restored->GetYValues("collect1"); - EXPECT_EQ(1u, yvals1.size()); - EXPECT_NEAR(2.0, yvals1[0], abs_error::value); - } - delete restored; -} - -// ----------------------------------------------------------------------------- -TEST(TimeSeries, StoreJson) { - TimeSeries ts; - - auto collect_function = [](Simulation* sim) { - return static_cast(4.0); - }; - ts.AddCollector("collect", collect_function); - - ts.Add("my-entry", {1, 2}, {3, 4}); - ts.SaveJson("ts.json"); -} - // ----------------------------------------------------------------------------- TEST(TimeSeries, MergeNullptr) { std::vector tss(2); @@ -434,14 +364,18 @@ TEST(TimeSeries, Merge) { tss[2].Add("entry-0", {1, 2}, {1, 13}); TimeSeries merged; - TimeSeries::Merge( - &merged, tss, - [](const std::vector& all_y_values, real_t* y, real_t* el, - real_t* eh) { - *y = TMath::Median(all_y_values.size(), all_y_values.data()); - *el = *y - *TMath::LocMin(all_y_values.begin(), all_y_values.end()); - *eh = *TMath::LocMax(all_y_values.begin(), all_y_values.end()) - *y; - }); + TimeSeries::Merge(&merged, tss, + [](const std::vector& all_y_values, real_t* y, + real_t* el, real_t* eh) { + auto sorted = all_y_values; + std::sort(sorted.begin(), sorted.end()); + auto middle = sorted.size() / 2; + *y = sorted.size() % 2 == 0 + ? (sorted[middle - 1] + sorted[middle]) / 2 + : sorted[middle]; + *el = *y - sorted.front(); + *eh = sorted.back() - *y; + }); EXPECT_EQ(1u, merged.Size()); const auto& xvals = merged.GetXValues("entry-0"); diff --git a/test/unit/core/command_line_options_test.cc b/test/unit/core/command_line_options_test.cc index 9a3f710b0..6c9098286 100644 --- a/test/unit/core/command_line_options_test.cc +++ b/test/unit/core/command_line_options_test.cc @@ -28,8 +28,6 @@ TEST(CommandLineOptionsTest, CoreOptions) { EXPECT_EQ("binary_name", clo.GetSimulationName()); EXPECT_EQ(0u, clo.Get>("config").size()); - EXPECT_EQ("", clo.Get("backup")); - EXPECT_EQ("", clo.Get("restore")); } TEST(CommandLineOptionsTest, MultipleOptions) { diff --git a/test/unit/core/multi_simulation/algorithm_test.cc b/test/unit/core/multi_simulation/algorithm_test.cc deleted file mode 100644 index 75e1706da..000000000 --- a/test/unit/core/multi_simulation/algorithm_test.cc +++ /dev/null @@ -1,62 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/algorithm/algorithm.h" -#include "core/multi_simulation/algorithm/algorithm_registry.h" -#include "unit/test_util/test_util.h" - -namespace bdm { -namespace experimental { - -// ----------------------------------------------------------------------------- -TEST(AlgorithmTest, Registry) { - auto* algo_registry = AlgorithmRegistry::GetInstance(); - - EXPECT_NE(nullptr, algo_registry); - - auto* param_sweep = algo_registry->GetAlgorithm("ParameterSweep"); - EXPECT_NE(nullptr, param_sweep); - auto* pso = algo_registry->GetAlgorithm("ParticleSwarm"); - EXPECT_NE(nullptr, pso); -} - -// ----------------------------------------------------------------------------- -struct MyAlgorithm : public Algorithm { - BDM_ALGO_HEADER(); - void operator()(Functor& dispatch_experiment, - Param* default_param) {} -}; -BDM_REGISTER_ALGO(MyAlgorithm) - -TEST(AlgorithmTest, AddAlgorithm) { - auto* algo_registry = AlgorithmRegistry::GetInstance(); - auto* my_algo = algo_registry->GetAlgorithm("MyAlgorithm"); - EXPECT_NE(nullptr, my_algo); -} - -// ----------------------------------------------------------------------------- -TEST(AlgorithmTest, UnregisteredAlgorithm) { - EXPECT_DEATH_IF_SUPPORTED( - { - auto* algo_registry = AlgorithmRegistry::GetInstance(); - auto* nen = algo_registry->GetAlgorithm("NonExistingName"); - EXPECT_EQ(nullptr, nen); - }, - ".*Algorithm not found in registry*"); -} - -} // namespace experimental -} // namespace bdm diff --git a/test/unit/core/multi_simulation/dynamic_loop_test.cc b/test/unit/core/multi_simulation/dynamic_loop_test.cc deleted file mode 100644 index 5d4b93d02..000000000 --- a/test/unit/core/multi_simulation/dynamic_loop_test.cc +++ /dev/null @@ -1,64 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/dynamic_loop.h" -#include "core/multi_simulation/optimization_param_type/log_range_param.h" -#include "core/multi_simulation/optimization_param_type/range_param.h" -#include "core/multi_simulation/optimization_param_type/set_param.h" -#include "unit/test_util/test_util.h" - -namespace bdm { -namespace experimental { - -TEST(DynamicLoopTest, DynamicLoop) { - std::vector ranges = { - new RangeParam("a", -1.5, 1.5, 0.5), new LogRangeParam("b", 2, 0, 10, 5), - new SetParam("c", {0, 1})}; - - // Write out the nested for loops and extract the expected results - std::vector> expected; - for (int j = 0; j < 2; j++) { - for (real_t lrp = 0; lrp < 11; lrp += 5) { - for (real_t rp = -1.5; rp < 1.6; rp += 0.5) { - expected.push_back({rp, static_cast(std::pow(2, lrp)), - static_cast(j)}); - } - } - } - - std::vector paramset(3); - - int it = 0; - auto lambda = [&](std::vector slots) { - int i = 0; - for (auto& param : paramset) { - param = ranges[i]->GetValue(slots[i]); - i++; - } - - EXPECT_VEC_NEAR(expected[it], paramset); - it++; - }; - - DynamicNestedLoop(ranges, lambda); - - delete ranges[0]; - delete ranges[1]; - delete ranges[2]; -} - -} // namespace experimental -} // namespace bdm diff --git a/test/unit/core/multi_simulation/optimization_param_type_test.cc b/test/unit/core/multi_simulation/optimization_param_type_test.cc deleted file mode 100644 index e441820ad..000000000 --- a/test/unit/core/multi_simulation/optimization_param_type_test.cc +++ /dev/null @@ -1,73 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include - -#include "core/multi_simulation/optimization_param_type/log_range_param.h" -#include "core/multi_simulation/optimization_param_type/optimization_param_type.h" -#include "core/multi_simulation/optimization_param_type/particle_swarm_param.h" -#include "core/multi_simulation/optimization_param_type/range_param.h" -#include "core/multi_simulation/optimization_param_type/set_param.h" -#include "unit/test_util/test_util.h" - -namespace bdm { - -TEST(OptimizationParamTypeTest, RangeParam) { - RangeParam rp("TestParam", 0, 10, 1); - EXPECT_EQ(11u, rp.GetNumElements()); - - for (uint32_t i = 0; i < rp.GetNumElements(); i++) { - EXPECT_EQ(i, rp.GetValue(i)); - } - - RangeParam rp2("TestParam", -3.5, 3.5, 0.5); - EXPECT_EQ(15u, rp2.GetNumElements()); - EXPECT_EQ(0, rp2.GetValue(7)); - EXPECT_EQ(-3.5, rp2.GetValue(0)); -} - -TEST(OptimizationParamTypeTest, InvertedBounds) { - EXPECT_DEATH_IF_SUPPORTED( - { RangeParam rp("TestParam", 10, 1, 1); }, - ".*with a lower_bound value higher than upper_bound*"); - - EXPECT_DEATH_IF_SUPPORTED( - { LogRangeParam rp("TestParam", 2, 10, 1, 1); }, - ".*with a lower_bound value higher than upper_bound*"); - - EXPECT_DEATH_IF_SUPPORTED( - { ParticleSwarmParam rp("TestParam", 10, 1, 1); }, - ".*with a lower_bound value higher than upper_bound*"); -} - -TEST(OptimizationParamTypeTest, LogRangeParam) { - LogRangeParam lrp("TestParam", 2, 0, 10, 1); - EXPECT_EQ(11u, lrp.GetNumElements()); - - for (uint32_t i = 0; i < lrp.GetNumElements(); i++) { - EXPECT_EQ(std::pow(2, i), lrp.GetValue(i)); - } -} - -TEST(OptimizationParamTypeTest, SetParam) { - std::vector vals = {1, 12, 4, 4, 5, 91, -2.4, -93}; - SetParam sp("TestParam", vals); - EXPECT_EQ(8u, sp.GetNumElements()); - - for (uint32_t i = 0; i < sp.GetNumElements(); i++) { - EXPECT_EQ(vals[i], sp.GetValue(i)); - } -} - -} // namespace bdm diff --git a/test/unit/core/param/param_test.cc b/test/unit/core/param/param_test.cc deleted file mode 100644 index aacf38ee9..000000000 --- a/test/unit/core/param/param_test.cc +++ /dev/null @@ -1,158 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include -#include - -#include "core/multi_simulation/optimization_param.h" -#include "core/multi_simulation/optimization_param_type/particle_swarm_param.h" -#include "unit/core/param/param_test.h" -#include "unit/test_util/test_util.h" - -using nlohmann::json; - -namespace bdm { - -const ParamGroupUid TestParamGroup::kUid = - ParamGroupUidGenerator::Get()->NewUid(); - -// ----------------------------------------------------------------------------- -TEST(ParamTest, ToJsonString) { - Param::RegisterParamGroup(new TestParamGroup()); - Param param; - auto j_param = json::parse(param.ToJsonString()); - - EXPECT_REAL_EQ(real_t(3.14), - j_param["bdm::TestParamGroup"]["test_param1"].get()); - EXPECT_EQ(42u, j_param["bdm::TestParamGroup"]["test_param2"].get()); - EXPECT_EQ(-1, j_param["bdm::TestParamGroup"]["test_param3"].get()); - EXPECT_EQ("output", j_param["bdm::Param"]["output_dir"].get()); -} - -// ----------------------------------------------------------------------------- -TEST(ParamTest, RestoreFromJson) { - Param::RegisterParamGroup(new TestParamGroup()); - Param param; - - std::string patch1 = R"EOF( -{ - "bdm::Param": { - "visualize_agents": { - "Cell": ["type"] - } - }, - "bdm::TestParamGroup": { - "test_param1": 6.28, - "test_param3": -10 - } -} -)EOF"; - - std::string patch2 = R"EOF( -{ - "bdm::Param": { - "simulation_time_step" : 1.0, - "visualize_agents": { - "Cell": ["type", "some-dm"] - } - }, - "bdm::TestParamGroup": { - "test_param2": 123 - } -} -)EOF"; - - param.MergeJsonPatch(patch1); - - EXPECT_EQ(1u, param.visualize_agents.size()); - auto vis_cell = param.visualize_agents["Cell"]; - EXPECT_EQ(1u, vis_cell.size()); - EXPECT_TRUE(vis_cell.find("type") != vis_cell.end()); - - auto* test_param = param.Get(); - EXPECT_REAL_EQ(real_t(6.28), test_param->test_param1); - EXPECT_EQ(42u, test_param->test_param2); - EXPECT_EQ(-10, test_param->test_param3); - - param.MergeJsonPatch(patch2); - - EXPECT_EQ(1u, param.visualize_agents.size()); - vis_cell = param.visualize_agents["Cell"]; - EXPECT_EQ(2u, vis_cell.size()); - EXPECT_TRUE(vis_cell.find("type") != vis_cell.end()); - EXPECT_TRUE(vis_cell.find("some-dm") != vis_cell.end()); - - test_param = param.Get(); - EXPECT_REAL_EQ(real_t(6.28), test_param->test_param1); - EXPECT_EQ(123u, test_param->test_param2); - EXPECT_EQ(-10, test_param->test_param3); -} - -TEST(ParamTest, OptimizationParam) { - Param param; - auto* opt_param = param.Get(); - - EXPECT_TRUE(opt_param != nullptr); - EXPECT_EQ("", opt_param->algorithm); - EXPECT_EQ(0u, opt_param->params.size()); - EXPECT_EQ(1u, opt_param->repetition); - EXPECT_EQ(100u, opt_param->max_iterations); - - std::string patch = R"EOF( -{ - "bdm::OptimizationParam": { - "algorithm" : "ParticleSwarm", - "repetition" : 10, - "max_iterations" : 1000, - "params" : [ - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::infection_probablity", - "lower_bound" : 0.001, - "upper_bound" : 1, - "initial_value" : 0.005 - }, - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::infection_radius", - "lower_bound" : 5, - "upper_bound" : 50, - "initial_value" : 5 - }, - { - "_typename": "bdm::ParticleSwarmParam", - "param_name" : "bdm::SimParam::agent_speed", - "lower_bound" : 2, - "upper_bound" : 50, - "initial_value" : 2 - } - ] - } -} -)EOF"; - - param.MergeJsonPatch(patch); - opt_param = param.Get(); - EXPECT_EQ("ParticleSwarm", opt_param->algorithm); - EXPECT_EQ(3u, opt_param->params.size()); - auto* swarm_param = static_cast(opt_param->params[0]); - EXPECT_EQ("bdm::SimParam::infection_probablity", swarm_param->param_name); - EXPECT_EQ(real_t(0.001), swarm_param->lower_bound); - EXPECT_EQ(1, swarm_param->upper_bound); - EXPECT_EQ(real_t(0.005), swarm_param->initial_value); - EXPECT_EQ(10u, opt_param->repetition); - EXPECT_EQ(1000u, opt_param->max_iterations); -} - -} // namespace bdm diff --git a/test/unit/core/param/test.json b/test/unit/core/param/test.json deleted file mode 100644 index be44d7153..000000000 --- a/test/unit/core/param/test.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "bdm::Param": { - "simulation_time_step" : 1.0, - "visualize_sim_objects": { - "Cell": ["type", "some-dm"] - } - }, - "bdm::OptimizationParam": { - "algorithm" : "ParameterSweep", - "params" : [ - { - "_typename": "bdm::RangeParam", - "param_name" : "bdm::SimParam::monocyte_diameter", - "lower_bound" : 1.0, - "upper_bound" : 10.0, - "stride" : 1 - }, - { - "_typename": "bdm::SetParam", - "param_name" : "bdm::SimParam::t_cell_walkspeed", - "values" : [0, 8, 13, 42] - }, - { - "_typename": "bdm::LogRangeParam", - "param_name" : "bdm::SimParam::stokes_u", - "base" : 10, - "lower_bound" : -10.0, - "upper_bound" : 1.0, - "stride" : 1 - } - ] - } -} diff --git a/test/unit/core/scheduler_test.cc b/test/unit/core/scheduler_test.cc index f472e6477..e379f21fc 100644 --- a/test/unit/core/scheduler_test.cc +++ b/test/unit/core/scheduler_test.cc @@ -12,11 +12,16 @@ // // ----------------------------------------------------------------------------- -#include "unit/core/scheduler_test.h" +#include "core/scheduler.h" + +#include + +#include "core/agent/cell.h" #include "core/environment/uniform_grid_environment.h" #include "core/model_initializer.h" #include "core/operation/operation_registry.h" #include "unit/test_util/test_agent.h" +#include "unit/test_util/test_util.h" namespace bdm { @@ -50,7 +55,7 @@ class SchedulerTest : public ::testing::Test { void TearDown() override {} - void Initialize() { scheduler_->restore_point_++; } + void Initialize() { scheduler_->Initialize(); } ParallelResizeVector* GetBoxes() { return &(env_->boxes_); @@ -63,38 +68,6 @@ class SchedulerTest : public ::testing::Test { UniformGridEnvironment* env_ = nullptr; }; -#ifdef USE_DICT -TEST_F(SchedulerTest, NoRestoreFile) { - auto set_param = [](auto* param) { param->restore_file = ""; }; - Simulation simulation(TEST_NAME, set_param); - auto* rm = simulation.GetResourceManager(); - - remove(ROOTFILE); - - Cell* cell = new Cell(); - cell->SetDiameter(10); // important for env to determine box size - rm->AddAgent(cell); - - // start restore validation - TestSchedulerRestore scheduler; - scheduler.Simulate(100); - EXPECT_EQ(100u, scheduler.execute_calls); - EXPECT_EQ(1u, rm->GetNumAgents()); - - scheduler.Simulate(100); - EXPECT_EQ(200u, scheduler.execute_calls); - EXPECT_EQ(1u, rm->GetNumAgents()); - - scheduler.Simulate(100); - EXPECT_EQ(300u, scheduler.execute_calls); - EXPECT_EQ(1u, rm->GetNumAgents()); -} - -TEST_F(SchedulerTest, Restore) { RunRestoreTest(); } - -TEST_F(SchedulerTest, Backup) { RunBackupTest(); } -#endif // USE_DICT - TEST_F(SchedulerTest, EmptySimulationFromBeginning) { auto set_param = [](auto* param) { param->bound_space = Param::BoundSpaceMode::kClosed; diff --git a/test/unit/core/scheduler_test.h b/test/unit/core/scheduler_test.h deleted file mode 100644 index d48cc0fc4..000000000 --- a/test/unit/core/scheduler_test.h +++ /dev/null @@ -1,127 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef UNIT_CORE_SCHEDULER_TEST_H_ -#define UNIT_CORE_SCHEDULER_TEST_H_ - -#include "core/scheduler.h" - -#include -#include -#include - -#include "core/agent/cell.h" -#include "core/environment/environment.h" -#include "core/simulation_backup.h" -#include "core/util/io.h" -#include "unit/test_util/test_util.h" - -#define ROOTFILE "bdmFile.root" - -namespace bdm { - -class TestSchedulerRestore : public Scheduler { - public: - void Execute() override { execute_calls++; } - - unsigned execute_calls = 0; -}; - -class TestSchedulerBackup : public Scheduler { - public: - void Execute() override { - // sleep - usleep(350000); - // backup should be created every second -> every three iterations - if (execute_calls_ % 3 != 0 || execute_calls_ == 0) { - EXPECT_FALSE(FileExists(ROOTFILE)); - } else { - EXPECT_TRUE(FileExists(ROOTFILE)); - remove(ROOTFILE); - } - execute_calls_++; - } - unsigned execute_calls_ = 0; -}; - -inline void RunRestoreTest() { - { - Simulation simulation("SchedulerTest_RunRestoreTest"); - auto* rm = simulation.GetResourceManager(); - remove(ROOTFILE); - - // create backup that will be restored later on - Cell* cell = new Cell(); - cell->SetDiameter(10); // important for grid to determine box size - rm->AddAgent(cell); - SimulationBackup backup(ROOTFILE, ""); - backup.Backup(149); - rm->ClearAgents(); - EXPECT_EQ(0u, rm->GetNumAgents()); - } - - // start restore validation - auto set_param = [](auto* param) { param->restore_file = ROOTFILE; }; - Simulation simulation("SchedulerTest_RunRestoreTest", set_param); - auto* rm = simulation.GetResourceManager(); - TestSchedulerRestore scheduler; - // 149 simulation steps have already been calculated. Therefore, this call - // should be ignored - scheduler.Simulate(100); - EXPECT_EQ(0u, scheduler.execute_calls); - EXPECT_EQ(0u, rm->GetNumAgents()); - - // Restore should happen within this call - scheduler.Simulate(100); - // only 51 steps should be simulated - EXPECT_EQ(51u, scheduler.execute_calls); - EXPECT_EQ(1u, rm->GetNumAgents()); - - // add element to see if if restore happens again - rm->AddAgent(new Cell()); - - // normal simulation - no restore - scheduler.Simulate(100); - EXPECT_EQ(151u, scheduler.execute_calls); - EXPECT_EQ(2u, rm->GetNumAgents()); - - remove(ROOTFILE); -} - -inline void RunBackupTest() { - auto set_param = [](auto* param) { - param->backup_file = ROOTFILE; - param->backup_interval = 1; - }; - - Simulation simulation("SchedulerTest_RunBackupTest", set_param); - auto* rm = simulation.GetResourceManager(); - - remove(ROOTFILE); - - Cell* cell = new Cell(); - cell->SetDiameter(10); // important for grid to determine box size - rm->AddAgent(cell); - - TestSchedulerBackup scheduler; - - // one simulation step takes 350 ms -> backup should be created every three - // steps - scheduler.Simulate(4); - remove(ROOTFILE); -} - -} // namespace bdm - -#endif // UNIT_CORE_SCHEDULER_TEST_H_ diff --git a/test/unit/core/simulation_backup_test.cc b/test/unit/core/simulation_backup_test.cc deleted file mode 100644 index d1017d3d5..000000000 --- a/test/unit/core/simulation_backup_test.cc +++ /dev/null @@ -1,148 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/simulation_backup.h" - -#include -#include "core/agent/cell.h" -#include "core/resource_manager.h" -#include "core/util/io.h" -#include "gtest/gtest.h" -#include "unit/test_util/test_util.h" - -#define ROOTFILE "bdmFile.root" - -#ifdef USE_DICT - -namespace bdm { - -class SimulationBackupTest : public ::testing::Test {}; -using SimulationBackupDeathTest = SimulationBackupTest; - -TEST(SimulationBackupDeathTest, GetSimulationStepsFromBackup) { - ASSERT_DEATH( - { - SimulationBackup backup("", ""); - backup.GetSimulationStepsFromBackup(); - }, - ".*Requested to restore data, but no restore file given..*"); -} - -TEST(SimulationBackupTest, GetSimulationStepsFromBackup) { - remove(ROOTFILE); - - IntegralTypeWrapper wrapper(26); - WritePersistentObject(ROOTFILE, "completed_simulation_steps", wrapper, - "recreate"); - - SimulationBackup backup("", ROOTFILE); - auto iteration = backup.GetSimulationStepsFromBackup(); - - EXPECT_EQ(26u, iteration); - - remove(ROOTFILE); -} - -TEST(SimulationBackupDeathTest, BackupNoBackupFileSpecified) { - ASSERT_DEATH( - { - size_t iterations = 1; - SimulationBackup backup("", ""); - backup.Backup(iterations); - }, - ".*Requested to backup data, but no backup file given..*"); -} - -TEST(SimulationBackupTest, Backup) { - remove(ROOTFILE); - Simulation simulation(TEST_NAME); - auto* rm = simulation.GetResourceManager(); - - rm->AddAgent(new Cell()); - size_t iterations = 26; - - SimulationBackup backup(ROOTFILE, ""); - backup.Backup(iterations); - - ASSERT_TRUE(FileExists(ROOTFILE)); - - TFileRaii file(TFile::Open(ROOTFILE)); - - // RuntimeVariables - RuntimeVariables* restored_rv; - file.Get()->GetObject(SimulationBackup::kRuntimeVariableName.c_str(), - restored_rv); - RuntimeVariables this_system; - EXPECT_EQ(this_system, *restored_rv); - - // iterations - IntegralTypeWrapper* wrapper = nullptr; - file.Get()->GetObject(SimulationBackup::kSimulationStepName.c_str(), wrapper); - EXPECT_EQ(26u, wrapper->Get()); - - // Simulation - Simulation* restored_simulation = nullptr; - file.Get()->GetObject(SimulationBackup::kSimulationName.c_str(), - restored_simulation); - EXPECT_EQ(1u, restored_simulation->GetResourceManager()->GetNumAgents()); - // Writing and reading Simulation is tested in simulation_test.cc - - remove(ROOTFILE); -} - -TEST(SimulationBackupDeathTest, RestoreNoRestoreFileSpecified) { - ASSERT_DEATH( - { - SimulationBackup backup("", ""); - backup.Restore(); - }, - ".*Requested to restore data, but no restore file given..*"); -} - -TEST(SimulationBackupDeathTest, RestoreFileDoesNotExist) { - ASSERT_DEATH({ SimulationBackup backup("", "file-does-not-exist.root"); }, - ".*Given restore file does not exist.*"); -} - -TEST(SimulationBackupTest, BackupAndRestore) { - remove(ROOTFILE); - Simulation simulation(TEST_NAME); - auto* rm = simulation.GetResourceManager(); - - rm->AddAgent(new Cell()); - size_t iterations = 26; - - SimulationBackup backup(ROOTFILE, ""); - backup.Backup(iterations); - - // restore - SimulationBackup restore("", ROOTFILE); - // iterations - auto restored_iterations = restore.GetSimulationStepsFromBackup(); - EXPECT_EQ(26u, restored_iterations); - restore.Restore(); - - // ResourceManager should not have changed - EXPECT_EQ(rm, simulation.GetResourceManager()); - - // get new ResourceManager - rm = simulation.GetResourceManager(); - EXPECT_EQ(1u, rm->GetNumAgents()); - - remove(ROOTFILE); -} - -} // namespace bdm - -#endif // USE_DICT diff --git a/test/unit/core/simulation_test.cc b/test/unit/core/simulation_test.cc index 357c39b1a..2c1597e8f 100644 --- a/test/unit/core/simulation_test.cc +++ b/test/unit/core/simulation_test.cc @@ -5,47 +5,41 @@ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. -// // See the LICENSE file distributed with this work for details. // See the NOTICE file distributed with this work for additional information // regarding copyright ownership. // // ----------------------------------------------------------------------------- -#include -#include +#include #include #include -#include +#include #include -#include +#include + +#include -#include "core/agent/cell.h" #include "core/environment/environment.h" #include "core/resource_manager.h" -#include "core/simulation_backup.h" -#include "core/util/io.h" -#include "unit/test_util/io_test.h" +#include "core/simulation.h" #include "unit/test_util/test_util.h" namespace bdm { class SimulationTest : public ::testing::Test { - public: - static constexpr const char* kTomlFileName = "bdm.toml"; - static constexpr const char* kTomlContent = + protected: + static constexpr const char* kDefaultConfig = "bdm.toml"; + static constexpr const char* kConfigContent = "[simulation]\n" "unschedule_default_operations = [\"mechanical forces\"]\n" "random_seed = 123\n" "output_dir = \"result-dir\"\n" - "backup_file = \"backup.root\"\n" - "restore_file = \"restore.root\"\n" - "backup_interval = 3600\n" "time_step = 0.0125\n" "max_displacement = 2.0\n" - "bound_space = 0\n" + "bound_space = \"closed\"\n" "min_bound = -100\n" - "max_bound = 200\n" + "max_bound = 200\n" "diffusion_method = \"euler\"\n" "thread_safety_mechanism = \"automatic\"\n" "\n" @@ -53,521 +47,187 @@ class SimulationTest : public ::testing::Test { "insitu = false\n" "export = true\n" "pv_insitu_pipeline = \"my-insitu-script.py\"\n" - "pv_insitu_pipelinearguments = \"--param1=123\"\n" + "pv_insitu_pipelinearguments = \"param1=123\"\n" "interval = 100\n" "export_generate_pvsm = false\n" "compress_pv_files = false\n" "\n" - " [[visualize_agent]]\n" - " name = \"Cell\"\n" - "\n" - " [[visualize_agent]]\n" - " name = \"Neurite\"\n" - " additional_data_members = [ \"spring_axis_\", \"tension_\" ]\n" + "[[visualize_agent]]\n" + "name = \"Cell\"\n" "\n" + "[[visualize_agent]]\n" + "name = \"Neurite\"\n" + "additional_data_members = [\"spring_axis_\", \"tension_\"]\n" "\n" - " [[visualize_diffusion]]\n" - " name = \"Na\"\n" - " concentration = false\n" - " gradient = true\n" + "[[visualize_diffusion]]\n" + "name = \"Na\"\n" + "concentration = false\n" + "gradient = true\n" "\n" - " [[visualize_diffusion]]\n" - " name = \"K\"\n" + "[[visualize_diffusion]]\n" + "name = \"K\"\n" "\n" "[performance]\n" "scheduling_batch_size = 123\n" "detect_static_agents = true\n" "cache_neighbors = true\n" - "use_bdm_mem_mgr = false\n" - "mem_mgr_aligned_pages_shift = 7\n" "mem_mgr_growth_rate = 1.123\n" "mem_mgr_max_mem_per_thread_factor = 3\n" "minimize_memory_while_rebalancing = false\n" - "mapped_data_array_mode = \"cache\"\n" "\n" "[development]\n" - "# this is a comment\n" "statistics = false\n" "debug_numa = true\n"; - protected: void SetUp() override { - remove(kTomlFileName); - remove("restore.root"); - CreateEmptyRestoreFile("restore.root"); + std::remove(kDefaultConfig); Simulation::counter_ = 0; } - void TearDown() override { - remove(kTomlFileName); - remove("restore.root"); - } + void TearDown() override { std::remove(kDefaultConfig); } - /// Creates an empty file restore file. \n - /// It is needed, because BioDynaMo throws a fatal exception if it is - /// initialized with a restore file that does not exist. - void CreateEmptyRestoreFile(const std::string& filename) { - Simulation sim("CreateEmptyRestoreFile"); - SimulationBackup b(filename, ""); - b.Backup(0); - Simulation::counter_ = 0; + static void WriteConfig(const std::string& path) { + std::ofstream config(path); + config << kConfigContent; } - void ValidateNonCLIParameter(const Param* param) { - EXPECT_EQ(123u, param->random_seed); - EXPECT_EQ("paraview", param->visualization_engine); - EXPECT_EQ("result-dir", param->output_dir); - EXPECT_EQ("euler", param->diffusion_method); - EXPECT_EQ(3600u, param->backup_interval); - EXPECT_EQ(real_t(0.0125), param->simulation_time_step); - EXPECT_EQ(1u, param->unschedule_default_operations.size()); - EXPECT_EQ("mechanical forces", param->unschedule_default_operations[0]); - EXPECT_EQ(2.0, param->simulation_max_displacement); - EXPECT_EQ(0, param->bound_space); - EXPECT_EQ(-100, param->min_bound); - EXPECT_EQ(200, param->max_bound); - EXPECT_EQ(Param::ThreadSafetyMechanism::kAutomatic, - param->thread_safety_mechanism); - EXPECT_FALSE(param->insitu_visualization); - EXPECT_TRUE(param->export_visualization); - EXPECT_EQ("my-insitu-script.py", param->pv_insitu_pipeline); - EXPECT_EQ("--param1=123", param->pv_insitu_pipelinearguments); - EXPECT_EQ(100u, param->visualization_interval); - EXPECT_FALSE(param->visualization_export_generate_pvsm); - EXPECT_FALSE(param->visualization_compress_pv_files); - - // visualize_agent - EXPECT_EQ(2u, param->visualize_agents.size()); - auto it = param->visualize_agents.cbegin(); - uint64_t counter = 0; - while (it != param->visualize_agents.cend()) { - if (counter == 0) { - EXPECT_EQ("Cell", (*it).first); - EXPECT_EQ(0u, (*it).second.size()); - } else if (counter == 1) { - EXPECT_EQ("Neurite", (*it).first); - auto additional_dm = (*it).second; - EXPECT_EQ(2u, additional_dm.size()); - EXPECT_TRUE(additional_dm.find("spring_axis_") != additional_dm.end()); - EXPECT_TRUE(additional_dm.find("tension_") != additional_dm.end()); - } - counter++; - it++; - } - - // visualize_diffusion - EXPECT_EQ(2u, param->visualize_diffusion.size()); - for (uint64_t i = 0; i < 2; i++) { - auto vd = param->visualize_diffusion[i]; - if (i == 0) { - EXPECT_EQ("Na", vd.name); - EXPECT_FALSE(vd.concentration); - EXPECT_TRUE(vd.gradient); - } else if (i == 1) { - EXPECT_EQ("K", vd.name); - EXPECT_TRUE(vd.concentration); - EXPECT_FALSE(vd.gradient); - } - } - - // performance group - EXPECT_EQ(123u, param->scheduling_batch_size); - EXPECT_TRUE(param->detect_static_agents); - EXPECT_TRUE(param->cache_neighbors); - EXPECT_NEAR(1.123, param->mem_mgr_growth_rate, abs_error::value); - EXPECT_EQ(3u, param->mem_mgr_max_mem_per_thread_factor); - EXPECT_FALSE(param->minimize_memory_while_rebalancing); - EXPECT_EQ(Param::MappedDataArrayMode::kCache, - param->mapped_data_array_mode); - - // development group - EXPECT_FALSE(param->statistics); - EXPECT_TRUE(param->debug_numa); + static void ValidateConfig(const Param& param) { + EXPECT_EQ(param.random_seed, 123u); + EXPECT_EQ(param.output_dir, "result-dir"); + EXPECT_EQ(param.diffusion_method, "euler"); + EXPECT_REAL_EQ(param.simulation_time_step, real_t(0.0125)); + EXPECT_REAL_EQ(param.simulation_max_displacement, real_t(2)); + EXPECT_EQ(param.bound_space, Param::BoundSpaceMode::kClosed); + EXPECT_EQ(param.min_bound, -100); + EXPECT_EQ(param.max_bound, 200); + EXPECT_EQ(param.thread_safety_mechanism, + Param::ThreadSafetyMechanism::kAutomatic); + EXPECT_EQ(param.unschedule_default_operations, + std::vector{"mechanical forces"}); + + EXPECT_FALSE(param.insitu_visualization); + EXPECT_TRUE(param.export_visualization); + EXPECT_EQ(param.pv_insitu_pipeline, "my-insitu-script.py"); + EXPECT_EQ(param.pv_insitu_pipelinearguments, "param1=123"); + EXPECT_EQ(param.visualization_interval, 100u); + EXPECT_FALSE(param.visualization_export_generate_pvsm); + EXPECT_FALSE(param.visualization_compress_pv_files); + ASSERT_EQ(param.visualize_agents.size(), 2u); + EXPECT_TRUE(param.visualize_agents.at("Cell").empty()); + EXPECT_EQ(param.visualize_agents.at("Neurite"), + (std::set{"spring_axis_", "tension_"})); + ASSERT_EQ(param.visualize_diffusion.size(), 2u); + EXPECT_EQ(param.visualize_diffusion[0].name, "Na"); + EXPECT_FALSE(param.visualize_diffusion[0].concentration); + EXPECT_TRUE(param.visualize_diffusion[0].gradient); + EXPECT_EQ(param.visualize_diffusion[1].name, "K"); + + EXPECT_EQ(param.scheduling_batch_size, 123u); + EXPECT_TRUE(param.detect_static_agents); + EXPECT_TRUE(param.cache_neighbors); + EXPECT_NEAR(param.mem_mgr_growth_rate, 1.123, abs_error::value); + EXPECT_EQ(param.mem_mgr_max_mem_per_thread_factor, 3u); + EXPECT_FALSE(param.minimize_memory_while_rebalancing); + EXPECT_FALSE(param.statistics); + EXPECT_TRUE(param.debug_numa); } }; -#ifdef USE_DICT -TEST_F(SimulationTest, InitializeRuntimeParams) { - std::ofstream config_file(kTomlFileName); - config_file << kTomlContent; - config_file.close(); - - const char* argv[1] = {"./binary_name"}; - Simulation simulation(1, argv); - auto* param = simulation.GetParam(); - - EXPECT_EQ("backup.root", param->backup_file); - EXPECT_EQ("restore.root", param->restore_file); - EXPECT_EQ("binary_name", simulation.GetUniqueName()); - ValidateNonCLIParameter(param); -} - -TEST_F(SimulationTest, InitializeRuntimeParams2) { - std::ofstream config_file(kTomlFileName); - config_file << kTomlContent; - config_file.close(); - +TEST_F(SimulationTest, LoadsDefaultTomlConfig) { + WriteConfig(kDefaultConfig); Simulation simulation("my-simulation"); - auto* param = simulation.GetParam(); - - EXPECT_EQ("backup.root", param->backup_file); - EXPECT_EQ("restore.root", param->restore_file); - EXPECT_EQ("my-simulation", simulation.GetUniqueName()); - ValidateNonCLIParameter(param); -} -TEST_F(SimulationTest, InitializeRuntimeParamsWithCLIArguments) { - std::ofstream config_file(kTomlFileName); - config_file << kTomlContent; - config_file.close(); - - CreateEmptyRestoreFile("myrestore.root"); - const char* argv[5] = {"./binary_name", "-b", "mybackup.root", "-r", - "myrestore.root"}; - Simulation simulation(5, argv); - auto* param = simulation.GetParam(); - - // the following two parameters should contain the values from the command - // line arguments. - EXPECT_EQ("mybackup.root", param->backup_file); - EXPECT_EQ("myrestore.root", param->restore_file); - EXPECT_EQ("binary_name", simulation.GetUniqueName()); - ValidateNonCLIParameter(param); - remove("myrestore.root"); + EXPECT_EQ(simulation.GetUniqueName(), "my-simulation"); + ValidateConfig(*simulation.GetParam()); } -TEST_F(SimulationTest, InitializeRuntimeParamsCLIConfigFileName) { - std::string config_filename = "my-config-file.toml"; - remove(kTomlFileName); - remove(config_filename.c_str()); - std::ofstream config_file(config_filename); - config_file << kTomlContent; - config_file.close(); - - const char* argv[3] = {"./binary_name", "-c", config_filename.c_str()}; - Simulation simulation(3, argv); - - ValidateNonCLIParameter(simulation.GetParam()); - remove("myrestore.root"); - remove(config_filename.c_str()); -} - -TEST_F(SimulationTest, InitializeRuntimeParamsCtorConfigFileName) { - std::string config_filename = "my-config-file.toml"; - remove(kTomlFileName); - remove(config_filename.c_str()); - std::ofstream config_file(config_filename); - config_file << kTomlContent; - config_file.close(); - +TEST_F(SimulationTest, LoadsConstructorTomlConfig) { + constexpr auto kConfig = "constructor-config.toml"; + WriteConfig(kConfig); { - const char* argv[1] = {"./binary_name"}; - Simulation simulation(1, argv, {config_filename}); - ValidateNonCLIParameter(simulation.GetParam()); + Simulation simulation("my-simulation", {kConfig}); + ValidateConfig(*simulation.GetParam()); } + std::remove(kConfig); +} +TEST_F(SimulationTest, LoadsCommandLineTomlConfig) { + constexpr auto kConfig = "command-line-config.toml"; + WriteConfig(kConfig); + const char* argv[] = {"binary-name", "-c", kConfig}; { - Simulation simulation("./binary_name", {config_filename}); - ValidateNonCLIParameter(simulation.GetParam()); + Simulation simulation(3, argv); + EXPECT_EQ(simulation.GetUniqueName(), "binary-name"); + ValidateConfig(*simulation.GetParam()); } - - remove("myrestore.root"); - remove(config_filename.c_str()); + std::remove(kConfig); } -TEST_F(SimulationTest, InitializeRuntimeParamsSimulationName) { - // same working dir - const char* argv0[1] = {"./binary_name"}; - Simulation simulation0(1, argv0); - EXPECT_EQ("binary_name", simulation0.GetUniqueName()); - - // in PATH - const char* argv1[1] = {"binary_name"}; - Simulation simulation1(1, argv1); - EXPECT_EQ("binary_name1", simulation1.GetUniqueName()); +TEST_F(SimulationTest, DerivesUniqueNamesFromProgramPath) { + const char* first_argv[] = {"./binary-name"}; + Simulation first(1, first_argv); + EXPECT_EQ(first.GetUniqueName(), "binary-name"); - // binary dir != working dir - const char* argv2[1] = {"./build/binary_name"}; - Simulation simulation2(1, argv2); - EXPECT_EQ("binary_name2", simulation2.GetUniqueName()); + const char* second_argv[] = {"binary-name"}; + Simulation second(1, second_argv); + EXPECT_EQ(second.GetUniqueName(), "binary-name1"); - Simulation simulation3("binary_name"); - EXPECT_EQ("binary_name3", simulation3.GetUniqueName()); -} - -TEST_F(SimulationTest, MultipleJsonConfigsAndPrecedence) { - const char* ctor1_config = R"EOF( -{ - "bdm::Param": { - "random_seed": 1, - "scheduling_batch_size": 1, - "backup_file": "ctor1", - "mem_mgr_growth_rate": 1.11, - "backup_interval": 1, - "simulation_time_step": 1 - } -} -)EOF"; - - // overwrite all but first parameter - const char* ctor2_config = R"EOF( -{ - "bdm::Param": { - "scheduling_batch_size": 2, - "backup_file": "ctor2", - "mem_mgr_growth_rate": 1.12, - "backup_interval": 2, - "simulation_time_step": 2 - } -} -)EOF"; - - // overwrite all but first two parameter - const char* cli1_config = R"EOF( -{ - "bdm::Param": { - "backup_file": "cli1", - "mem_mgr_growth_rate": 1.13, - "backup_interval": 3, - "simulation_time_step": 3 - } -} -)EOF"; - - // overwrite all but first three parameter - const char* cli2_config = R"EOF( -{ - "bdm::Param": { - "mem_mgr_growth_rate": 1.14, - "backup_interval": 4, - "simulation_time_step": 4 - } -} -)EOF"; - - WriteToFile("ctor1.json", ctor1_config); - WriteToFile("ctor2.json", ctor2_config); - WriteToFile("cli1.json", cli1_config); - WriteToFile("cli2.json", cli2_config); - - const char* argv[9] = {TEST_NAME, - "-c", - "cli1.json", - "-c", - "cli2.json", - "--inline-config", - "{ \"bdm::Param\": { \"backup_interval\": 5, " - "\"simulation_time_step\": 5 }}", - "--inline-config", - "{ \"bdm::Param\": { \"simulation_time_step\": 6 }}"}; - - Simulation sim(9, argv, {"ctor1.json", "ctor2.json"}); - auto* param = sim.GetParam(); - - EXPECT_EQ(1u, param->random_seed); - EXPECT_EQ(2u, param->scheduling_batch_size); - EXPECT_EQ("cli1", param->backup_file); - EXPECT_NEAR(1.14, param->mem_mgr_growth_rate, abs_error::value); - EXPECT_EQ(5u, param->backup_interval); - EXPECT_NEAR(6.0, param->simulation_time_step, abs_error::value); - - std::remove("ctor1.json"); - std::remove("ctor2.json"); - std::remove("cli1.json"); - std::remove("cli2.json"); + const char* third_argv[] = {"./build/binary-name"}; + Simulation third(1, third_argv); + EXPECT_EQ(third.GetUniqueName(), "binary-name2"); } -#endif // USE_DICT - -TEST_F(SimulationTest, SimulationId_OutputDir) { - Simulation simulation("my-simulation"); - Simulation simulation1("my-simulation"); - - EXPECT_EQ("my-simulation", simulation.GetUniqueName()); - EXPECT_EQ("output/my-simulation", simulation.GetOutputDir()); - - EXPECT_EQ("my-simulation1", simulation1.GetUniqueName()); - EXPECT_EQ("output/my-simulation1", simulation1.GetOutputDir()); -} +TEST_F(SimulationTest, OutputDirectoryUsesUniqueName) { + Simulation first("my-simulation"); + Simulation second("my-simulation"); -TEST_F(SimulationTest, SimulationId_OutputDir_TimeStamp) { - auto SetParam = [](Param* param) { - param->remove_output_dir_contents = false; - }; - Simulation simulation("my-simulation", SetParam); - Simulation simulation1("my-simulation", SetParam); - - // The regex below, is supposed to catch the following example structure - // output[D+]/my-simulation[D+]/2021[d{4}]-08[d{2}]-09[d{2}]- - // 12[d{2}]:24[d{2}]:51[d{2}] - // For timestamp2, we add an additional [d] after the second [D+] to capture - // my-simulation1 [D+d]. - std::regex timestamp1{ - "\\D+\\/\\D+\\/\\d{4}-\\d{2}-\\d{2}-\\d{2}:\\d{2}:\\d{2}"}; - std::regex timestamp2{ - "\\D+\\/\\D+\\d\\/\\d{4}-\\d{2}-\\d{2}-\\d{2}:\\d{2}:\\d{2}"}; - - std::string out1 = simulation.GetOutputDir(); - std::string out2 = simulation1.GetOutputDir(); - - EXPECT_EQ("my-simulation", simulation.GetUniqueName()); - EXPECT_TRUE(regex_match(out1, timestamp1)); - // EXPECT_TRUE( ) - - EXPECT_EQ("my-simulation1", simulation1.GetUniqueName()); - EXPECT_TRUE(regex_match(out2, timestamp2)); + EXPECT_EQ(first.GetOutputDir(), "output/my-simulation"); + EXPECT_EQ(second.GetOutputDir(), "output/my-simulation1"); } -TEST_F(SimulationTest, SimulationId_OutputDir_NoSimName) { +TEST_F(SimulationTest, EmptyNameUsesOutputRoot) { Simulation simulation(""); - EXPECT_EQ("", simulation.GetUniqueName()); - EXPECT_EQ("output", simulation.GetOutputDir()); -} - -TEST_F(SimulationTest, SimulationId_OutputDir_NoSimName_TimeStamp) { - auto SetParam = [](Param* param) { - param->remove_output_dir_contents = false; - }; - Simulation simulation("", SetParam); - - // The regex below, is supposed to catch the following example structure - // output[D+]/2021[d{4}]-08[d{2}]-09[d{2}]-12[d{2}]:24[d{2}]:51[d{2}] - std::regex timestamp{"\\D+\\/\\d{4}-\\d{2}-\\d{2}-\\d{2}:\\d{2}:\\d{2}"}; - - EXPECT_EQ("", simulation.GetUniqueName()); - EXPECT_TRUE(regex_match(simulation.GetOutputDir(), timestamp)); -} - -TEST_F(SimulationTest, InlineConfig) { - const char* argv[3] = { - "./binary_name", "--inline-config", - "{ \"bdm::Param\": { \"simulation_time_step\": 6.28}}"}; - Simulation sim(3, argv); - EXPECT_NEAR(6.28, sim.GetParam()->simulation_time_step, 1e-5); + EXPECT_EQ(simulation.GetUniqueName(), ""); + EXPECT_EQ(simulation.GetOutputDir(), "output"); } -TEST_F(SimulationTest, DontRemoveOutputDirContents) { - std::filesystem::create_directory(Concat("output/", TEST_NAME)); - std::filesystem::create_directory(Concat("output/", TEST_NAME, "/subdir")); - EXPECT_FALSE(std::filesystem::is_empty(Concat("output/", TEST_NAME))); +TEST_F(SimulationTest, PreservesOutputDirectoryContentsWhenRequested) { + const auto output = std::filesystem::path("output") / TEST_NAME; + std::filesystem::create_directories(output / "subdir"); - auto SetParam = [](Param* param) { + auto preserve_contents = [](Param* param) { param->remove_output_dir_contents = false; }; - Simulation sim(TEST_NAME, SetParam); - EXPECT_FALSE(std::filesystem::is_empty(Concat("output/", TEST_NAME))); -} + Simulation simulation(TEST_NAME, preserve_contents); -TEST_F(SimulationTest, RemoveOutputDirContents) { - std::filesystem::create_directory(Concat("output/", TEST_NAME)); - std::filesystem::create_directory(Concat("output/", TEST_NAME, "/subdir")); - EXPECT_FALSE(std::filesystem::is_empty(Concat("output/", TEST_NAME))); - - auto set_param = [](Param* param) { - param->remove_output_dir_contents = true; - }; - Simulation sim(TEST_NAME, set_param); - EXPECT_TRUE(std::filesystem::is_empty(Concat("output/", TEST_NAME))); + EXPECT_FALSE(std::filesystem::is_empty(output)); } -#ifdef USE_DICT -TEST_F(IOTest, Simulation) { - // change state of each data member in Simulation - - auto set_param = [](Param* param) { param->simulation_time_step = 3.14; }; - Simulation sim(TEST_NAME, set_param); - auto* rm = sim.GetResourceManager(); - auto* param = sim.GetParam(); - rm->AddAgent(new Cell()); - rm->AddAgent(new Cell()); -#pragma omp parallel - { - auto* r = sim.GetRandom(); - r->SetSeed(42); - r->Uniform(12, 34); - } +TEST_F(SimulationTest, RemovesOutputDirectoryContentsByDefault) { + const auto output = std::filesystem::path("output") / TEST_NAME; + std::filesystem::create_directories(output / "subdir"); - Simulation* restored; - BackupAndRestore(sim, &restored); - EXPECT_EQ(2u, restored->GetResourceManager()->GetNumAgents()); - - // store next random number for later comparison - std::vector next_rand; - next_rand.resize(omp_get_max_threads()); -#pragma omp parallel - { - auto* r = sim.GetRandom(); - next_rand[omp_get_thread_num()] = r->Uniform(12, 34); - } + Simulation simulation(TEST_NAME); - // change state to see if call to Simulation::Restore was successful - rm->ClearAgents(); - const_cast(param)->simulation_time_step = 6.28; - // check if rm is really empty to avoid false positive test results - EXPECT_EQ(0u, rm->GetNumAgents()); - - // assign restored simulation to current one - sim.Restore(std::move(*restored)); - delete restored; - - // Validate results; - // From each data member in simulation do one check - // For more detailed iotest see the repective classes - // rm and param should still be valid! - const real_t kEpsilon = abs_error::value; - EXPECT_EQ(2u, rm->GetNumAgents()); - EXPECT_NEAR(3.14, param->simulation_time_step, kEpsilon); -#pragma omp parallel - { - auto* r = sim.GetRandom(); - EXPECT_NEAR(next_rand[omp_get_thread_num()], r->Uniform(12, 34), kEpsilon); - } + EXPECT_TRUE(std::filesystem::is_empty(output)); } -// The Param IOTest is located here to reuse the infrastructure used to test -// parsing parameters. -TEST_F(SimulationTest, ParamIOTest) { - std::ofstream config_file(kTomlFileName); - config_file << kTomlContent; - config_file.close(); - +TEST_F(SimulationTest, RetainsResourceManagerWhenSetToSameInstance) { Simulation simulation(TEST_NAME); - auto* param = simulation.GetParam(); - - Param* restored; - BackupAndRestore(*param, &restored); - const char* root_file = "param.root"; - remove(root_file); - // write to root file - WritePersistentObject(root_file, "param", *param, "new"); - - // read back - GetPersistentObject(root_file, "param", restored); - // NB visualize_agents is currently not backed up due to a ROOT error - restored->visualize_agents = param->visualize_agents; - - ValidateNonCLIParameter(restored); - remove(root_file); - delete restored; -} + auto* resource_manager = simulation.GetResourceManager(); -#endif // USE_DICT + simulation.SetResourceManager(resource_manager); -TEST(Simulation, SetResourceManagerSame) { - Simulation sim(TEST_NAME); - auto* rm = sim.GetResourceManager(); - sim.SetResourceManager(rm); - EXPECT_EQ(0u, rm->GetNumAgents()); + EXPECT_EQ(resource_manager->GetNumAgents(), 0u); } -TEST(Simulation, SetEnvironmentSame) { - Simulation sim(TEST_NAME); - auto* env = sim.GetEnvironment(); - sim.SetEnvironment(env); - // will segfault if env has been deleted inside - // SetEnvironment - env->Clear(); +TEST_F(SimulationTest, RetainsEnvironmentWhenSetToSameInstance) { + Simulation simulation(TEST_NAME); + auto* environment = simulation.GetEnvironment(); + + simulation.SetEnvironment(environment); + environment->Clear(); } } // namespace bdm diff --git a/test/unit/core/util/io_test.cc b/test/unit/core/util/io_test.cc deleted file mode 100644 index 9baf89f80..000000000 --- a/test/unit/core/util/io_test.cc +++ /dev/null @@ -1,54 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#include "core/util/io.h" -#include - -#define ROOTFILE "bdmFile.root" - -namespace bdm { - -#ifdef USE_DICT - -TEST(IOUtilTest, RuntimeVars) { - RuntimeVariables this_machine; - - SysInfo_t si = this_machine.GetSystemInfo(); - si.fOS = "Non-Existing_OS"; - RuntimeVariables different_machine; - different_machine.SetSystemInfo(si); - - if (this_machine == different_machine) { - FAIL(); - } - - RuntimeVariables this_machine_copy; - if (this_machine != this_machine_copy) { - FAIL(); - } - - WritePersistentObject(ROOTFILE, "RuntimeVars", this_machine, "RECREATE"); - RuntimeVariables* this_machine_r = nullptr; - GetPersistentObject(ROOTFILE, "RuntimeVars", this_machine_r); - - if (this_machine != *this_machine_r) { - FAIL(); - } - - remove(ROOTFILE); -} - -#endif // USE_DICT - -} // namespace bdm diff --git a/test/unit/test_util/io_test.h b/test/unit/test_util/io_test.h deleted file mode 100644 index cd80c35e8..000000000 --- a/test/unit/test_util/io_test.h +++ /dev/null @@ -1,78 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -#ifndef UNIT_TEST_UTIL_IO_TEST_H_ -#define UNIT_TEST_UTIL_IO_TEST_H_ - -#include -#include "core/param/param.h" -#include "core/simulation.h" -#include "core/util/io.h" -#include "unit/test_util/test_util.h" - -#include "TBufferJSON.h" - -#define ROOT_FILE "io-test.root" -#define JSON_FILE "io-test.json" - -namespace bdm { - -// Hide testing::Test from the generated dictionary. -// Otherwise ROOT is unable to load it into cling. -#ifndef __ROOTCLING__ - -/// Test fixture for io tests that follow the same form -/// Usage: -/// -/// TEST_F(IOTest, Type) { -/// // assign value to each data member -/// Type t; -/// t.SetDataMember1(...); -/// ... -/// Type *restored = nullptr; -/// -/// BackupAndRestore(t, &restored); -/// -/// // verify if all data members have been restored correctly -/// EXPECT_EQ(..., restored->GetDataMember1()); -/// ... -/// } -class IOTest : public ::testing::Test {}; - -#endif // __ROOTCLING__ - -/// Writes backup to file and reads it back into restored -/// Outside the test fixture so it can be called in a function from the header. -/// TEST_F can't be used inside a header due to multiple references linking -/// error and must be placed in a source file. -template -void BackupAndRestore(const T& backup, T** restored) { - remove(ROOT_FILE); - remove(JSON_FILE); - - // write to root file - WritePersistentObject(ROOT_FILE, "T", backup, "new"); - - // Two benefits of writing an object to JSON: - // 1) Ensures that a dictionary must exists; otherwise linking error - // 2) Print out the object's content for debugging purposes - TBufferJSON::ExportToFile(JSON_FILE, &backup, backup.Class()); - - // read back - GetPersistentObject(ROOT_FILE, "T", *restored); -} - -} // namespace bdm - -#endif // UNIT_TEST_UTIL_IO_TEST_H_ diff --git a/test/util.inc b/test/util.inc index 8794db0b7..a639ce77d 100755 --- a/test/util.inc +++ b/test/util.inc @@ -17,7 +17,7 @@ # # $1 the directory containing the CMake simulation code function run_cmake_simulation() { - # Create a temporary file on your system referenced by log + # Create a temporary file on your system referenced by log log=$(mktemp) # Set trap, e.g. whenever the scirpt returns, we delete the temporary file trap "rm -rf \"${log}\"" RETURN @@ -38,7 +38,7 @@ function run_cmake_simulation() { # the `biodynamo test` command if [ "$ISTEST" = "true" ]; then # The scheduled GHA are usually configured with -Dtest=off in which case there - # will not be a test executable. The following checks if a test executable + # will not be a test executable. The following checks if a test executable # was built, if not it does not test the test command. if [ -f "build/test-sim-test" ]; then echo "GHA tests the 'bdm test' command." @@ -53,7 +53,7 @@ function run_cmake_simulation() { fi fi - # return to original dictionary + # return to original directory popd # Check if run and test commands were successful @@ -61,12 +61,12 @@ function run_cmake_simulation() { echo -n "Faild with return value ${SIM_RET_VAL}. The three digits " echo -n "correspond to:\nSimulation return value, ctest return value, test" echo " results." - return 1 + return 1 elif [ "${SIM_RET_VAL}" != "0" ]; then return $SIM_RET_VAL fi - # If commands were successful, we further check if the output of the + # If commands were successful, we further check if the output of the # simulation is correct. expected="Simulation completed successfully!" grep --quiet "${expected}" "${log}" diff --git a/third_party/OptionParser.h b/third_party/OptionParser.h deleted file mode 100644 index a7c83f91e..000000000 --- a/third_party/OptionParser.h +++ /dev/null @@ -1,2889 +0,0 @@ -/* - * The Lean Mean C++ Option Parser - * - * Copyright (C) 2012 Matthias S. Benkmann - * - * The "Software" in the following 2 paragraphs refers to this file containing - * the code to The Lean Mean C++ Option Parser. - * The "Software" does NOT refer to any other files which you - * may have received alongside this file (e.g. as part of a larger project that - * incorporates The Lean Mean C++ Option Parser). - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this 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. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -/* - * NOTE: It is recommended that you read the processed HTML doxygen documentation - * rather than this source. If you don't know doxygen, it's like javadoc for C++. - * If you don't want to install doxygen you can find a copy of the processed - * documentation at - * - * http://optionparser.sourceforge.net/ - * - */ - -/* -Danio Piparo - Since we import this parser from tan external source, we keep -track of the changes: - -New Features 6-7-12: - o Added FullArg class from the examples in the header - -Bugs Fixed 8-7-12: - o Cov: Add initialisation of screenlen variable in LinePartIterator - o Cov: LineWrapper databuf, lenbuf and wrote_something are now initialised - o Cov: Option::operator= now returns Option& (return *this;) and not void - */ - - -#include -#include - -/** - * @file - * - * @brief This is the only file required to use The Lean Mean C++ Option Parser. - * Just \#include it and you're set. - * - * The Lean Mean C++ Option Parser handles the program's command line arguments - * (argc, argv). - * It supports the short and long option formats of getopt(), getopt_long() - * and getopt_long_only() but has a more convenient interface. - * The following features set it apart from other option parsers: - * - * @par Highlights: - *
    - *
  • It is a header-only library. Just \#include "optionparser.h" and you're set. - *
  • It is freestanding. There are no dependencies whatsoever, not even the - * C or C++ standard library. - *
  • It has a usage message formatter that supports column alignment and - * line wrapping. This aids localization because it adapts to - * translated strings that are shorter or longer (even if they contain - * Asian wide characters). - *
  • Unlike getopt() and derivatives it doesn't force you to loop through - * options sequentially. Instead you can access options directly like this: - *
      - *
    • Test for presence of a switch in the argument vector: - * @code if ( options[QUIET] ) ... @endcode - *
    • Evaluate --enable-foo/--disable-foo pair where the last one used wins: - * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode - *
    • Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): - * @code int verbosity = options[VERBOSE].count(); @endcode - *
    • Iterate over all --file=<fname> arguments: - * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) - * fname = opt->arg; ... @endcode - *
    • If you really want to, you can still process all arguments in order: - * @code - * for (int i = 0; i < p.optionsCount(); ++i) { - * Option& opt = buffer[i]; - * switch(opt.index()) { - * case HELP: ... - * case VERBOSE: ... - * case FILE: fname = opt.arg; ... - * case UNKNOWN: ... - * @endcode - *
    - *
@n - * Despite these features the code size remains tiny. - * It is smaller than uClibc's GNU getopt() and just a - * couple 100 bytes larger than uClibc's SUSv3 getopt(). @n - * (This does not include the usage formatter, of course. But you don't have to use that.) - * - * @par Download: - * Tarball with examples and test programs: - * optionparser-1.3.tar.gz @n - * Just the header (this is all you really need): - * optionparser.h - * - * @par Changelog: - * Version 1.3: Compatible with Microsoft Visual C++. @n - * Version 1.2: Added @ref option::Option::namelen "Option::namelen" and removed the extraction - * of short option characters into a special buffer. @n - * Changed @ref option::Arg::Optional "Arg::Optional" to accept arguments if they are attached - * rather than separate. This is what GNU getopt() does and how POSIX recommends - * utilities should interpret their arguments.@n - * Version 1.1: Optional mode with argument reordering as done by GNU getopt(), so that - * options and non-options can be mixed. See - * @ref option::Parser::parse() "Parser::parse()". - * - * @par Feedback: - * Send questions, bug reports, feature requests etc. to: optionparser-feedback (a) lists.sourceforge.net - * @htmlonly @endhtmlonly - * - * - * @par Example program: - * (Note: @c option::* identifiers are links that take you to their documentation.) - * @code - * #include - * #include "optionparser.h" - * - * enum optionIndex { UNKNOWN, HELP, PLUS }; - * const option::Descriptor usage[] = - * { - * {UNKNOWN, 0,"" , "" ,option::Arg::None, "USAGE: example [options]\n\n" - * "Options:" }, - * {HELP, 0,"" , "help",option::Arg::None, " --help \tPrint usage and exit." }, - * {PLUS, 0,"p", "plus",option::Arg::None, " --plus, -p \tIncrement count." }, - * {UNKNOWN, 0,"" , "" ,option::Arg::None, "\nExamples:\n" - * " example --unknown -- --this_is_no_option\n" - * " example -unk --plus -ppp file1 file2\n" }, - * {0,0,0,0,0,0} - * }; - * - * int main(int argc, char* argv[]) - * { - * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present - * option::Stats stats(usage, argc, argv); - * option::Option options[stats.options_max], buffer[stats.buffer_max]; - * option::Parser parse(usage, argc, argv, options, buffer); - * - * if (parse.error()) - * return 1; - * - * if (options[HELP] || argc == 0) { - * option::printUsage(std::cout, usage); - * return 0; - * } - * - * std::cout << "--plus count: " << - * options[PLUS].count() << "\n"; - * - * for (option::Option* opt = options[UNKNOWN]; opt; opt = opt->next()) - * std::cout << "Unknown option: " << opt->name << "\n"; - * - * for (int i = 0; i < parse.nonOptionsCount(); ++i) - * std::cout << "Non-option #" << i << ": " << parse.nonOption(i) << "\n"; - * } - * @endcode - * - * @par Option syntax: - * @li The Lean Mean C++ Option Parser follows POSIX getopt() conventions and supports - * GNU-style getopt_long() long options as well as Perl-style single-minus - * long options (getopt_long_only()). - * @li short options have the format @c -X where @c X is any character that fits in a char. - * @li short options can be grouped, i.e. -X -Y is equivalent to @c -XY. - * @li a short option may take an argument either separate (-X foo) or - * attached (@c -Xfoo). You can make the parser accept the additional format @c -X=foo by - * registering @c X as a long option (in addition to being a short option) and - * enabling single-minus long options. - * @li an argument-taking short option may be grouped if it is the last in the group, e.g. - * @c -ABCXfoo or -ABCX foo (@c foo is the argument to the @c -X option). - * @li a lone minus character @c '-' is not treated as an option. It is customarily used where - * a file name is expected to refer to stdin or stdout. - * @li long options have the format @c --option-name. - * @li the option-name of a long option can be anything and include any characters. - * Even @c = characters will work, but don't do that. - * @li [optional] long options may be abbreviated as long as the abbreviation is unambiguous. - * You can set a minimum length for abbreviations. - * @li [optional] long options may begin with a single minus. The double minus form is always - * accepted, too. - * @li a long option may take an argument either separate ( --option arg ) or - * attached ( --option=arg ). In the attached form the equals sign is mandatory. - * @li an empty string can be passed as an attached long option argument: --option-name= . - * Note the distinction between an empty string as argument and no argument at all. - * @li an empty string is permitted as separate argument to both long and short options. - * @li Arguments to both short and long options may start with a @c '-' character. E.g. - * -X-X , -X -X or --long-X=-X . If @c -X - * and @c --long-X take an argument, that argument will be @c "-X" in all 3 cases. - * @li If using the built-in @ref option::Arg::Optional "Arg::Optional", optional arguments must - * be attached. - * @li the special option @c -- (i.e. without a name) terminates the list of - * options. Everything that follows is a non-option argument, even if it starts with - * a @c '-' character. The @c -- itself will not appear in the parse results. - * @li the first argument that doesn't start with @c '-' or @c '--' and does not belong to - * a preceding argument-taking option, will terminate the option list and is the - * first non-option argument. All following command line arguments are treated as - * non-option arguments, even if they start with @c '-' . @n - * NOTE: This behaviour is mandated by POSIX, but GNU getopt() only honours this if it is - * explicitly requested (e.g. by setting POSIXLY_CORRECT). @n - * You can enable the GNU behaviour by passing @c true as first argument to - * e.g. @ref option::Parser::parse() "Parser::parse()". - * @li Arguments that look like options (i.e. @c '-' followed by at least 1 character) but - * aren't, are NOT treated as non-option arguments. They are treated as unknown options and - * are collected into a list of unknown options for error reporting. @n - * This means that in order to pass a first non-option - * argument beginning with the minus character it is required to use the - * @c -- special option, e.g. - * @code - * program -x -- --strange-filename - * @endcode - * In this example, @c --strange-filename is a non-option argument. If the @c -- - * were omitted, it would be treated as an unknown option. @n - * See @ref option::Descriptor::longopt for information on how to collect unknown options. - * - */ - -#ifndef OPTIONPARSER_H_ -#define OPTIONPARSER_H_ - -namespace ROOT { -/** @brief The namespace of The Lean Mean C++ Option Parser. */ -namespace option -{ - -#ifdef _MSC_VER -#include -#pragma intrinsic(_BitScanReverse) -struct MSC_Builtin_CLZ -{ - static int builtin_clz(unsigned x) - { - unsigned long index; - _BitScanReverse(&index, x); - return 32-index; // int is always 32bit on Windows, even for target x64 - } -}; -#define __builtin_clz(x) MSC_Builtin_CLZ::builtin_clz(x) -#endif - -class Option; - -/** - * @brief Possible results when checking if an argument is valid for a certain option. - * - * In the case that no argument is provided for an option that takes an - * optional argument, return codes @c ARG_OK and @c ARG_IGNORE are equivalent. - */ -enum ArgStatus -{ - //! The option does not take an argument. - ARG_NONE, - //! The argument is acceptable for the option. - ARG_OK, - //! The argument is not acceptable but that's non-fatal because the option's argument is optional. - ARG_IGNORE, - //! The argument is not acceptable and that's fatal. - ARG_ILLEGAL -}; - -/** - * @brief Signature of functions that check if an argument is valid for a certain type of option. - * - * Every Option has such a function assigned in its Descriptor. - * @code - * Descriptor usage[] = { {UNKNOWN, 0, "", "", Arg::None, ""}, ... }; - * @endcode - * - * A CheckArg function has the following signature: - * @code ArgStatus CheckArg(const Option& option, bool msg); @endcode - * - * It is used to check if a potential argument would be acceptable for the option. - * It will even be called if there is no argument. In that case @c option.arg will be @c NULL. - * - * If @c msg is @c true and the function determines that an argument is not acceptable and - * that this is a fatal error, it should output a message to the user before - * returning @ref ARG_ILLEGAL. If @c msg is @c false the function should remain silent (or you - * will get duplicate messages). - * - * See @ref ArgStatus for the meaning of the return values. - * - * While you can provide your own functions, - * often the following pre-defined checks (which never return @ref ARG_ILLEGAL) will suffice: - * - * @li @c Arg::None @copybrief Arg::None - * @li @c Arg::Optional @copybrief Arg::Optional - * - */ -typedef ArgStatus (*CheckArg)(const Option& option, bool msg); - -/** - * @brief Describes an option, its help text (usage) and how it should be parsed. - * - * The main input when constructing an option::Parser is an array of Descriptors. - - * @par Example: - * @code - * enum OptionIndex {CREATE, ...}; - * enum OptionType {DISABLE, ENABLE, OTHER}; - * - * const option::Descriptor usage[] = { - * { CREATE, // index - * OTHER, // type - * "c", // shortopt - * "create", // longopt - * Arg::None, // check_arg - * "--create Tells the program to create something." // help - * } - * , ... - * }; - * @endcode - */ -struct Descriptor -{ - /** - * @brief Index of this option's linked list in the array filled in by the parser. - * - * Command line options whose Descriptors have the same index will end up in the same - * linked list in the order in which they appear on the command line. If you have - * multiple long option aliases that refer to the same option, give their descriptors - * the same @c index. - * - * If you have options that mean exactly opposite things - * (e.g. @c --enable-foo and @c --disable-foo ), you should also give them the same - * @c index, but distinguish them through different values for @ref type. - * That way they end up in the same list and you can just take the last element of the - * list and use its type. This way you get the usual behaviour where switches later - * on the command line override earlier ones without having to code it manually. - * - * @par Tip: - * Use an enum rather than plain ints for better readability, as shown in the example - * at Descriptor. - */ - const unsigned index; - - /** - * @brief Used to distinguish between options with the same @ref index. - * See @ref index for details. - * - * It is recommended that you use an enum rather than a plain int to make your - * code more readable. - */ - const int type; - - /** - * @brief Each char in this string will be accepted as a short option character. - * - * The string must not include the minus character @c '-' or you'll get undefined - * behaviour. - * - * If this Descriptor should not have short option characters, use the empty - * string "". NULL is not permitted here! - * - * See @ref longopt for more information. - */ - const char* const shortopt; - - /** - * @brief The long option name (without the leading @c -- ). - * - * If this Descriptor should not have a long option name, use the empty - * string "". NULL is not permitted here! - * - * While @ref shortopt allows multiple short option characters, each - * Descriptor can have only a single long option name. If you have multiple - * long option names referring to the same option use separate Descriptors - * that have the same @ref index and @ref type. You may repeat - * short option characters in such an alias Descriptor but there's no need to. - * - * @par Dummy Descriptors: - * You can use dummy Descriptors with an - * empty string for both @ref shortopt and @ref longopt to add text to - * the usage that is not related to a specific option. See @ref help. - * The first dummy Descriptor will be used for unknown options (see below). - * - * @par Unknown Option Descriptor: - * The first dummy Descriptor in the list of Descriptors, - * whose @ref shortopt and @ref longopt are both the empty string, will be used - * as the Descriptor for unknown options. An unknown option is a string in - * the argument vector that is not a lone minus @c '-' but starts with a minus - * character and does not match any Descriptor's @ref shortopt or @ref longopt. @n - * Note that the dummy descriptor's @ref check_arg function @e will be called and - * its return value will be evaluated as usual. I.e. if it returns @ref ARG_ILLEGAL - * the parsing will be aborted with Parser::error()==true. @n - * if @c check_arg does not return @ref ARG_ILLEGAL the descriptor's - * @ref index @e will be used to pick the linked list into which - * to put the unknown option. @n - * If there is no dummy descriptor, unknown options will be dropped silently. - * - */ - const char* const longopt; - - /** - * @brief For each option that matches @ref shortopt or @ref longopt this function - * will be called to check a potential argument to the option. - * - * This function will be called even if there is no potential argument. In that case - * it will be passed @c NULL as @c arg parameter. Do not confuse this with the empty - * string. - * - * See @ref CheckArg for more information. - */ - const CheckArg check_arg; - - /** - * @brief The usage text associated with the options in this Descriptor. - * - * You can use option::printUsage() to format your usage message based on - * the @c help texts. You can use dummy Descriptors where - * @ref shortopt and @ref longopt are both the empty string to add text to - * the usage that is not related to a specific option. - * - * See option::printUsage() for special formatting characters you can use in - * @c help to get a column layout. - * - * @attention - * Must be UTF-8-encoded. If your compiler supports C++11 you can use the "u8" - * prefix to make sure string literals are properly encoded. - */ - const char* help; -}; - -/** - * @brief A parsed option from the command line together with its argument if it has one. - * - * The Parser chains all parsed options with the same Descriptor::index together - * to form a linked list. This allows you to easily implement all of the common ways - * of handling repeated options and enable/disable pairs. - * - * @li Test for presence of a switch in the argument vector: - * @code if ( options[QUIET] ) ... @endcode - * @li Evaluate --enable-foo/--disable-foo pair where the last one used wins: - * @code if ( options[FOO].last()->type() == DISABLE ) ... @endcode - * @li Cumulative option (-v verbose, -vv more verbose, -vvv even more verbose): - * @code int verbosity = options[VERBOSE].count(); @endcode - * @li Iterate over all --file=<fname> arguments: - * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) - * fname = opt->arg; ... @endcode - */ -class Option -{ - Option* next_; - Option* prev_; -public: - /** - * @brief Pointer to this Option's Descriptor. - * - * Remember that the first dummy descriptor (see @ref Descriptor::longopt) is used - * for unknown options. - * - * @attention - * @c desc==NULL signals that this Option is unused. This is the default state of - * elements in the result array. You don't need to test @c desc explicitly. You - * can simply write something like this: - * @code - * if (options[CREATE]) - * { - * ... - * } - * @endcode - * This works because of operator const Option*() . - */ - const Descriptor* desc; - - /** - * @brief The name of the option as used on the command line. - * - * The main purpose of this string is to be presented to the user in messages. - * - * In the case of a long option, this is the actual @c argv pointer, i.e. the first - * character is a '-'. In the case of a short option this points to the option - * character within the @c argv string. - * - * Note that in the case of a short option group or an attached option argument, this - * string will contain additional characters following the actual name. Use @ref namelen - * to filter out the actual option name only. - * - */ - const char* name; - - /** - * @brief Pointer to this Option's argument (if any). - * - * NULL if this option has no argument. Do not confuse this with the empty string which - * is a valid argument. - */ - const char* arg; - - /** - * @brief The length of the option @ref name. - * - * Because @ref name points into the actual @c argv string, the option name may be - * followed by more characters (e.g. other short options in the same short option group). - * This value is the number of bytes (not characters!) that are part of the actual name. - * - * For a short option, this length is always 1. For a long option this length is always - * at least 2 if single minus long options are permitted and at least 3 if they are disabled. - * - * @note - * In the pathological case of a minus within a short option group (e.g. @c -xf-z), this - * length is incorrect, because this case will be misinterpreted as a long option and the - * name will therefore extend to the string's 0-terminator or a following '=" character - * if there is one. This is irrelevant for most uses of @ref name and @c namelen. If you - * really need to distinguish the case of a long and a short option, compare @ref name to - * the @c argv pointers. A long option's @c name is always identical to one of them, - * whereas a short option's is never. - */ - int namelen; - - /** - * @brief Returns Descriptor::type of this Option's Descriptor, or 0 if this Option - * is invalid (unused). - * - * Because this method (and last(), too) can be used even on unused Options with desc==0, you can (provided - * you arrange your types properly) switch on type() without testing validity first. - * @code - * enum OptionType { UNUSED=0, DISABLED=0, ENABLED=1 }; - * enum OptionIndex { FOO }; - * const Descriptor usage[] = { - * { FOO, ENABLED, "", "enable-foo", Arg::None, 0 }, - * { FOO, DISABLED, "", "disable-foo", Arg::None, 0 }, - * { 0, 0, 0, 0, 0, 0 } }; - * ... - * switch(options[FOO].last()->type()) // no validity check required! - * { - * case ENABLED: ... - * case DISABLED: ... // UNUSED==DISABLED ! - * } - * @endcode - */ - int type() const - { - return desc == 0 ? 0 : desc->type; - } - - /** - * @brief Returns Descriptor::index of this Option's Descriptor, or -1 if this Option - * is invalid (unused). - */ - int index() const - { - return desc == 0 ? -1 : desc->index; - } - - /** - * @brief Returns the number of times this Option (or others with the same Descriptor::index) - * occurs in the argument vector. - * - * This corresponds to the number of elements in the linked list this Option is part of. - * It doesn't matter on which element you call count(). The return value is always the same. - * - * Use this to implement cumulative options, such as -v, -vv, -vvv for - * different verbosity levels. - * - * Returns 0 when called for an unused/invalid option. - */ - int count() - { - int c = (desc == 0 ? 0 : 1); - Option* p = first(); - while (!p->isLast()) - { - ++c; - p = p->next_; - }; - return c; - } - - /** - * @brief Returns true iff this is the first element of the linked list. - * - * The first element in the linked list is the first option on the command line - * that has the respective Descriptor::index value. - * - * Returns true for an unused/invalid option. - */ - bool isFirst() const - { - return isTagged(prev_); - } - - /** - * @brief Returns true iff this is the last element of the linked list. - * - * The last element in the linked list is the last option on the command line - * that has the respective Descriptor::index value. - * - * Returns true for an unused/invalid option. - */ - bool isLast() const - { - return isTagged(next_); - } - - /** - * @brief Returns a pointer to the first element of the linked list. - * - * Use this when you want the first occurrence of an option on the command line to - * take precedence. Note that this is not the way most programs handle options. - * You should probably be using last() instead. - * - * @note - * This method may be called on an unused/invalid option and will return a pointer to the - * option itself. - */ - Option* first() - { - Option* p = this; - while (!p->isFirst()) - p = p->prev_; - return p; - } - - /** - * @brief Returns a pointer to the last element of the linked list. - * - * Use this when you want the last occurrence of an option on the command line to - * take precedence. This is the most common way of handling conflicting options. - * - * @note - * This method may be called on an unused/invalid option and will return a pointer to the - * option itself. - * - * @par Tip: - * If you have options with opposite meanings (e.g. @c --enable-foo and @c --disable-foo), you - * can assign them the same Descriptor::index to get them into the same list. Distinguish them by - * Descriptor::type and all you have to do is check last()->type() to get - * the state listed last on the command line. - */ - Option* last() - { - return first()->prevwrap(); - } - - /** - * @brief Returns a pointer to the previous element of the linked list or NULL if - * called on first(). - * - * If called on first() this method returns NULL. Otherwise it will return the - * option with the same Descriptor::index that precedes this option on the command - * line. - */ - Option* prev() - { - return isFirst() ? 0 : prev_; - } - - /** - * @brief Returns a pointer to the previous element of the linked list with wrap-around from - * first() to last(). - * - * If called on first() this method returns last(). Otherwise it will return the - * option with the same Descriptor::index that precedes this option on the command - * line. - */ - Option* prevwrap() - { - return untag(prev_); - } - - /** - * @brief Returns a pointer to the next element of the linked list or NULL if called - * on last(). - * - * If called on last() this method returns NULL. Otherwise it will return the - * option with the same Descriptor::index that follows this option on the command - * line. - */ - Option* next() - { - return isLast() ? 0 : next_; - } - - /** - * @brief Returns a pointer to the next element of the linked list with wrap-around from - * last() to first(). - * - * If called on last() this method returns first(). Otherwise it will return the - * option with the same Descriptor::index that follows this option on the command - * line. - */ - Option* nextwrap() - { - return untag(next_); - } - - /** - * @brief Makes @c new_last the new last() by chaining it into the list after last(). - * - * It doesn't matter which element you call append() on. The new element will always - * be appended to last(). - * - * @attention - * @c new_last must not yet be part of a list, or that list will become corrupted, because - * this method does not unchain @c new_last from an existing list. - */ - void append(Option* new_last) - { - Option* p = last(); - Option* f = first(); - p->next_ = new_last; - new_last->prev_ = p; - new_last->next_ = tag(f); - f->prev_ = tag(new_last); - } - - /** - * @brief Casts from Option to const Option* but only if this Option is valid. - * - * If this Option is valid (i.e. @c desc!=NULL), returns this. - * Otherwise returns NULL. This allows testing an Option directly - * in an if-clause to see if it is used: - * @code - * if (options[CREATE]) - * { - * ... - * } - * @endcode - * It also allows you to write loops like this: - * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) - * fname = opt->arg; ... @endcode - */ - operator const Option*() const - { - return desc ? this : 0; - } - - /** - * @brief Casts from Option to Option* but only if this Option is valid. - * - * If this Option is valid (i.e. @c desc!=NULL), returns this. - * Otherwise returns NULL. This allows testing an Option directly - * in an if-clause to see if it is used: - * @code - * if (options[CREATE]) - * { - * ... - * } - * @endcode - * It also allows you to write loops like this: - * @code for (Option* opt = options[FILE]; opt; opt = opt->next()) - * fname = opt->arg; ... @endcode - */ - operator Option*() - { - return desc ? this : 0; - } - - /** - * @brief Creates a new Option that is a one-element linked list and has NULL - * @ref desc, @ref name, @ref arg and @ref namelen. - */ - Option() : - desc(0), name(0), arg(0), namelen(0) - { - prev_ = tag(this); - next_ = tag(this); - } - - /** - * @brief Creates a new Option that is a one-element linked list and has the given - * values for @ref desc, @ref name and @ref arg. - * - * If @c name_ points at a character other than '-' it will be assumed to refer to a - * short option and @ref namelen will be set to 1. Otherwise the length will extend to - * the first '=' character or the string's 0-terminator. - */ - Option(const Descriptor* desc_, const char* name_, const char* arg_) - { - init(desc_, name_, arg_); - } - - /** - * @brief Makes @c *this a copy of @c orig except for the linked list pointers. - * - * After this operation @c *this will be a one-element linked list. - */ - //void operator=(const Option& orig) - Option& operator=(const Option& orig) - { - init(orig.desc, orig.name, orig.arg); - return *this; - } - - /** - * @brief Makes @c *this a copy of @c orig except for the linked list pointers. - * - * After this operation @c *this will be a one-element linked list. - */ - Option(const Option& orig) - { - init(orig.desc, orig.name, orig.arg); - } - -private: - /** - * @internal - * @brief Sets the fields of this Option to the given values (extracting @c name if necessary). - * - * If @c name_ points at a character other than '-' it will be assumed to refer to a - * short option and @ref namelen will be set to 1. Otherwise the length will extend to - * the first '=' character or the string's 0-terminator. - */ - void init(const Descriptor* desc_, const char* name_, const char* arg_) - { - desc = desc_; - name = name_; - arg = arg_; - prev_ = tag(this); - next_ = tag(this); - namelen = 0; - if (name == 0) - return; - namelen = 1; - if (name[0] != '-') - return; - while (name[namelen] != 0 && name[namelen] != '=') - ++namelen; - } - - static Option* tag(Option* ptr) - { - return (Option*) ((unsigned long long) ptr | 1); - } - - static Option* untag(Option* ptr) - { - return (Option*) ((unsigned long long) ptr & ~1ull); - } - - static bool isTagged(Option* ptr) - { - return ((unsigned long long) ptr & 1); - } -}; - -/** - * @brief Functions for checking the validity of option arguments. - * - * @copydetails CheckArg - * - * The following example code - * can serve as starting place for writing your own more complex CheckArg functions: - * @code - * struct Arg: public option::Arg - * { - * static void printError(const char* msg1, const option::Option& opt, const char* msg2) - * { - * fprintf(stderr, "ERROR: %s", msg1); - * fwrite(opt.name, opt.namelen, 1, stderr); - * fprintf(stderr, "%s", msg2); - * } - * - * static option::ArgStatus Unknown(const option::Option& option, bool msg) - * { - * if (msg) printError("Unknown option '", option, "'\n"); - * return option::ARG_ILLEGAL; - * } - * - * static option::ArgStatus Required(const option::Option& option, bool msg) - * { - * if (option.arg != 0) - * return option::ARG_OK; - * - * if (msg) printError("Option '", option, "' requires an argument\n"); - * return option::ARG_ILLEGAL; - * } - * - * static option::ArgStatus NonEmpty(const option::Option& option, bool msg) - * { - * if (option.arg != 0 && option.arg[0] != 0) - * return option::ARG_OK; - * - * if (msg) printError("Option '", option, "' requires a non-empty argument\n"); - * return option::ARG_ILLEGAL; - * } - * - * static option::ArgStatus Numeric(const option::Option& option, bool msg) - * { - * char* endptr = 0; - * if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; - * if (endptr != option.arg && *endptr == 0) - * return option::ARG_OK; - * - * if (msg) printError("Option '", option, "' requires a numeric argument\n"); - * return option::ARG_ILLEGAL; - * } - * }; - * @endcode - */ -struct Arg -{ - //! @brief For options that don't take an argument: Returns ARG_NONE. - static ArgStatus None(const Option&, bool) - { - return ARG_NONE; - } - - //! @brief Returns ARG_OK if the argument is attached and ARG_IGNORE otherwise. - static ArgStatus Optional(const Option& option, bool) - { - if (option.arg && option.name[option.namelen] != 0) - return ARG_OK; - else - return ARG_IGNORE; - } -}; - -/** - * @brief Determines the minimum lengths of the buffer and options arrays used for Parser. - * - * Because Parser doesn't use dynamic memory its output arrays have to be pre-allocated. - * If you don't want to use fixed size arrays (which may turn out too small, causing - * command line arguments to be dropped), you can use Stats to determine the correct sizes. - * Stats work cumulative. You can first pass in your default options and then the real - * options and afterwards the counts will reflect the union. - */ -struct Stats -{ - /** - * @brief Number of elements needed for a @c buffer[] array to be used for - * @ref Parser::parse() "parsing" the same argument vectors that were fed - * into this Stats object. - * - * @note - * This number is always 1 greater than the actual number needed, to give - * you a sentinel element. - */ - unsigned buffer_max; - - /** - * @brief Number of elements needed for an @c options[] array to be used for - * @ref Parser::parse() "parsing" the same argument vectors that were fed - * into this Stats object. - * - * @note - * @li This number is always 1 greater than the actual number needed, to give - * you a sentinel element. - * @li This number depends only on the @c usage, not the argument vectors, because - * the @c options array needs exactly one slot for each possible Descriptor::index. - */ - unsigned options_max; - - /** - * @brief Creates a Stats object with counts set to 1 (for the sentinel element). - */ - Stats() : - buffer_max(1), options_max(1) // 1 more than necessary as sentinel - { - } - - /** - * @brief Creates a new Stats object and immediately updates it for the - * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, - * if you just want to update @ref options_max. - * - * @note - * The calls to Stats methods must match the later calls to Parser methods. - * See Parser::parse() for the meaning of the arguments. - */ - Stats(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) : - buffer_max(1), options_max(1) // 1 more than necessary as sentinel - { - add(gnu, usage, argc, argv, min_abbr_len, single_minus_longopt); - } - - //! @brief Stats(...) with non-const argv. - Stats(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) : - buffer_max(1), options_max(1) // 1 more than necessary as sentinel - { - add(gnu, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); - } - - //! @brief POSIX Stats(...) (gnu==false). - Stats(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) : - buffer_max(1), options_max(1) // 1 more than necessary as sentinel - { - add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); - } - - //! @brief POSIX Stats(...) (gnu==false) with non-const argv. - Stats(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) : - buffer_max(1), options_max(1) // 1 more than necessary as sentinel - { - add(false, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); - } - - /** - * @brief Updates this Stats object for the - * given @c usage and argument vector. You may pass 0 for @c argc and/or @c argv, - * if you just want to update @ref options_max. - * - * @note - * The calls to Stats methods must match the later calls to Parser methods. - * See Parser::parse() for the meaning of the arguments. - */ - void add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false); - - //! @brief add() with non-const argv. - void add(bool gnu, const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) - { - add(gnu, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); - } - - //! @brief POSIX add() (gnu==false). - void add(const Descriptor usage[], int argc, const char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) - { - add(false, usage, argc, argv, min_abbr_len, single_minus_longopt); - } - - //! @brief POSIX add() (gnu==false) with non-const argv. - void add(const Descriptor usage[], int argc, char** argv, int min_abbr_len = 0, // - bool single_minus_longopt = false) - { - add(false, usage, argc, const_cast(argv), min_abbr_len, single_minus_longopt); - } -private: - class CountOptionsAction; -}; - -/** - * @brief Checks argument vectors for validity and parses them into data - * structures that are easier to work with. - * - * @par Example: - * @code - * int main(int argc, char* argv[]) - * { - * argc-=(argc>0); argv+=(argc>0); // skip program name argv[0] if present - * option::Stats stats(usage, argc, argv); - * option::Option options[stats.options_max], buffer[stats.buffer_max]; - * option::Parser parse(usage, argc, argv, options, buffer); - * - * if (parse.error()) - * return 1; - * - * if (options[HELP]) - * ... - * @endcode - */ -class Parser -{ - int op_count; //!< @internal @brief see optionsCount() - int nonop_count; //!< @internal @brief see nonOptionsCount() - const char** nonop_args; //!< @internal @brief see nonOptions() - bool err; //!< @internal @brief see error() -public: - - /** - * @brief Creates a new Parser. - */ - Parser() : - op_count(0), nonop_count(0), nonop_args(0), err(false) - { - } - - /** - * @brief Creates a new Parser and immediately parses the given argument vector. - * @copydetails parse() - */ - Parser(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], - int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : - op_count(0), nonop_count(0), nonop_args(0), err(false) - { - parse(gnu, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - //! @brief Parser(...) with non-const argv. - Parser(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], - int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) : - op_count(0), nonop_count(0), nonop_args(0), err(false) - { - parse(gnu, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - //! @brief POSIX Parser(...) (gnu==false). - Parser(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], int min_abbr_len = 0, - bool single_minus_longopt = false, int bufmax = -1) : - op_count(0), nonop_count(0), nonop_args(0), err(false) - { - parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - //! @brief POSIX Parser(...) (gnu==false) with non-const argv. - Parser(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, - bool single_minus_longopt = false, int bufmax = -1) : - op_count(0), nonop_count(0), nonop_args(0), err(false) - { - parse(false, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - /** - * @brief Parses the given argument vector. - * - * @param gnu if true, parse() will not stop at the first non-option argument. Instead it will - * reorder arguments so that all non-options are at the end. This is the default behaviour - * of GNU getopt() but is not conforming to POSIX. @n - * Note, that once the argument vector has been reordered, the @c gnu flag will have - * no further effect on this argument vector. So it is enough to pass @c gnu==true when - * creating Stats. - * @param usage Array of Descriptor objects that describe the options to support. The last entry - * of this array must have 0 in all fields. - * @param argc The number of elements from @c argv that are to be parsed. If you pass -1, the number - * will be determined automatically. In that case the @c argv list must end with a NULL - * pointer. - * @param argv The arguments to be parsed. If you pass -1 as @c argc the last pointer in the @c argv - * list must be NULL to mark the end. - * @param options Each entry is the first element of a linked list of Options. Each new option - * that is parsed will be appended to the list specified by that Option's - * Descriptor::index. If an entry is not yet used (i.e. the Option is invalid), - * it will be replaced rather than appended to. @n - * The minimum length of this array is the greatest Descriptor::index value that - * occurs in @c usage @e PLUS ONE. - * @param buffer Each argument that is successfully parsed (including unknown arguments, if they - * have a Descriptor whose CheckArg does not return @ref ARG_ILLEGAL) will be stored in this - * array. parse() scans the array for the first invalid entry and begins writing at that - * index. You can pass @c bufmax to limit the number of options stored. - * @param min_abbr_len Passing a value min_abbr_len > 0 enables abbreviated long - * options. The parser will match a prefix of a long option as if it was - * the full long option (e.g. @c --foob=10 will be interpreted as if it was - * @c --foobar=10 ), as long as the prefix has at least @c min_abbr_len characters - * (not counting the @c -- ) and is unambiguous. - * @n Be careful if combining @c min_abbr_len=1 with @c single_minus_longopt=true - * because the ambiguity check does not consider short options and abbreviated - * single minus long options will take precedence over short options. - * @param single_minus_longopt Passing @c true for this option allows long options to begin with - * a single minus. The double minus form will still be recognized. Note that - * single minus long options take precedence over short options and short option - * groups. E.g. @c -file would be interpreted as @c --file and not as - * -f -i -l -e (assuming a long option named @c "file" exists). - * @param bufmax The greatest index in the @c buffer[] array that parse() will write to is - * @c bufmax-1. If there are more options, they will be processed (in particular - * their CheckArg will be called) but not stored. @n - * If you used Stats::buffer_max to dimension this array, you can pass - * -1 (or not pass @c bufmax at all) which tells parse() that the buffer is - * "large enough". - * @attention - * Remember that @c options and @c buffer store Option @e objects, not pointers. Therefore it - * is not possible for the same object to be in both arrays. For those options that are found in - * both @c buffer[] and @c options[] the respective objects are independent copies. And only the - * objects in @c options[] are properly linked via Option::next() and Option::prev(). - * You can iterate over @c buffer[] to - * process all options in the order they appear in the argument vector, but if you want access to - * the other Options with the same Descriptor::index, then you @e must access the linked list via - * @c options[]. You can get the linked list in options from a buffer object via something like - * @c options[buffer[i].index()]. - */ - void parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], - int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1); - - //! @brief parse() with non-const argv. - void parse(bool gnu, const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], - int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) - { - parse(gnu, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - //! @brief POSIX parse() (gnu==false). - void parse(const Descriptor usage[], int argc, const char** argv, Option options[], Option buffer[], - int min_abbr_len = 0, bool single_minus_longopt = false, int bufmax = -1) - { - parse(false, usage, argc, argv, options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - //! @brief POSIX parse() (gnu==false) with non-const argv. - void parse(const Descriptor usage[], int argc, char** argv, Option options[], Option buffer[], int min_abbr_len = 0, - bool single_minus_longopt = false, int bufmax = -1) - { - parse(false, usage, argc, const_cast(argv), options, buffer, min_abbr_len, single_minus_longopt, bufmax); - } - - /** - * @brief Returns the number of valid Option objects in @c buffer[]. - * - * @note - * @li The returned value always reflects the number of Options in the buffer[] array used for - * the most recent call to parse(). - * @li The count (and the buffer[]) includes unknown options if they are collected - * (see Descriptor::longopt). - */ - int optionsCount() - { - return op_count; - } - - /** - * @brief Returns the number of non-option arguments that remained at the end of the - * most recent parse() that actually encountered non-option arguments. - * - * @note - * A parse() that does not encounter non-option arguments will leave this value - * as well as nonOptions() undisturbed. This means you can feed the Parser a - * default argument vector that contains non-option arguments (e.g. a default filename). - * Then you feed it the actual arguments from the user. If the user has supplied at - * least one non-option argument, all of the non-option arguments from the default - * disappear and are replaced by the user's non-option arguments. However, if the - * user does not supply any non-option arguments the defaults will still be in - * effect. - */ - int nonOptionsCount() - { - return nonop_count; - } - - /** - * @brief Returns a pointer to an array of non-option arguments (only valid - * if nonOptionsCount() >0 ). - * - * @note - * @li parse() does not copy arguments, so this pointer points into the actual argument - * vector as passed to parse(). - * @li As explained at nonOptionsCount() this pointer is only changed by parse() calls - * that actually encounter non-option arguments. A parse() call that encounters only - * options, will not change nonOptions(). - */ - const char** nonOptions() - { - return nonop_args; - } - - /** - * @brief Returns nonOptions()[i] (@e without checking if i is in range!). - */ - const char* nonOption(int i) - { - return nonOptions()[i]; - } - - /** - * @brief Returns @c true if an unrecoverable error occurred while parsing options. - * - * An illegal argument to an option (i.e. CheckArg returns @ref ARG_ILLEGAL) is an - * unrecoverable error that aborts the parse. Unknown options are only an error if - * their CheckArg function returns @ref ARG_ILLEGAL. Otherwise they are collected. - * In that case if you want to exit the program if either an illegal argument - * or an unknown option has been passed, use code like this - * - * @code - * if (parser.error() || options[UNKNOWN]) - * exit(1); - * @endcode - * - */ - bool error() - { - return err; - } - -private: - friend struct Stats; - class StoreOptionAction; - struct Action; - - /** - * @internal - * @brief This is the core function that does all the parsing. - * @retval false iff an unrecoverable error occurred. - */ - static bool workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, - bool single_minus_longopt, bool print_errors, int min_abbr_len); - - /** - * @internal - * @brief Returns true iff @c st1 is a prefix of @c st2 and - * in case @c st2 is longer than @c st1, then - * the first additional character is '='. - * - * @par Examples: - * @code - * streq("foo", "foo=bar") == true - * streq("foo", "foobar") == false - * streq("foo", "foo") == true - * streq("foo=bar", "foo") == false - * @endcode - */ - static bool streq(const char* st1, const char* st2) - { - while (*st1 != 0) - if (*st1++ != *st2++) - return false; - return (*st2 == 0 || *st2 == '='); - } - - /** - * @internal - * @brief Like streq() but handles abbreviations. - * - * Returns true iff @c st1 and @c st2 have a common - * prefix with the following properties: - * @li (if min > 0) its length is at least @c min characters or the same length as @c st1 (whichever is smaller). - * @li (if min <= 0) its length is the same as that of @c st1 - * @li within @c st2 the character following the common prefix is either '=' or end-of-string. - * - * Examples: - * @code - * streqabbr("foo", "foo=bar",) == true - * streqabbr("foo", "fo=bar" , 2) == true - * streqabbr("foo", "fo" , 2) == true - * streqabbr("foo", "fo" , 0) == false - * streqabbr("foo", "f=bar" , 2) == false - * streqabbr("foo", "f" , 2) == false - * streqabbr("fo" , "foo=bar",) == false - * streqabbr("foo", "foobar" ,) == false - * streqabbr("foo", "fobar" ,) == false - * streqabbr("foo", "foo" ,) == true - * @endcode - */ - static bool streqabbr(const char* st1, const char* st2, long long min) - { - const char* st1start = st1; - while (*st1 != 0 && (*st1 == *st2)) - { - ++st1; - ++st2; - } - - return (*st1 == 0 || (min > 0 && (st1 - st1start) >= min)) && (*st2 == 0 || *st2 == '='); - } - - /** - * @internal - * @brief Returns true iff character @c ch is contained in the string @c st. - * - * Returns @c true for @c ch==0 . - */ - static bool instr(char ch, const char* st) - { - while (*st != 0 && *st != ch) - ++st; - return *st == ch; - } - - /** - * @internal - * @brief Rotates args[-count],...,args[-1],args[0] to become - * args[0],args[-count],...,args[-1]. - */ - static void shift(const char** args, int count) - { - for (int i = 0; i > -count; --i) - { - const char* temp = args[i]; - args[i] = args[i - 1]; - args[i - 1] = temp; - } - } -}; - -/** - * @internal - * @brief Interface for actions Parser::workhorse() should perform for each Option it - * parses. - */ -struct Parser::Action -{ - /** - * @brief Called by Parser::workhorse() for each Option that has been successfully - * parsed (including unknown - * options if they have a Descriptor whose Descriptor::check_arg does not return - * @ref ARG_ILLEGAL. - * - * Returns @c false iff a fatal error has occured and the parse should be aborted. - */ - virtual bool perform(Option&) - { - return true; - } - - /** - * @brief Called by Parser::workhorse() after finishing the parse. - * @param numargs the number of non-option arguments remaining - * @param args pointer to the first remaining non-option argument (if numargs > 0). - * - * @return - * @c false iff a fatal error has occurred. - */ - virtual bool finished(int numargs, const char** args) - { - (void) numargs; - (void) args; - return true; - } - - virtual ~Action() = default; -}; - -/** - * @internal - * @brief An Action to pass to Parser::workhorse() that will increment a counter for - * each parsed Option. - */ -class Stats::CountOptionsAction: public Parser::Action -{ - unsigned* buffer_max; -public: - /** - * Creates a new CountOptionsAction that will increase @c *buffer_max_ for each - * parsed Option. - */ - CountOptionsAction(unsigned* buffer_max_) : - buffer_max(buffer_max_) - { - } - - bool perform(Option&) - { - if (*buffer_max == 0x7fffffff) - return false; // overflow protection: don't accept number of options that doesn't fit signed int - ++*buffer_max; - return true; - } -}; - -/** - * @internal - * @brief An Action to pass to Parser::workhorse() that will store each parsed Option in - * appropriate arrays (see Parser::parse()). - */ -class Parser::StoreOptionAction: public Parser::Action -{ - Parser& parser; - Option* options; - Option* buffer; - int bufmax; //! Number of slots in @c buffer. @c -1 means "large enough". -public: - /** - * @brief Creates a new StoreOption action. - * @param parser_ the parser whose op_count should be updated. - * @param options_ each Option @c o is chained into the linked list @c options_[o.desc->index] - * @param buffer_ each Option is appended to this array as long as there's a free slot. - * @param bufmax_ number of slots in @c buffer_. @c -1 means "large enough". - */ - StoreOptionAction(Parser& parser_, Option options_[], Option buffer_[], int bufmax_) : - parser(parser_), options(options_), buffer(buffer_), bufmax(bufmax_) - { - // find first empty slot in buffer (if any) - int bufidx = 0; - while ((bufmax < 0 || bufidx < bufmax) && buffer[bufidx]) - ++bufidx; - - // set parser's optionCount - parser.op_count = bufidx; - } - - bool perform(Option& option) - { - if (bufmax < 0 || parser.op_count < bufmax) - { - if (parser.op_count == 0x7fffffff) - return false; // overflow protection: don't accept number of options that doesn't fit signed int - - buffer[parser.op_count] = option; - int idx = buffer[parser.op_count].desc->index; - if (options){ - if (options[idx]) - options[idx].append(buffer[parser.op_count]); - else - options[idx] = buffer[parser.op_count]; - } - ++parser.op_count; - } - return true; // NOTE: an option that is discarded because of a full buffer is not fatal - } - - bool finished(int numargs, const char** args) - { - // only overwrite non-option argument list if there's at least 1 - // new non-option argument. Otherwise we keep the old list. This - // makes it easy to use default non-option arguments. - if (numargs > 0) - { - parser.nonop_count = numargs; - parser.nonop_args = args; - } - - return true; - } -}; - -inline void Parser::parse(bool gnu, const Descriptor usage[], int argc, const char** argv, Option options[], - Option buffer[], int min_abbr_len, bool single_minus_longopt, int bufmax) -{ - StoreOptionAction action(*this, options, buffer, bufmax); - err = !workhorse(gnu, usage, argc, argv, action, single_minus_longopt, true, min_abbr_len); -} - -inline void Stats::add(bool gnu, const Descriptor usage[], int argc, const char** argv, int min_abbr_len, - bool single_minus_longopt) -{ - // determine size of options array. This is the greatest index used in the usage + 1 - int i = 0; - while (usage[i].shortopt != 0) - { - if (usage[i].index + 1 >= options_max) - options_max = (usage[i].index + 1) + 1; // 1 more than necessary as sentinel - - ++i; - } - - CountOptionsAction action(&buffer_max); - Parser::workhorse(gnu, usage, argc, argv, action, single_minus_longopt, false, min_abbr_len); -} - -inline bool Parser::workhorse(bool gnu, const Descriptor usage[], int numargs, const char** args, Action& action, - bool single_minus_longopt, bool print_errors, int min_abbr_len) -{ - // protect against NULL pointer - if (args == 0) - numargs = 0; - - int nonops = 0; - - while (numargs != 0 && *args != 0) - { - const char* param = *args; // param can be --long-option, -srto or non-option argument - - // in POSIX mode the first non-option argument terminates the option list - // a lone minus character is a non-option argument - if (param[0] != '-' || param[1] == 0) - { - if (gnu) - { - ++nonops; - ++args; - if (numargs > 0) - --numargs; - continue; - } - else - break; - } - - // -- terminates the option list. The -- itself is skipped. - if (param[1] == '-' && param[2] == 0) - { - shift(args, nonops); - ++args; - if (numargs > 0) - --numargs; - break; - } - - bool handle_short_options; - const char* longopt_name; - if (param[1] == '-') // if --long-option - { - handle_short_options = false; - longopt_name = param + 2; - } - else - { - handle_short_options = true; - longopt_name = param + 1; //for testing a potential -long-option - } - - bool try_single_minus_longopt = single_minus_longopt; - bool have_more_args = (numargs > 1 || numargs < 0); // is referencing argv[1] valid? - - do // loop over short options in group, for long options the body is executed only once - { - int idx=0; - - const char* optarg=nullptr; - - /******************** long option **********************/ - if (handle_short_options == false || try_single_minus_longopt) - { - idx = 0; - while (usage[idx].longopt != 0 && !streq(usage[idx].longopt, longopt_name)) - ++idx; - - if (usage[idx].longopt == 0 && min_abbr_len > 0) // if we should try to match abbreviated long options - { - int i1 = 0; - while (usage[i1].longopt != 0 && !streqabbr(usage[i1].longopt, longopt_name, min_abbr_len)) - ++i1; - if (usage[i1].longopt != 0) - { // now test if the match is unambiguous by checking for another match - int i2 = i1 + 1; - while (usage[i2].longopt != 0 && !streqabbr(usage[i2].longopt, longopt_name, min_abbr_len)) - ++i2; - - if (usage[i2].longopt == 0) // if there was no second match it's unambiguous, so accept i1 as idx - idx = i1; - } - } - - // if we found something, disable handle_short_options (only relevant if single_minus_longopt) - if (usage[idx].longopt != 0) - handle_short_options = false; - - try_single_minus_longopt = false; // prevent looking for longopt in the middle of shortopt group - - optarg = longopt_name; - while (*optarg != 0 && *optarg != '=') - ++optarg; - if (*optarg == '=') // attached argument - ++optarg; - else - // possibly detached argument - optarg = (have_more_args ? args[1] : 0); - } - - /************************ short option ***********************************/ - if (handle_short_options) - { - if (*++param == 0) // point at the 1st/next option character - break; // end of short option group - - idx = 0; - while (usage[idx].shortopt != 0 && !instr(*param, usage[idx].shortopt)) - ++idx; - - if (param[1] == 0) // if the potential argument is separate - optarg = (have_more_args ? args[1] : 0); - else - // if the potential argument is attached - optarg = param + 1; - } - - const Descriptor* descriptor = &usage[idx]; - - if (descriptor->shortopt == 0) /************** unknown option ********************/ - { - // look for dummy entry (shortopt == "" and longopt == "") to use as Descriptor for unknown options - idx = 0; - while (usage[idx].shortopt != 0 && (usage[idx].shortopt[0] != 0 || usage[idx].longopt[0] != 0)) - ++idx; - descriptor = (usage[idx].shortopt == 0 ? 0 : &usage[idx]); - } - - if (descriptor != 0) - { - Option option(descriptor, param, optarg); - switch (descriptor->check_arg(option, print_errors)) - { - case ARG_ILLEGAL: - return false; // fatal - case ARG_OK: - // skip one element of the argument vector, if it's a separated argument - if (optarg != 0 && have_more_args && optarg == args[1]) - { - shift(args, nonops); - if (numargs > 0) - --numargs; - ++args; - } - - // No further short options are possible after an argument - handle_short_options = false; - - break; - case ARG_IGNORE: - case ARG_NONE: - option.arg = 0; - break; - } - - if (!action.perform(option)) - return false; - } - - } while (handle_short_options); - - shift(args, nonops); - ++args; - if (numargs > 0) - --numargs; - - } // while - - if (numargs > 0 && *args == 0) // It's a bug in the caller if numargs is greater than the actual number - numargs = 0; // of arguments, but as a service to the user we fix this if we spot it. - - if (numargs < 0) // if we don't know the number of remaining non-option arguments - { // we need to count them - numargs = 0; - while (args[numargs] != 0) - ++numargs; - } - - return action.finished(numargs + nonops, args - nonops); -} - -/** - * @internal - * @brief The implementation of option::printUsage(). - */ -struct PrintUsageImplementation -{ - /** - * @internal - * @brief Interface for Functors that write (part of) a string somewhere. - */ - struct IStringWriter - { - /** - * @brief Writes the given number of chars beginning at the given pointer somewhere. - */ - virtual void operator()(const char*, int) - { - } - - virtual ~IStringWriter() = default; - }; - - /** - * @internal - * @brief Encapsulates a function with signature func(string, size) where - * string can be initialized with a const char* and size with an int. - */ - template - struct FunctionWriter: public IStringWriter - { - Function* write; - - virtual void operator()(const char* str, int size) - { - (*write)(str, size); - } - - FunctionWriter(Function* w) : - write(w) - { - } - }; - - /** - * @internal - * @brief Encapsulates a reference to an object with a write(string, size) - * method like that of @c std::ostream. - */ - template - struct OStreamWriter: public IStringWriter - { - OStream& ostream; - - virtual void operator()(const char* str, int size) - { - ostream.write(str, size); - } - - OStreamWriter(OStream& o) : - ostream(o) - { - } - }; - - /** - * @internal - * @brief Like OStreamWriter but encapsulates a @c const reference, which is - * typically a temporary object of a user class. - */ - template - struct TemporaryWriter: public IStringWriter - { - const Temporary& userstream; - - virtual void operator()(const char* str, int size) - { - userstream.write(str, size); - } - - TemporaryWriter(const Temporary& u) : - userstream(u) - { - } - }; - - /** - * @internal - * @brief Encapsulates a function with the signature func(fd, string, size) (the - * signature of the @c write() system call) - * where fd can be initialized from an int, string from a const char* and size from an int. - */ - template - struct SyscallWriter: public IStringWriter - { - Syscall* write; - int fd; - - virtual void operator()(const char* str, int size) - { - (*write)(fd, str, size); - } - - SyscallWriter(Syscall* w, int f) : - write(w), fd(f) - { - } - }; - - /** - * @internal - * @brief Encapsulates a function with the same signature as @c std::fwrite(). - */ - template - struct StreamWriter: public IStringWriter - { - Function* fwrite; - Stream* stream; - - virtual void operator()(const char* str, int size) - { - (*fwrite)(str, size, 1, stream); - } - - StreamWriter(Function* w, Stream* s) : - fwrite(w), stream(s) - { - } - }; - - /** - * @internal - * @brief Sets i1 = max(i1, i2) - */ - static void upmax(int& i1, int i2) - { - i1 = (i1 >= i2 ? i1 : i2); - } - - /** - * @internal - * @brief Moves the "cursor" to column @c want_x assuming it is currently at column @c x - * and sets @c x=want_x . - * If x > want_x , a line break is output before indenting. - * - * @param write Spaces and possibly a line break are written via this functor to get - * the desired indentation @c want_x . - * @param[in,out] x the current indentation. Set to @c want_x by this method. - * @param want_x the desired indentation. - */ - static void indent(IStringWriter& write, int& x, int want_x) - { - int indent = want_x - x; - if (indent < 0) - { - write("\n", 1); - indent = want_x; - } - - if (indent > 0) - { - char space = ' '; - for (int i = 0; i < indent; ++i) - write(&space, 1); - x = want_x; - } - } - - /** - * @brief Returns true if ch is the unicode code point of a wide character. - * - * @note - * The following character ranges are treated as wide - * @code - * 1100..115F - * 2329..232A (just 2 characters!) - * 2E80..A4C6 except for 303F - * A960..A97C - * AC00..D7FB - * F900..FAFF - * FE10..FE6B - * FF01..FF60 - * FFE0..FFE6 - * 1B000...... - * @endcode - */ - static bool isWideChar(unsigned ch) - { - if (ch == 0x303F) - return false; - - return ((0x1100 <= ch && ch <= 0x115F) || (0x2329 <= ch && ch <= 0x232A) || (0x2E80 <= ch && ch <= 0xA4C6) - || (0xA960 <= ch && ch <= 0xA97C) || (0xAC00 <= ch && ch <= 0xD7FB) || (0xF900 <= ch && ch <= 0xFAFF) - || (0xFE10 <= ch && ch <= 0xFE6B) || (0xFF01 <= ch && ch <= 0xFF60) || (0xFFE0 <= ch && ch <= 0xFFE6) - || (0x1B000 <= ch)); - } - - /** - * @internal - * @brief Splits a @c Descriptor[] array into tables, rows, lines and columns and - * iterates over these components. - * - * The top-level organizational unit is the @e table. - * A table begins at a Descriptor with @c help!=NULL and extends up to - * a Descriptor with @c help==NULL. - * - * A table consists of @e rows. Due to line-wrapping and explicit breaks - * a row may take multiple lines on screen. Rows within the table are separated - * by \\n. They never cross Descriptor boundaries. This means a row ends either - * at \\n or the 0 at the end of the help string. - * - * A row consists of columns/cells. Columns/cells within a row are separated by \\t. - * Line breaks within a cell are marked by \\v. - * - * Rows in the same table need not have the same number of columns/cells. The - * extreme case are interjections, which are rows that contain neither \\t nor \\v. - * These are NOT treated specially by LinePartIterator, but they are treated - * specially by printUsage(). - * - * LinePartIterator iterates through the usage at 3 levels: table, row and part. - * Tables and rows are as described above. A @e part is a line within a cell. - * LinePartIterator iterates through 1st parts of all cells, then through the 2nd - * parts of all cells (if any),... @n - * Example: The row "1 \v 3 \t 2 \v 4" has 2 cells/columns and 4 parts. - * The parts will be returned in the order 1, 2, 3, 4. - * - * It is possible that some cells have fewer parts than others. In this case - * LinePartIterator will "fill up" these cells with 0-length parts. IOW, LinePartIterator - * always returns the same number of parts for each column. Note that this is different - * from the way rows and columns are handled. LinePartIterator does @e not guarantee that - * the same number of columns will be returned for each row. - * - */ - class LinePartIterator - { - const Descriptor* tablestart; //!< The 1st descriptor of the current table. - const Descriptor* rowdesc; //!< The Descriptor that contains the current row. - const char* rowstart; //!< Ptr to 1st character of current row within rowdesc->help. - const char* ptr; //!< Ptr to current part within the current row. - int col; //!< Index of current column. - int len; //!< Length of the current part (that ptr points at) in BYTES - int screenlen; //!< Length of the current part in screen columns (taking narrow/wide chars into account). - int max_line_in_block; //!< Greatest index of a line within the block. This is the number of \\v within the cell with the most \\vs. - int line_in_block; //!< Line index within the current cell of the current part. - int target_line_in_block; //!< Line index of the parts we should return to the user on this iteration. - bool hit_target_line; //!< Flag whether we encountered a part with line index target_line_in_block in the current cell. - - /** - * @brief Determines the byte and character lengths of the part at @ref ptr and - * stores them in @ref len and @ref screenlen respectively. - */ - void update_length() - { - screenlen = 0; - for (len = 0; ptr[len] != 0 && ptr[len] != '\v' && ptr[len] != '\t' && ptr[len] != '\n'; ++len) - { - ++screenlen; - unsigned ch = (unsigned char) ptr[len]; - if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte - { - // int __builtin_clz (unsigned int x) - // Returns the number of leading 0-bits in x, starting at the most significant bit - unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); - ch = ch & mask; // mask out length bits, we don't verify their correctness - while (((unsigned char) ptr[len + 1] ^ 0x80) <= 0x3F) // while next byte is continuation byte - { - ch = (ch << 6) ^ (unsigned char) ptr[len + 1] ^ 0x80; // add continuation to char code - ++len; - } - // ch is the decoded unicode code point - if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case - ++screenlen; - } - } - } - - public: - //! @brief Creates an iterator for @c usage. - LinePartIterator(const Descriptor usage[]) : - tablestart(usage), rowdesc(0), rowstart(0), ptr(0), col(-1), len(0), screenlen(0), max_line_in_block(0), line_in_block(0), - target_line_in_block(0), hit_target_line(true) - { - } - - /** - * @brief Moves iteration to the next table (if any). Has to be called once on a new - * LinePartIterator to move to the 1st table. - * @retval false if moving to next table failed because no further table exists. - */ - bool nextTable() - { - // If this is NOT the first time nextTable() is called after the constructor, - // then skip to the next table break (i.e. a Descriptor with help == 0) - if (rowdesc != 0) - { - while (tablestart->help != 0 && tablestart->shortopt != 0) - ++tablestart; - } - - // Find the next table after the break (if any) - while (tablestart->help == 0 && tablestart->shortopt != 0) - ++tablestart; - - restartTable(); - return rowstart != 0; - } - - /** - * @brief Reset iteration to the beginning of the current table. - */ - void restartTable() - { - rowdesc = tablestart; - rowstart = tablestart->help; - ptr = 0; - } - - /** - * @brief Moves iteration to the next row (if any). Has to be called once after each call to - * @ref nextTable() to move to the 1st row of the table. - * @retval false if moving to next row failed because no further row exists. - */ - bool nextRow() - { - if (ptr == 0) - { - restartRow(); - return rowstart != 0; - } - - while (*ptr != 0 && *ptr != '\n') - ++ptr; - - if (*ptr == 0) - { - if ((rowdesc + 1)->help == 0) // table break - return false; - - ++rowdesc; - rowstart = rowdesc->help; - } - else // if (*ptr == '\n') - { - rowstart = ptr + 1; - } - - restartRow(); - return true; - } - - /** - * @brief Reset iteration to the beginning of the current row. - */ - void restartRow() - { - ptr = rowstart; - col = -1; - len = 0; - screenlen = 0; - max_line_in_block = 0; - line_in_block = 0; - target_line_in_block = 0; - hit_target_line = true; - } - - /** - * @brief Moves iteration to the next part (if any). Has to be called once after each call to - * @ref nextRow() to move to the 1st part of the row. - * @retval false if moving to next part failed because no further part exists. - * - * See @ref LinePartIterator for details about the iteration. - */ - bool next() - { - if (ptr == 0) - return false; - - if (col == -1) - { - col = 0; - update_length(); - return true; - } - - ptr += len; - while (true) - { - switch (*ptr) - { - case '\v': - upmax(max_line_in_block, ++line_in_block); - ++ptr; - break; - case '\t': - if (!hit_target_line) // if previous column did not have the targetline - { // then "insert" a 0-length part - update_length(); - hit_target_line = true; - return true; - } - - hit_target_line = false; - line_in_block = 0; - ++col; - ++ptr; - break; - case 0: - case '\n': - if (!hit_target_line) // if previous column did not have the targetline - { // then "insert" a 0-length part - update_length(); - hit_target_line = true; - return true; - } - - if (++target_line_in_block > max_line_in_block) - { - update_length(); - return false; - } - - hit_target_line = false; - line_in_block = 0; - col = 0; - ptr = rowstart; - continue; - default: - ++ptr; - continue; - } // switch - - if (line_in_block == target_line_in_block) - { - update_length(); - hit_target_line = true; - return true; - } - } // while - } - - /** - * @brief Returns the index (counting from 0) of the column in which - * the part pointed to by @ref data() is located. - */ - int column() - { - return col; - } - - /** - * @brief Returns the index (counting from 0) of the line within the current column - * this part belongs to. - */ - int line() - { - return target_line_in_block; // NOT line_in_block !!! It would be wrong if !hit_target_line - } - - /** - * @brief Returns the length of the part pointed to by @ref data() in raw chars (not UTF-8 characters). - */ - int length() - { - return len; - } - - /** - * @brief Returns the width in screen columns of the part pointed to by @ref data(). - * Takes multi-byte UTF-8 sequences and wide characters into account. - */ - int screenLength() - { - return screenlen; - } - - /** - * @brief Returns the current part of the iteration. - */ - const char* data() - { - return ptr; - } - }; - - /** - * @internal - * @brief Takes input and line wraps it, writing out one line at a time so that - * it can be interleaved with output from other columns. - * - * The LineWrapper is used to handle the last column of each table as well as interjections. - * The LineWrapper is called once for each line of output. If the data given to it fits - * into the designated width of the last column it is simply written out. If there - * is too much data, an appropriate split point is located and only the data up to this - * split point is written out. The rest of the data is queued for the next line. - * That way the last column can be line wrapped and interleaved with data from - * other columns. The following example makes this clearer: - * @code - * Column 1,1 Column 2,1 This is a long text - * Column 1,2 Column 2,2 that does not fit into - * a single line. - * @endcode - * - * The difficulty in producing this output is that the whole string - * "This is a long text that does not fit into a single line" is the - * 1st and only part of column 3. In order to produce the above - * output the string must be output piecemeal, interleaved with - * the data from the other columns. - */ - class LineWrapper - { - static const int bufmask = 15; //!< Must be a power of 2 minus 1. - /** - * @brief Ring buffer for length component of pair (data, length). - */ - int lenbuf[bufmask + 1]; - /** - * @brief Ring buffer for data component of pair (data, length). - */ - const char* datbuf[bufmask + 1]; - /** - * @brief The indentation of the column to which the LineBuffer outputs. LineBuffer - * assumes that the indentation has already been written when @ref process() - * is called, so this value is only used when a buffer flush requires writing - * additional lines of output. - */ - int x; - /** - * @brief The width of the column to line wrap. - */ - int width; - int head; //!< @brief index for next write - int tail; //!< @brief index for next read - 1 (i.e. increment tail BEFORE read) - - /** - * @brief Multiple methods of LineWrapper may decide to flush part of the buffer to - * free up space. The contract of process() says that only 1 line is output. So - * this variable is used to track whether something has output a line. It is - * reset at the beginning of process() and checked at the end to decide if - * output has already occurred or is still needed. - */ - bool wrote_something; - - bool buf_empty() - { - return ((tail + 1) & bufmask) == head; - } - - bool buf_full() - { - return tail == head; - } - - void buf_store(const char* data, int len) - { - lenbuf[head] = len; - datbuf[head] = data; - head = (head + 1) & bufmask; - } - - //! @brief Call BEFORE reading ...buf[tail]. - void buf_next() - { - tail = (tail + 1) & bufmask; - } - - /** - * @brief Writes (data,len) into the ring buffer. If the buffer is full, a single line - * is flushed out of the buffer into @c write. - */ - void output(IStringWriter& write, const char* data, int len) - { - if (buf_full()) - write_one_line(write); - - buf_store(data, len); - } - - /** - * @brief Writes a single line of output from the buffer to @c write. - */ - void write_one_line(IStringWriter& write) - { - if (wrote_something) // if we already wrote something, we need to start a new line - { - write("\n", 1); - int _ = 0; - indent(write, _, x); - } - - if (!buf_empty()) - { - buf_next(); - write(datbuf[tail], lenbuf[tail]); - } - - wrote_something = true; - } - public: - - /** - * @brief Writes out all remaining data from the LineWrapper using @c write. - * Unlike @ref process() this method indents all lines including the first and - * will output a \\n at the end (but only if something has been written). - */ - void flush(IStringWriter& write) - { - if (buf_empty()) - return; - int _ = 0; - indent(write, _, x); - wrote_something = false; - while (!buf_empty()) - write_one_line(write); - write("\n", 1); - } - - /** - * @brief Process, wrap and output the next piece of data. - * - * process() will output at least one line of output. This is not necessarily - * the @c data passed in. It may be data queued from a prior call to process(). - * If the internal buffer is full, more than 1 line will be output. - * - * process() assumes that the a proper amount of indentation has already been - * output. It won't write any further indentation before the 1st line. If - * more than 1 line is written due to buffer constraints, the lines following - * the first will be indented by this method, though. - * - * No \\n is written by this method after the last line that is written. - * - * @param write where to write the data. - * @param data the new chunk of data to write. - * @param len the length of the chunk of data to write. - */ - void process(IStringWriter& write, const char* data, int len) - { - wrote_something = false; - - while (len > 0) - { - if (len <= width) // quick test that works because utf8width <= len (all wide chars have at least 2 bytes) - { - output(write, data, len); - len = 0; - } - else // if (len > width) it's possible (but not guaranteed) that utf8len > width - { - int utf8width = 0; - int maxi = 0; - while (maxi < len && utf8width < width) - { - int charbytes = 1; - unsigned ch = (unsigned char) data[maxi]; - if (ch > 0xC1) // everything <= 0xC1 (yes, even 0xC1 itself) is not a valid UTF-8 start byte - { - // int __builtin_clz (unsigned int x) - // Returns the number of leading 0-bits in x, starting at the most significant bit - unsigned mask = (unsigned) -1 >> __builtin_clz(ch ^ 0xff); - ch = ch & mask; // mask out length bits, we don't verify their correctness - while ((maxi + charbytes < len) && // - (((unsigned char) data[maxi + charbytes] ^ 0x80) <= 0x3F)) // while next byte is continuation byte - { - ch = (ch << 6) ^ (unsigned char) data[maxi + charbytes] ^ 0x80; // add continuation to char code - ++charbytes; - } - // ch is the decoded unicode code point - if (ch >= 0x1100 && isWideChar(ch)) // the test for 0x1100 is here to avoid the function call in the Latin case - { - if (utf8width + 2 > width) - break; - ++utf8width; - } - } - ++utf8width; - maxi += charbytes; - } - - // data[maxi-1] is the last byte of the UTF-8 sequence of the last character that fits - // onto the 1st line. If maxi == len, all characters fit on the line. - - if (maxi == len) - { - output(write, data, len); - len = 0; - } - else // if (maxi < len) at least 1 character (data[maxi] that is) doesn't fit on the line - { - int i; - for (i = maxi; i >= 0; --i) - if (data[i] == ' ') - break; - - if (i >= 0) - { - output(write, data, i); - data += i + 1; - len -= i + 1; - } - else // did not find a space to split at => split before data[maxi] - { // data[maxi] is always the beginning of a character, never a continuation byte - output(write, data, maxi); - data += maxi; - len -= maxi; - } - } - } - } - if (!wrote_something) // if we didn't already write something to make space in the buffer - write_one_line(write); // write at most one line of actual output - } - - /** - * @brief Constructs a LineWrapper that wraps its output to fit into - * screen columns @c x1 (incl.) to @c x2 (excl.). - * - * @c x1 gives the indentation LineWrapper uses if it needs to indent. - */ - LineWrapper(int x1, int x2) : - lenbuf(), datbuf(), x(x1), width(x2 - x1), head(0), tail(bufmask), wrote_something(false) - { - if (width < 2) // because of wide characters we need at least width 2 or the code breaks - width = 2; - } - }; - - /** - * @internal - * @brief This is the implementation that is shared between all printUsage() templates. - * Because all printUsage() templates share this implementation, there is no template bloat. - */ - static void printUsage(IStringWriter& write, const Descriptor usage[], int width = 80, // - int last_column_min_percent = 50, int last_column_own_line_max_percent = 75) - { - if (width < 1) // protect against nonsense values - width = 80; - - if (width > 10000) // protect against overflow in the following computation - width = 10000; - - int last_column_min_width = ((width * last_column_min_percent) + 50) / 100; - int last_column_own_line_max_width = ((width * last_column_own_line_max_percent) + 50) / 100; - if (last_column_own_line_max_width == 0) - last_column_own_line_max_width = 1; - - LinePartIterator part(usage); - while (part.nextTable()) - { - - /***************** Determine column widths *******************************/ - - const int maxcolumns = 8; // 8 columns are enough for everyone - int col_width[maxcolumns]; - int lastcolumn; - int leftwidth; - int overlong_column_threshold = 10000; - do - { - lastcolumn = 0; - for (int i = 0; i < maxcolumns; ++i) - col_width[i] = 0; - - part.restartTable(); - while (part.nextRow()) - { - while (part.next()) - { - if (part.column() < maxcolumns) - { - upmax(lastcolumn, part.column()); - if (part.screenLength() < overlong_column_threshold) - // We don't let rows that don't use table separators (\t or \v) influence - // the width of column 0. This allows the user to interject section headers - // or explanatory paragraphs that do not participate in the table layout. - if (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' - || part.data()[part.length()] == '\v') - upmax(col_width[part.column()], part.screenLength()); - } - } - } - - /* - * If the last column doesn't fit on the same - * line as the other columns, we can fix that by starting it on its own line. - * However we can't do this for any of the columns 0..lastcolumn-1. - * If their sum exceeds the maximum width we try to fix this by iteratively - * ignoring the widest line parts in the width determination until - * we arrive at a series of column widths that fit into one line. - * The result is a layout where everything is nicely formatted - * except for a few overlong fragments. - * */ - - leftwidth = 0; - overlong_column_threshold = 0; - for (int i = 0; i < lastcolumn; ++i) - { - leftwidth += col_width[i]; - upmax(overlong_column_threshold, col_width[i]); - } - - } while (leftwidth > width); - - /**************** Determine tab stops and last column handling **********************/ - - int tabstop[maxcolumns]; - tabstop[0] = 0; - for (int i = 1; i < maxcolumns; ++i) - tabstop[i] = tabstop[i - 1] + col_width[i - 1]; - - int rightwidth = width - tabstop[lastcolumn]; - bool print_last_column_on_own_line = false; - if (rightwidth < last_column_min_width && rightwidth < col_width[lastcolumn]) - { - print_last_column_on_own_line = true; - rightwidth = last_column_own_line_max_width; - } - - // If lastcolumn == 0 we must disable print_last_column_on_own_line because - // otherwise 2 copies of the last (and only) column would be output. - // Actually this is just defensive programming. It is currently not - // possible that lastcolumn==0 and print_last_column_on_own_line==true - // at the same time, because lastcolumn==0 => tabstop[lastcolumn] == 0 => - // rightwidth==width => rightwidth>=last_column_min_width (unless someone passes - // a bullshit value >100 for last_column_min_percent) => the above if condition - // is false => print_last_column_on_own_line==false - if (lastcolumn == 0) - print_last_column_on_own_line = false; - - LineWrapper lastColumnLineWrapper(width - rightwidth, width); - LineWrapper interjectionLineWrapper(0, width); - - part.restartTable(); - - /***************** Print out all rows of the table *************************************/ - - while (part.nextRow()) - { - int x = -1; - while (part.next()) - { - if (part.column() > lastcolumn) - continue; // drop excess columns (can happen if lastcolumn == maxcolumns-1) - - if (part.column() == 0) - { - if (x >= 0) - write("\n", 1); - x = 0; - } - - indent(write, x, tabstop[part.column()]); - - if ((part.column() < lastcolumn) - && (part.column() > 0 || part.line() > 0 || part.data()[part.length()] == '\t' - || part.data()[part.length()] == '\v')) - { - write(part.data(), part.length()); - x += part.screenLength(); - } - else // either part.column() == lastcolumn or we are in the special case of - // an interjection that doesn't contain \v or \t - { - // NOTE: This code block is not necessarily executed for - // each line, because some rows may have fewer columns. - - LineWrapper& lineWrapper = (part.column() == 0) ? interjectionLineWrapper : lastColumnLineWrapper; - - if (!print_last_column_on_own_line) - lineWrapper.process(write, part.data(), part.length()); - } - } // while - - if (print_last_column_on_own_line) - { - part.restartRow(); - while (part.next()) - { - if (part.column() == lastcolumn) - { - write("\n", 1); - int _ = 0; - indent(write, _, width - rightwidth); - lastColumnLineWrapper.process(write, part.data(), part.length()); - } - } - } - - write("\n", 1); - lastColumnLineWrapper.flush(write); - interjectionLineWrapper.flush(write); - } - } - } - -} -; - -/** - * @brief Outputs a nicely formatted usage string with support for multi-column formatting - * and line-wrapping. - * - * printUsage() takes the @c help texts of a Descriptor[] array and formats them into - * a usage message, wrapping lines to achieve the desired output width. - * - * Table formatting: - * - * Aside from plain strings which are simply line-wrapped, the usage may contain tables. Tables - * are used to align elements in the output. - * - * @code - * // Without a table. The explanatory texts are not aligned. - * -c, --create |Creates something. - * -k, --kill |Destroys something. - * - * // With table formatting. The explanatory texts are aligned. - * -c, --create |Creates something. - * -k, --kill |Destroys something. - * @endcode - * - * Table formatting removes the need to pad help texts manually with spaces to achieve - * alignment. To create a table, simply insert \\t (tab) characters to separate the cells - * within a row. - * - * @code - * const option::Descriptor usage[] = { - * {..., "-c, --create \tCreates something." }, - * {..., "-k, --kill \tDestroys something." }, ... - * @endcode - * - * Note that you must include the minimum amount of space desired between cells yourself. - * Table formatting will insert further spaces as needed to achieve alignment. - * - * You can insert line breaks within cells by using \\v (vertical tab). - * - * @code - * const option::Descriptor usage[] = { - * {..., "-c,\v--create \tCreates\vsomething." }, - * {..., "-k,\v--kill \tDestroys\vsomething." }, ... - * - * // results in - * - * -c, Creates - * --create something. - * -k, Destroys - * --kill something. - * @endcode - * - * You can mix lines that do not use \\t or \\v with those that do. The plain - * lines will not mess up the table layout. Alignment of the table columns will - * be maintained even across these interjections. - * - * @code - * const option::Descriptor usage[] = { - * {..., "-c, --create \tCreates something." }, - * {..., "----------------------------------" }, - * {..., "-k, --kill \tDestroys something." }, ... - * - * // results in - * - * -c, --create Creates something. - * ---------------------------------- - * -k, --kill Destroys something. - * @endcode - * - * You can have multiple tables within the same usage whose columns are - * aligned independently. Simply insert a dummy Descriptor with @c help==0. - * - * @code - * const option::Descriptor usage[] = { - * {..., "Long options:" }, - * {..., "--very-long-option \tDoes something long." }, - * {..., "--ultra-super-mega-long-option \tTakes forever to complete." }, - * {..., 0 }, // ---------- table break ----------- - * {..., "Short options:" }, - * {..., "-s \tShort." }, - * {..., "-q \tQuick." }, ... - * - * // results in - * - * Long options: - * --very-long-option Does something long. - * --ultra-super-mega-long-option Takes forever to complete. - * Short options: - * -s Short. - * -q Quick. - * - * // Without the table break it would be - * - * Long options: - * --very-long-option Does something long. - * --ultra-super-mega-long-option Takes forever to complete. - * Short options: - * -s Short. - * -q Quick. - * @endcode - * - * Output methods: - * - * Because TheLeanMeanC++Option parser is freestanding, you have to provide the means for - * output in the first argument(s) to printUsage(). Because printUsage() is implemented as - * a set of template functions, you have great flexibility in your choice of output - * method. The following example demonstrates typical uses. Anything that's similar enough - * will work. - * - * @code - * #include // write() - * #include // cout - * #include // ostringstream - * #include // fwrite() - * using namespace std; - * - * void my_write(const char* str, int size) { - * fwrite(str, size, 1, stdout); - * } - * - * struct MyWriter { - * void write(const char* buf, size_t size) const { - * fwrite(str, size, 1, stdout); - * } - * }; - * - * struct MyWriteFunctor { - * void operator()(const char* buf, size_t size) { - * fwrite(str, size, 1, stdout); - * } - * }; - * ... - * printUsage(my_write, usage); // custom write function - * printUsage(MyWriter(), usage); // temporary of a custom class - * MyWriter writer; - * printUsage(writer, usage); // custom class object - * MyWriteFunctor wfunctor; - * printUsage(&wfunctor, usage); // custom functor - * printUsage(write, 1, usage); // write() to file descriptor 1 - * printUsage(cout, usage); // an ostream& - * printUsage(fwrite, stdout, usage); // fwrite() to stdout - * ostringstream sstr; - * printUsage(sstr, usage); // an ostringstream& - * - * @endcode - * - * @par Notes: - * @li the @c write() method of a class that is to be passed as a temporary - * as @c MyWriter() is in the example, must be a @c const method, because - * temporary objects are passed as const reference. This only applies to - * temporary objects that are created and destroyed in the same statement. - * If you create an object like @c writer in the example, this restriction - * does not apply. - * @li a functor like @c MyWriteFunctor in the example must be passed as a pointer. - * This differs from the way functors are passed to e.g. the STL algorithms. - * @li All printUsage() templates are tiny wrappers around a shared non-template implementation. - * So there's no penalty for using different versions in the same program. - * @li printUsage() always interprets Descriptor::help as UTF-8 and always produces UTF-8-encoded - * output. If your system uses a different charset, you must do your own conversion. You - * may also need to change the font of the console to see non-ASCII characters properly. - * This is particularly true for Windows. - * @li @b Security @b warning: Do not insert untrusted strings (such as user-supplied arguments) - * into the usage. printUsage() has no protection against malicious UTF-8 sequences. - * - * @param prn The output method to use. See the examples above. - * @param usage the Descriptor[] array whose @c help texts will be formatted. - * @param width the maximum number of characters per output line. Note that this number is - * in actual characters, not bytes. printUsage() supports UTF-8 in @c help and will - * count multi-byte UTF-8 sequences properly. Asian wide characters are counted - * as 2 characters. - * @param last_column_min_percent (0-100) The minimum percentage of @c width that should be available - * for the last column (which typically contains the textual explanation of an option). - * If less space is available, the last column will be printed on its own line, indented - * according to @c last_column_own_line_max_percent. - * @param last_column_own_line_max_percent (0-100) If the last column is printed on its own line due to - * less than @c last_column_min_percent of the width being available, then only - * @c last_column_own_line_max_percent of the extra line(s) will be used for the - * last column's text. This ensures an indentation. See example below. - * - * @code - * // width=20, last_column_min_percent=50 (i.e. last col. min. width=10) - * --3456789 1234567890 - * 1234567890 - * - * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) - * // last_column_own_line_max_percent=75 - * --3456789 - * 123456789012345 - * 67890 - * - * // width=20, last_column_min_percent=75 (i.e. last col. min. width=15) - * // last_column_own_line_max_percent=33 (i.e. max. 5) - * --3456789 - * 12345 - * 67890 - * 12345 - * 67890 - * @endcode - */ -template -void printUsage(OStream& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, - int last_column_own_line_max_percent = 75) -{ - PrintUsageImplementation::OStreamWriter write(prn); - PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); -} - -template -void printUsage(Function* prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, - int last_column_own_line_max_percent = 75) -{ - PrintUsageImplementation::FunctionWriter write(prn); - PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); -} - -template -void printUsage(const Temporary& prn, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, - int last_column_own_line_max_percent = 75) -{ - PrintUsageImplementation::TemporaryWriter write(prn); - PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); -} - -template -void printUsage(Syscall* prn, int fd, const Descriptor usage[], int width = 80, int last_column_min_percent = 50, - int last_column_own_line_max_percent = 75) -{ - PrintUsageImplementation::SyscallWriter write(prn, fd); - PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); -} - -template -void printUsage(Function* prn, Stream* stream, const Descriptor usage[], int width = 80, int last_column_min_percent = - 50, - int last_column_own_line_max_percent = 75) -{ - PrintUsageImplementation::StreamWriter write(prn, stream); - PrintUsageImplementation::printUsage(write, usage, width, last_column_min_percent, last_column_own_line_max_percent); -} - -struct FullArg: public Arg -{ - static void printError(const char* msg1, const option::Option& opt, const char* msg2) - { - fprintf(stderr, "%s", msg1); - fwrite(opt.name, opt.namelen, 1, stderr); - fprintf(stderr, "%s", msg2); - } - - static option::ArgStatus Unknown(const option::Option& option, bool msg) - { - if (msg) printError("Unknown option '", option, "'\n"); - return option::ARG_ILLEGAL; - } - - static option::ArgStatus Required(const option::Option& option, bool msg) - { - if (option.arg != 0) - return option::ARG_OK; - - if (msg) printError("Option '", option, "' requires an argument\n"); - return option::ARG_ILLEGAL; - } - - static option::ArgStatus NonEmpty(const option::Option& option, bool msg) - { - if (option.arg != 0 && option.arg[0] != 0) - return option::ARG_OK; - - if (msg) printError("Option '", option, "' requires a non-empty argument\n"); - return option::ARG_ILLEGAL; - } - - static option::ArgStatus Numeric(const option::Option& option, bool msg) - { - char* endptr = 0; - if (option.arg != 0 && strtol(option.arg, &endptr, 10)){}; - if (endptr != option.arg && *endptr == 0) - return option::ARG_OK; - - if (msg) printError("Option '", option, "' requires a numeric argument\n"); - return option::ARG_ILLEGAL; - } -}; - - -} -// namespace option -} -// namespace ROOT - -#endif /* OPTIONPARSER_H_ */ diff --git a/third_party/cpptoml/cpptoml.h b/third_party/cpptoml/cpptoml.h index ea05f8664..180f0f7e9 100644 --- a/third_party/cpptoml/cpptoml.h +++ b/third_party/cpptoml/cpptoml.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/util/build-third-party/build-all.sh b/util/build-third-party/build-all.sh index eddf81284..443471531 100755 --- a/util/build-third-party/build-all.sh +++ b/util/build-third-party/build-all.sh @@ -16,7 +16,7 @@ if [[ $# -ne 0 ]]; then echo "ERROR: Wrong number of arguments. Description: - This script builds all third party dependencies. + This script builds the bundled third party dependency. The archives will be stored in BDM_PROJECT_DIR/build No Arguments" exit 1 @@ -27,17 +27,10 @@ set -e -x SCRIPTPATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # Install the prerequisites -. ${SCRIPTPATH}/util/build-third-party/third-party-prerequisites.sh +. "${SCRIPTPATH}/third-party-prerequisites.sh" # Software versions -ROOT_VERSION=6.26.10 ROADRUNNER_VERSION=release -# root -$SCRIPTPATH/build-root.sh $ROOT_VERSION - -# paraview and qt -$SCRIPTPATH/build-paraview.sh - # roadrunner -$SCRIPTPATH/build-roadrunner.sh $ROADRUNNER_VERSION +"$SCRIPTPATH/build-roadrunner.sh" "$ROADRUNNER_VERSION" diff --git a/util/build-third-party/build-paraview.sh b/util/build-third-party/build-paraview.sh deleted file mode 100755 index 954d2afd5..000000000 --- a/util/build-third-party/build-paraview.sh +++ /dev/null @@ -1,131 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -##################################### -## Building ParaView for BioDynaMo ## -##################################### -WORKING_DIR="$HOME/bdm-build-third-party/paraview" -PV_FLAVOR="default" - -function printUsageAndExit { - echo " - $0 [-w path-to-working-dir -f paraview-flavor -p] -Description: - This script builds paraview. - The archive will be stored in $BDM_PROJECT_DIR/build -Arguments: - -w - working dir path - Default value: $WORKING_DIR - -f - paraview flavour. Possible values: default or nvidia-headless - Default value: $PV_FLAVOR - -d - ignore dirty working dir - -p - install prerequisites. Skip this step if -p is missing - -C - skip checkout-code.sh - -Q - skip prerequisite Qt5 download and install - -M - don't install prerequisite packages using the system's package manager - -P - don't install pyenv prerequisite - -Z - skip package.sh" - exit 1 -} - -# parse options -while getopts ":w:f:pdCMPQZ" opt; do - case ${opt} in - w ) - WORKING_DIR=$(realpath $OPTARG) - ;; - f ) - PV_FLAVOR=$OPTARG - ;; - p ) - INSTALL_PREREQUISITES=1 - ;; - d ) - DIRTY_DIR=1 - ;; - C ) - SKIP_CHECKOUT=1 - ;; - M ) - SKIP_PACKAGE_MAN=1 - ;; - P ) - SKIP_PYENV=1 - ;; - Q ) - SKIP_QT=1 - ;; - Z ) - SKIP_PACKAGING=1 - ;; - \? ) - echo "Invalid option: $OPTARG" 1>&2 - printUsageAndExit - ;; - : ) - echo "Invalid option: $OPTARG requires an argument" 1>&2 - printUsageAndExit - ;; - esac -done -shift $((OPTIND -1)) - -BDM_PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../.." -cd $BDM_PROJECT_DIR - -set -e -x - -mkdir -p "$WORKING_DIR" - -if [ -z "$DIRTY_DIR" ] && [ -n "$(ls -A \"$WORKING_DIR\")" ]; then - echo "ERROR: Working directory ($WORKING_DIR) is not empty" - exit 2 -fi - -cp "$BDM_PROJECT_DIR/util/build-third-party/paraview/"* "$WORKING_DIR" -cd $WORKING_DIR - -# Prepend parameters to env.sh so scripts can be called again at a later stage -# This helps debugging an error at one stage. -echo "export BDM_PROJECT_DIR=$BDM_PROJECT_DIR" > env.sh -echo "export WORKING_DIR=$WORKING_DIR" >> env.sh -echo "export SKIP_QT=$SKIP_QT" >> env.sh -echo "export SKIP_PACKAGE_MAN=$SKIP_PACKAGE_MAN" >> env.sh -echo "export SKIP_PYENV=$SKIP_PYENV" >> env.sh -echo "export PV_FLAVOR=$PV_FLAVOR" >> env.sh -cat "$BDM_PROJECT_DIR/util/build-third-party/paraview/env.sh" >> env.sh - -if [ -n "$INSTALL_PREREQUISITES" ]; then - ./prerequisites.sh -fi - -if [ -z "$SKIP_CHECKOUT" ]; then - ./checkout-code.sh -fi - -./build.sh - -if [ -z "$SKIP_PACKAGING" ]; then - ./package.sh -fi diff --git a/util/build-third-party/build-qt.sh b/util/build-third-party/build-qt.sh deleted file mode 100755 index 4b88fc304..000000000 --- a/util/build-third-party/build-qt.sh +++ /dev/null @@ -1,101 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -BDM_PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../.." - -if [[ $# -ne 0 ]]; then - echo "ERROR: Wrong number of arguments. -Description: - This script creates qt.tar.gz file. - The archive will be stored in $BDM_PROJECT_DIR/build/ -No Arguments" - exit 1 -fi - -set -e -x - -cd $BDM_PROJECT_DIR - -# import util functions -. $BDM_PROJECT_DIR/util/installation/common/util.sh - -# archive destination dir -DEST_DIR=$BDM_PROJECT_DIR/build -mkdir -p $DEST_DIR -EchoNewStep "Start building QT. Result will be stored in $DEST_DIR" -# working dir -WORKING_DIR=$HOME/bdm-build-third-party -mkdir -p $WORKING_DIR -cd $WORKING_DIR - -QT_INSTALL_DIR=$WORKING_DIR/qt -if [ -d $QT_INSTALL_DIR ]; then - echo "ERROR: $QT_INSTALL_DIR exists already." - exit 1 -fi - -# install prerequisites -. $BDM_PROJECT_DIR/util/build-third-party/third-party-prerequisites.sh - -################################################################################ -# Since 2020, Qt requires you to login with an account to download the -# libraries. Instead, we download a previously built Qt directly from cernbox -################################################################################ - -# if [ `uname` = "Linux" ]; then -# QT_INSTALLER=qt-installer.run -# QT_URL="https://download.qt.io/archive/qt/5.11/5.11.0/qt-opensource-linux-x64-5.11.0.run" -# QT_SILENT_INSTALL_JS=$BDM_PROJECT_DIR/util/build-third-party/qt-silent-install-linux.js -# QT_LIB_PLUGINS_PARENT=$QT_INSTALL_DIR/5.11.0/gcc_64 -# else -# QT_INSTALLER=qt-installer.dmg -# QT_URL="https://download.qt.io/archive/qt/5.11/5.11.0/qt-opensource-mac-x64-5.11.0.dmg" -# QT_SILENT_INSTALL_JS=$BDM_PROJECT_DIR/util/build-third-party/qt-silent-install-macos.js -# QT_LIB_PLUGINS_PARENT=$QT_INSTALL_DIR/5.11.0/clang_64 -# fi - -# # Download and install qt -# wget --progress=dot:giga -O $QT_INSTALLER $QT_URL -# if [ `uname` = "Linux" ]; then -# chmod u+x $QT_INSTALLER -# ./$QT_INSTALLER --script $QT_SILENT_INSTALL_JS --platform minimal -# rm $QT_INSTALLER -# else -# hdiutil attach $QT_INSTALLER -# /Volumes/qt-opensource-mac-x64-5.11.0/qt-opensource-mac-x64-5.11.0.app/Contents/MacOS/qt-opensource-mac-x64-5.11.0 \ -# --script $QT_SILENT_INSTALL_JS \ -# --platform minimal -# hdiutil detach /Volumes/qt-opensource-mac-x64-5.11.0 -# rm $QT_INSTALLER -# fi - -# # package -# cd $QT_LIB_PLUGINS_PARENT -# tar -zcf qt-v5.11.0-$(DetectOs).tar.gz * - -# # mv to destination directory -# mv qt-v5.11.0-$(DetectOs).tar.gz $DEST_DIR - -################################################################################ - -mkdir -p $QT_INSTALL_DIR -QT_TAR="qt-v5.12.10-$(DetectOs).tar.gz" -QT_TAR_FILE="${QT_INSTALL_DIR}/${QT_TAR}" -QT_URL=http://cern.ch/biodynamo-lfs/third-party/${QT_TAR} -wget --progress=dot:giga -O $QT_TAR_FILE $QT_URL -cd ${QT_INSTALL_DIR} -tar -zxf $QT_TAR -shasum -a256 ${QT_TAR} > ${QT_TAR}.sha256 -mv $QT_TAR $QT_TAR.sha256 $DEST_DIR diff --git a/util/build-third-party/build-root.sh b/util/build-third-party/build-root.sh deleted file mode 100755 index 34178c1bc..000000000 --- a/util/build-third-party/build-root.sh +++ /dev/null @@ -1,187 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -if [[ $# -ne 1 ]]; then - echo "ERROR: Wrong number of arguments. -Description: - This script builds ROOT. - The archive will be stored in BDM_PROJECT_DIR/build/root.tar.gz -Arguments: - \$1 ROOT version that should be build (e.g. v6-22-00)" - exit 1 -fi - -set -e -x - -ROOT_VERSION=$1 -PYVERS=3.9.1 - -BDM_PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../.." -cd $BDM_PROJECT_DIR - -# import util functions -. $BDM_PROJECT_DIR/util/installation/common/util.sh - -# archive destination dir -BDM_OS=$(DetectOs) -DEST_DIR=$BDM_PROJECT_DIR/build/build-third-party -mkdir -p $DEST_DIR -EchoNewStep "Start building ROOT $ROOT_VERSION. Result will be stored in $DEST_DIR" -# working dir -WORKING_DIR=~/bdm-build-third-party -mkdir -p $WORKING_DIR -cd $WORKING_DIR - -ROOT_INSTALL_DIR=$WORKING_DIR/root-install -if [ -d $ROOT_INSTALL_DIR ]; then - echo "ERROR: $ROOT_INSTALL_DIR exists already." - exit 1 -fi -mkdir -p $ROOT_INSTALL_DIR - -# install prerequisites -. $BDM_PROJECT_DIR/util/build-third-party/third-party-prerequisites.sh - -# Get the right ROOT source version, untar creates "root-$ROOT_VERSION" -wget https://root.cern.ch/download/root_v$ROOT_VERSION.source.tar.gz -tar -zxf root_v$ROOT_VERSION.source.tar.gz -cd root-$ROOT_VERSION -ROOTSRC=`pwd` -cd .. - -# On macOS use brew's python -brewpy=no -if [[ $(uname -s) == "Darwin" ]]; then - brewpy=yes -fi - -if [ $brewpy == "yes" ]; then - pyth="$(brew --prefix)/bin/python3" -else - # Set Python to $PYVERS - if [[ $(uname -s) == "Darwin" ]]; then - export PYENV_ROOT=/usr/local/opt/.pyenv - fi - eval "$(pyenv init -)" - pyenv shell $PYVERS - pyth="`pyenv which python`" -fi - -# Make sure numpy is installed for python -#$pyth -m pip install numpy - -# unset any env var to local installed libraries -unset XRDSYS -unset RFIO -unset CASTOR -unset FFTW3 -unset MONALISA -unset ORACLE -unset PYTHIA6 -unset PYTHIA8 -unset DAVIX - -mkdir build -cd build - -if [[ $(uname -s) == "Darwin" ]]; then - OSXARCH=`arch` - if [ $OSXARCH == "arm64" ]; then - cmake -G Ninja \ - -Dmacos_native=YES \ - -Dbuiltin_fftw3=ON \ - -Dbuiltin_freetype=ON \ - -Dbuiltin_ftgl=ON \ - -Dbuiltin_glew=ON \ - -Dbuiltin_gsl=ON \ - -Dbuiltin_lz4=ON \ - -Dbuiltin_lzma=ON \ - -Dbuiltin_openssl=ON \ - -Dbuiltin_pcre=ON \ - -Dbuiltin_tbb=ON \ - -Dbuiltin_unuran=ON \ - -Dbuiltin_xxhash=ON \ - -Dbuiltin_zlib=ON \ - -Dbuiltin_zstd=ON \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$ROOT_INSTALL_DIR \ - -DCMAKE_CXX_STANDARD=14 \ - -DTBB_ROOT_DIR=$(brew --prefix) - -DPYTHON_EXECUTABLE="$pyth" \ - $ROOTSRC - else - cmake -G Ninja \ - -Dmacos_native=YES \ - -Dbuiltin_fftw3=ON \ - -Dbuiltin_freetype=ON \ - -Dbuiltin_ftgl=ON \ - -Dbuiltin_glew=ON \ - -Dbuiltin_gsl=ON \ - -Dbuiltin_lz4=ON \ - -Dbuiltin_lzma=ON \ - -Dbuiltin_openssl=ON \ - -Dbuiltin_pcre=ON \ - -Dbuiltin_tbb=ON \ - -Dbuiltin_unuran=ON \ - -Dbuiltin_xxhash=ON \ - -Dbuiltin_zlib=ON \ - -Dbuiltin_zstd=ON \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_INSTALL_PREFIX=$ROOT_INSTALL_DIR \ - -DCMAKE_CXX_STANDARD=14 \ - -DPYTHON_EXECUTABLE="$pyth" \ - $ROOTSRC - fi -else - # -Droot7=OFF only because centos7 fails on one construct. - cmake -G Ninja \ - -Dbuiltin_fftw3=ON \ - -Dbuiltin_freetype=ON \ - -Dbuiltin_ftgl=ON \ - -Dbuiltin_glew=ON \ - -Dbuiltin_gsl=ON \ - -Dbuiltin_lz4=ON \ - -Dbuiltin_lzma=ON \ - -Dbuiltin_openssl=ON \ - -Dbuiltin_pcre=ON \ - -Dbuiltin_tbb=ON \ - -Dbuiltin_unuran=ON \ - -Dbuiltin_xxhash=ON \ - -Dbuiltin_zlib=ON \ - -Dbuiltin_zstd=ON \ - -Droot7=OFF \ - -DCMAKE_BUILD_TYPE=Release \ - -DCMAKE_C_COMPILER=$CC \ - -DCMAKE_CXX_COMPILER=$CXX \ - -DCMAKE_INSTALL_PREFIX=$ROOT_INSTALL_DIR \ - -DCMAKE_CXX_STANDARD=14 \ - -DPYTHON_EXECUTABLE="$pyth" \ - $ROOTSRC -fi - -ninja install - -cd $ROOT_INSTALL_DIR -if [[ $(uname -s) == "Darwin" ]]; then - RESULT_FILE=root_v${ROOT_VERSION}_python3_${BDM_OS}-${OSXARCH}.tar.gz -else - RESULT_FILE=root_v${ROOT_VERSION}_python3_${BDM_OS}.tar.gz -fi -tar -zcf ${RESULT_FILE} * - -# mv to destination directory -mv ${RESULT_FILE} $DEST_DIR -cd $DEST_DIR -shasum -a256 ${RESULT_FILE} > ${RESULT_FILE}.sha256 diff --git a/util/build-third-party/paraview/build.sh b/util/build-third-party/paraview/build.sh deleted file mode 100755 index ccd7d0728..000000000 --- a/util/build-third-party/paraview/build.sh +++ /dev/null @@ -1,145 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "${SCRIPT_DIR}/env.sh" - -set -e -x - -mkdir -p "$SCRIPT_DIR/build" -cd "$SCRIPT_DIR/build" - -# set build environement variables -if [ "$(uname)" = "Linux" ]; then - export Qt5_DIR=$WORKING_DIR/qt - export QT_CMAKE_DIR=$WORKING_DIR/qt/lib/cmake/Qt5 - export LD_LIBRARY_PATH=$WORKING_DIR/qt/lib:$LD_LIBRARY_PATH - CC=gcc - CXX=g++ - export PATH=$WORKING_DIR/cmake-3.19.3/bin:$PATH - if [ "$BDM_OS" = "centos-7" ]; then - set +e - . /etc/profile.d/modules.sh - module load mpi - . scl_source enable devtoolset-10 - set -e - fi - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv shell 3.9.1 -else - # XCode compilers work fine now - export CC=clang - export CXX=clang++ - # From ParaView 5.10 on, we use brew qt@5. - if [ "$PV_VERSION" = "v5.10.0" ]; then - export Qt5_DIR=$(brew --prefix)/opt/qt@5 - export QT_CMAKE_DIR=$(brew --prefix)/opt/qt@5/lib/cmake/Qt5 - export DYLD_LIBRARY_PATH=$(brew --prefix)/opt/qt@5/lib:$DYLD_LIBRARY_PATH - else - export Qt5_DIR=$WORKING_DIR/qt - export QT_CMAKE_DIR=$WORKING_DIR/qt/lib/cmake/Qt5 - export DYLD_LIBRARY_PATH=$WORKING_DIR/qt/lib:$DYLD_LIBRARY_PATH - fi -fi - -# The CMAKE_INSTALL_RPATH will put all the specified paths in all the installed -# targets (libraries and binaries) (upon make install). Since the relative paths -# from the ParaView targets are always the same we can set the rpaths to be -# relative from the ParaView targets (which are located at @loader_path). This -# makes the ParaView installation portable (as long as we copy Qt with it) -# -DPARAVIEW_DO_UNIX_STYLE_INSTALLS forces CMake to install OSX build similarly -# to Linux, and enforces the RPATH (instead of @executable_path/../). -# The three RPATHS are respectively as follows: -# 1. ParaView binaries -> Qt libraries -# 2. ParaView libraries -> Qt libraries -# 3. ParaView binaries / libraries -> ParaView libraries - -BDM_PV_BUILD_CMAKE_ARGS="-GNinja - -DCMAKE_BUILD_TYPE:STRING=Release - -Dparaview_SOURCE_SELECTION=source - -Dparaview_SOURCE_DIR=${WORKING_DIR}/src - -DENABLE_ospray:BOOL=ON - -DENABLE_ospraymaterials:BOOL=ON - -DENABLE_paraviewsdk:BOOL=ON - -DENABLE_python3:BOOL=ON - -DENABLE_qt5:BOOL=ON - -DUSE_SYSTEM_qt5:BOOL=ON - -DENABLE_mpi:BOOL=ON - -DUSE_SYSTEM_mpi:BOOL=ON - -DUSE_SYSTEM_python3:BOOL=ON" - -if [ "$(uname)" = "Darwin" ]; then - BDM_MACOS_PY="$(brew --prefix)/bin/python3" - BDM_PV_BUILD_CMAKE_ARGS="$BDM_PV_BUILD_CMAKE_ARGS - -DPYTHON_EXECUTABLE=$BDM_MACOS_PY - -DPARAVIEW_DO_UNIX_STYLE_INSTALLS:BOOL=ON - -DCMAKE_MACOSX_RPATH:BOOL=ON - -DCMAKE_INSTALL_RPATH:STRING=@loader_path/../../qt/lib;@loader_path/../../../../../qt/lib;@loader_path/../lib" - if [ "$PV_VERSION" = "v5.10.0" ]; then - # For ParaView-5.10 we need to specify the Qt version used for VTK files. - # If we do not fix this to 5, the build will fail in the configuration phase - # because it is incompatible with other options. Possibly, consider moving - # to Qt6 entirely once it is supported. - BDM_PV_BUILD_CMAKE_ARGS="$BDM_PV_BUILD_CMAKE_ARGS - -DPARAVIEW_EXTRA_CMAKE_ARGUMENTS='-DVTK_QT_VERSION=5'" - fi -fi - -if [ "$PV_FLAVOR" = "default" ]; then - cmake $(echo $BDM_PV_BUILD_CMAKE_ARGS) ../superbuild -elif [ "$PV_FLAVOR" = "nvidia-headless" ] && ! [ "$(uname)" = "Darwin" ]; then - cmake \ - -GNinja \ - -DCMAKE_BUILD_TYPE:STRING="RelWithDebInfo" \ - -Dparaview_SOURCE_SELECTION="source" \ - -Dparaview_SOURCE_DIR="${WORKING_DIR}/src" \ - -DENABLE_ospray:BOOL=OFF \ - -DENABLE_ospraymaterials:BOOL=OFF \ - -DENABLE_tbb:BOOL=OFF \ - -DENABLE_paraviewsdk:BOOL=ON \ - -DENABLE_python3:BOOL=ON \ - -DENABLE_egl:BOOL=ON \ - -DUSE_SYSTEM_egl:BOOL=ON \ - -DENABLE_vtkm:BOOL=ON \ - -DENABLE_mpi:BOOL=ON \ - -DUSE_SYSTEM_mpi:BOOL=ON \ - -DUSE_SYSTEM_python3:BOOL=ON \ - ../superbuild -else - echo "ERROR: Illegal OS+Flavor combination" - exit 3 -fi - -# Workaround; without removing the following file, the paraview build won't -# be started, even if files have changed -rm superbuild/paraview/stamp/paraview-build || true - -# compile and install -command -v ninja-build && ninja-build || ninja - -# patch and bundle -if ! [ "$(uname)" = "Darwin" ]; then - cd install - # For some reason this path is hardcoded in this file, which causes CMake to - # panic. We just remove it. - sed -i "s|${PYENV_ROOT}|\$ENV{USER}/.pyenv|g" lib/cmake/paraview-5.9/vtk/VTK-targets.cmake || true - # Some dependencies could be put into lib64 (e.g. OpenImageDenoise), so we copy - # it into the lib directory (don't delete lib64, because some CMake files will - # be referring to that directory) - # rsync -a lib64/ lib/ || true -fi diff --git a/util/build-third-party/paraview/checkout-code.sh b/util/build-third-party/paraview/checkout-code.sh deleted file mode 100755 index 09456c2ea..000000000 --- a/util/build-third-party/paraview/checkout-code.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "${SCRIPT_DIR}/env.sh" - -set -e -x - -cd $SCRIPT_DIR - -## Clone paraview github repository -git clone https://gitlab.kitware.com/paraview/paraview-superbuild.git superbuild -cd superbuild -git fetch origin -git submodule update --init --recursive -git checkout $PV_SUPERBUILD_VERSION -git submodule update --init --recursive - -# Currently we only have an OpenMP patch for v5.9.0 and for all others we do not -# apply a patch. -if [ "${PV_SUPERBUILD_VERSION}" = "v5.9.0" ]; then - git apply "$SCRIPT_DIR/paraview-superbuild-openmp.${PV_SUPERBUILD_VERSION}.patch" -fi - -cd .. - -git clone $PV_GIT_REPO src -cd src -git fetch origin -git checkout $PV_VERSION -git submodule update --init --recursive diff --git a/util/build-third-party/paraview/env.sh b/util/build-third-party/paraview/env.sh deleted file mode 100755 index 461481e2b..000000000 --- a/util/build-third-party/paraview/env.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -# Parameters will be prepended here by util/build-third-party/build-paraview.sh - -# import util functions -. "$BDM_PROJECT_DIR/util/installation/common/util.sh" - -if [ "$(uname)" = "Darwin" ]; then - export PV_SUPERBUILD_VERSION="v5.10.0" - export PV_VERSION="v5.10.0" - export QT_VERSION="USE_BREW_qt@5" -else - export PV_SUPERBUILD_VERSION="v5.9.0" - export PV_VERSION="v5.9.0" - export QT_VERSION="v5.12.10" -fi -export PV_GIT_REPO="https://gitlab.kitware.com/paraview/paraview.git" - -export BDM_OS=$(DetectOs) -export QT_INSTALL_DIR="$WORKING_DIR/qt" - diff --git a/util/build-third-party/paraview/make_macos_pvsdk_relocatable.py b/util/build-third-party/paraview/make_macos_pvsdk_relocatable.py deleted file mode 100755 index 873365b29..000000000 --- a/util/build-third-party/paraview/make_macos_pvsdk_relocatable.py +++ /dev/null @@ -1,1347 +0,0 @@ -#!/usr/bin/env python3 -''' -Make macOS UNIX-like ParaView SDK bundles relocatable (using rpaths). - -Kludgy, but necessary at the moment. As of Dec. 2020, -ParaView-Superbuild (SB) can only generate macOS ``.app``-style -relocatable bundles. While the functionality to make Unix-like SDK bundles -exists in SB through the use of cmake macro calls to ``fixup_bundle.apple.py``, -seemingly large modifications are necessary for our use-case. Making these -changes is certainly the long-term solution, but this is best left to -the upstream developers. This script essentially avoids modifying SB -cmake files by replicating multiple macro calls to ``fixup_bundle.apple.py``. - -Large portions of this script are adapted from: -https://gitlab.kitware.com/paraview/common-superbuild/cmake/scripts/fixup_bundle.apple.py - -Unused bits of the script above are still kept in case we end up needing them. - -Example usage: -``` -python3 make_macos_pvsdk_relocatable.py \ - --source $HOME/bdm-build-third-party/paraview/build/install \ - --dest $HOME/bdm-build-third-party/paraview/paraview \ - --third-party $HOME/bdm-build-third-party/paraview qt \ - --pv 5.9 --py 3.9 -``` - -Prerequisites: - * Python 3.8+ - * The build output of 'util/build-third-party/build-paraview.sh'. - The directory structure should resemble a UNIX build, with the - exception of '/Applications/paraview.app'. - * Any non-system third-party libraries to link against this bundle should - be placed in ``--third-party``. This is to facilitate bundles distributed - in the manner below: - ``` - . (--third-party) - ├── paraview (--dest) - │ ├── bin - │ │ └── paraview - │ │ $ otool -l paraview - │ │ @rpath/some_qt_lib.dylib ... - │ │ @rpath/some_pv_lib.dylib ... - │ │ where @rpath="@loader_path/../lib;@loader_path/../../qt/lib" - │ ├── lib - │ └── ... - └── qt - ├── bin - ├── lib - └── ... - ``` -''' -import json -import os -import platform -import re -import shutil -import subprocess -import operator -from functools import reduce - -dry_run: bool = True -is_verbose: bool = False -install_source: str = None -install_dest: str = None -third_party_path: str = None -third_party_libs: list[str] = None - -python_v: str = '3.9' -paraview_v: str = '5.9' - - -def vprint(*args, **kwargs): - '''print if ``is_verbose`` global is true''' - if is_verbose: - print(*args, *kwargs) - - -def startswith_any(_str: str, _list: list[str]): - for prefix in _list: - if _str.startswith(prefix): - return True - return False - - -def os_makedirs(path): - ''' - A function to fix up the fact that os.makedirs - chokes if the path already exists. - ''' - if os.path.exists(path): - return - os.makedirs(path) - - -def copy_tree(src, dst, symlinks=False, ignore=None, copy_function=shutil.copy2, - ignore_dangling_symlinks=False, dirs_exist_ok=True, skip_symlinks=False): - ''' - Modified version of ``shutil.copytree`` for copying directory trees and symlinks - *without* overwriting or raising exceptions on existing files, dirs and symlinks - in ``dst``. You may skip all actions on symlinks using ``skip_symlinks=True``. - ''' - with os.scandir(src) as itr: - entries = list(itr) - return _copy_tree(entries=entries, src=src, dst=dst, symlinks=symlinks, - ignore=ignore, copy_function=copy_function, - ignore_dangling_symlinks=ignore_dangling_symlinks, - dirs_exist_ok=dirs_exist_ok, skip_symlinks=skip_symlinks) - - -def _copy_tree(entries, src, dst, symlinks, ignore, copy_function, - ignore_dangling_symlinks, dirs_exist_ok=False, skip_symlinks=False): - if ignore is not None: - ignored_names = ignore(os.fspath(src), [x.name for x in entries]) - else: - ignored_names = set() - - os.makedirs(dst, exist_ok=dirs_exist_ok) - errors = [] - use_srcentry = copy_function is shutil.copy2 or copy_function is shutil.copy - - for srcentry in entries: - if srcentry.name in ignored_names: - continue - srcname = os.path.join(src, srcentry.name) - dstname = os.path.join(dst, srcentry.name) - srcobj = srcentry if use_srcentry else srcname - try: - is_symlink = srcentry.is_symlink() - if is_symlink and os.name == 'nt': - # Special check for directory junctions, which appear as - # symlinks but we want to recurse. - lstat = srcentry.stat(follow_symlinks=False) - if lstat.st_reparse_tag == os.stat.IO_REPARSE_TAG_MOUNT_POINT: - is_symlink = False - if is_symlink: - linkto = os.readlink(srcname) - if skip_symlinks: - vprint(f" skip {linkto}") - else: - if symlinks: - # We can't just leave it to `copy_function` because legacy - # code with a custom `copy_function` may rely on copytree - # doing the right thing. - if not os.path.exists(dstname): - vprint(f" {linkto} -> {dstname}") - os.symlink(linkto, dstname) - shutil.copystat(srcobj, dstname, follow_symlinks=not symlinks) - else: - # ignore dangling symlink if the flag is on - if not os.path.exists(linkto) and ignore_dangling_symlinks: - continue - # otherwise let the copy occur. copy2 will raise an error - if srcentry.is_dir(): - vprint(srcname, dstname) - copy_tree(srcobj, dstname, symlinks, ignore, - copy_function, dirs_exist_ok=dirs_exist_ok) - else: - if not os.path.exists(dstname): - vprint(srcname, dstname) - copy_function(srcobj, dstname) - elif srcentry.is_dir(): - vprint(srcname, dstname) - copy_tree(srcobj, dstname, symlinks, ignore, copy_function, - dirs_exist_ok=dirs_exist_ok) - else: - vprint(srcname, dstname) - # Will raise a SpecialFileError for unsupported file types - if not os.path.exists(dstname): - copy_function(srcobj, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except shutil.Error as err: - errors.extend(err.args[0]) - except OSError as why: - errors.append((srcname, dstname, str(why))) - try: - shutil.copystat(src, dst) - except OSError as why: - # Copying file access times may fail on Windows - if getattr(why, 'winerror', None) is None: - errors.append((src, dst, str(why))) - if errors: - raise shutil.Error(errors) - return dst - - -class Pipeline(object): - ''' - A simple class to handle a list of shell commands - which need to pass input to each other. - ''' - - def __init__(self, *commands): - if not commands: - raise RuntimeError('Pipeline: at least one command must be given') - - self._commands = commands - - def __call__(self): - # Use /dev/null as the input for the first command. - last_input = open(os.devnull, 'r') - command = None - for command_args in self._commands: - command = subprocess.Popen( - command_args, stdin=last_input, stdout=subprocess.PIPE) - last_input.close() - last_input = command.stdout - - stdout, stderr = command.communicate() - if command.returncode: - raise RuntimeError('failed to execute pipeline:\n%s' % stderr) - return stdout.decode('utf-8') - - def call_non_dry(self, fatal=True): - try: - return self.__call__() if not dry_run else '' - except RuntimeError as e: - if fatal: - raise e - else: - vprint(f' {e}') - - -class Library(object): - ''' - A representation of a library. - - This class includes information that a runtime loader needs in order to - perform its job. It tries to implement the behavior of ``dyld(1)`` as - closely as possible. - - Known Issues - ------------ - - ``@rpath/`` and ``DYLD_LIBRARY_PATH`` - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - When a library contains a reference to a library like - ``@rpath/libname.dylib``, if ``DYLD_LIBRARY_PATH`` is set to contain a path - which has a ``libname.dylib``, ``dyld(1)`` will find it even if no - ``LC_RPATH`` commands are present. This behavior is not documented and it - only seems to work if a library is directly underneath a - ``DYLD_LIBRARY_PATH`` path. If the library reference is - ``@rpath/dir/libname.dylib``, even if a ``dir/libname.dylib`` exists in a - ``DYLD_LIBRARY_PATH`` path, it will still not be found. It is unknown - whether this behavior is expected or not due to the lack of documentation. - The logic in this script includes neither of these behaviors. - ''' - - def __init__(self, path, parent=None, search_paths=None, ignores=None): - # This is the actual path to a physical file - self._path = os.path.normpath(path) - - if search_paths is None: - self._search_paths = [] - else: - self._search_paths = search_paths - - if ignores is None: - self._ignores = [] - else: - self._ignores = ignores - - self._parent = parent - self._symlinks = None - self._framework_info = None - self._executable_path = None - self._dependencies = None - self._rpaths = None - self._raw_rpaths = None - self._raw_trans_rpaths = None - self._pending_rpaths: set[str] = set() - self._installed_id = None - - def __hash__(self): - return self._path.__hash__() - - def __eq__(self, other): - return self._path == other._path - - def __repr__(self): - return 'Library(%s : %s)' % (self._installed_id, self.path) - - @property - def path(self): - '''The absolute path to the library.''' - return self._path - - @property - def parent(self): - '''The binary which loaded the library.''' - return self._parent - - @property - def name(self): - '''The name of the library.''' - return os.path.basename(self.path) - - @property - def ignores(self): - '''Regular expressions of IDs to ignore from this library.''' - if self.parent is None: - return self._ignores - return self.parent.ignores - - @property - def installed_id(self): - ''' - The ID of the library. - - This is the string by which the library will be referenced by other - binaries in the installation. - ''' - return self._installed_id - - @property - def pending_rpaths(self): - return self._pending_rpaths - - def set_installed_id(self, installed_id): - '''Set the ID of the library as it is installed as.''' - self._installed_id = installed_id - - def extend_pending_rpaths(self, pending_rpaths: set[str]): - self._pending_rpaths = self._pending_rpaths.union(pending_rpaths) - - @property - def dependent_reference(self): - ''' - The prefix to use for a library loaded by the library. - - This is used as the prefix for IDs for libraries loaded by the library. - It is based on the initial binary which loaded the library. For - example, executables use ``@executable_path`` and plugins use - ``@loader_path``. In a chain of loaded libraries, the loader (parent) - of a library determines the prefix. - ''' - # Refer to libraries the same way that the library which is loading it - # references it. - if self.parent is None: - raise RuntimeError('Unable to get a reference') - return self.parent.dependent_reference - - @property - def symlinks(self): - ''' - A list of symlinks to the library. - - Symlinks are looked for only beside the library and the names of these - files are returned, not their full paths. - ''' - if self._symlinks is None: - realpath = os.path.realpath(self.path) - dirname = os.path.dirname(realpath) - symlinks = set(Pipeline([ - 'find', '-L', dirname, - '-depth', '1', - '-samefile', realpath, - ])().split()) - - symlink_bases = [] - for symlink in symlinks: - symlink_dir, symlink_base = os.path.split(symlink) - if not symlink_dir == dirname: - continue - symlink_bases.append(symlink_base) - if self.name in symlink_bases: - symlink_bases.remove(self.name) - self._symlinks = symlink_bases - - return self._symlinks - - @property - def executable_path(self): - '''The path to the loading executable (if available).''' - if self._parent is not None: - return self._parent.executable_path - return self._executable_path - - @property - def loader_path(self): - '''The path to use for ``@loader_path`` references from the library.''' - return os.path.dirname(self.path) - - @property - def loader_paths(self): - ''' - A list of paths to look for libraries due to where the loading - libraries look. - ''' - loader_paths = [self.loader_path] - if self.parent is not None: - loader_paths.extend(self.parent.loader_paths) - return loader_paths - - @property - def is_framework(self): - '''Whether the library is a framework or not.''' - return self.path.count('.framework') - - @property - def framework_info(self): - ''' - Information for frameworks. - - The return value is a tuple of path (where the framework is located), - name (the ``NAME.framework`` part of its path), and associated library - (the path under the ``.framework`` directory which contains the actual - library binary). - - See the ``framework_path``, ``framework_name``, and - ``framework_library`` properties. - ''' - if self._framework_info is None: - if not self.is_framework: - self._framework_info = (None, None, None) - else: - name = None - library = [] - - path = self.path - while path: - path, component = os.path.split(path) - if component.endswith('.framework'): - name = component - break - library.append(component) - - if name is None: - raise RuntimeError('%s is not a framework?' % self.path) - - self._framework_info = ( - os.path.join(path), - name, - os.path.join(*reversed(library)), - ) - return self._framework_info - - @property - def framework_path(self): - ''' - The path which contains the ``.framework`` for the library. - - ``None`` if the library is not a framework. - ''' - return self.framework_info[0] - - @property - def framework_name(self): - ''' - The name of the framework containing the library. - - ``None`` if the library is not a framework. - ''' - return self.framework_info[1] - - @property - def framework_library(self): - ''' - The path to the library under the ``.framework`` directory. - - ``None`` if the library is not a framework. - ''' - return self.framework_info[2] - - @property - def raw_rpaths(self) -> set[str]: - '''Unresolved ``LC_RPATH`` load commands of ``self``.''' - if self._raw_rpaths is None: - get_rpaths = Pipeline([ - 'otool', - '-l', - self.path, - ], [ - 'awk', - ''' - $1 == "cmd" { - cmd = $2 - } - - $1 == "path" { - if (cmd == "LC_RPATH") { - print $2 - } - } - ''', - ]) - self._raw_rpaths = set(get_rpaths().split('\n')) - self._raw_rpaths.discard('') - - return self._raw_rpaths - - @property - def raw_trans_rpaths(self) -> set[str]: - ''' - Unresolved ``LC_RPATH`` load commands of ``self`` *and parents*. - - In addition to the ``LC_RPATH`` load commands contained within the - library, rpaths in the binaries which loaded the library are - referenced. These are included in the property. - ''' - if self._raw_trans_rpaths is None: - self._raw_trans_rpaths = self.raw_rpaths \ - if self._parent is None \ - else self._parent.raw_rpaths.union(self.raw_rpaths) - self._raw_trans_rpaths.discard('') - return self._raw_trans_rpaths - - @property - def rpaths(self): - ''' - The list of rpaths used when resolving ``@rpath/`` references in the - library. - - In addition to the ``LC_RPATH`` load commands contained within the - library, rpaths in the binaries which loaded the library are - referenced. These are included in the property. - ''' - if self._rpaths is None: - # rpaths may contain magic ``@`` references. This property only - # contains full paths, so we resolve them now. - resolved_rpaths = [] - for rpath in self.raw_trans_rpaths: - if rpath.startswith('@executable_path'): - # If the loader does not have an executable path, it is a plugin or - # a framework and we trust the executable which loads the plugin to - # provide the library instead. - if self.executable_path is None: - continue - resolved_rpaths.append(rpath.replace( - '@executable_path', self.executable_path)) - elif rpath.startswith('@loader_path'): - resolved_rpaths.append(rpath.replace( - '@loader_path', self.loader_path)) - elif rpath: - resolved_rpaths.append(rpath) - - self._rpaths = resolved_rpaths - return self._rpaths - - def _get_dependencies(self): - '''Get the dependent library IDs of the library.''' - pipe = Pipeline([ - 'otool', - '-L', - self.path, - ], [ - 'sed', - '-n', - '-e', '/compatibility version/s/ (compatibility.*)//p', - ]) - return pipe().split() - - @property - def dependencies(self): - '''Dependent libraries of the library.''' - if self._dependencies is None: - collection = {} - for dep in self._get_dependencies(): - deplib = Library.from_reference(dep, self) - if deplib is not None \ - and not deplib.path == self.path: - collection[dep] = deplib - self._dependencies = collection - return self._dependencies - - def _find_library(self, ref): - ''' - Find a library using search paths. - - Use of this method to find a dependent library indicates that the - library dependencies are not properly specified. As such, it warns - when it is used. - ''' - print('WARNING: dependency from %s to %s requires a search path' % - (self.path, ref)) - for loc in self._search_paths: - path = os.path.join(loc, ref) - if os.path.exists(path): - return path - return ref - - @classmethod - def from_reference(cls, ref, loader): - '''Create a library representation given an ID and a loading binary.''' - paths = [ref] - if ref.startswith('@executable_path/'): - # If the loader does not have an executable path, it is a plugin or - # a framework and we trust the executable which loads the plugin to - # provide this library instead. - if loader.executable_path is None: - return None - paths.append(ref.replace('@executable_path', loader.executable_path)) - elif ref.startswith('@loader_path/'): - paths.append(ref.replace('@loader_path', loader.loader_path)) - elif ref.startswith('@rpath/'): - for rpath in loader.rpaths: - paths.append(ref.replace('@rpath', rpath)) - paths.append(os.path.join(os.path.dirname(loader.path), ref)) - for path in paths: - if os.path.exists(path): - return cls.from_path(os.path.realpath(path), parent=loader) - if loader.ignores: - for ignore in loader.ignores: - if ignore.match(ref): - return None - if ref.startswith('/System/Library/Frameworks/') or \ - ref.startswith('/usr/lib/'): - # These files do not exist on-disk as of macOS 11. This is Apple - # magic and assumed to be a system library. - return None - search_path = loader._find_library(ref) - if os.path.exists(search_path): - return cls.from_path(os.path.realpath(search_path), parent=loader) - raise RuntimeError( - 'Unable to find the %s library from %s' % (ref, loader.path)) - - __cache = {} - - @classmethod - def from_path(cls, path, parent=None, _search_paths=None): - '''Create a library representation from a path.''' - if not os.path.exists(path): - raise RuntimeError('%s does not exist' % path) - - path = os.path.normpath(path) - if path not in cls.__cache: - search_paths = _search_paths - if search_paths is None and parent is not None: - search_paths = parent._search_paths - - cls.__cache[path] = Library(path, parent=parent, - search_paths=search_paths) - - return cls.__cache[path] - - @classmethod - def from_manifest(cls, path, installed_id): - '''Create a library representation from a cached manifest entry.''' - if path in cls.__cache: - raise RuntimeError('There is already a library for %s' % path) - - library = Library(path) - library.set_installed_id(installed_id) - library._dependencies = {} - library._symlinks = [] - library._is_cached = True - - cls.__cache[path] = library - return cls.__cache[path] - - -class Plugin(Library): - ''' - A plugin library. - - These libraries are expected to be loaded by an executable and use - ``@executable_path/`` references where possible, but for any libraries - required by the plugin and not otherwise provided, ``@loader_path/`` is - used instead. - - Some plugins may require to be considered as their own ``@executable_path`` - reference. This may indicate errors in the building of the plugin. - ''' - - def __init__(self, path, fake_exe_path=False, **kwargs): - super(Plugin, self).__init__(path, None, **kwargs) - - if fake_exe_path: - self._executable_path = os.path.dirname(path) - - # @property - # def bundle_location(self): - # return 'Contents/Plugins' - - @property - def dependent_reference(self): - return '@loader_path/..' - - -class Module(Library): - ''' - A library loaded programmatically at runtime. - - Modules are usually used by interpreted languages (as opposed to compiled - languages) and loaded at runtime. They may live at any depth in the installation. - - Currently it is assumed that the only executables which will load these - modules is a binary in the same installation. It is unknown if this - assumption is actually valid and documentation is scarce. - - Some modules may require to be considered as their own ``@executable_path`` - reference. This may indicate errors in the building of the module. - ''' - - def __init__(self, path, fake_exe_path=False, **kwargs): - super(Module, self).__init__(path, None, **kwargs) - - self._bundle_location = os.path.normpath( - os.path.dirname(os.path.relpath(path, install_source))) - if fake_exe_path: - self._executable_path = path - for _ in range(self.bundle_location.count('/')): - self._executable_path = os.path.dirname(self._executable_path) - - parent_parts = ['..'] * self.bundle_location.count('/') - self._dependent_reference = os.path.join('@loader_path', *parent_parts) - - @property - def bundle_location(self): - return self._bundle_location - - @property - def dependent_reference(self): - return '@executable_path/..' - # XXX(modules): is this right? should modules ever not be loaded by - # their owning application? - # return self._dependent_reference - - -def copy_library(root_dest: str, library: Library, sub_dest: str='lib'): - '''Copy a library into the ``.app`` bundle.''' - if library.is_framework: - # Frameworks go into Contents/. - - app_dest = os.path.join(root_dest, sub_dest) - binary = os.path.join( - app_dest, library.framework_name, library.framework_library) - - print(' %s/%s -> %s' % (library.framework_path, library.framework_name, - os.path.join(sub_dest, library.framework_name, - library.framework_library))) - - library.set_installed_id(os.path.join( - '@executable_path', '..', sub_dest, - library.framework_name, library.framework_library)) - root_dest = os.path.join(app_dest, library.framework_name) - - if not dry_run: - # TODO: This could be optimized to only copy the particular version. - if os.path.exists(root_dest): - shutil.rmtree(root_dest) - os_makedirs(app_dest) - shutil.copytree(os.path.join(library.framework_path, - library.framework_name), root_dest, symlinks=True) - - # We need to make sure the copied libraries are writable. - chmod = Pipeline([ - 'chmod', - '-R', - 'u+w', - root_dest, - ]) - chmod() - else: - app_dest = os.path.join(root_dest, sub_dest) - binary = os.path.join(app_dest, library.name) - print(' %s -> %s' % - (library.path, os.path.join(sub_dest, library.name))) - - # FIXME(plugins, frameworks): fix the installed id of the library based - # on what drags it in. - library.set_installed_id(os.path.join('@rpath', library.name)) - root_dest = app_dest - - if not dry_run: - os_makedirs(app_dest) - shutil.copy2(library.path, root_dest) - - # We need to make the library after copying it. - chmod = Pipeline([ - 'chmod', - 'u+w', - os.path.join(root_dest, os.path.basename(library.path)), - ]) - chmod() - - # Create any symlinks we found for the library as well. - for symlink in library.symlinks: - print(' %s/%s -> %s' % - (sub_dest, library.name, os.path.join(sub_dest, symlink))) - if not dry_run: - symlink_path = os.path.join(app_dest, symlink) - if os.path.exists(symlink_path): - vprint('exists, removing %s ' % symlink_path) - os.remove(symlink_path) - ln = Pipeline([ - 'ln', - '-s', - library.name, - symlink_path, - ]) - ln() - - return binary - - -def _arg_parser(): - import argparse - - # https://stackoverflow.com/questions/4194948/python-argparse-is-there-a-way-to-specify-a-range-in-nargs - def required_length(nmin, nmax=999): - class RequiredLength(argparse.Action): - def __call__(self, parser, args, values, option_string=None): - if not nmin <= len(values) <= nmax: - msg = 'argument "{f}" requires between {nmin} and {nmax} arguments'.format( - f=self.dest, nmin=nmin, nmax=nmax) - raise argparse.ArgumentTypeError(msg) - setattr(args, self.dest, values) - - return RequiredLength - - parser = argparse.ArgumentParser( - description='Make macOS UNIX-like ParaView SDK bundles relocatable') - parser.add_argument('-S', '--source', metavar='SOURCE', required=True, - help='location of the PV SDK superbuild install'), - parser.add_argument('-O', '--dest', metavar='DEST', required=True, - help='destination of the relocatable PV SDK'), - parser.add_argument('-T', '--third-party', metavar='PATH', nargs='+', - action=required_length(2), required=True, - help='Third-party libs that will be loaded relative to --dest.' - 'Syntax: { }'), - parser.add_argument('-n', '--dry-run', action='store_true', - help='do not actually modify filesystem', default=False) - parser.add_argument('-v', '--verbose', action='store_true', - help='enable verbose output', default=False) - parser.add_argument('--py', metavar="MAJOR.MINOR", - help='Python 3 version', default='3.8') - parser.add_argument('--pv', metavar="MAJOR.MINOR", - help='ParaView version', default='5.9') - - return parser - - -def update_manifest(manifest, installed): - '''Update the manifest file with a set of newly installed binaries.''' - for input_path, binary_info in installed.items(): - binary, _ = binary_info - manifest[input_path] = binary.installed_id - - -def path_in_dest(path: str): - subdir = os.path.relpath(path, install_source) - return os.path.join(install_dest, subdir) - - -def pend_rpaths_from_deps(binary: Library, is_excluded, rpath_suffixes): - ''' - Build rpath entries of the form ``@loader_path ['/' ]`` - using rpath_suffixes. Mark them to be added by fix_installed_binaries. - ''' - deps: list[Library] = list(binary.dependencies.values()) - loader_to_dep_relpaths: set[str] = set() - - for dep in deps: - if is_excluded(dep.path): - continue - dep_relpath = '' - - if dep.path.startswith(install_source): - dep_relpath = \ - os.path.relpath(dep.path, binary.loader_path) - elif startswith_any(dep.path, third_party_libs): - # 3rd party deps need to be viewed relative - # to the current binaries final destination - dep_relpath = \ - os.path.relpath(dep.path, path_in_dest(binary.loader_path)) - - loader_to_dep_relpaths.add(os.path.split(dep_relpath)[0]) - - vprint(f' {loader_to_dep_relpaths}') - if len(loader_to_dep_relpaths) > 0: - pend_rpaths = set() - # dependency in one of the suffixes - for dep_relp in loader_to_dep_relpaths: - for suffix in rpath_suffixes: - if dep_relp == suffix or dep_relp.startswith(suffix): - to_add = os.path.join('@loader_path', suffix) - # make all suffixes end with trailing slash - to_add = to_add if to_add.endswith('/') else f'{to_add}/' - pend_rpaths.add(to_add) - break - # dependency in @loader_path - if '' in loader_to_dep_relpaths: - pend_rpaths.add('@loader_path') - - vprint(f" {binary.path}\n\t<-{pend_rpaths}") - binary.extend_pending_rpaths(pend_rpaths) - - -def install_binary(binary: Library, is_excluded, bundle_dest, - installed, manifest, rpath_suffixes, sub_dest='lib'): - '''Install the main binary into the package.''' - print(f" {os.path.basename(binary.path)}") - pend_rpaths_from_deps(binary, is_excluded, rpath_suffixes) - # Start looking at our main executable's dependencies. - deps = list(binary.dependencies.values()) - while deps: - dep = deps.pop(0) - - # Ignore dependencies which the bundle already provides. - if dep.path in manifest: - continue - - # Ignore dependencies we don't care about. - if is_excluded(dep.path): - vprint(f" {dep.path}") - continue - - # If we've already installed this dependency - # for some other library, skip it. - if dep.path in installed: - continue - - # Add this dependency's dependencies to the pile. - deps.extend(dep.dependencies.values()) - if dep.path.startswith(install_source): - dep_sub_dest = os.path.normpath( - os.path.dirname(os.path.relpath(dep.path, install_source))) - vprint(f" {dep.path}") - pend_rpaths_from_deps(dep, is_excluded, rpath_suffixes) - # Remember what we installed and where. - installed[dep.path] = \ - (dep, copy_library(bundle_dest, dep, sub_dest=dep_sub_dest)) - elif startswith_any(dep.path, third_party_libs): - vprint(f" {dep.path}") - installed[dep.path] = \ - (dep, os.path.relpath(dep.path, install_source)) - else: - # This call resulted in an error on arm64 and ParaView-5.10 and was - # therefore turned into an exception. - try: - vprint(f" {dep.paths}") - except Exception as ex: - print(ex) - vprint(f"'Library' object has no attribute 'paths'") - - - # Install the main executable itself. - app_dest = os.path.join(bundle_dest, sub_dest) - binary_destination = os.path.join(app_dest, os.path.basename(binary.path)) - installed[binary.path] = (binary, binary_destination) - binary.set_installed_id(os.path.join(sub_dest, binary.name)) - - print(' %s -> %s' % (binary.path, sub_dest)) - if not dry_run: - os_makedirs(app_dest) - shutil.copy2(binary.path, app_dest) - - -_fin_rpaths: dict[str, list[str]] = dict() - - -def fix_installed_binaries(installed: dict[str, (Library, str)]): - ''' - This function updates all of the installed binaries to use consistent - library IDs when referring to each other. - ''' - # Go through all of the binaries installed and fix up references to other things. - for binary_info in installed.values(): - binary, installed_path = binary_info - print(f' {binary.path}') - if binary.path.endswith('.a'): - # nothing to fix - continue - - vprint(f'\t\n\t\t{binary.pending_rpaths.difference(binary.raw_rpaths)}') - - if binary.installed_id: - # Set the ID on the binary. - vprint( - f" {binary.installed_id}") - Pipeline([ - 'install_name_tool', - '-id', binary.installed_id, - installed_path, - ]).call_non_dry() - - changes = [] - for old_name, library in binary.dependencies.items(): - if library.installed_id is not None \ - and not old_name == library.installed_id: - if startswith_any(old_name, ['@loader_path', '@rpath']): - pass - else: - changes.extend(['-change', old_name, library.installed_id]) - - # Fix up the library names. - if changes: - install_name_tool = \ - ['install_name_tool'] + changes + [installed_path] - vprint(' '.join(install_name_tool)) - Pipeline(install_name_tool).call_non_dry() - - # Add pending rpaths to binary. - if not installed_path in _fin_rpaths: - rp_diff = binary.pending_rpaths.difference(binary.raw_rpaths) - rp_isect = binary.pending_rpaths.intersection(binary.raw_rpaths) - _fin_rpaths[installed_path] = list(rp_diff.union(rp_isect)) - rpaths_to_add = [] - for pending in rp_diff: - rpaths_to_add.extend(['-add_rpath', pending]) - if rpaths_to_add: - install_name_tool = \ - ['install_name_tool'] + rpaths_to_add + [installed_path] - vprint(' '.join(install_name_tool)) - Pipeline(install_name_tool).call_non_dry() - - -def _is_excluded(path): - # System libraries - ## Apple - if path.startswith('/System/Library'): - return True - if path.startswith('/usr/lib'): - return True - - ## Homebrew - if path.startswith('/usr/local/lib'): - return True - if path.startswith('/usr/local/Cellar'): - return True - if path.startswith('/opt/homebrew'): - return True - - ## Macports - if path.startswith('/opt/local/lib'): - return True - - return False - - -def is_binary(fpath): - finfo = Pipeline(['file', '-Ib', fpath])().splitlines()[0] - return re.match(r"application/(x-mach-binary|x-archive).*", finfo) is not None - - -def find_bins_in(path): - pred='( -type f ) -and ( -perm +111 -or -name *.dylib -or -name *.so -or -name *.a )' - bin_candidates = Pipeline(f'find {path} {pred}'.split())().split() - return [cand for cand in bin_candidates if is_binary(cand)] - - -_manifest = {} -_installed = {} - - -class BinaryGroup(object): - def __init__(self, - path_or_bins, - rpath_suffixes, - search_paths=None, - preproc_fn=lambda x: x, - exclude_fn=_is_excluded, - typ='lib', - rpath_map=None, - installed_map=None, - bin_manifest=None): - ''' - A ``BinaryGroup`` contains a collection of binaries along - with instructions for how to copy over and install them - from ``--source`` to ``--dest``. - - Args: - path_or_bins (Union[str, list[str]]): - Path containing binaries (will be recursively searched by - ``find``) or a list of paths to each binary in this group. - NB: All paths passed in must be relative to ``--source``. - rpath_suffixes (list[str]): - List of suffixes to match against each binaries' relative paths - to its dependencies . Matches will be used to build rpath entries - of the form ``@loader_path ['/' ]``. - search_paths (Optional[list[str]]): - List of paths (default ``install_source/{bin,lib}``) - to search for dependent libraries. - preproc_fn (Callable[[str], Any]): - Callback called just before the creation of the path's corresponding - ``Library`` (sub)class. This callback will be applied to the binary - in ``--dest``, so make sure its side-effect is idempotent, or that - it at least doesn't break anything. - exclude_fn (Callable[[str], bool]): - Callback to determine which binary files to exclude. - typ (str): - One of {'lib', 'module', 'plugin'} (default 'lib'). Determines - which subclass of ``Library`` the binaries in this group will be. - The behavior of ``self.install()`` depends on this type. - rpath_map (Optional[dict[str, str]]): - For each binary 'b' in this group, and each key-value pair - 'k', 'v' in `rpath_map`; if 'k' matches an rpath entry in 'b', - replace it with 'v', or if 'v' is None, then delete the entry. - - Returns: - ``BinaryGroup`` ready to be ``self.install()``ed. - ''' - _default_searchpaths = \ - [os.path.join(install_source, _dir) for _dir in ['bin', 'lib']] - - self.installed_map = \ - _installed if installed_map is None else installed_map - self.bin_manifest = \ - _manifest if bin_manifest is None else bin_manifest - self.rpath_suffixes = rpath_suffixes - vprint(path_or_bins) - if isinstance(path_or_bins, str): - self.bin_relpaths = find_bins_in(path_or_bins) - elif isinstance(path_or_bins, list): - self.bin_relpaths = \ - [cand for cand in path_or_bins if is_binary(cand)] - else: - raise RuntimeError('path_or_bins is either list[str] or str') - - self.exclude_fn = exclude_fn - self.bin_preproc_fn = preproc_fn - self._is_installed = False - self.typ = typ - self.rpath_map = {} if rpath_map is None else rpath_map - self.search_paths = \ - _default_searchpaths if search_paths is None else search_paths - - def install(self): - if self._is_installed: - vprint("WARNING: This group is already installed!") - return - - (bin_relpaths, search_paths, typ) = \ - (self.bin_relpaths, self.search_paths, self.typ) - - for bin_relpath in bin_relpaths: - bin_path = os.path.abspath(bin_relpath) - - try: - self.bin_preproc_fn(bin_path) - except RuntimeError: - pass - - _bin: Library = None - if typ == 'plugin': - _bin = Plugin.from_path(bin_path, - _search_paths=search_paths) - elif typ == 'module': - _bin = Module.from_path(bin_path, - _search_paths=search_paths) - else: - _bin = Library.from_path(bin_path, - _search_paths=search_paths) - - _sub_dest = os.path.normpath(os.path.dirname(bin_relpath)) - install_binary(_bin, self.exclude_fn, install_dest, - self.installed_map, self.bin_manifest, - self.rpath_suffixes, sub_dest=_sub_dest) - - # Remap rpaths from any maching keys in rpath_map to - # their values, if the value is not None, delete otherwise. - bin_abs_dest = os.path.join( - os.path.join(install_dest, _sub_dest), - os.path.basename(_bin.path)) - for key, value in self.rpath_map.items(): - if key in _bin.raw_trans_rpaths: - if value is not None: - vprint(f" {key} -> {value}") - Pipeline([ - 'install_name_tool', - '-rpath', key, value, bin_abs_dest - ]).call_non_dry(fatal=False) - else: - vprint(f" {key}") - Pipeline([ - 'install_name_tool', - '-delete_rpath', key, bin_abs_dest - ]).call_non_dry(fatal=False) - - if typ == 'module': - _bin.set_installed_id(os.path.join('@rpath', _bin.name)) - - update_manifest(_manifest, _installed) - self._is_installed = True - - -def main(args): - # Check if we are running on an ARM-based Apple device - system_info = platform.uname() - is_arm_based = (system_info.system == "Darwin" and - system_info.machine == "arm64") - if is_arm_based: - print("Detected M1 machine, support experimental ..") - - # Parse and initialize arguments. - parser = _arg_parser() - opts = parser.parse_args(args) - - global dry_run, is_verbose, install_source, install_dest, \ - third_party_path, third_party_libs, paraview_v, python_v - - install_source, install_dest = (opts.source, opts.dest) - third_party_path = opts.third_party[0] - third_party_libs = \ - [os.path.join(third_party_path, ldir) for ldir in set(opts.third_party[1:])] - dry_run, is_verbose = (opts.dry_run, opts.verbose) - paraview_v, python_v = (opts.pv, opts.py) - - # Shell commands will be run relative to install_source. - os.chdir(install_source) - - # Copy paraview binary from dummy .app to bin. - os_makedirs(os.path.dirname(f'{install_dest}/bin')) - shutil.copy2(f'{install_source}/Applications/paraview.app/Contents/MacOS/paraview', f'{install_dest}/bin') - - # The order is important. Match longest first. - # Some paths may have higher precedence than others. - # E.g., ../qt/lib < ../root/lib - rp_suffixes = [ - '../../../../../qt/lib', - '../../../..', - '../../qt/lib', - '../../..', - '../lib' - ] - # Add variants with unnecessary trailing slash. - rp_suffixes = \ - reduce(operator.concat, [[s+'/', s] for s in rp_suffixes]) - - # Remove the old bundle. - if os.path.exists(install_dest): - vprint(f"rm -rf {install_dest}") - if not dry_run: - shutil.rmtree(install_dest, ignore_errors=True) - - def _preprocess_uni_bin(bin_path): - # libs in lib/universal require special treatment - # where their @loader_path is added as an rpath - # entry *before* creating their Library objects - Pipeline([ - 'install_name_tool', - '-add_rpath', '@loader_path', - bin_path, - ]).call_non_dry() - - # Qt is always a dependency. Make sure it's in --third-party. - qt_lib_dir = os.path.join(third_party_path, 'qt', 'lib') - - # For 5.9, Qt5 is not installed via brew, thus, the explicit check. - if paraview_v == '5.9': - if not os.path.isdir(qt_lib_dir): - raise RuntimeError(f"./qt/lib directory does not exist in {third_party_path}") - - # Mark undesirable for deletion with None. - rpath_map = { qt_lib_dir: None, '@executable_path/': None, '@executable_path/../lib': None } - - print("==> Install binary groups") - bin_groups = \ - [ - BinaryGroup("./bin", rp_suffixes, rpath_map=rpath_map), - BinaryGroup(f"./lib/python{python_v}", rp_suffixes, rpath_map=rpath_map), - BinaryGroup(f"./lib/paraview-{paraview_v}", rp_suffixes, rpath_map=rpath_map), - ] - # The following BinaryGroup was not found on the tested M1 machine and - # caused problems. We therefore remove it if we're not building the outdated - # ParaView 5.9 - if not is_arm_based: - bin_groups.append(BinaryGroup("./lib/universal", - rp_suffixes, - preproc_fn=_preprocess_uni_bin, - rpath_map=rpath_map)) - - for bin_group in bin_groups: - bin_group.install() - - print("==> Installing remaining (likely runtime loaded) binaries as modules") - rem_set = set(find_bins_in('./lib')).difference(_installed.keys()) - - remaining = BinaryGroup(list(rem_set), rp_suffixes, typ='module', rpath_map=rpath_map) - remaining.install() - - print("==> Fixing installed binary groups") - fix_installed_binaries(_installed) - - print("==> Dump manifest.json to --source") - # Dump manifest to --source, like a sort of receipt. - with open('manifest.json', 'w') as fout: - json.dump(_manifest, fout) - - print("==> Dump final_rpaths.json to --source") - # For manually checking if any crazy rpaths are generated. - with open('final_rpaths.json', 'w') as fout: - json.dump(_fin_rpaths, fout) - - # Copy dummy .app too, just to keep 'clever' cmake files happy. - print("==> Copying remaining files in --source to --dest") - if not dry_run: - for _path in ['Applications', 'bin', 'include', 'lib', 'materials', 'share']: - # First copy over tree without symlinks, then just the - # symlinks to make sure everything is copied correctly. - for symlinks, skip_symlinks in [(False, True), (True, False)]: - copy_tree(os.path.join(install_source, _path), - os.path.join(install_dest, _path), - symlinks=symlinks, - skip_symlinks=skip_symlinks, - dirs_exist_ok=True) - - # Clean references to source install path in misc. files. - # This is all manual, I'm afraid. When upgrading, whoever - # maintains this script is advised to run a search for - # references to --source in a dummy install (e.g., with ripgrep), - # then write some clever find&replace commands to remove them. - if not dry_run: - os.chdir(install_dest) - - print("==> Cleaning references to --source in --dest") - - print(" include/ospray/SDK/**/*_ispc.h") - os.system("find ./include/ospray/SDK -name '*_ispc.h' -exec sed -i '' 2d {} \\;") - - print(f" include/paraview-{paraview_v}/vtkCPConfig.h") - os.system("sed -i '' " - "'s|#define PARAVIEW_BINARY_DIR.*|#define PARAVIEW_BINARY_DIR \"./bin\"|g; " - "s|#define PARAVIEW_INSTALL_DIR.*|#define PARAVIEW_INSTALL_DIR \"./\"|g;' " - f'include/paraview-{paraview_v}/vtkCPConfig.h' - ) - - print(" lib/cmake/**/*.cmake") - os.system(f"find {install_dest}/lib/cmake -name '*.cmake' -exec sed -E -i '' " - f'\'s|([[:space:]]*)(IMPORTED_SONAME_RELEASE)([[:space:]]*)"{install_source}/(.*)"|\\1\\2\\3"\\4"|g\'' - ' {} +' - ) - - print(" lib/pkgconfig/nlohmann_json.pc") - os.system(f"sed -i '' 's|Cflags:.*|Cflags: |g;' lib/pkgconfig/nlohmann_json.pc") - - print('==> Looking for broken or circular symlinks') - if not dry_run: - broken_links = \ - Pipeline((f'find {install_dest} -type l -exec test ! -e' + ' {} ; -print').split())().split() - if len(broken_links) > 0: - print('WARNING: Found broken or circular links:') - for link in broken_links: - print(link) - else: - print('==> None found') - - print('==> Done.') - - -if __name__ == '__main__': - import sys - - main(sys.argv[1:]) diff --git a/util/build-third-party/paraview/package.sh b/util/build-third-party/paraview/package.sh deleted file mode 100755 index f4dee3cf4..000000000 --- a/util/build-third-party/paraview/package.sh +++ /dev/null @@ -1,73 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "${SCRIPT_DIR}/env.sh" - -set -e -x - -if [ "$(uname)" = "Darwin" ]; then - # copy paraview binary from .app bundle to bin - __BDM_INSTALL_SOURCE=$SCRIPT_DIR/build/install - cp -f $__BDM_INSTALL_SOURCE/Applications/paraview.app/Contents/MacOS/paraview $__BDM_INSTALL_SOURCE/bin - # create install destination dir - mkdir $SCRIPT_DIR/paraview - # run the fix - python3 $SCRIPT_DIR/make_macos_pvsdk_relocatable.py \ - --source $__BDM_INSTALL_SOURCE \ - --dest $SCRIPT_DIR/paraview \ - --third-party $SCRIPT_DIR qt \ - --pv 5.10 --py 3.9 - cd $SCRIPT_DIR/paraview - # Replace dummy .app binary with slightly more functional version from bin. - # It still won't work, it just won't contain any refereces to the source dir. - rm Applications/paraview.app/Contents/MacOS/paraview - cp bin/paraview Applications/paraview.app/Contents/MacOS - # Get rid of old paraview.conf in the dummy .app - rm Applications/paraview.app/Contents/Resources/paraview.conf - - MACOS_VERS=$(sw_vers | sed -n 's/ProductVersion://p' | cut -d . -f 1-2 | sed -e 's/^[[:space:]]*//') - MACOS_ARCH=$(arch) - BDM_OS_VERS=${BDM_OS}-${MACOS_VERS}-${MACOS_ARCH} - PV_TAR=paraview_${PV_VERSION}_${BDM_OS_VERS}_${PV_FLAVOR}.tar.gz - -else - cd "$SCRIPT_DIR/build/install" - - BDM_OS_VERS=${BDM_OS} - PV_TAR=paraview_${PV_VERSION}_${BDM_OS_VERS}_${PV_FLAVOR}.tar.gz -fi - -# If we run on macOS, we have to remove `ospray::ospray` from the file -# VTK-targets.cmake -if [ "$(uname)" = "Darwin" ]; then - sed -i "" "s/;ospray::ospray//g" $(find $(pwd) -name "*VTK-targets.cmake") -fi - -## tar the install directory -RESULT_FILE=paraview-$PV_VERSION-$BDM_OS-$PV_FLAVOR.tar.gz -tar -zcf $PV_TAR * -shasum -a256 ${PV_TAR} >${PV_TAR}.sha256 - -# After untarring the directory tree should like like this: -# paraview -# |-- bin -# |-- include -# |-- lib -# |-- share - -# Step 5: cp to destination directory -cp ${PV_TAR} $BDM_PROJECT_DIR/build -cp ${PV_TAR}.sha256 $BDM_PROJECT_DIR/build diff --git a/util/build-third-party/paraview/paraview-superbuild-openmp.v5.9.0.patch b/util/build-third-party/paraview/paraview-superbuild-openmp.v5.9.0.patch deleted file mode 100644 index 7bcc183f4..000000000 --- a/util/build-third-party/paraview/paraview-superbuild-openmp.v5.9.0.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/projects/paraview.cmake 2020-11-10 23:48:48.000000000 +0100 -+++ b/projects/paraview.cmake 2020-11-10 23:48:55.000000000 +0100 -@@ -22,7 +22,7 @@ - - set(paraview_all_plugins) - --set(paraview_smp_backend "Sequential") -+set(paraview_smp_backend "OpenMP") - if (tbb_enabled) - set(paraview_smp_backend "TBB") - endif () -@@ -30,6 +30,7 @@ - set(paraview_enable_cuda "OFF") - if(vtkm_enabled AND cuda_enabled) - set(paraview_enable_cuda "ON") -+ message("ENABLE CUDA ---------------------------------------------------------------") - endif() - - set(PARAVIEW_EXTERNAL_PROJECTS "" diff --git a/util/build-third-party/paraview/prerequisites.sh b/util/build-third-party/paraview/prerequisites.sh deleted file mode 100755 index cde77981b..000000000 --- a/util/build-third-party/paraview/prerequisites.sh +++ /dev/null @@ -1,127 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -# Installs the required packages to build the third_party dependencies - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -. "${SCRIPT_DIR}/env.sh" - -set -e -x - -cd "$WORKING_DIR" - -if [ -z "$SKIP_PACKAGE_MAN" ]; then - if [ $(uname) = "Linux" ]; then - if [ $BDM_OS = "centos-7" ]; then - sudo yum update -y || true - - # paraview - ## issues with mpich and valgrind: - ## https://github.com/flow123d/flow123d/issues/806 - sudo yum install -y openmpi3-devel || true - sudo yum install -y libXt-devel freeglut3-devel - - sudo yum install -y centos-release-scl epel-release - sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm || true - sudo yum install -y devtoolset-10-gcc* - sudo yum install -y ninja-build - sudo yum install -y rsync - - # OpenGL packages - sudo yum install -y mesa-libGL-devel mesa-libGLU-devel glew-devel ftgl-devel - - # Install dependencies to install Python with PyEnv - sudo yum install -y @development zlib-devel bzip2 bzip2-devel readline-devel sqlite \ - sqlite-devel openssl-devel xz xz-devel libffi-devel findutils - - if [ "$PV_FLAVOR" = "nvidia-headless" ]; then - sudo yum install -y mesa-libEGL-devel libglvnd libglvnd-egl libglvnd-opengl - fi - else - sudo apt update - sudo apt-get -y install gcc g++ - sudo apt-get -y install rsync wget git make - # paraview - sudo apt-get -y install libopenmpi-dev || true - sudo apt-get install -y ninja-build - - # OpenGL packages - sudo apt-get install -y xlibmesa-glu-dev libglew1.5-dev libftgl-dev - - # Install dependencies to install Python with PyEnv - sudo apt-get install -y libssl-dev zlib1g-dev libbz2-dev \ - libreadline-dev libsqlite3-dev wget curl llvm \ - xz-utils tk-dev libffi-dev liblzma-dev python-openssl git - - sudo apt install -y libxt-dev freeglut3-dev - - if [ "$PV_FLAVOR" = "nvidia-headless" ]; then - sudo apt install -y libegl1-mesa-dev libegl1 libgl1 libglvnd libglvnd-dev - fi - fi - - # update cmake - URL="https://cmake.org/files/v3.19/cmake-3.19.3-Linux-x86_64.tar.gz" - DownloadTarAndExtract $URL $WORKING_DIR/cmake-3.19.3 1 - export PATH=$WORKING_DIR/cmake-3.19.3/bin:$PATH - - # pyenv - if [ -z "$SKIP_PYENV" ]; then - # Install pyenv and python 3.9.1 - curl https://pyenv.run | bash - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - env PYTHON_CONFIGURE_OPTS="--enable-shared" pyenv install 3.9.1 - else - export PYENV_ROOT="$HOME/.pyenv" - export PATH="$PYENV_ROOT/bin:$PATH" - eval "$(pyenv init --path)" - eval "$(pyenv init -)" - pyenv update - fi - pyenv shell 3.9.1 - - BDM_OS_VERS=${BDM_OS} - else - brew update --preinstall - brew install bash git cmake ninja swig python@3.9 libomp open-mpi git-lfs qt@5 - - MACOS_VERS=`sw_vers | sed -n 's/ProductVersion://p' | cut -d . -f 1-2 | sed -e 's/^[[:space:]]*//'` - MACOS_ARCH=`arch` - BDM_OS_VERS=${BDM_OS}-${MACOS_VERS}-${MACOS_ARCH} - fi -fi - -# qt -if [ -z "$SKIP_QT" ]; then - # The QT5 download is only executed on linux because we use brew qt@5 on macOS - if [ $(uname) = "Linux" ]; then - QT_TAR=qt_${QT_VERSION}_${BDM_OS_VERS}.tar.gz - mkdir -p $QT_INSTALL_DIR - QT_TAR_FILE="${QT_INSTALL_DIR}/${QT_TAR}" - - if [ -n "$BDM_LOCAL_LFS" ]; then - tar -zxf "${BDM_LOCAL_LFS}third-party/${QT_TAR}" -C "$QT_INSTALL_DIR" - cd ${QT_INSTALL_DIR} - else - QT_URL=http://cern.ch/biodynamo-lfs/third-party/${QT_TAR} - wget --progress=dot:giga -O $QT_TAR_FILE $QT_URL - cd ${QT_INSTALL_DIR} - tar -zxf $QT_TAR - fi - fi -fi diff --git a/util/build-third-party/qt-silent-install-linux.js b/util/build-third-party/qt-silent-install-linux.js deleted file mode 100644 index ab34e26eb..000000000 --- a/util/build-third-party/qt-silent-install-linux.js +++ /dev/null @@ -1,67 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -function Controller() { - installer.autoRejectMessageBoxes(); - installer.installationFinished.connect(function() { - gui.clickButton(buttons.NextButton); - }) -} - -Controller.prototype.WelcomePageCallback = function() { - gui.clickButton(buttons.NextButton, 2000); -} - -Controller.prototype.CredentialsPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.IntroductionPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.TargetDirectoryPageCallback = function() { - gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.value("HomeDir") + "/bdm-build-third-party/qt"); - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.ComponentSelectionPageCallback = function() { - var widget = gui.currentPageWidget(); - - widget.deselectAll(); - widget.selectComponent("qt.qt5.5110.gcc_64"); - - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.LicenseAgreementPageCallback = function() { - gui.currentPageWidget().AcceptLicenseRadioButton.setChecked(true); - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.StartMenuDirectoryPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.ReadyForInstallationPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.FinishedPageCallback = function() { - var checkBoxForm = gui.currentPageWidget().LaunchQtCreatorCheckBoxForm - if (checkBoxForm && checkBoxForm.launchQtCreatorCheckBox) { - checkBoxForm.launchQtCreatorCheckBox.checked = false; - } - gui.clickButton(buttons.FinishButton); -} diff --git a/util/build-third-party/qt-silent-install-macos.js b/util/build-third-party/qt-silent-install-macos.js deleted file mode 100644 index bc7a04061..000000000 --- a/util/build-third-party/qt-silent-install-macos.js +++ /dev/null @@ -1,67 +0,0 @@ -// ----------------------------------------------------------------------------- -// -// Copyright (C) 2021 CERN & University of Surrey for the benefit of the -// BioDynaMo collaboration. All Rights Reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// -// See the LICENSE file distributed with this work for details. -// See the NOTICE file distributed with this work for additional information -// regarding copyright ownership. -// -// ----------------------------------------------------------------------------- - -function Controller() { - installer.autoRejectMessageBoxes(); - installer.installationFinished.connect(function() { - gui.clickButton(buttons.NextButton); - }) -} - -Controller.prototype.WelcomePageCallback = function() { - gui.clickButton(buttons.NextButton, 2000); -} - -Controller.prototype.CredentialsPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.IntroductionPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.TargetDirectoryPageCallback = function() { - gui.currentPageWidget().TargetDirectoryLineEdit.setText(installer.value("HomeDir") + "/bdm-build-third-party/qt"); - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.ComponentSelectionPageCallback = function() { - var widget = gui.currentPageWidget(); - - widget.deselectAll(); - widget.selectComponent("qt.qt5.5110.clang_64"); - - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.LicenseAgreementPageCallback = function() { - gui.currentPageWidget().AcceptLicenseRadioButton.setChecked(true); - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.StartMenuDirectoryPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.ReadyForInstallationPageCallback = function() { - gui.clickButton(buttons.NextButton); -} - -Controller.prototype.FinishedPageCallback = function() { - var checkBoxForm = gui.currentPageWidget().LaunchQtCreatorCheckBoxForm - if (checkBoxForm && checkBoxForm.launchQtCreatorCheckBox) { - checkBoxForm.launchQtCreatorCheckBox.checked = false; - } - gui.clickButton(buttons.FinishButton); -} diff --git a/util/build-third-party/third-party-prerequisites.sh b/util/build-third-party/third-party-prerequisites.sh index c7fb6893b..de0ef4d02 100644 --- a/util/build-third-party/third-party-prerequisites.sh +++ b/util/build-third-party/third-party-prerequisites.sh @@ -43,18 +43,6 @@ gpgkey=http://springdale.math.ias.edu/data/puias/7.6/x86_64/os/RPM-GPG-KEY-puias EOF' sudo yum update -y - # root required packages - sudo yum install -y git binutils \ - libX11-devel libXpm-devel libXft-devel libXext-devel - # root optional packages - sudo yum install -y gcc-gfortran openssl-devel pcre-devel \ - mesa-libGL-devel mesa-libGLU-devel glew-devel ftgl-devel mysql-devel \ - fftw-devel cfitsio-devel graphviz-devel \ - avahi-compat-libdns_sd-devel libldap-dev python-devel \ - libxml2-devel gsl-static || true - sudo yum install -y atlas-devel - sudo yum install -y libXt-devel freeglut3-devel - sudo yum install -y centos-release-scl epel-release sudo yum -y install https://centos7.iuscommunity.org/ius-release.rpm || true sudo yum install -y devtoolset-10-gcc* @@ -85,18 +73,6 @@ EOF' CXX=g++ # only for ubuntu image sudo apt-get -y install wget git make ninja-build - # root required packages - sudo apt-get -y install git dpkg-dev g++ gcc binutils libx11-dev libxpm-dev \ - libxft-dev libxext-dev - # root optional packages - sudo apt-get -y install gfortran libssl-dev libpcre3-dev \ - xlibmesa-glu-dev libglew1.5-dev libftgl-dev \ - libmysqlclient-dev libfftw3-dev libcfitsio-dev \ - graphviz-dev libavahi-compat-libdnssd-dev \ - libldap2-dev python-dev libxml2-dev libkrb5-dev \ - libgsl0-dev libqt4-dev || true - sudo apt install -y libatlas-base-dev - # Install dependencies to install Python with PyEnv sudo apt-get install -y libssl-dev zlib1g-dev libbz2-dev \ libreadline-dev libsqlite3-dev wget curl llvm \ @@ -110,8 +86,6 @@ EOF' sudo apt-get install -y python-openssl fi - sudo apt install -y libxt-dev freeglut3-dev - # libroadrunner # Different versions of Ubuntu have different LLVM packages if [ `lsb_release -rs` = "22.04" ] || [ `lsb_release -rs` = "22.10" ]; then @@ -126,7 +100,7 @@ EOF' export LLVM_CONFIG="/usr/bin/llvm-config-14" fi fi - # update cmake to build ROOT + # Use the CMake version required by the bundled third-party builds. URL="https://cmake.org/files/v3.19/cmake-3.19.3-Linux-x86_64.tar.gz" DownloadTarAndExtract $URL $WORKING_DIR/cmake-3.19.3 1 export PATH=$WORKING_DIR/cmake-3.19.3/bin:$PATH @@ -144,5 +118,5 @@ EOF' else xcode-select --install || true brew update --preinstall - brew install bash git cmake ninja swig python@3.9 libomp open-mpi git-lfs qt@5 + brew install bash git cmake ninja swig python@3.9 libomp open-mpi git-lfs fi diff --git a/util/clean-build-dir.sh b/util/clean-build-dir.sh index 2b1da59e8..611b4ec54 100755 --- a/util/clean-build-dir.sh +++ b/util/clean-build-dir.sh @@ -41,6 +41,3 @@ done for f in .ninja*; do rm -f $f done - -# remove file created in third_party/paraview/lib/cmake/paraview-5.5/Modules/ -find . -name BDMGlyphFilterHierarchy.txt -exec rm -f {} \; diff --git a/util/demo_to_notebook.py b/util/demo_to_notebook.py deleted file mode 100644 index 99798ca39..000000000 --- a/util/demo_to_notebook.py +++ /dev/null @@ -1,486 +0,0 @@ -import re -import os -import sys -import json -import time -import doctest -import textwrap -import subprocess -from nbformat import v3, v4 -from datetime import datetime, date -import argparse - -# Hacky solution to avoid picking up ParaView's python packages (i.e. pygments) -# that causes the notebooks to not be generated -try: - os.environ['PYTHONPATH'] = os.environ['ROOTSYS'] + "/lib" -except: - print("Error: ROOTSYS was not set. Please source thisbdm.sh.") - exit(1) - -# List of types that will be considered when looking for a C++ function. If a macro returns a -# type not included on the list, the regular expression will not match it, and thus the function -# will not be properly defined. Thus, any other type returned by function must be added to this list -# for the script to work correctly. -gTypesList = ["inline int", "void", "int", - "string", "bool", "real_t", "float", "char"] - - -def Indent(string, spaces=2): - new_string = '' - lines = string.splitlines() - skip = True - for line in lines: - if line == "" and skip: - continue - new_string += line + "\n" - skip = False - return new_string - - -def Unindent(string, spaces=2): - """ - Returns string with each line unindented by 2 spaces. If line isn't indented, it stays the same. - >>> Unindent(" foobar") - 'foobar\\n' - >>> Unindent("foobar") - 'foobar\\n' - >>> Unindent('''foobar - ... foobar - ... foobar''') - 'foobar\\nfoobar\\nfoobar\\n' - """ - newstring = '' - lines = string.splitlines() - for line in lines: - if line.startswith(spaces*' '): - newstring += (line[spaces:] + "\n") - else: - newstring += (line + "\n") - - return newstring - - -def ReadHeader(text): - """ - Extracts the description from the header, and removes the copyright notice - """ - lines = text.splitlines() - - # Skip copyright notice - lines = lines[13:] - - newTitle = "" - visualize = False - - description = '' - for i, line in enumerate(lines): - if line.startswith("// \\title "): - newTitle = line[9:] - elif line.startswith("// \\visualize"): - visualize = True - elif line.startswith("//"): - if line == "//" or not line.startswith("// --"): - description += ('# ' + line[3:] + '\n') - else: - break - newtext = '' - for line in lines[i:]: - newtext += (line + "\n") - description = description.replace("\\f$", "$") - description = description.replace("\\f[", "$$") - description = description.replace("\\f]", "$$") - return newtext, description, newTitle, visualize - - -def ExtractMainFunction(text): - """ - Extracts the contents of the Simulate(argc, argv) function. - """ - functionContentRe = re.compile( - r'{((\n|.)*)}', flags=re.DOTALL | re.MULTILINE) - - match = functionContentRe.search(text) - - text = match.group() - text = text[1:-1] # remove "{" and "}" - - new_text = '' - for line in text.splitlines(): - if "argc, argv" in line: - new_text += line.replace("argc, argv", - '"{}"'.format(tutName)) + "\n" - continue - if "return 0;" in line: - new_text += '\n' - continue - new_text += line + "\n" - return new_text - - -def Comments(text): - """ - Converts comments delimited by // and on a new line into a markdown cell. - >>> Comments('''// This is a - ... // multiline comment - ... void function(){}''') - '# \\n# This is a\\n# multiline comment\\n# \\nvoid function(){}\\n' - >>> Comments('''void function(){ - ... int variable = 5 // Comment not in cell - ... // Comment also not in cell - ... }''') - 'void function(){\\n int variable = 5 // Comment not in cell\\n // Comment also not in cell\\n}\\n' - """ - text = text.splitlines() - newtext = '' - inComment = False - - for line in text: - if line.startswith("//") and not inComment: # True if first line of comment - inComment = True - newtext += "# \n" - # Don't use .capitalize() if line starts with hash, ie it is a header - if line[2:].lstrip().startswith("#"): - newtext += ("# " + line[2:]+"\n") - else: - newtext += ("# " + line[2:].lstrip().capitalize()+"\n") - # True if first line after comment - elif inComment and not line.startswith("//"): - inComment = False - newtext += "# \n" - newtext += (line+"\n") - # True if in the middle of a comment block - elif inComment and line.startswith("//"): - newtext += ("# " + line[2:] + "\n") - else: - newtext += (line+"\n") - - return newtext - - -def split(text): - """ - Splits the text string into main, helpers, and rest. main is the main function, - i.e. the function tha thas the same name as the macro file. Helpers is a list of - strings, each a helper function, i.e. any other function that is not the main function. - Finally, rest is a string containing any top-level code outside of any function. - Comments immediately prior to a helper cell are converted into markdown cell, - added to the helper, and removed from rest. - Intended for C++ files only. - >>> split('''void tutorial(){ - ... content of tutorial - ... }''') - ('void tutorial(){\\n content of tutorial\\n}', [], '') - >>> split('''void tutorial(){ - ... content of tutorial - ... } - ... void helper(arguments = values){ - ... helper function - ... content spans lines - ... }''') - ('void tutorial(){\\n content of tutorial\\n}', ['\\n# \\n A helper function is created: \\n# \\n%%cpp -d\\nvoid helper(arguments = values){\\n helper function\\n content spans lines\\n}'], '') - >>> split('''#include - ... using namespace NAMESPACE - ... void tutorial(){ - ... content of tutorial - ... } - ... void helper(arguments = values){ - ... helper function - ... content spans lines - ... }''') - ('void tutorial(){\\n content of tutorial\\n}', ['\\n# \\n A helper function is created: \\n# \\n%%cpp -d\\nvoid helper(arguments = values){\\n helper function\\n content spans lines\\n}'], '#include \\nusing namespace NAMESPACE') - >>> split('''void tutorial(){ - ... content of tutorial - ... } - ... // This is a multiline - ... // description of the - ... // helper function - ... void helper(arguments = values){ - ... helper function - ... content spans lines - ... }''') - ('void tutorial(){\\n content of tutorial\\n}', ['\\n# \\n This is a multiline\\n description of the\\n helper function\\n \\n# \\n%%cpp -d\\nvoid helper(arguments = values){\\n helper function\\n content spans lines\\n}'], '') - """ - functionReString = "(" - for cpptype in gTypesList: - functionReString += ("^%s|") % cpptype - - functionReString = functionReString[:-1] + \ - r")\s?\*?&?\s?[\w:]*?\s?\([^\)]*\)\s*\{.*?^\}" - - functionRe = re.compile(functionReString, flags=re.DOTALL | re.MULTILINE) - #functionre = re.compile(r'(^void|^int|^Int_t|^TF1|^string|^bool|^real_t|^float|^char|^TCanvas|^TTree|^TString|^TSeqCollection|^Double_t|^TFile|^Long64_t|^Bool_t)\s?\*?\s?[\w:]*?\s?\([^\)]*\)\s*\{.*?^\}', flags = re.DOTALL | re.MULTILINE) - functionMatches = functionRe.finditer(text) - helpers = [] - main = "" - for matchString in [match.group() for match in functionMatches]: - if findFunctionName(matchString) == "Simulate": # the main simulation function - main = matchString - else: - helpers.append(matchString) - - # Create rest by replacing the main and helper functions with blank strings - rest = text.replace(main, "") - - for helper in helpers: - rest = rest.replace(helper, "") - - newHelpers = [] - lines = text.splitlines() - for helper in helpers: # For each helper function - # Look through the lines until the - for i, line in enumerate(lines): - # first line of the helper is found - if line.startswith(helper[:helper.find("\n")]): - j = 1 - commentList = [] - # Add comment lines immediately prior to list - while lines[i-j].startswith("//"): - commentList.append(lines[i-j]) - j += 1 - if commentList: # Convert list to string - commentList.reverse() - helperDescription = '' - for comment in commentList: - if comment in ("//", "// "): - helperDescription += "\n\n" # Two newlines to create hard break in Markdown - else: - helperDescription += (comment[2:] + "\n") - rest = rest.replace(comment, "") - break - else: # If no comments are found create generic description - helperDescription = "A helper function is created:" - break - - if findFunctionName(helper) != "main": # remove void main function - newHelpers.append("\n# \n " + - helperDescription + " \n# \n%%cpp -d\n" + helper) - - headers = '' - for line in rest.splitlines(): - if line.startswith("#include"): - headers += line + "\n" - rest = rest.replace(line, "") - - # remove newlines and empty comments at the end of string - rest = rest.rstrip("\n /") - - return main, newHelpers, headers, rest - - -def findFunctionName(text): - """ - Takes a string representation of a C++ function as an input, - finds and returns the name of the function - >>> findFunctionName('void functionName(arguments = values){}') - 'functionName' - >>> findFunctionName('void functionName (arguments = values){}') - 'functionName' - >>> findFunctionName('void *functionName(arguments = values){}') - 'functionName' - >>> findFunctionName('void* functionName(arguments = values){}') - 'functionName' - >>> findFunctionName('void * functionName(arguments = values){}') - 'functionName' - >>> findFunctionName('void class::functionName(arguments = values){}') - 'class::functionName' - """ - functionNameReString = "(?<=" - for cpptype in gTypesList: - functionNameReString += ("(?<=%s)|") % cpptype - - functionNameReString = functionNameReString[:- - 1] + r")\s?\*?\s?[^\s]*?(?=\s?\()" - - functionNameRe = re.compile( - functionNameReString, flags=re.DOTALL | re.MULTILINE) - - #functionnamere = re.compile(r'(?<=(?<=int)|(?<=void)|(?<=TF1)|(?<=Int_t)|(?<=string)|(?<=real_t)|(?<=Double_t)|(?<=float)|(?<=char)|(?<=TString)|(?<=bool)|(?<=TSeqCollection)|(?<=TCanvas)|(?<=TTree)|(?<=TFile)|(?<=Long64_t)|(?<=Bool_t))\s?\*?\s?[^\s]*?(?=\s?\()', flags = re.DOTALL | re.MULTILINE) - match = functionNameRe.search(text) - functionname = match.group().strip(" *\n") - return functionname - - -def processmain(text): - argumentsCell = '' - - if text: - argumentsre = re.compile( - r'(?<=\().*?(?=\))', flags=re.DOTALL | re.MULTILINE) - arguments = argumentsre.search(text) - - if len(arguments.group()) > 3: - # argumentsCell = "# \n Arguments are defined. \n# \n" - # , flags = re.DOTALL) #| re.MULTILINE) - individualArgumentre = re.compile(r'[^/\n,]*?=[^/\n,]*') - argumentList = individualArgumentre.findall(arguments.group()) - for argument in argumentList: - argumentsCell += argument.strip("\n ") + ";\n" - # argumentsCell += "# \n" - - return text, argumentsCell - - -def changeMarkdown(code): - code = code.replace("~~~", "```") - code = code.replace("{.cpp}", "cpp") - code = code.replace("{.bash}", "bash") - return code - - -def RemoveIncludeGuardsAndNamespace(text): - lines = text.splitlines() - new_text = '' - for line in lines: - if line.startswith("#ifndef DEMO_") or line.startswith("#define DEMO_") or line.startswith("#endif // DEMO_"): - continue - elif line.startswith("namespace") or line.startswith("} // namespace"): - continue - else: - new_text += line + "\n" - - return new_text - -# Creates the macro function declaration, such that `root -x function_name.C` -# can be used -def CreateMainFunction(content): - signature = "void {}()".format(tutName) + " {\n" - return signature + Indent(content) + "\n}\n" - -# ------------------------------------- -# ------------ Main Program------------ -# ------------------------------------- -def mainfunction(text, visualize): - """ - Main function. Calls all other functions. Also, it adds a cell that draws the result. The working text is - then converted to a version 3 jupyter notebook, subsequently updated to a version 4. Then, metadata - associated with the language the macro is written in is attatched to he notebook. Finally the - notebook is executed and output as a Jupyter notebook. - """ - # Modify text from macros to suit a notebook - main, helpers, headers, rest = split(text) - main_macro = CreateMainFunction(Indent(ExtractMainFunction(main))) - main, argumentsCell = processmain(main) - # Remove function, Unindent, and convert comments to Markdown cells - main = Comments(Unindent(ExtractMainFunction(main))) - rest = RemoveIncludeGuardsAndNamespace(rest) - - # Command for loading rootlogon.C - libloading_macro = '%jsroot on\ngROOT->LoadMacro("${BDMSYS}/etc/rootlogon.C");\n\n' - - c_macro = headers + rest + main_macro - with open(outPathNameMacro, 'w') as fout: - fout.write(c_macro) - - if argumentsCell: - main = argumentsCell + main - - if visualize: - visComment = "# \n Let's visualize the output!" - main += '\n%s\n# \nVisualizeInNotebook();\n' % visComment - - # Convert top level code comments to Markdown cells - rest = Comments(rest) - - # Construct text by starting with top level code, then the helper functions, and finally the main function. - # Also add cells for headerfile, or keepfunction - text = "# \n" + rest - - for helper in helpers: - text += helper - - text += ("\n# \n" + main) - - # Change to standard Markdown - newDescription = changeMarkdown(description) - - # Horizontal title line - hline = '
' - - # Add the title and header of the notebook - text = "# \n# # %s\n%s\n%s# \n# \n# \n%s\n# \n%s\n# \n%s" % ( - tutTitle, hline, newDescription, libloading_macro, headers, text) - - # Create a notebook from the working text - nbook = v3.reads_py(text) - nbook = v4.upgrade(nbook) # Upgrade v3 to v4 - - # Load notebook string into json format, essentially creating a dictionary - json_data = json.loads(v4.writes(nbook)) - - # add the corresponding metadata - json_data['metadata'] = { - "kernelspec": { - "display_name": "ROOT C++", - "language": "c++", - "name": "root" - }, - "language_info": { - "codemirror_mode": "text/x-c++src", - "file_extension": ".C", - "mimetype": " text/x-c++src", - "name": "c++" - } - } - - # write the json file with the metadata - with open(outPathName, 'w') as fout: - json.dump(json_data, fout, indent=1, sort_keys=True) - - timeout = 60 - - execute = "--execute" - if args.skip: - execute = "" - - # Call commmand that executes the notebook and creates a new notebook with the output - nbconvert_cmd = "jupyter nbconvert --to=html --ExecutePreprocessor.timeout=%d %s %s" % (timeout, execute, outPathName) - r = subprocess.call(["jupyter", "nbconvert", "--to=html", "--ExecutePreprocessor.timeout=%d" % - timeout, execute, outPathName]) - - if r != 0: - sys.stderr.write( - "NOTEBOOK_CONVERSION_ERROR: nbconvert failed for notebook %s with return code %s\n" % (outname, r)) - sys.stderr.write("FAILED COMMAND: %s\n" % nbconvert_cmd) - exit(1) - - -if __name__ == "__main__": - - parser = argparse.ArgumentParser() - parser.add_argument('--tutpath', type=str) - parser.add_argument('--outdir', type=str) - parser.add_argument('--skip', action='store_true') - - args = parser.parse_args() - - tutPathName = args.tutpath - tutPath = os.path.dirname(tutPathName) - tutFileName = os.path.basename(tutPathName) - tutName, extension = tutFileName.split(".") - tutTitle = re.sub(r"([A-Z\d])", r" \1", tutName).title() - tutTitle = tutTitle.replace("_", " ") - outname = tutName + ".ipynb" - outnameMacro = tutName + ".C" - outnameconverted = tutName + ".html" - - # Extract output directory - if args.outdir: - outdir = args.outdir - else: - outdir = tutPath - outPathName = os.path.join(outdir, outname) - outPathNameMacro = os.path.join(outdir, outnameMacro) - date = datetime.now().strftime("%A, %B %d, %Y at %I:%M %p") - - # Open the file to be converted - with open(tutPathName) as fin: - text = fin.read() - - text, description, newTitle, visualize = ReadHeader(text) - - if newTitle != "": - tutTitle = newTitle - - starttime = time.time() - mainfunction(text, visualize) diff --git a/util/git/pr_checklist.md b/util/git/pr_checklist.md index be597dd08..9bd3aa47f 100644 --- a/util/git/pr_checklist.md +++ b/util/git/pr_checklist.md @@ -49,7 +49,7 @@ First time contributor? Make sure to review our contributing guidelines: - [ ] **New feature** - [ ] Update documentation for website (if significant feature) - - [ ] Consider adding notebook or example showing how to use the new feature + - [ ] Consider adding an example showing how to use the new feature - [ ] **New example** - [ ] Make sure that the example is checked in the System CIs diff --git a/util/install b/util/install index 960e579be..2ad344bc7 100755 --- a/util/install +++ b/util/install @@ -73,15 +73,8 @@ trap "echo $out_msg" ERR # Manifest exit code of command that is piped to tee set -o pipefail -# In Github Actions we run the notebooks in a separate step -if [ ! -z ${GITHUB_ACTIONS+x} ]; then - BDM_NOTEBOOKS="-Dnotebooks=off" -else - BDM_NOTEBOOKS="-Dnotebooks=on" -fi - pwd # Run ./install.sh -BDM_CMAKE_FLAGS="-Dtest=off $BDM_NOTEBOOKS $SBML ${BDM_CMAKE_FLAGS}" ./install.sh 2>&1 | tee "$log" +BDM_CMAKE_FLAGS="-Dtest=off $SBML ${BDM_CMAKE_FLAGS}" ./install.sh 2>&1 | tee "$log" set +o pipefail diff --git a/util/installation/centos-7/Dockerfile b/util/installation/centos-7/Dockerfile index 45e68264f..d1a5d5c39 100644 --- a/util/installation/centos-7/Dockerfile +++ b/util/installation/centos-7/Dockerfile @@ -17,12 +17,10 @@ FROM centos:7 # workaround for https://github.com/containers/buildah/issues/1046 RUN echo "" >> /etc/hosts && cat /etc/hosts && yum -y install setup -# man required by ROOT # mesa-dri-drivers: OpenGl driver (software renderer) RUN yum update -y && yum install -y \ git \ sudo \ - man \ wget \ xorg-x11-server-Xvfb \ mesa-dri-drivers diff --git a/util/installation/osx/package_list_required b/util/installation/osx/package_list_required index 024ecbe41..ca5c6f8b3 100644 --- a/util/installation/osx/package_list_required +++ b/util/installation/osx/package_list_required @@ -1,4 +1,3 @@ -tbb libomp open-mpi python@3.9 @@ -6,4 +5,3 @@ wget cmake ninja bash -qt@5 diff --git a/util/installation/osx/prerequisites.sh b/util/installation/osx/prerequisites.sh index ef45853c4..5899b6611 100755 --- a/util/installation/osx/prerequisites.sh +++ b/util/installation/osx/prerequisites.sh @@ -56,11 +56,6 @@ brew install \ # Install the optional packages if [ $1 == "all" ]; then - # Fix jinja2 version because of failing build target `notebooks` on - # macOS System CI. - PIP_PACKAGES="markupsafe==2.0.1 nbformat jupyter metakernel jupyterlab jinja2==3.0" - # Don't install --user: the packages should end up in the PYENV_ROOT directory - python3.9 -m pip install $PIP_PACKAGES brew install \ $(cat $BDM_PROJECT_DIR/util/installation/osx/package_list_extra) || true fi diff --git a/util/installation/ubuntu-18.04/Dockerfile b/util/installation/ubuntu-18.04/Dockerfile index 4eb567163..a119c5e0e 100644 --- a/util/installation/ubuntu-18.04/Dockerfile +++ b/util/installation/ubuntu-18.04/Dockerfile @@ -14,11 +14,9 @@ FROM ubuntu:18.04 -# man required by ROOT RUN apt-get update && apt-get install -y \ git \ sudo \ - man \ software-properties-common \ wget \ xvfb diff --git a/util/installation/ubuntu-20.04/Dockerfile b/util/installation/ubuntu-20.04/Dockerfile index 22684daf9..a22962367 100644 --- a/util/installation/ubuntu-20.04/Dockerfile +++ b/util/installation/ubuntu-20.04/Dockerfile @@ -20,11 +20,9 @@ RUN if ! [ -L /etc/localtime ]; then \ ln -fs /usr/share/zoneinfo/Europe/Berlin /etc/localtime; \ fi -# man required by ROOT RUN apt-get update && apt-get install -y \ git \ sudo \ - man \ software-properties-common \ wget \ xvfb diff --git a/util/installation/ubuntu-22.04/Dockerfile b/util/installation/ubuntu-22.04/Dockerfile index 7e8618887..8bc4f8f87 100644 --- a/util/installation/ubuntu-22.04/Dockerfile +++ b/util/installation/ubuntu-22.04/Dockerfile @@ -14,11 +14,9 @@ FROM ubuntu:22.04 -# man required by ROOT RUN apt-get update && apt-get install -y \ git \ sudo \ - man \ software-properties-common \ wget \ xvfb diff --git a/util/installation/ubuntu-24.04/Dockerfile b/util/installation/ubuntu-24.04/Dockerfile index b13f29c3a..71e99f3e9 100644 --- a/util/installation/ubuntu-24.04/Dockerfile +++ b/util/installation/ubuntu-24.04/Dockerfile @@ -14,11 +14,9 @@ FROM ubuntu:24.04 -# man required by ROOT RUN apt-get update && apt-get install -y \ git \ sudo \ - man \ software-properties-common \ wget \ xvfb diff --git a/util/makefile-build/bdm-code-generation b/util/makefile-build/bdm-code-generation deleted file mode 100755 index cd7dce8b8..000000000 --- a/util/makefile-build/bdm-code-generation +++ /dev/null @@ -1,70 +0,0 @@ -#!/bin/bash -# ----------------------------------------------------------------------------- -# -# Copyright (C) 2021 CERN & University of Surrey for the benefit of the -# BioDynaMo collaboration. All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# -# See the LICENSE file distributed with this work for details. -# See the NOTICE file distributed with this work for additional information -# regarding copyright ownership. -# -# ----------------------------------------------------------------------------- - -# This script generates ROOT dictionaries for NON CMake builds - -if [ $# -lt 4 ]; then - echo "Wrong number of arguments" - echo "Usage: bdm-code-generation DICTIONARY BDM_CONFIG [CXX_FLAGS] -i include-dir1 [include-dir2] -h header1.h [header2.h ...]" - echo " DICTIONARY file name of the dictionary that gets generated" - echo " (e.g., my-sim_dict.cc)" - echo " BDM_CONFIG bdm config command. Used to pass optional compiler and build type" - echo " (e.g., \"bdm-config --debug --opt\")" - echo " CXX_FLAGS additional CXX flags (optional). Add includes or defines only!" - echo " INCLUDE_DIRS at least one include directory containing the headers" - echo " HEADERS at least one header file containing the biodynamo definitions" - exit -fi - -DICT=$1 -shift -BDM_CONFIG=$1 -shift -if [ $1 != "-i" ]; then - ADDITIONAL_CXX_FLAGS=$1 - shift - while [ $1 != "-i" ]; do - ADDITIONAL_CXX_FLAGS="$ADDITIONAL_CXX_FLAGS $1" - shift - done -fi -shift -if [ $1 != "-h" ]; then - INCLUDE_DIRS=$1 - shift - while [ $1 != "-h" ]; do - INCLUDE_DIRS="$INCLUDE_DIRS $1" - shift - done -fi -shift -HEADERS=$@ - -SELECTIONFILE=$(${BDM_CONFIG} --cmakedir)/selection.xml - -CXX_INCLUDES=$(${BDM_CONFIG} --cxxincludes | sed 's|-isystem |-I|g') - -CXX_DEFINES=$(${BDM_CONFIG} --cxxdefines) - -genreflex ${HEADERS} -o ${DICT} --noIncludePaths --select=${SELECTIONFILE} ${CXX_DEFINES} ${CXX_INCLUDES} $ADDITIONAL_CXX_FLAGS - -# Generate bdm dictionary and append to DICT -BDM_DICT=$(mktemp) -bdm-dictionary --output $BDM_DICT --out-of-source --include-dirs $INCLUDE_DIRS --headers $HEADERS -echo "" >> $DICT -echo "// -------------------------------------------------------------------" >> $DICT -echo "// Start BioDynaMo dictionary" >> $DICT -cat $BDM_DICT >> $DICT -rm $BDM_DICT diff --git a/util/valgrind-bdm.supp b/util/valgrind-bdm.supp deleted file mode 100644 index 48c8e9f2a..000000000 --- a/util/valgrind-bdm.supp +++ /dev/null @@ -1,624 +0,0 @@ -# Additional valgrind suppression file for BioDynaMo. -# -# To use, run valgrind with: -# valgrind --suppressions=valgrind.supp ... -# -# This file suppresses known and expected / inevitable valgrind -# reports, e.g. due to ROOT's runtime type information that must -# survive until the end of the process and thus leaks. - -{ - OSMesa - Memcheck:Leak - match-leak-kinds: possible - fun:malloc - obj:/usr/lib/x86_64-linux-gnu/libOSMesa.so.8.0.0 -} - -######### Suppress OpenMP possible lost warning -{ - ignore_openmp_possible_lost_warning - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_* - obj:*/libgomp.so* - #fun:GOMP_parallel -} - -{ - ignore_openmp_possible_lost_warning_1 - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:_dl_allocate_tls - fun:pthread_create@@GLIBC_* - obj:*/libgomp.so* - fun:GOMP_parallel -} - -{ - ignore_openmp_possible_lost_warning_icc - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_* - fun:* - fun:__kmp_allocate_thread - fun:__kmp_allocate_team - fun:__kmp_fork_call - fun:__kmpc_fork_call -} - -{ - ignore_openmp_initialization_warnings_icc - Memcheck:Cond - fun:__intel_sse2_* - fun:__kmp_query_cpuid - fun:__kmp_runtime_initialize - fun:_Z26__kmp_do_serial_initializev - fun:__kmp_get_global_thread_id_reg -} - -{ - ignore_openmp_initialization_warnings_icc_2 - Memcheck:Param - sched_setaffinity(mask) - fun:syscall - fun:__kmp_affinity_determine_capable - fun:_Z20__kmp_env_initializePKc - fun:_Z26__kmp_do_serial_initializev - fun:__kmp_get_global_thread_id_reg -} - -{ - ignore_Syscall_param_sched_setaffinity_mask__points_to_unaddressable_bytes - Memcheck:Param - sched_setaffinity(mask) - fun:syscall - fun:__kmp_affinity_determine_capable - fun:_Z20__kmp_env_initializePKc - fun:_ZL26__kmp_do_serial_initializev - fun:__kmp_get_global_thread_id_reg - fun:GOMP_parallel@@VERSION -} - -######### Suppress ICC false positives -{ - gtest_uninitialized_value_icc - Memcheck:Cond - fun:_ZN7testing8internal12UnitTestImpl11FilterTestsENS1_18ReactionToShardingE - fun:_ZN7testing8internal12UnitTestImpl11RunAllTestsEv - fun:_ZN7testing8UnitTest3RunEv - fun:main -} - - -######### Suppress ROOT issues, they are checked by the ROOT team -{ - ignore_root_libs_leak - Memcheck:Leak - ... - obj:*/root/lib/*.so -} - -{ - ignore_root_libs_cond - Memcheck:Cond - ... - obj:*/root/lib/*.so -} - -{ - ignore_macos_dyld_leak - Memcheck:Leak - ... - obj:/usr/lib/dyld -} - -{ - ignore_macos_dyld_cond - Memcheck:Cond - ... - obj:/usr/lib/dyld -} - -{ - ignore_macos_dyld_val8 - Memcheck:Value8 - ... - obj:/usr/lib/dyld -} - -{ - ignore_macos_frameworks_leak - Memcheck:Leak - ... - obj:/System/Library/Frameworks/* -} - -{ - ignore_macos_libs_leak - Memcheck:Leak - ... - obj:/usr/lib/system/*.dylib -} - -{ - ignore_root_zipLZ4 - Memcheck:Value8 - ... - fun:R__zipLZ4 - fun:R__zipMultipleAlgorithm -} - -{ - ignore_root_write_invalid_param - Memcheck:Param - write(buf) - obj:/lib/x86_64-linux-gnu/libpthread-2.23.so - fun:_ZN5TFile11WriteBufferEPKci.part.* -} - -{ - ignore_root_write_invalid_param1 - Memcheck:Param - write(count) - obj:/lib/x86_64-linux-gnu/libpthread-2.23.so - fun:_ZN5TFile11WriteBufferEPKci.part.* -} - -{ - ignore_root_lseek_invalid_param - Memcheck:Param - lseek(offset) - fun:lseek - fun:_ZN5TFile4SeekExNS_11ERelativeToE -} - -######### Suppress uninitialized value complaints for IO of InlineVector -{ - ignore_uninitialized_heap_io - Memcheck:Param - write(buf) - ... - fun:_ZN5TFile11WriteBufferEPKci - fun:_ZN4TKey9WriteFileEiP5TFile - fun:_ZN14TDirectoryFile14WriteObjectAnyEPKvPK6TClassPKcS6_i - ... -} - -{ - ignore_uninitialized_heap_io_root-v6-18-04 - Memcheck:Param - write(buf) - obj:/lib/x86_64-linux-gnu/libpthread-2.23.so - fun:_ZN5TFile11WriteBufferEPKci.part.56.constprop.201 - fun:_ZN4TKey9WriteFileEiP5TFile - fun:_ZN14TDirectoryFile14WriteObjectAnyEPKvPK6TClassPKcS6_i - fun:WriteObject - fun:Backup - fun:_ZN3bdm23scheduler_test_internal14RunRestoreTestEv - fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc - fun:_ZN7testing8internal35HandleExceptionsInMethodIfSupportedINS_4TestEvEET0_PT_MS4_FS3_vEPKc - fun:_ZN7testing4Test3RunEv - fun:_ZN7testing8TestInfo3RunEv - fun:_ZN7testing8TestCase3RunEv - fun:_ZN7testing8internal12UnitTestImpl11RunAllTestsEv - fun:_ZN7testing8internal38HandleSehExceptionsInMethodIfSupportedINS0_12UnitTestImplEbEET0_PT_MS4_FS3_vEPKc -} - -{ - false_positive_ThreadInfo - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_2.34 - obj:/usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0 - fun:GOMP_parallel - fun:_ZN3bdm10ThreadInfoC1Ev - fun:_ZN3bdm10ThreadInfo11GetInstanceEv - fun:_ZN3bdm18MechanicalForcesOpC1Ev -} - -######### Suppress rootcling false positives -{ - false_positive_root_1 - Memcheck:Leak - match-leak-kinds: possible - fun:_Znwm - fun:_ZN4llvm8FunctionC1EPNS_12FunctionTypeENS_11GlobalValue12LinkageTypesERKNS_5TwineEPNS_6ModuleE - fun:_ZN4llvm6Module19getOrInsertFunctionENS_9StringRefEPNS_12FunctionTypeENS_12AttributeSetE - fun:_ZN4llvm6Module19getOrInsertFunctionENS_9StringRefEPNS_12FunctionTypeE - fun:_ZN4llvm9Intrinsic14getDeclarationEPNS_6ModuleENS0_2IDENS_8ArrayRefIPNS_4TypeEEE - fun:_ZN4llvm13IRBuilderBase19CreateLifetimeStartEPNS_5ValueEPNS_11ConstantIntE - fun:_ZN4llvm14InlineFunctionENS_8CallSiteERNS_18InlineFunctionInfoEPNS_9AAResultsEb - fun:_ZN4llvm7Inliner11inlineCallsERNS_12CallGraphSCCE - fun:_ZN12_GLOBAL__N_113CGPassManager11runOnModuleERN4llvm6ModuleE - fun:_ZN4llvm6legacy15PassManagerImpl3runERNS_6ModuleE - fun:_ZN5cling13BackendPasses11runOnModuleERN4llvm6ModuleE - fun:_ZN5cling17IncrementalParser22transformTransactionIREPNS_11TransactionE -} - -{ - false_positive_root_2 - Memcheck:Leak - match-leak-kinds: possible - fun:_Znwm - fun:_ZN4llvm4UsernwEmj - fun:_ZN4llvm8CastInst6CreateENS_11Instruction7CastOpsEPNS_5ValueEPNS_4TypeERKNS_5TwineEPS1_ - fun:_ZN4llvm9IRBuilderINS_14ConstantFolderEN5clang7CodeGen17CGBuilderInserterEE13CreateIntCastEPNS_5ValueEPNS_4TypeEbRKNS_5TwineE - ... -} - -{ - false_positive_root_3 - Memcheck:Param - msync(start) - ... - fun:cling_runtime_internal_throwIfInvalidPointer - ... -} - -{ - false_positive_root_4 - Memcheck:Overlap - ... - fun:CreateInterpreter - ... -} - -{ - root_6_28_02_unknown_1 - Memcheck:Addr8 - fun:strncmp - fun:is_dst - fun:_dl_dst_count - fun:expand_dynamic_string_token - fun:fillin_rpath.isra.0 - fun:decompose_rpath - fun:cache_rpath - fun:cache_rpath - fun:_dl_map_object - fun:openaux - fun:_dl_catch_exception - fun:_dl_map_object_deps - fun:dl_open_worker_begin - fun:_dl_catch_exception - fun:dl_open_worker - fun:_dl_catch_exception - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_exception - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen_implementation - fun:dlopen@@GLIBC_2.34 - fun:_ZN5TROOT15InitInterpreterEv - fun:_ZN4ROOT8Internal8GetROOT2Ev - fun:_ZN10TDirectoryD1Ev - fun:_ZN3bdm10Simulation10InitializeEPNS_18CommandLineOptionsERKSt8functionIFvPNS_5ParamEEERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISG_EE - fun:_ZN3bdm10SimulationC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt8functionIFvPNS_5ParamEEERKSt6vectorIS6_SaIS6_EE - fun:_ZN3bdm10SimulationC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS6_SaIS6_EE -} - -{ - root_6_28_02_unknown_2 - Memcheck:Addr8 - fun:strncmp - fun:is_dst - fun:_dl_dst_substitute - fun:fillin_rpath.isra.0 - fun:decompose_rpath - fun:cache_rpath - fun:cache_rpath - fun:_dl_map_object - fun:openaux - fun:_dl_catch_exception - fun:_dl_map_object_deps - fun:dl_open_worker_begin - fun:_dl_catch_exception - fun:dl_open_worker - fun:_dl_catch_exception - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_exception - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen_implementation - fun:dlopen@@GLIBC_2.34 - fun:_ZN5TROOT15InitInterpreterEv - fun:_ZN4ROOT8Internal8GetROOT2Ev - fun:_ZN10TDirectoryD1Ev - fun:_ZN3bdm10Simulation10InitializeEPNS_18CommandLineOptionsERKSt8functionIFvPNS_5ParamEEERKSt6vectorINSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEESaISG_EE - fun:_ZN3bdm10SimulationC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt8functionIFvPNS_5ParamEEERKSt6vectorIS6_SaIS6_EE - fun:_ZN3bdm10SimulationC1ERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEERKSt6vectorIS6_SaIS6_EE -} - -######### Suppress protobuf library issues -{ - ignore_protobuf_memleaks - Memcheck:Leak - ... - fun:_ZN6google8protobuf14DescriptorPool24InternalAddGeneratedFileEPKvi - ... -} - -######### Suppress glibc issues -{ - glibc_issue_1 - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:do_dlopen - fun:_dl_catch_error - fun:dlerror_run - fun:__libc_dlopen_mode - fun:nss_load_library - fun:__nss_lookup_function - fun:__nss_lookup - fun:getpwuid_r@@GLIBC_2.2.5 -} - -{ - glibc_issue_root-v6-18-04 - Memcheck:Leak - match-leak-kinds: definite - fun:malloc - fun:_dl_map_object_deps - fun:dl_open_worker - fun:_dl_catch_error - fun:_dl_open - fun:do_dlopen - fun:_dl_catch_error - fun:dlerror_run - fun:__libc_dlopen_mode - fun:nss_load_library - fun:__nss_lookup_function - fun:init_nss_interface - fun:_nss_compat_getpwuid_r - fun:getpwuid_r@@GLIBC_2.2.5 -} - -{ - glib_issue_root_v6-30-02 - Memcheck:Addr8 - fun:strncmp - fun:is_dst - fun:_dl_dst_substitute - fun:fillin_rpath.isra.0 - fun:decompose_rpath - fun:cache_rpath - fun:cache_rpath - fun:_dl_map_object - fun:openaux - fun:_dl_catch_exception - fun:_dl_map_object_deps - fun:dl_open_worker_begin - fun:_dl_catch_exception - fun:dl_open_worker - fun:_dl_catch_exception - fun:_dl_open - fun:dlopen_doit - fun:_dl_catch_exception - fun:_dl_catch_error - fun:_dlerror_run - fun:dlopen_implementation - fun:dlopen@@GLIBC_2.34 -} - -######### Suppress OpenMPI issues -{ - ignore_openmpi_false_positives - Memcheck:Leak - ... - obj:*/openmpi/*.so* - ... -} - -{ - ignore_openmpi_false_positives_cond - Memcheck:Cond - ... - obj:*/openmpi/*.so* - ... -} - -{ - gh_actions_centos_false_positives - Memcheck:Leak - match-leak-kinds: all - fun:malloc - ... - fun:opal_libevent2022_event_base_loop - ... - fun:start_thread - fun:clone -} - -######### Suppress libevent issues -{ - ignore_libevent_false_positives - Memcheck:Leak - ... - obj:*/libevent*.so* - ... -} - -######### Suppress OpenCL issues -{ - ignore_opencl_false_positives - Memcheck:Leak - ... - obj:*/lib*OpenCL.so* - ... -} - -{ - ignore_opencl_false_positives_param - Memcheck:Param - ioctl(generic) - ... - obj:*/lib*OpenCL.so* - ... -} - - -{ - ignore_opencl_intel_specific_false_positives_free - Memcheck:Free - ... - obj:*/libigdrcl.so - ... -} - -{ - ignore_opencl_intel_specific_false_positives_cond - Memcheck:Cond - ... - obj:*/libigdrcl.so - ... -} - -{ - ignore_opencl_intel_specific_false_positives_cond_2 - Memcheck:Cond - ... - obj:*/libigdccl.so - ... -} - - -{ - ignore_opencl_intel_specific_false_positives_leak - Memcheck:Leak - ... - obj:*/libigdrcl.so - ... -} - -######### Suppress Paraview - - -{ - paraview-21 - Memcheck:Leak - match-leak-kinds: possible - fun:malloc - fun:emutls_alloc - fun:__emutls_get_address -} - -{ - paraview-catalyst - Memcheck:Leak - ... - obj:*/libvtk*.so.* -} - -######### Suppress TBB issues - -{ - ignore_tbb_clear - Memcheck:Cond - fun:isLargeObject - fun:internalPoolFree - fun:internalFree - fun:scalable_free - ... -} - -{ - tbb-1 - Memcheck:Cond - fun:isLargeObject - fun:internalPoolFree - fun:internalFree - fun:scalable_aligned_free - fun:on_thread_leaving - fun:_ZN3tbb8internal17generic_scheduler14cleanup_masterEb - fun:terminate_auto_initialized_scheduler - fun:_ZN3tbb8internal14__TBB_InitOnceD1Ev - fun:__cxa_finalize - ... -} - -######### Suppress Memory Leak for Ubuntu - -{ - ignore_memory_leak_ubuntu_20_04 - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_2.2.5 - fun:launch - fun:wake_or_launch - fun:_ZN3tbb8internal3rml14private_server9wake_someEi - fun:propagate_chain_reaction - fun:_ZN3tbb8internal3rml14private_worker3runEv - fun:_ZN3tbb8internal3rml14private_worker14thread_routineEPv - fun:start_thread - fun:clone -} - -{ - ignore_memory_leak_ubuntu_22_04 - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_2.34 - fun:launch - fun:wake_or_launch - fun:_ZN3tbb8internal3rml14private_server9wake_someEi - fun:propagate_chain_reaction - fun:_ZN3tbb8internal3rml14private_worker3runEv - fun:_ZN3tbb8internal3rml14private_worker14thread_routineEPv - fun:start_thread - fun:clone -} - -{ - ignore_memory_leak_ubuntu_24_04 - Memcheck:Leak - match-leak-kinds: possible - fun:calloc - fun:calloc - fun:allocate_dtv - fun:_dl_allocate_tls - fun:allocate_stack - fun:pthread_create@@GLIBC_2.34 - obj:/usr/lib/x86_64-linux-gnu/libgomp.so.1.0.0 - fun:GOMP_parallel - fun:_ZN3bdm10ThreadInfo11GetInstanceEv - fun:_ZN3bdm18MechanicalForcesOpC1Ev - fun:_Z41__static_initialization_and_destruction_0v - fun:call_init.part.0 - fun:call_init - fun:_dl_init - obj:/usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 - obj:* - obj:* - obj:* - obj:* -} \ No newline at end of file diff --git a/util/valgrind.sh b/util/valgrind.sh index 215e30341..788a585d3 100755 --- a/util/valgrind.sh +++ b/util/valgrind.sh @@ -13,8 +13,6 @@ # # ----------------------------------------------------------------------------- -BDM_PROJECT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/.." - valgrind \ --track-origins=yes \ --num-callers=50 \ @@ -24,8 +22,6 @@ valgrind \ --show-leak-kinds=all \ --gen-suppressions=all \ --show-reachable=no \ - --suppressions=${BDM_PROJECT_DIR}/util/valgrind-bdm.supp \ - --suppressions=$ROOTSYS/etc/valgrind-root.supp \ --error-exitcode=1 \ --num-callers=25 \ "$@"