From 8bd2d8eeb026a99bb00925b23bca92ad184de054 Mon Sep 17 00:00:00 2001 From: Cyrille Pierre Henri Favreau Date: Wed, 27 Mar 2024 18:37:05 +0100 Subject: [PATCH] Docker image --- .github/workflows/docker_push.yml | 22 + Dockerfile | 88 ++++ Nuon_Model_Visualizer.egg-info/SOURCES.txt | 11 - .../dependency_links.txt | 1 - Nuon_Model_Visualizer.egg-info/requires.txt | 1 - Nuon_Model_Visualizer.egg-info/top_level.txt | 1 - notebooks/events_collide.ipynb | 426 ++++++++++++++++++ nuon_model_visualizer_python_sdk | 6 + requirements.txt | 3 +- 9 files changed, 543 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/docker_push.yml create mode 100644 Dockerfile delete mode 100644 Nuon_Model_Visualizer.egg-info/SOURCES.txt delete mode 100644 Nuon_Model_Visualizer.egg-info/dependency_links.txt delete mode 100644 Nuon_Model_Visualizer.egg-info/requires.txt delete mode 100644 Nuon_Model_Visualizer.egg-info/top_level.txt create mode 100644 notebooks/events_collide.ipynb create mode 100755 nuon_model_visualizer_python_sdk diff --git a/.github/workflows/docker_push.yml b/.github/workflows/docker_push.yml new file mode 100644 index 0000000..696825f --- /dev/null +++ b/.github/workflows/docker_push.yml @@ -0,0 +1,22 @@ +on: [push] + +jobs: + nuon_model_visualizer_job: + runs-on: ubuntu-latest + name: NuonModelVisualizer + steps: + - uses: actions/checkout@v2 + name: Check out code + - name: Login to DockerHub + uses: docker/login-action@v1.8.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push Docker Python SDK image + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: ${{ secrets.DOCKERHUB_ORGANIZATION }}/nuon-model-visualizer:latest + - name: Image digest + run: echo ${{ steps.docker_build.outputs.digest }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a8e499e --- /dev/null +++ b/Dockerfile @@ -0,0 +1,88 @@ + +# The Blue Brain BioExplorer is a tool for scientists to extract and analyse +# scientific data from visualization +# +# Copyright 2020-2023 Blue BrainProject / EPFL +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU General Public License as published by the Free Software +# Foundation, either version 3 of the License, or (at your option) any later +# version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more +# details. +# +# You should have received a copy of the GNU General Public License along with +# this program. If not, see . + +FROM python:3.10-slim as builder +LABEL maintainer="cyrille.favreau@epfl.ch" + +RUN apt-get update && \ + apt-get install -y --no-install-recommends wget git g++ gcc binutils libxpm-dev libxft-dev libxext-dev python3 libssl-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* + +# -------------------------------------------------------------------------------- +# Install ROOT +# -------------------------------------------------------------------------------- +ARG ROOT_VERSION=6.30.04 +ARG ROOT_DIR=root_v${ROOT_VERSION}.Linux-ubuntu22.04-x86_64-gcc11.4 +ARG ROOT_PATH=/app/$ROOT_DIR + +RUN mkdir -p ${ROOT_PATH} \ + && wget --no-verbose https://root.cern/download/${ROOT_DIR}.tar.gz \ + && tar zxvf ${ROOT_DIR}.tar.gz -C ${ROOT_PATH} --strip-components=1 \ + && rm ${ROOT_DIR}.tar.gz + +# Add ROOT bin to the PATH +ENV PATH $PATH:${ROOT_PATH}/bin +ENV PYTHONPATH $PYTHONPATH:${ROOT_PATH}/lib + +WORKDIR /app +ADD . /app/NuonModelVisualizer + +RUN cd /app/NuonModelVisualizer && \ + python3 -m venv /app/NuonModelVisualizer/env \ + && . /app/NuonModelVisualizer/env/bin/activate \ + && python3 -m pip install --upgrade pip --use-deprecated=legacy-resolver \ + && python3 -m pip install wheel \ + && python3 -m pip install -e . + +# -------------------------------------------------------------------------------- +# Install BioExplorer +# https://github.com/favreau/BioExplorer +# -------------------------------------------------------------------------------- +ARG BIOEXPLORER_SRC=/app/bioexplorer + +RUN mkdir -p ${BIOEXPLORER_SRC} \ + && git clone https://github.com/favreau/BioExplorer.git ${BIOEXPLORER_SRC} \ + && cd ${BIOEXPLORER_SRC}/bioexplorer/pythonsdk \ + && . /app/NuonModelVisualizer/env/bin/activate \ + && pip install . --use-deprecated=legacy-resolver + +# -------------------------------------------------------------------------------- +# Install Rockets (from favreau for Python 3.10) +# https://github.com/favreau/Rockets +# -------------------------------------------------------------------------------- +ARG ROCKETS_SRC=/app/rockets + +RUN mkdir -p ${ROCKETS_SRC} \ + && git clone https://github.com/favreau/Rockets.git ${ROCKETS_SRC} \ + && cd ${ROCKETS_SRC}/python \ + && . /app/NuonModelVisualizer/env/bin/activate \ + && pip install . --use-deprecated=legacy-resolver \ + && pip install numpy==1.22.4 + +ENV PATH /app/NuonModelVisualizer:$PATH + +RUN chmod +x /app/NuonModelVisualizer/nuon_model_visualizer_python_sdk + +# Expose a port from the container +# For more ports, use the `--expose` flag when running the container, +# see https://docs.docker.com/engine/reference/run/#expose-incoming-ports for docs. +EXPOSE 8888 + +ENTRYPOINT ["nuon_model_visualizer_python_sdk"] diff --git a/Nuon_Model_Visualizer.egg-info/SOURCES.txt b/Nuon_Model_Visualizer.egg-info/SOURCES.txt deleted file mode 100644 index f8c34da..0000000 --- a/Nuon_Model_Visualizer.egg-info/SOURCES.txt +++ /dev/null @@ -1,11 +0,0 @@ -README.md -setup.cfg -setup.py -Nuon_Model_Visualizer.egg-info/PKG-INFO -Nuon_Model_Visualizer.egg-info/SOURCES.txt -Nuon_Model_Visualizer.egg-info/dependency_links.txt -Nuon_Model_Visualizer.egg-info/requires.txt -Nuon_Model_Visualizer.egg-info/top_level.txt -nuon_model_visualizer/__init__.py -nuon_model_visualizer/nuon_model_visualizer.py -nuon_model_visualizer/version.py \ No newline at end of file diff --git a/Nuon_Model_Visualizer.egg-info/dependency_links.txt b/Nuon_Model_Visualizer.egg-info/dependency_links.txt deleted file mode 100644 index 8b13789..0000000 --- a/Nuon_Model_Visualizer.egg-info/dependency_links.txt +++ /dev/null @@ -1 +0,0 @@ - diff --git a/Nuon_Model_Visualizer.egg-info/requires.txt b/Nuon_Model_Visualizer.egg-info/requires.txt deleted file mode 100644 index cbf4e4f..0000000 --- a/Nuon_Model_Visualizer.egg-info/requires.txt +++ /dev/null @@ -1 +0,0 @@ -bioexplorer~=1.7.1 diff --git a/Nuon_Model_Visualizer.egg-info/top_level.txt b/Nuon_Model_Visualizer.egg-info/top_level.txt deleted file mode 100644 index ddb98e3..0000000 --- a/Nuon_Model_Visualizer.egg-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -nuon_model_visualizer diff --git a/notebooks/events_collide.ipynb b/notebooks/events_collide.ipynb new file mode 100644 index 0000000..840e714 --- /dev/null +++ b/notebooks/events_collide.ipynb @@ -0,0 +1,426 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from bioexplorer import BioExplorer, Widgets, TransferFunction, MovieMaker\n", + "from nuon_model_visualizer import NuonModelVisualizer\n", + "from IPython.display import clear_output\n", + "from ipywidgets import IntSlider\n", + "\n", + "import os\n", + "import seaborn as sns" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "be_url = 'localhost:5000'\n", + "use_cpu = True\n", + "be = BioExplorer(be_url)\n", + "core = be.core_api()\n", + "nmv = NuonModelVisualizer(\n", + " bio_explorer=be,\n", + " root_proton_file='../keep_findall_64004.root',\n", + " root_collision_file='../collide_298792_events.root')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def set_field_parameters():\n", + " if use_cpu:\n", + " nmv.set_field_parameters(\n", + " cutoff_distance=350,\n", + " sampling_rate=1.25,\n", + " gradient_shading=False, gradient_offset=0.01, epsilon=1.5, \n", + " accumulation_steps=0,\n", + " use_octree=True\n", + " )\n", + " else:\n", + " nmv.set_field_parameters(\n", + " cutoff_distance=500,\n", + " sampling_rate=0.25,\n", + " gradient_shading=False, gradient_offset=0.01, epsilon=0.25, \n", + " accumulation_steps=0,\n", + " use_octree=True\n", + " )\n", + "set_field_parameters()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if True:\n", + " core.set_camera(\n", + " current='perspective',\n", + " orientation=[-0.3234696528321516, 0.7512876706246714, 0.5041260587420526, 0.2771121371596832],\n", + " position=[0.9307057768653164, 9.661146740468132, -3.467553964472151],\n", + " target=[0.0, 0.0, 0.019711971282959873], \n", + " )\n", + " params = core.PerspectiveCameraParams()\n", + " params.main_exposure = 1.5\n", + " core.set_camera_params(params)\n", + "else:\n", + " core.set_camera(\n", + " current='orthographic',\n", + " orientation=[0.0, 0.0, 0.0, 1.0],\n", + " position=[-0.06137990951538086, 0.04454469680786133, 23.159679065442788],\n", + " target=[-0.06137990951538086, 0.04454469680786133, 0.438176155090332],\n", + " )\n", + " params = core.OrthographicCameraParams()\n", + " params.height = 2.5\n", + " core.set_camera_params(params)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Event collision" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "event_id = 10\n", + "\n", + "def force_reset():\n", + " while True:\n", + " be.reset_scene()\n", + " ids = be.get_model_ids()['ids']\n", + " if not ids:\n", + " break\n", + " import time\n", + " time.sleep(0.5)\n", + "\n", + "force_reset()\n", + "set_field_parameters()\n", + "if use_cpu:\n", + " nmv.plot_event(\n", + " # event_id, 'nuons_v22.1dt',\n", + " event_id, 'nuons_v22_cpu.1dt',\n", + " value_range=[-0.005, 0.08],\n", + " timestamp=-1.01, \n", + " magnetic=True, show_grid=True, z_scale=1.0,\n", + " marker_size=2.0, voxel_size=0.1,\n", + " # export_filename='/home/favreau/Videos/particles/20240219/afmhot/00000/v6/00000.png'\n", + " )\n", + "else:\n", + " nmv.plot_event(\n", + " event_id, 'nuons_v22.1dt',\n", + " value_range=[-0.005, 0.08],\n", + " timestamp=-1.01, \n", + " magnetic=True, show_grid=True, z_scale=1.0,\n", + " marker_size=2.0, voxel_size=0.1,\n", + " # export_filename='/home/favreau/Videos/particles/20240219/afmhot/00000/v6/00000.png'\n", + " )\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "status = core.set_renderer(\n", + " background_color=[0,0,0],\n", + " current='advanced',subsampling=4, max_accum_frames=128)\n", + "params = core.AdvancedRendererParams()\n", + "params.gi_ray_length = 1000.0\n", + "params.shadow_intensity = 0.0\n", + "params.soft_shadow_strength = 0.25\n", + "params.epsilon_multiplier = 1.0\n", + "# params.max_ray_depth = 30\n", + "params.max_ray_depth = 3\n", + "params.show_background = False\n", + "params.main_exposure = 10.0\n", + "status = core.set_renderer_params(params)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "stop" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Individual snapshot" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mm = MovieMaker(be)\n", + "mm.create_snapshot(\n", + " renderer='advanced',\n", + " path='/tmp', base_name='test',\n", + " samples_per_pixel=32, size=[512, 512])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Render all events" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "output_folder = '/home/favreau/Videos/particles/20240219/afmhot'\n", + "os.makedirs(output_folder, exist_ok=True)\n", + "for event_id in tqdm(range(10)):\n", + " clear_output()\n", + " nmv.plot_event(event_id, 'nuons_v19.1dt', True, timestamp=0.0)\n", + " mm.create_snapshot(\n", + " renderer='advanced',\n", + " path=output_folder, base_name='%05d' % event_id,\n", + " samples_per_pixel=64, size=[1080, 1080])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Event collision animation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "mm = MovieMaker(be)\n", + "\n", + "magnetic = True\n", + "show_grid = False\n", + "\n", + "spp = 128\n", + "suffix = 'fields'\n", + "if not magnetic:\n", + " spp = 64\n", + " suffix = 'diagram'\n", + "image_size = [512, 512]\n", + "time_interval = [-3.5, 3.5, 0.1]\n", + "\n", + "for event_id in range(nmv.get_nb_events()):\n", + " output_folder = '/gpfs/bbp.cscs.ch/project/proj129/scratch/particles/20240313/%05d/%s' % (event_id, suffix)\n", + " os.makedirs(output_folder, exist_ok=True)\n", + "\n", + " set_field_parameters()\n", + "\n", + " frame = 0\n", + " timestamp = time_interval[0] # to avoid particles at the exact same location\n", + " while timestamp<=time_interval[1]:\n", + " clear_output()\n", + " force_reset()\n", + "\n", + " export_filename = None\n", + " if time_interval == 1.0:\n", + " export_filename = os.path.join(output_folder, '%05d.png' % event_id)\n", + "\n", + " if use_cpu:\n", + " nmv.plot_event(\n", + " event_id, 'nuons_v22_cpu.1dt',\n", + " magnetic=magnetic, z_scale=1.0,\n", + " timestamp=timestamp + 0.01, marker_size=2.0,\n", + " voxel_size=0.1, value_range=[-0.005, 0.07],\n", + " export_filename=export_filename, show_grid=show_grid\n", + " )\n", + " else:\n", + " nmv.plot_event(\n", + " event_id, 'nuons_v22.1dt',\n", + " magnetic=magnetic, z_scale=1.0,\n", + " timestamp=timestamp + 0.01, marker_size=2.0,\n", + " voxel_size=0.1, value_range=[-0.005, 0.07],\n", + " export_filename=export_filename, show_grid=show_grid\n", + " )\n", + "\n", + " mm.create_snapshot(\n", + " renderer='advanced',\n", + " path=output_folder, base_name='%05d' % frame,\n", + " size=image_size,\n", + " samples_per_pixel=spp, \n", + " )\n", + " frame += 1\n", + " timestamp += time_interval[2]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Testing" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "model_id = be.get_model_ids()['ids'][-1:][0]\n", + "tf = TransferFunction(\n", + " bioexplorer=be, model_id=model_id,\n", + " filename='nuons_v22_cpu.1dt',\n", + " # size=10, name='Set1', alpha=0.1,\n", + " # value_range=[-0.005, 0.06],\n", + " value_range=[-0.005, 0.08],\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tf.set_range([-0.005, 0.06])\n", + "# tf.set_palette('Set2')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nmv.set_field_parameters(\n", + " cutoff_distance=350,\n", + " sampling_rate=0.25,\n", + " gradient_shading=False, gradient_offset=0.01, epsilon=1.0, \n", + " accumulation_steps=0,\n", + " use_octree=True\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "tf.save('nuons_v22_cpu.1dt')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Event browser" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def update_event(value):\n", + " nmv.plot_event(value.new, 'nuons_v19.1dt', magnetic=True, voxel_size=0.05)\n", + " \n", + "event_slider = IntSlider(min=0, max=1000)\n", + "event_slider.observe(update_event, \"value\")\n", + "display(event_slider)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "model_id = be.get_model_ids()['ids'][-1:][0]\n", + "tf = TransferFunction(\n", + " bioexplorer=be, model_id=model_id,\n", + " filename='nuons_v18.1dt',\n", + " value_range=[0.0, 0.025],\n", + ")\n", + "\n", + "def update_colormap(value):\n", + " tf.set_palette(Widgets.COLOR_MAPS[value.new])\n", + " \n", + "colormap_slider = IntSlider(min=0, max=len(Widgets.COLOR_MAPS))\n", + "colormap_slider.observe(update_colormap, \"value\")\n", + "display(colormap_slider)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nb_frames = 25\n", + "\n", + "status = core.set_camera(\n", + " orientation=[0.0, 0.0, 0.0, 1.0],\n", + " position=[-3.4689903259277344e-05, -5.841255187544192e-06, 4.3377393854193365],\n", + " target=[-3.4689903259277344e-05, -5.841255187544192e-06, 1.9173471992531512]\n", + ")\n", + "\n", + "for event_id in tqdm(range(1000)):\n", + " output_folder = '/home/favreau/Videos/particles/v7/%05d' % event_id\n", + " os.makedirs(output_folder, exist_ok=True)\n", + " for i in tqdm(range(nb_frames)):\n", + " clear_output()\n", + " nmv.plot_event(event_id, 'nuons_v12.1dt', True, timestamp=float(i) / 10.0)\n", + " mm.create_snapshot(\n", + " renderer='bio_explorer_fields',\n", + " path=output_folder, base_name='%05d' % i,\n", + " samples_per_pixel=64, size=[1080, 1080])" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/nuon_model_visualizer_python_sdk b/nuon_model_visualizer_python_sdk new file mode 100755 index 0000000..f014742 --- /dev/null +++ b/nuon_model_visualizer_python_sdk @@ -0,0 +1,6 @@ +#!/bin/sh + +cd /app/root_v6.30.04.Linux-ubuntu22.04-x86_64-gcc11.4/bin +. thisroot.sh +. /app/NuonModelVisualizer/env/bin/activate +jupyter notebook --allow-root --ip=0.0.0.0 --port=8888 --notebook-dir=/app/NuonModelVisualizer/notebooks --NotebookApp.token='' --NotebookApp.password='' diff --git a/requirements.txt b/requirements.txt index bffd366..6f914b6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -17,5 +17,4 @@ # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # All rights reserved. Do not distribute without further notice. - -bioexplorer~=1.7.1 +# bioexplorer~=1.7.1