diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..af96791fc63ed27af167ba8856d2a0088506d0cc --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.vscode +build diff --git a/CMakeLists.txt b/CMakeLists.txt index a1ea9f56542c851155ec9eb1199fd9a1ce1d89c2..31220fe87030cc1f0658c3b2fa2e13ab736c0fcd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,7 +40,7 @@ set( MODULE_NAME ${SHORT_NAME}module ) # 2) Add all your sources here set( MODULE_SOURCES streamingmodule.h streamingmodule.cpp - recording_backend_nesci_contra.h recording_backend_nesci_contra.cpp + streaming_recording_backend.h streaming_recording_backend.cpp ) # 3) We require a header name like this: @@ -179,6 +179,17 @@ execute_process( OUTPUT_STRIP_TRAILING_WHITESPACE ) +#-------------------------------------------------------------------- +set(CMAKE_CXX_STANDARD 14) + +if (NOT CONTRA_TRANSPORT) + set(CONTRA_TRANSPORT shared_memory) +endif() + +find_package(contra COMPONENTS contra ${CONTRA_TRANSPORT} REQUIRED) +find_package(nesci COMPONENTS producer REQUIRED) +#-------------------------------------------------------------------- + # on OS X set( CMAKE_MACOSX_RPATH ON ) @@ -231,14 +242,13 @@ add_custom_target( dist COMMENT "Creating a source distribution from ${MODULE_NAME}..." ) -include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup( TARGETS ) +add_subdirectory(demos) if ( BUILD_SHARED_LIBS ) # When building shared libraries, also create a module for loading at runtime # with the `Install` command. add_library( ${MODULE_NAME}_module MODULE ${MODULE_SOURCES} ) - target_link_libraries( ${MODULE_NAME}_module CONAN_PKG::nesci CONAN_PKG::contra ) + target_link_libraries( ${MODULE_NAME}_module nesci::producer contra::${CONTRA_TRANSPORT} ) set_target_properties( ${MODULE_NAME}_module PROPERTIES COMPILE_FLAGS "${NEST_CXXFLAGS} -DLTX_MODULE" @@ -252,7 +262,7 @@ endif () # Build dynamic/static library for standard linking from NEST. add_library( ${MODULE_NAME}_lib ${MODULE_SOURCES} ) -target_link_libraries( ${MODULE_NAME}_lib CONAN_PKG::nesci CONAN_PKG::contra ) +target_link_libraries( ${MODULE_NAME}_lib nesci::producer contra::${CONTRA_TRANSPORT} ) if ( BUILD_SHARED_LIBS ) # Dynamic libraries are initiated by a `global` variable of the `SLIModule`, # which is included, when the flag `LINKED_MODULE` is set. @@ -296,7 +306,6 @@ if ( NOT CMAKE_CROSSCOMPILING ) ) endif () - message( "" ) message( "-------------------------------------------------------" ) message( "${MODULE_NAME} Configuration Summary" ) diff --git a/CPPLINT.cfg b/CPPLINT.cfg new file mode 100644 index 0000000000000000000000000000000000000000..ce7c7e4c264e5a39da61062cc86686e28865fee8 --- /dev/null +++ b/CPPLINT.cfg @@ -0,0 +1,4 @@ +set noparent +filter=-readability/check,-build/c++tr1,-build/c++11,-build/c++14 +linelength=80 +headers=h,hpp diff --git a/README.md b/README.md index 84571b76334196e2989fe88346b6f463b5ff2476..959031604698864c49194136ac7276d464606bde 100644 --- a/README.md +++ b/README.md @@ -3,15 +3,15 @@ ## Prerequisites * CMake >= 3.6.0 (https://cmake.org/) * Python 2.7 (https://www.python.org/) -* Conan (`pip install conan`) -* NEST: the latest release of NEST does currently not support modules. Thus, a custom version is required that can be found [here](https://github.com/jougs/nest-simulator/tree/feature/custom-recording-backend). +* NEST: the latest release of NEST does currently not support modules. Thus, a custom version is required that can be found [here](https://github.com/jougs/nest-simulator/tree/feature/custom-recording-backend). You need to checkout and build the branch `feature/custom-recording-backend` ## Building 1. Create a build directory 2. Open terminal in build directory 3. Run CMake: `cmake -Dwith-nest=${PATH_TO_NEST_INSTALLATION} ${PATH_TO_NEST_STREAMING_MODULE_SOURCE}` -4. Build: `cmake --build .` -5. Install: `cmake --build . --target install` +4. Run Conan: `conan install ${PATH_TO_NEST_STREAMING_MODULE_SOURCE} --build=missing` +5. Build: `cmake --build .` +6. Install: `cmake --build . --target install` ## How to use the nest-streaming-module? The *nest-streaming-module* registers a new RecordingBackend to the simulator. When registering a `RecordingDevice` using PyNEST the used recording backend can be specified in the `record_to` parameter. If you want to stream the data, set this parameter to `['streaming']`. Clients that receive the data can be either written in Python or C++. See https://devhub.vr.rwth-aachen.de/VR-Group/nesci-contra-demos for examples. \ No newline at end of file diff --git a/conanfile.py b/conanfile.py deleted file mode 100644 index 89c81b32798f259395ba22372cca213e4b43691e..0000000000000000000000000000000000000000 --- a/conanfile.py +++ /dev/null @@ -1,37 +0,0 @@ -# conanfile.py -# -# This file is part of NEST. -# -# Copyright (C) 2004 The NEST Initiative -# -# NEST 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 2 of the License, or -# (at your option) any later version. -# -# NEST 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 NEST. If not, see <http://www.gnu.org/licenses/> - -from conans import ConanFile, CMake - -class nest(ConanFile): - name = "NEST" - version = "18.05" - license = "GNU General Public License, Version 2" - description = """NEST is a simulator for spiking neural network models that focuses on the dynamics, size and structure of neural systems rather than on the exact morphology of individual neurons.""" - settings = "os", "compiler", "build_type", "arch" - - requires = (("contra/18.05@RWTH-VR/develop"), - ("nesci/18.05@RWTH-VR/develop")) - generators = "cmake" - - def configure(self): - pass - - def imports(self): - pass diff --git a/demos/CMakeLists.txt b/demos/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..406fe9e6e986f14f50b815e53eacb80d1dafea05 --- /dev/null +++ b/demos/CMakeLists.txt @@ -0,0 +1,33 @@ +#------------------------------------------------------------------------------- +# nest-streaming-module +# +# Copyright (c) 2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualization Group. +#------------------------------------------------------------------------------- +# License +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +option(BUILD_BRUNEL_SIMULATION "Build the brunel simulation" ON) +option(BUILD_QVTK_DEMO "Build the QVTK visualization demo" OFF) + +if (${BUILD_BRUNEL_SIMULATION}) + add_subdirectory(brunel_simulation) +endif (${BUILD_BRUNEL_SIMULATION}) + +if (${BUILD_QVTK_DEMO}) + add_subdirectory(QVTK-Demo) +endif (${BUILD_QVTK_DEMO}) + + diff --git a/demos/QVTK-Demo/CMakeLists.txt b/demos/QVTK-Demo/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..492be448f7d430f12d10ca085c0e18ce7c72454e --- /dev/null +++ b/demos/QVTK-Demo/CMakeLists.txt @@ -0,0 +1,24 @@ +#------------------------------------------------------------------------------- +# QVTK-Demo +# +# Copyright (c) 2017-2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualization Group. +#------------------------------------------------------------------------------- +# License +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +add_subdirectory(qvtk-app) +add_subdirectory(qvtk-lib) + diff --git a/demos/QVTK-Demo/Readme.txt b/demos/QVTK-Demo/Readme.txt new file mode 100644 index 0000000000000000000000000000000000000000..8602ac1f9b151f31187404906c1cbde5b65e521d --- /dev/null +++ b/demos/QVTK-Demo/Readme.txt @@ -0,0 +1,36 @@ +#------------------------------------------------------------------------------- +# QVTK-Demo +# +# Copyright (c) 2017-2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualization Group. +#------------------------------------------------------------------------------- +# License +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +This is a brief summary on how to get the QVTK-Demo running. + +Prerequisites: + -QT (Version 5.9 or higher is advised! -older versions might work aswell but havent been tested). + -Get this first and build it. + -The Visualization Toolkit(VTK) (The demo was originally build with version 8.0.1. Newer versions should work too but havent been tested). + -Ŵhen building VTK with CMake make sure you enable VTK_BUILD_QT_DESIGNER_PLUGIN, VTK_Group_Qt and set VTK_QT_VERSION to 5. + +Installing: +When running CMake enable BUILD_QVTK_DEMO and BUILD_BRUNEL_SIMULATION. + +Running the Demo: +To run the Demo start both, the QVTK-Demo(qvtk-app) and the Brunel Simulation(run_sim.sh) from your build folder. + + diff --git a/demos/QVTK-Demo/qvtk-app/CMakeLists.txt b/demos/QVTK-Demo/qvtk-app/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..aa8b8c96f551b878ec5dfbbb749c9b7d9e5c0009 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-app/CMakeLists.txt @@ -0,0 +1,71 @@ +#------------------------------------------------------------------------------- +# QVTK-Demo +# +# Copyright (c) 2017-2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualisation Group. +#------------------------------------------------------------------------------- +# License +# +# This framework is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# In the future, we may decide to add a commercial license +# at our own discretion without further notice. +# +# 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesse r General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +#------------------------------------------------------------------------------- + +set(CMAKE_AUTOMOC ON) +set(QVTK_APP_API_HEADER_DIR include/qvtk_app) + +file(GLOB QVTK_APP_SOURCES src/*.cpp) +file(GLOB QVTK_APP_HEADERS include/qvtk_app/*.hpp) +file(GLOB QVTK_APP_API_HEADERS ${QVTK_APP_API_HEADER_DIR}/*.hpp) +file(GLOB QVTK_APP_SUPPRESS_WARNING_HEADERS include/qvtk_app/suppress_warnings/Qt *.hpp) + +add_executable(qvtk_app + ${QVTK_APP_SOURCES} + ${QVTK_APP_HEADERS} + ${QVTK_APP_API_HEADERS} + ${QVTK_APP_SUPPRESS_WARNING_HEADERS} +) + +target_include_directories( + qvtk_app PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${CMAKE_BINARY_DIR} +) + +#add_test_cpplint(NAME "qvtk_app--cpplint" +# ${QVTK_APP_SOURCES} +# ${QVTK_APP_HEADERS} +# ${QVTK_APP_API_HEADERS} +# ${QVTK_APP_SUPPRESS_WARNING_HEADERS} +#) + +set_warning_levels_RWTH(qvtk_app + SUPPRESS_WARNINGS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/include/qt_app/suppress_warnings.hpp +) + +include_directories(include) + +# --- dependencies --- + +# VTK +find_package(VTK REQUIRED) +include(${VTK_USE_FILE}) +target_include_directories(qvtk_app PUBLIC ${VTK_INCLUDE_DIR}) + +#vtkexperiment +target_include_directories(qvtk_app PUBLIC ${QVTK_LIB_INCLUDE_DIRS}) + +target_link_libraries(qvtk_app PUBLIC qvtk-lib debug ${VTK_LIBRARIES} optimized ${VTK_LIBRARIES}) + diff --git a/demos/QVTK-Demo/qvtk-app/include/qvtk_app/application.hpp b/demos/QVTK-Demo/qvtk-app/include/qvtk_app/application.hpp new file mode 100644 index 0000000000000000000000000000000000000000..b2beda8abf3487f26919ba90f914135075bb5e5c --- /dev/null +++ b/demos/QVTK-Demo/qvtk-app/include/qvtk_app/application.hpp @@ -0,0 +1,49 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_APP_INCLUDE_QVTK_APP_APPLICATION_HPP_ +#define QVTK_APP_INCLUDE_QVTK_APP_APPLICATION_HPP_ + +#include "QApplication" + +#include "qvtk-lib/main_window.hpp" +#include "qvtk-lib/point_data.hpp" + +class Application +{ +public: + Application(int *argc, char **argv); + ~Application() {} + + int Run(); + +private: + QApplication qt_app_; + + vtkexp::PointData points_; + vtkexp::MainWindow window_; +}; + +#endif // QVTK_APP_INCLUDE_QVTK_APP_APPLICATION_HPP_ diff --git a/demos/QVTK-Demo/qvtk-app/src/application.cpp b/demos/QVTK-Demo/qvtk-app/src/application.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3b5fd95dab12a074e3b1eb5875cb22666947bb9c --- /dev/null +++ b/demos/QVTK-Demo/qvtk-app/src/application.cpp @@ -0,0 +1,35 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk_app/application.hpp" + +Application::Application(int *argc, char **argv) + : qt_app_{*argc, argv}, points_(6, 6, 1), window_{&points_} {} + +int Application::Run() +{ + window_.show(); + return qt_app_.exec(); +} diff --git a/demos/QVTK-Demo/qvtk-app/src/main.cpp b/demos/QVTK-Demo/qvtk-app/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1fc8d5018dc15715da06ac22aace0dd6ab7a78b6 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-app/src/main.cpp @@ -0,0 +1,32 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk_app/application.hpp" + +int main(int argc, char **argv) +{ + Application app(&argc, argv); + return app.Run(); +} diff --git a/demos/QVTK-Demo/qvtk-lib/CMakeLists.txt b/demos/QVTK-Demo/qvtk-lib/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..32ce237d4fbb58314fee48eb5541bf8bc4f9ba4a --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/CMakeLists.txt @@ -0,0 +1,83 @@ +#------------------------------------------------------------------------------- +# QVTK-Demo +# +# Copyright (c) 2017-2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualisation Group. +#------------------------------------------------------------------------------- +# License +# +# This framework is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# In the future, we may decide to add a commercial license +# at our own discretion without further notice. +# +# 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 Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesse r General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. +#------------------------------------------------------------------------------- + +set(CMAKE_AUTOMOC ON) +set(QVTK_LIB_API_HEADER_DIR include/qvtk-lib) + +file(GLOB QVTK_LIB_SOURCES src/*.cpp) +file(GLOB QVTK_LIB_HEADERS include/qvtk-lib/*.hpp) +file(GLOB QVTK_LIB_API_HEADERS ${QVTK_LIB_API_HEADER_DIR}/*.hpp) + +set(QVTK_LIB_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/include + ${PROJECT_SOURCE_DIR}qvtk-lib/include + ${PROJECT_BINARY_DIR} + CACHE PATH "Path to public headers in vtk's source tree." +) + +add_library(qvtk-lib + ${QVTK_LIB_SOURCES} + ${QVTK_LIB_HEADERS} +) + +target_include_directories(qvtk-lib + PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} + PUBLIC ${CMAKE_CURRENT_BINARY_DIR} +) + +generate_export_header(qvtk-lib + EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/include/qvtk-lib/export.hpp +) + +set_warning_levels_RWTH(qvtk-lib + SUPPRESS_WARNINGS_HEADER ${CMAKE_CURRENT_BINARY_DIR}/include/qvtk-lib/suppress_warnings.hpp +) + +#add_test_cpplint(NAME "vtkexperiment--cpplint" +# ${VTKEXPERIMENT_SOURCES} +# ${VTKEXPERIMENT_HEADERS} +#) + +include_directories(include) + +# --- dependencies --- +# VTK +find_package(VTK REQUIRED) +include(${VTK_USE_FILE}) +target_include_directories(qvtk-lib PUBLIC ${VTK_INCLUDE_DIR}) + +target_include_directories(qvtk-lib PUBLIC + ${CONAN_INCLUDE_DIRS} +) + +target_link_libraries(qvtk-lib + PUBLIC ${CONAN_OR_CMAKE_contra} + PUBLIC ${CONAN_OR_CMAKE_nesci} + PUBLIC ${CONAN_OR_CMAKE_conduit} + PUBLIC ${CONAN_OR_CMAKE_Qt} + PUBLIC ${CONAN_OR_CMAKE_VTK} + debug ${VTK_LIBRARIES} + optimized ${VTK_LIBRARIES} +) diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/animate.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/animate.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bdedbbb2a48fbb1af8ebc09ba19d67a7ce51dad8 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/animate.hpp @@ -0,0 +1,76 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_ANIMATE_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_ANIMATE_HPP_ + +#include "QObject" +#include "QTimer" + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#include "qvtk-lib/point_data.hpp" +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +class Animate : public QObject +{ + Q_OBJECT + +public: + explicit Animate(PointData *points); + ~Animate() {} + + void StartTimer(); + +signals: + void DataChanged(); + void DataChanged(int time_step); + void NextStep(); + void LastStep(); + void SwitchRealtime(); + void SwitchPlayPause(); + +public slots: // NOLINT + void ChangeData(int timestep = -1); + void IncreaseSpeed(); + void DecreaseSpeed(); + void Iterate(); + void RealtimeButton(); + void PlayButton(); + void SpeedMenu(int index); + +private: + PointData *points_; + QTimer *rt_timer_; + QTimer *play_timer_; + int play_speed_ = 1000; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_ANIMATE_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/data_stream.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/data_stream.hpp new file mode 100644 index 0000000000000000000000000000000000000000..7254ccf5045a38be1e1a0289dda4fd2773c25ec0 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/data_stream.hpp @@ -0,0 +1,64 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_DATA_STREAM_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_DATA_STREAM_HPP_ + +#include <vector> + +#include "conduit/conduit_node.hpp" +//#include "contra/boost-shmem/shared_memory_transport.hpp" +#include "contra/relay.hpp" +#include "contra/zmq/zeromq_transport.hpp" + +#include "nesci/consumer/nest_multimeter.hpp" + +namespace vtkexp +{ + +class DataStream +{ +public: + DataStream(); + ~DataStream() {} + + std::vector<double> GetMultValuesAt(int time_step); + std::vector<double> GetTimeSteps(); + +private: + void SetUpStream(); + void Update(int time_step); + + std::vector<double> mult_values_; + + contra::Relay<contra::ZMQTransport> *relay_; + nesci::consumer::NestMultimeter *multimeter_; + + conduit::Node node_; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_DATA_STREAM_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/interaction.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/interaction.hpp new file mode 100644 index 0000000000000000000000000000000000000000..cfc6b51abc9a946416fdae1aac9885ac5eef47fa --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/interaction.hpp @@ -0,0 +1,87 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_INTERACTION_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_INTERACTION_HPP_ + +#include <string> + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#include <vtkActor.h> +#include <vtkDataSetMapper.h> +#include <vtkMapper.h> +#include <vtkPointGaussianMapper.h> +#include <vtkPointPicker.h> +#include <vtkUnstructuredGrid.h> +#include "vtkInteractorStyleTrackballCamera.h" +#include "vtkPolyData.h" +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +class Interaction : public vtkInteractorStyleTrackballCamera +{ + public: + static Interaction *New(); + vtkTypeMacro(Interaction, vtkInteractorStyleTrackballCamera) + + Interaction(); + + virtual void OnLeftButtonUp(); + + void SetUpShaders(); + void SetUpActor(); + void SetUpMapper(); + + double GetNeuronValue(); + vtkIdType GetNeuronId(); + + void SetData(vtkSmartPointer<vtkPolyData> data); + void SwitchMapper(int rendertype); + void ExtractSelection(); + void HighlightSelection(); + void Deselect(); + void Pick(); + + private: + double neuron_value_; + vtkIdType id_; + vtkSmartPointer<vtkUnstructuredGrid> selected_; + + vtkSmartPointer<vtkPolyData> data_; + + vtkSmartPointer<vtkActor> actor_; + vtkSmartPointer<vtkPointGaussianMapper> mapper_; + vtkSmartPointer<vtkPointPicker> picker_; + + std::string point_shader_; + std::string sphere_shader_; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_INTERACTION_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_widget.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_widget.hpp new file mode 100644 index 0000000000000000000000000000000000000000..fd0ec97094735bb488f0a6ff010f87d9e7a80968 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_widget.hpp @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WIDGET_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WIDGET_HPP_ + +#include "qvtk-lib/visualize.hpp" + +#include "qvtk-lib/interaction.hpp" + +#include "QObject" + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "QVTKOpenGLWidget.h" +#include "vtkGenericOpenGLRenderWindow.h" +#pragma GCC diagnostic pop +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +class MainWidget : public QVTKOpenGLWidget +{ + Q_OBJECT + +public: + explicit MainWidget(PointData *points, QVTKOpenGLWidget *parent = 0); + ~MainWidget() {} + + void Rerender(); + +public slots: // NOLINT + void ChangeRendertype(int rendertype); + +protected: + void mouseReleaseEvent(QMouseEvent *event) override; + +private: + Visualize *vispoints_; + vtkSmartPointer<Interaction> style_; + vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderwindow_; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WIDGET_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_window.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_window.hpp new file mode 100644 index 0000000000000000000000000000000000000000..a9bf28246dd4a41fcfff408052b1315bd10761f2 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/main_window.hpp @@ -0,0 +1,99 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WINDOW_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WINDOW_HPP_ + +#include "include/qvtk-lib/suppress_warnings.hpp" + +#include "qvtk-lib/animate.hpp" +#include "qvtk-lib/main_widget.hpp" +SUPPRESS_WARNINGS_BEGIN +#include "qvtk-lib/point_data.hpp" +SUPPRESS_WARNINGS_END + +#include "QComboBox" +#include "QGridLayout" +#include "QLabel" +#include "QLineEdit" +#include "QMainWindow" +#include "QPushButton" +#include "QSlider" +#include "QTimer" + +namespace vtkexp +{ + +class MainWindow : public QMainWindow +{ + Q_OBJECT + +public: + explicit MainWindow(PointData *points); + ~MainWindow() {} + + QLineEdit *slider_line_edit_; + +public slots: // NOLINT + void Rerender(); + void Realtime(); + void PlayPause(); + void IncrementSlider(); + void UpdateSlider(); + void AdjustSlider(); + void SliderValue(); + void SliderValue(int time_step); + +private: + void ConnectSignals(); + void InitSlider(QSlider *slider); + void SetUpButtons(); + void SetUpContent(); + void SetUpLayout(); + void SetUpLineEdit(); + void SetUpSliders(); + void SetUpVisualization(); + void StartAnimation(); + + Animate *animation_; + PointData *points_; + + QWidget *dummywidget_; + MainWidget *mainwidget_; + QComboBox *render_type_; + QComboBox *speed_menu_; + QPushButton *rt_button_; + QPushButton *play_button_; + QGridLayout *grid_; + QLabel *time_label_; + QSlider *time_slider_; + + bool realtime_{true}; + bool play_{true}; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_MAIN_WINDOW_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/point_data.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/point_data.hpp new file mode 100644 index 0000000000000000000000000000000000000000..934ccb63c71b959d625599c0d47165c43f71e4c8 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/point_data.hpp @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_POINT_DATA_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_POINT_DATA_HPP_ + +#include <vector> + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#include "qvtk-lib/data_stream.hpp" + +#include "vtkDataObject.h" +#include "vtkFloatArray.h" +#include "vtkPolyData.h" +#include "vtkSmartPointer.h" +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +class PointData +{ +public: + PointData(int num_x, int num_y, int num_z); + ~PointData() {} + + void Update(int time_step = -1); + vtkSmartPointer<vtkPolyData> GetPolyPoints(); + vtkSmartPointer<vtkFloatArray> GetColors() const; + + int GetEndTime() const; + int GetStartTime() const; + +private: + void AttachColorsToPoints(const std::vector<double> &colors); + static vtkSmartPointer<vtkPoints> CreatePoints(int num_x, int num_y, + int num_z); + void Initialize(int x, int y, int z); + void ColorsModified(); + + DataStream *stream_; + + int num_points_; + vtkSmartPointer<vtkPolyData> points_polydata_; + vtkSmartPointer<vtkFloatArray> pointcolors_; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_POINT_DATA_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/visualize.hpp b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/visualize.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9b0fc750c88a364b742638dfca86b0cfaef2a5bc --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/include/qvtk-lib/visualize.hpp @@ -0,0 +1,98 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#ifndef QVTK_LIB_INCLUDE_QVTK_LIB_VISUALIZE_HPP_ +#define QVTK_LIB_INCLUDE_QVTK_LIB_VISUALIZE_HPP_ + +#include <string> + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "qvtk-lib/interaction.hpp" +#include "qvtk-lib/point_data.hpp" + +#include "vtkActor.h" +#include "vtkAxesActor.h" +#include "vtkColorTransferFunction.h" +#include "vtkGenericOpenGLRenderWindow.h" +#include "vtkOrientationMarkerWidget.h" +#include "vtkPointGaussianMapper.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRenderer.h" +#include "vtkScalarBarActor.h" +#include "vtkScalarBarWidget.h" +#include "vtkSmartPointer.h" +#pragma GCC diagnostic pop +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +class Visualize +{ +public: + explicit Visualize(PointData *points); + ~Visualize() {} + + void Initialize(vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderwindow, + vtkSmartPointer<vtkRenderWindowInteractor> interactor); + vtkSmartPointer<vtkRenderer> GetRenderer(); + + void SwitchMapper(int rendertype); + +private: + void SetUpAxes(); + void SetUpInteractor(); + void SetUpLegend(); + void SetUpMapper(); + void SetUpRenderer(); + void SetUpScene(); + void SetUpShaders(); + void SetUpTransferFunction(); + + PointData *points_; + + std::string point_shader_; + std::string sphere_shader_; + + vtkSmartPointer<vtkActor> actor_; + vtkSmartPointer<vtkRenderer> renderer_; + vtkSmartPointer<vtkRenderWindowInteractor> interactor_; + vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderwindow_; + + vtkSmartPointer<vtkPointGaussianMapper> mapper_; + vtkSmartPointer<vtkColorTransferFunction> transfer_function_; + + vtkSmartPointer<vtkAxesActor> axes_; + vtkSmartPointer<vtkOrientationMarkerWidget> axes_widget_; + vtkSmartPointer<vtkScalarBarWidget> scalar_bar_widget_; + vtkSmartPointer<vtkScalarBarActor> scalar_bar_; +}; + +} // namespace vtkexp + +#endif // QVTK_LIB_INCLUDE_QVTK_LIB_VISUALIZE_HPP_ diff --git a/demos/QVTK-Demo/qvtk-lib/src/animate.cpp b/demos/QVTK-Demo/qvtk-lib/src/animate.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fb736464121e7be169c2964721cefc1bc50b45fa --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/animate.cpp @@ -0,0 +1,107 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk-lib/animate.hpp" + +namespace vtkexp +{ + +Animate::Animate(PointData *points) : points_(points) +{ + rt_timer_ = new QTimer(this); + play_timer_ = new QTimer(this); + connect(rt_timer_, SIGNAL(timeout()), this, SLOT(ChangeData())); + connect(play_timer_, SIGNAL(timeout()), this, SLOT(Iterate())); +} + +void Animate::ChangeData(int time_step) +{ + points_->Update(time_step); + emit DataChanged(); +} + +void Animate::IncreaseSpeed() { play_speed_ += 1; } + +void Animate::DecreaseSpeed() { play_speed_ -= 1; } + +void Animate::Iterate() +{ + rt_timer_->isActive() ? emit LastStep() : emit NextStep(); +} + +void Animate::StartTimer() +{ + rt_timer_->start(1); + play_timer_->start(play_speed_); +} + +void Animate::RealtimeButton() +{ + if (rt_timer_->isActive()) + { + rt_timer_->stop(); + emit SwitchRealtime(); + } + else + { + rt_timer_->start(1); + emit SwitchRealtime(); + } +} + +void Animate::SpeedMenu(int index) +{ + switch (index) + { + case 0: + play_speed_ = 1000; + break; + case 1: + play_speed_ = 1000 / 5; + break; + case 2: + play_speed_ = 1000 / 10; + break; + case 3: + play_speed_ = 1000 / 50; + break; + case 4: + play_speed_ = 1000 / 100; + break; + default: + play_speed_ = 1000; + break; + } + play_timer_->setInterval(play_speed_); +} + +void Animate::PlayButton() +{ + play_timer_->isActive() ? play_timer_->stop() + : play_timer_->start(play_speed_); + emit SwitchPlayPause(); +} + +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/data_stream.cpp b/demos/QVTK-Demo/qvtk-lib/src/data_stream.cpp new file mode 100644 index 0000000000000000000000000000000000000000..16d39ab583025c37bb8a81023f361835eb6ec853 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/data_stream.cpp @@ -0,0 +1,78 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk-lib/data_stream.hpp" + +#include <vector> + +namespace vtkexp +{ + +DataStream::DataStream() { SetUpStream(); } + +void DataStream::SetUpStream() +{ + relay_ = new contra::Relay<contra::ZMQTransport>( + contra::ZMQTransport::Type::CLIENT, "tcp://localhost:5555"); + + multimeter_ = new nesci::consumer::NestMultimeter("recordingNode51"); + multimeter_->SetNode(&node_); +} + +void DataStream::Update(int time_step) +{ + auto time_step_string = std::to_string(static_cast<double>(time_step)); + + const auto received_nodes = relay_->Receive(); + for (auto node : received_nodes) + { + node_.update(node); + } + + if (time_step == -1 && !multimeter_->GetTimesteps().empty()) + { + time_step_string = multimeter_->GetTimesteps().back(); + } + + mult_values_ = multimeter_->GetTimestepData(time_step_string, "V_m"); +} + +std::vector<double> DataStream::GetMultValuesAt(int time_step) +{ + Update(time_step); + return mult_values_; +} + +std::vector<double> DataStream::GetTimeSteps() +{ + std::vector<double> ret; + for (auto value : multimeter_->GetTimesteps()) + { + ret.push_back(std::stod(value)); + } + return ret; +} + +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/interaction.cpp b/demos/QVTK-Demo/qvtk-lib/src/interaction.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d6554811cb363e5cf50c4f4e98e7f648ac146c31 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/interaction.cpp @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk-lib/interaction.hpp" + +#include <string> + +SUPPRESS_WARNINGS_BEGIN +#include "vtkExtractSelection.h" +#include "vtkGeometryFilter.h" +#include "vtkHardwareSelector.h" +#include "vtkIdTypeArray.h" +#include "vtkPointData.h" +#include "vtkProperty.h" +#include "vtkRenderWindow.h" +#include "vtkRenderWindowInteractor.h" +#include "vtkRendererCollection.h" +#include "vtkSelection.h" +#include "vtkSelectionNode.h" +#include "vtkSmartPointer.h" +#include "vtkVertexGlyphFilter.h" +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +vtkStandardNewMacro(Interaction) + + Interaction::Interaction() +{ + SetUpShaders(); + SetUpMapper(); + SetUpActor(); +} + +void Interaction::SetUpMapper() +{ + mapper_ = vtkSmartPointer<vtkPointGaussianMapper>::New(); + mapper_->SetSplatShaderCode(point_shader_.c_str()); + mapper_->ScalarVisibilityOff(); + mapper_->SetScaleFactor(0.35); + mapper_->UseLookupTableScalarRangeOn(); + mapper_->EmissiveOff(); + mapper_->Update(); +} + +void Interaction::SetUpActor() +{ + actor_ = vtkSmartPointer<vtkActor>::New(); + actor_->SetMapper(mapper_); + actor_->GetProperty()->SetColor(0.0, 1.0, 0.0); + actor_->GetProperty()->SetEdgeVisibility(1); +} + +void Interaction::OnLeftButtonUp() +{ + Pick(); + + vtkSmartPointer<vtkHardwareSelector> selector = + vtkSmartPointer<vtkHardwareSelector>::New(); + selector->SetRenderer( + this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()); + int *temp = this->Interactor->GetRenderWindow()->GetSize(); + unsigned int windowSize[4]; + windowSize[0] = temp[2]; + windowSize[1] = temp[3]; + windowSize[2] = temp[0]; + windowSize[3] = temp[1]; + /* + for(unsigned int i = 0; i < 4; i++) + { + windowSize[i] = temp[i]; + } + */ + selector->SetArea(windowSize); + selector->SetFieldAssociation(vtkDataObject::FIELD_ASSOCIATION_POINTS); + vtkSelection *selection = selector->Select(); + std::cout << "Selection has " << selection->GetNumberOfNodes() << " nodes." + << std::endl; + + vtkSmartPointer<vtkExtractSelection> extractSelection = + vtkSmartPointer<vtkExtractSelection>::New(); + extractSelection->SetInputData(0, data_); + extractSelection->Update(); + + vtkSmartPointer<vtkDataSetMapper> mapper = + vtkSmartPointer<vtkDataSetMapper>::New(); + mapper->SetInputConnection(extractSelection->GetOutputPort()); + + vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New(); + actor->SetMapper(mapper); + actor->GetProperty()->SetColor(1, 0, 0); + GetDefaultRenderer()->AddActor(actor); + + if (id_ != -1) + { + ExtractSelection(); + HighlightSelection(); + } + else + { + Deselect(); + } + vtkInteractorStyleTrackballCamera::OnLeftButtonUp(); +} + +void Interaction::Pick() +{ + int *pos = GetInteractor()->GetEventPosition(); + + picker_ = vtkSmartPointer<vtkPointPicker>::New(); + picker_->SetTolerance(0.015); + + picker_->Pick(pos[0], pos[1], 0, GetDefaultRenderer()); + id_ = picker_->GetPointId(); + std::cout << id_ << std::endl; +} + +void Interaction::ExtractSelection() +{ + vtkSmartPointer<vtkIdTypeArray> ids = vtkSmartPointer<vtkIdTypeArray>::New(); + ids->SetNumberOfComponents(1); + ids->InsertNextValue(picker_->GetPointId()); + + vtkSmartPointer<vtkSelectionNode> selectionNode = + vtkSmartPointer<vtkSelectionNode>::New(); + selectionNode->SetFieldType(vtkSelectionNode::POINT); + selectionNode->SetContentType(vtkSelectionNode::INDICES); + selectionNode->SetSelectionList(ids); + + vtkSmartPointer<vtkSelection> selection = + vtkSmartPointer<vtkSelection>::New(); + selection->AddNode(selectionNode); + + vtkSmartPointer<vtkExtractSelection> extract_selection = + vtkSmartPointer<vtkExtractSelection>::New(); + extract_selection->SetInputData(0, data_); + extract_selection->SetInputData(1, selection); + extract_selection->Update(); + + selected_ = vtkSmartPointer<vtkUnstructuredGrid>::New(); + selected_->ShallowCopy(extract_selection->GetOutput()); + + neuron_value_ = selected_->GetPointData()->GetScalars()->GetComponent(0, 0); +} + +void Interaction::HighlightSelection() +{ + vtkSmartPointer<vtkGeometryFilter> geometryFilter = + vtkSmartPointer<vtkGeometryFilter>::New(); + geometryFilter->SetInputData(selected_); + geometryFilter->Update(); + + vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter = + vtkSmartPointer<vtkVertexGlyphFilter>::New(); + glyphFilter->SetInputData(geometryFilter->GetOutput()); + glyphFilter->Update(); + + mapper_->SetInputData(glyphFilter->GetOutput()); + + CurrentRenderer->AddActor(actor_); + GetInteractor()->GetRenderWindow()->Render(); +} + +void Interaction::Deselect() +{ + vtkSmartPointer<vtkPolyData> empty = vtkSmartPointer<vtkPolyData>::New(); + + mapper_->SetInputData(empty); + mapper_->Update(); + + CurrentRenderer->AddActor(actor_); + GetInteractor()->GetRenderWindow()->Render(); +} + +void Interaction::SetData(vtkSmartPointer<vtkPolyData> data) { data_ = data; } + +void Interaction::SwitchMapper(int rendertype) +{ + if (rendertype == 0) + { + mapper_->SetSplatShaderCode(point_shader_.c_str()); + } + else if (rendertype == 1) + { + mapper_->SetSplatShaderCode(sphere_shader_.c_str()); + } +} + +double Interaction::GetNeuronValue() { return neuron_value_; } + +vtkIdType Interaction::GetNeuronId() { return id_; } + +void Interaction::SetUpShaders() +{ + sphere_shader_ = + "//VTK::Color::Impl\n" + "float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n" + "if (dist > 0.9) {\n" + " discard;\n" + "} else {\n" + " float scale = (1.0 - dist);\n" + " ambientColor *= 0.5;\n" + " diffuseColor *= 0.7;\n" + "}\n"; + + point_shader_ = + "//VTK::Color::Impl\n" + "ambientColor *= 0.5;\n" + "diffuseColor *= 0.7;\n" + "if (abs(offsetVCVSOutput.x) > 0.3 || abs(offsetVCVSOutput.y) > 0.3) " + "{\n" + " discard;\n" + "}\n" + "if (abs(offsetVCVSOutput.x) < 0.0 && abs(offsetVCVSOutput.y) < 0.0) " + "{\n" + " discard;\n" + "}\n"; +} +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/main_widget.cpp b/demos/QVTK-Demo/qvtk-lib/src/main_widget.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dcc6f6cf638bb7153e63d7cac1d99fc9f63e2c67 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/main_widget.cpp @@ -0,0 +1,68 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------ + +#include "qvtk-lib/main_widget.hpp" + +#include "vtkGenericOpenGLRenderWindow.h" + +#include "QString" +#include "QtWidgets" + +namespace vtkexp +{ + +MainWidget::MainWidget(PointData *points, QVTKOpenGLWidget *parent) + : QVTKOpenGLWidget(parent) +{ + renderwindow_ = vtkSmartPointer<vtkGenericOpenGLRenderWindow>::New(); + this->SetRenderWindow(renderwindow_.Get()); + + style_ = vtkSmartPointer<Interaction>::New(); + style_->SetData(points->GetPolyPoints()); + this->GetInteractor()->SetInteractorStyle(style_); + + vispoints_ = new Visualize(points); + vispoints_->Initialize(renderwindow_, this->GetInteractor()); +} + +void MainWidget::mouseReleaseEvent(QMouseEvent *event) +{ + QVTKOpenGLWidget::mouseReleaseEvent(event); + if (event->button() == Qt::LeftButton && style_->GetNeuronId() != -1) + { + QToolTip::showText(this->mapToGlobal(event->pos()), + QString::number(style_->GetNeuronValue())); + } +} + +void MainWidget::ChangeRendertype(int rendertype) +{ + vispoints_->SwitchMapper(rendertype); + style_->SwitchMapper(rendertype); +} + +void MainWidget::Rerender() { renderwindow_->Render(); } + +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/main_window.cpp b/demos/QVTK-Demo/qvtk-lib/src/main_window.cpp new file mode 100644 index 0000000000000000000000000000000000000000..980eb8afc59c25bff71de6222b5a2fa810fb21e2 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/main_window.cpp @@ -0,0 +1,208 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk-lib/main_window.hpp" + +namespace vtkexp +{ + +MainWindow::MainWindow(PointData *points) : points_(points) +{ + setWindowTitle("QVTK-Neuron-Viewer"); + SetUpVisualization(); + SetUpContent(); + setCentralWidget(dummywidget_); + ConnectSignals(); + StartAnimation(); +} + +void MainWindow::SetUpVisualization() +{ + animation_ = new Animate(points_); + mainwidget_ = new MainWidget(points_); +} + +void MainWindow::SetUpContent() +{ + SetUpSliders(); + SetUpLineEdit(); + SetUpButtons(); + SetUpLayout(); +} + +void MainWindow::SetUpLayout() +{ + dummywidget_ = new QWidget; + grid_ = new QGridLayout; + grid_->addWidget(mainwidget_, 0, 0, 1, -1); + grid_->addWidget(time_label_, 1, 0, 1, 1); + grid_->addWidget(time_slider_, 1, 1, 1, 1); + grid_->addWidget(slider_line_edit_, 1, 2, 1, 10); + grid_->addWidget(render_type_, 1, 14, 1, 1); + grid_->addWidget(rt_button_, 1, 15, 1, 1); + grid_->addWidget(play_button_, 1, 13, 1, 1); + grid_->addWidget(speed_menu_, 1, 12, 1, 1); + dummywidget_->setLayout(grid_); + + resize(800, 600); +} + +void MainWindow::SetUpLineEdit() +{ + slider_line_edit_ = new QLineEdit(); + slider_line_edit_->setText(std::to_string(0).c_str()); +} + +void MainWindow::SetUpSliders() +{ + time_slider_ = new QSlider(Qt::Horizontal); + time_label_ = new QLabel("Time:"); + InitSlider(time_slider_); + time_slider_->setEnabled(0); +} + +void MainWindow::InitSlider(QSlider *slider) +{ + slider->setFocusPolicy(Qt::StrongFocus); + slider->setTickPosition(QSlider::TicksAbove); + slider->setTickInterval(50); + slider->setSingleStep(20); + slider->setMinimum(0); + slider->setMaximum(100); + slider->setValue(100); +} + +void MainWindow::SetUpButtons() +{ + rt_button_ = new QPushButton("Replay", this); + rt_button_->setFixedSize(QSize(80, 32)); + play_button_ = new QPushButton("⏸", this); + play_button_->setFixedSize(QSize(32, 32)); + render_type_ = new QComboBox(this); + render_type_->setFixedSize(QSize(80, 32)); + render_type_->addItems({"Points", "Spheres"}); + speed_menu_ = new QComboBox(this); + speed_menu_->addItems({"1/sec", "5/sec", "10/sec", "50/sec", "100/sec"}); +} + +void MainWindow::StartAnimation() { animation_->StartTimer(); } + +void MainWindow::ConnectSignals() +{ + connect(speed_menu_, SIGNAL(activated(int)), animation_, + SLOT(SpeedMenu(int))); + connect(rt_button_, SIGNAL(clicked()), animation_, SLOT(RealtimeButton())); + connect(play_button_, SIGNAL(clicked()), animation_, SLOT(PlayButton())); + connect(time_slider_, SIGNAL(valueChanged(int)), animation_, + SLOT(ChangeData(int))); + connect(time_slider_, SIGNAL(valueChanged(int)), SLOT(SliderValue(int))); + connect(slider_line_edit_, SIGNAL(editingFinished()), SLOT(SliderValue())); + connect(render_type_, SIGNAL(currentIndexChanged(int)), mainwidget_, + SLOT(ChangeRendertype(int))); + connect(animation_, SIGNAL(SwitchRealtime()), this, SLOT(Realtime())); + connect(animation_, SIGNAL(SwitchPlayPause()), this, SLOT(PlayPause())); + connect(animation_, SIGNAL(DataChanged()), this, SLOT(Rerender())); + connect(animation_, SIGNAL(DataChanged()), this, SLOT(AdjustSlider())); + connect(animation_, SIGNAL(NextStep()), SLOT(IncrementSlider())); + connect(animation_, SIGNAL(LastStep()), SLOT(UpdateSlider())); +} + +void MainWindow::Rerender() { mainwidget_->Rerender(); } + +void MainWindow::IncrementSlider() +{ + int newval; + if (time_slider_->value() + 1 < time_slider_->maximum()) + { + newval = time_slider_->value() + 1; + } + else + { + newval = time_slider_->maximum(); + } + + time_slider_->setValue(newval); + slider_line_edit_->setText(std::to_string(newval).c_str()); +} + +void MainWindow::UpdateSlider() +{ + time_slider_->setValue(points_->GetEndTime()); + slider_line_edit_->setText(std::to_string(time_slider_->value()).c_str()); +} + +void MainWindow::AdjustSlider() +{ + time_slider_->setMinimum(points_->GetStartTime()); + time_slider_->setMaximum(points_->GetEndTime()); +} + +void MainWindow::SliderValue(int time_step) +{ + slider_line_edit_->setText(std::to_string(time_step).c_str()); + time_slider_->setMinimum(points_->GetStartTime()); + time_slider_->setMaximum(points_->GetEndTime()); +} + +void MainWindow::SliderValue() +{ + time_slider_->setValue(slider_line_edit_->text().toInt()); +} + +void MainWindow::Realtime() +{ + if (realtime_) + { + realtime_ = false; + rt_button_->setText("Realtime"); + time_slider_->setMinimum(points_->GetStartTime()); + time_slider_->setMaximum(points_->GetEndTime()); + time_slider_->setEnabled(1); + } + else + { + realtime_ = true; + time_slider_->setValue(points_->GetEndTime()); + rt_button_->setText("Replay"); + time_slider_->setEnabled(0); + } +} + +void MainWindow::PlayPause() +{ + if (play_) + { + play_ = false; + play_button_->setText("▶"); + SliderValue(slider_line_edit_->text().toInt()); + } + else + { + play_ = true; + play_button_->setText("⏸"); + } +} + +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/point_data.cpp b/demos/QVTK-Demo/qvtk-lib/src/point_data.cpp new file mode 100644 index 0000000000000000000000000000000000000000..263c7bc1d82a35fcb489f6fc975d98ad7c22edfc --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/point_data.cpp @@ -0,0 +1,133 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include <vector> + +#include "include/qvtk-lib/suppress_warnings.hpp" +SUPPRESS_WARNINGS_BEGIN +#include "qvtk-lib/point_data.hpp" + +#include "vtkCellArray.h" +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#include "vtkPointData.h" +#pragma GCC diagnostic pop +SUPPRESS_WARNINGS_END + +namespace vtkexp +{ + +PointData::PointData(int num_x, int num_y, int num_z) + : num_points_(num_x * num_y * num_z) +{ + Initialize(num_x, num_y, num_z); +} + +void PointData::Initialize(int x, int y, int z) +{ + points_polydata_ = vtkSmartPointer<vtkPolyData>::New(); + points_polydata_->SetPoints(CreatePoints(x, y, z)); + + pointcolors_ = vtkSmartPointer<vtkFloatArray>::New(); + pointcolors_->SetName("colors"); + pointcolors_->SetNumberOfTuples(num_points_); + + std::vector<double> init(num_points_); + std::fill(init.begin(), init.end(), 0); + AttachColorsToPoints(init); + + stream_ = new DataStream(); +} + +vtkSmartPointer<vtkPoints> PointData::CreatePoints(int num_x, int num_y, + int num_z) +{ + vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New(); + for (int i = 0; i < num_x; ++i) + { + for (int j = 0; j < num_y; ++j) + { + for (int k = 0; k < num_z; ++k) + { + points->InsertNextPoint(i, j, k); + } + } + } + return points; +} + +void PointData::ColorsModified() +{ + points_polydata_->GetPointData()->GetScalars()->Modified(); +} + +void PointData::AttachColorsToPoints(const std::vector<double> &scalars) +{ + if (!scalars.empty()) + { + for (int i = 0; i < num_points_; ++i) + { + pointcolors_->SetValue( + i, static_cast<float>(scalars.at(static_cast<int>(i)))); + } + points_polydata_->GetPointData()->SetScalars(pointcolors_); + } +} + +void PointData::Update(int time_step) +{ + AttachColorsToPoints(stream_->GetMultValuesAt(time_step)); + ColorsModified(); +} + +vtkSmartPointer<vtkPolyData> PointData::GetPolyPoints() +{ + return points_polydata_; +} + +vtkSmartPointer<vtkFloatArray> PointData::GetColors() const +{ + return pointcolors_; +} + +int PointData::GetStartTime() const +{ + if (!stream_->GetTimeSteps().empty()) + { + return static_cast<int>(stream_->GetTimeSteps().front()); + } + return 0; +} + +int PointData::GetEndTime() const +{ + if (!stream_->GetTimeSteps().empty()) + { + return static_cast<int>(stream_->GetTimeSteps().back()); + } + return 100; +} + +} // namespace vtkexp diff --git a/demos/QVTK-Demo/qvtk-lib/src/visualize.cpp b/demos/QVTK-Demo/qvtk-lib/src/visualize.cpp new file mode 100644 index 0000000000000000000000000000000000000000..614c74b13507c2eb05468c8c82d0c27f60686e96 --- /dev/null +++ b/demos/QVTK-Demo/qvtk-lib/src/visualize.cpp @@ -0,0 +1,157 @@ +//------------------------------------------------------------------------------ +// QVTK-Demo +// +// Copyright (c) 2017-2018 RWTH Aachen University, Germany, +// Virtual Reality & Immersive Visualisation Group. +//------------------------------------------------------------------------------ +// License +// +// This framework is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published +// by the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// In the future, we may decide to add a commercial license +// at our own discretion without further notice. +// +// 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 Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +//------------------------------------------------------------------------------ + +#include "qvtk-lib/visualize.hpp" + +#include <string> + +namespace vtkexp +{ + +Visualize::Visualize(PointData *points) { points_ = points; } + +vtkSmartPointer<vtkRenderer> Visualize::GetRenderer() { return renderer_; } + +void Visualize::Initialize( + vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderwindow, + vtkSmartPointer<vtkRenderWindowInteractor> interactor) +{ + renderwindow_ = renderwindow; + interactor_ = interactor; + SetUpTransferFunction(); + SetUpMapper(); + SetUpScene(); + SetUpRenderer(); + SetUpAxes(); + SetUpLegend(); +} + +void Visualize::SetUpLegend() +{ + scalar_bar_widget_ = vtkSmartPointer<vtkScalarBarWidget>::New(); + scalar_bar_widget_->SetInteractor(interactor_); + scalar_bar_widget_->SetEnabled(true); + + scalar_bar_ = scalar_bar_widget_->GetScalarBarActor(); + // scalar_bar_->SetTitle("Legend"); + scalar_bar_->SetLookupTable(transfer_function_); + scalar_bar_->SetOrientationToVertical(); + scalar_bar_->SetNumberOfLabels(0); + + scalar_bar_->SetPosition2(0, 0); + scalar_bar_->SetBarRatio(0.6); +} + +void Visualize::SetUpAxes() +{ + axes_ = vtkSmartPointer<vtkAxesActor>::New(); + + axes_widget_ = vtkSmartPointer<vtkOrientationMarkerWidget>::New(); + axes_widget_->SetOutlineColor(0.9300, 0.5700, 0.1300); + axes_widget_->SetOrientationMarker(axes_); + axes_widget_->SetInteractor(interactor_); + axes_widget_->SetViewport(0.0, 0.0, 0.2, 0.2); + axes_widget_->SetEnabled(1); + axes_widget_->InteractiveOn(); + + renderer_->ResetCamera(); +} + +void Visualize::SetUpScene() +{ + actor_ = vtkSmartPointer<vtkActor>::New(); + actor_->SetMapper(mapper_); +} + +void Visualize::SetUpRenderer() +{ + renderer_ = vtkSmartPointer<vtkRenderer>::New(); + renderwindow_->AddRenderer(renderer_); + renderer_->AddActor(actor_); + interactor_->GetInteractorStyle()->SetDefaultRenderer(renderer_); + + renderer_->GradientBackgroundOn(); + renderer_->SetBackground(0.3, 0.4, 0.5); + renderer_->SetBackground2(0.1, 0.2, 0.3); +} + +void Visualize::SetUpTransferFunction() +{ + transfer_function_ = vtkSmartPointer<vtkColorTransferFunction>::New(); + transfer_function_->SetColorSpaceToDiverging(); + transfer_function_->AddRGBPoint(-15, 0, 0, 1); + transfer_function_->AddRGBPoint(5, 1, 0, 0); +} + +void Visualize::SetUpMapper() +{ + SetUpShaders(); + + mapper_ = vtkSmartPointer<vtkPointGaussianMapper>::New(); + mapper_->SetInputData(points_->GetPolyPoints()); + mapper_->SetSplatShaderCode(point_shader_.c_str()); + mapper_->SetLookupTable(transfer_function_); + mapper_->SetScaleFactor(0.35); + mapper_->UseLookupTableScalarRangeOn(); + mapper_->EmissiveOff(); + mapper_->Update(); +} + +void Visualize::SetUpShaders() +{ + point_shader_ = + "//VTK::Color::Impl\n" + "ambientColor *= 1.0;\n" + "diffuseColor *= 1.0;\n" + "if (abs(offsetVCVSOutput.x) > 0.2 || abs(offsetVCVSOutput.y) > 0.2) " + "{\n" + " discard;\n" + "}\n"; + + sphere_shader_ = + "//VTK::Color::Impl\n" + "float dist = dot(offsetVCVSOutput.xy,offsetVCVSOutput.xy);\n" + "if (dist > 0.8) {\n" + " discard;\n" + "} else {\n" + " float scale = (1.0 - dist);\n" + " ambientColor *= scale;\n" + " diffuseColor *= scale;\n" + "}\n"; +} + +void Visualize::SwitchMapper(int rendertype) +{ + if (rendertype == 0) + { + mapper_->SetSplatShaderCode(point_shader_.c_str()); + } + else if (rendertype == 1) + { + mapper_->SetSplatShaderCode(sphere_shader_.c_str()); + } +} + +} // namespace vtkexp diff --git a/demos/brunel_simulation/CMakeLists.txt b/demos/brunel_simulation/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6fd813ebf9dbf4b4c0e2db0852fcc1879ec51b1a --- /dev/null +++ b/demos/brunel_simulation/CMakeLists.txt @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------- +# nest-streaming-module +# +# Copyright (c) 2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualization Group. +#------------------------------------------------------------------------------- +# License +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +get_filename_component(NEST_DIR ${with-nest} DIRECTORY) + +set(SCRIPT_FILENAME "${CMAKE_CURRENT_BINARY_DIR}/run_sim.sh") +execute_process( + COMMAND ${NEST_CONFIG} --python-executable + RESULT_VARIABLE RES_VAR + OUTPUT_VARIABLE PYTHON_EXECUTABLE + OUTPUT_STRIP_TRAILING_WHITESPACE +) +message(STATUS "PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE}") + +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/run_sim.sh.in ${SCRIPT_FILENAME}) +file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/brunel_example.py ${CMAKE_CURRENT_SOURCE_DIR}/nest_sim.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) +add_custom_target(brunel_simulation ALL chmod "+x" "run_sim.sh" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + DEPENDS ${SCRIPT_FILENAME} ${CMAKE_CURRENT_BINARY_DIR}/brunel_example.py ${CMAKE_CURRENT_SOURCE_DIR}/nest_sim.py) diff --git a/demos/brunel_simulation/brunel_example.py b/demos/brunel_simulation/brunel_example.py new file mode 100644 index 0000000000000000000000000000000000000000..4c59b60dbaa9fd1c84c694131ef9825f736d9a3c --- /dev/null +++ b/demos/brunel_simulation/brunel_example.py @@ -0,0 +1,265 @@ + +""" +Definition of spatially extended Brunel network. +This module provides layer and projections declarations suitable for +use with the NEST Topology Module. +It defines a Brunel-style network with neurons placed on a regular grid. +Connectivity is probabilitstic from the entire network, i.e., connectivity +is not structured spatially. +""" + +from copy import deepcopy +from math import sqrt +import numpy as np +from mpl_toolkits.mplot3d import Axes3D +import matplotlib.pyplot as plt + +import nest +import nest.raster_plot +import nest.topology as tp + + +class Brunel3D: + + def __init__(self): + self.layer_dict = {} + nest.Install("streamingmodule") + # nest.SetKernelStatus({'print_time': True}) + + class Parameters: + """ + Define model parameters. + """ + order = 9 # must be square + NE = 4 * order # number of excitatory neurons. + NI = 1 * order # number of inhibitory neurons + + lengthE = int(sqrt(NE)) + lengthI = int(sqrt(NI)) + + if not (lengthE**2 == NE and lengthI**2 == NI): + raise ValueError('Order must be a square number (order = n**2)') + + # neuron_model = 'iaf_psc_alpha' + neuron_model = 'mat2_psc_exp' + + g = 5.0 # ratio inhibitory weight/excitatory weight + eta = 2.0 # external rate relative to threshold rate + epsilon = 0.1 # connection probability + + delay = 1.5 # synaptic delay in ms + + tauMem = 20.0 # time constant of membrane potential in ms + theta = 20.0 # membrane threshold potential in mV + + J = 0.1 # postsynaptic amplitude in mV + J_ex = J # amplitude of excitatory postsynaptic potential + J_in = -g * J_ex # amplitude of inhibitory postsynaptic potential + + CE = int(epsilon * NE) # number of excitatory synapses per neuron + + nu_th = theta / (J * CE * tauMem) + nu_ex = eta * nu_th + p_rate = 1.0 * nu_ex * CE + + neuron_params = {"C_m": 1.0, + "tau_m": tauMem, + "t_ref": 2.0, + "E_L": 0.0, + # "V_reset": 0.0, # doesn't work with mat2_psc_exp + # "V_th": theta, # doesn't work with mat2_psc_exp + "V_m": 0.0 + } + mm_params = {'record_from': ['V_m', 'V_th'], + 'record_to': ['streaming']} + poisson_params = {"rate": p_rate} + + def modified_copy(self, orig, diff): + """ + Returns a deep copy of dictionary with changes applied. + @param orig original dictionary, will be deep-copied + @param diff copy will be updated with this dict + """ + + tmp = deepcopy(orig) + tmp.update(diff) + return tmp + + def make_layer_specs(self): + """ + Returns lists of dictionaries with model, layer, and synapse model + specifications. + """ + + P = self.Parameters + + self.models = [(P.neuron_model, 'excitatory', P.neuron_params), + (P.neuron_model, 'inhibitory', P.neuron_params), + ('poisson_generator', 'noise', P.poisson_params), + ('multimeter', 'recordingNode', P.mm_params)] + + self.syn_models = [('static_synapse', 'static_excitatory', {})] + + dE = 1.0 / float(P.lengthE) + limE = (1.0 - dE) / 2.0 + posE = np.linspace(-limE, limE, num=P.lengthE) + + dI = 1.0 / float(P.lengthI) + limI = (1.0 - dI) / 2.0 + posI = np.linspace(-limI, limI, num=P.lengthI) + + self.layers = [('Excitatory', {'positions': [[x, y, 0.4] + for x in posE + for y in posE], + 'edge_wrap': True, + 'elements': 'excitatory'}), + ('Inhibitory', {'positions': [[x, y, -0.4] + for x in posI + for y in posI], + 'edge_wrap': True, + 'elements': 'inhibitory'})] + self.layers.append(('PoissonGenerator', + {'positions': [[0.0, 0.0, 0.0]], + 'elements': 'noise'})) + self.layers.append(('Multimeter', + {'positions': [[0.0, 0.0, 0.0]], + 'elements': 'recordingNode'})) + self.layers.append(('SpikeDetector', + {'positions': [[0.0, 0.0, 0.0]], + 'elements': 'spike_detector'})) + + def make_connection_specs(self): + """ + Returns list of dictionaries specifying projections for Brunel network. + """ + + P = self.Parameters + + self.projections = [('Excitatory', 'Excitatory', + {'connection_type': 'convergent', + 'synapse_model': 'static_synapse', + 'kernel': P.epsilon, + 'weights': P.J_ex, + 'delays': P.delay}), + ('Excitatory', 'Inhibitory', + {'connection_type': 'convergent', + 'synapse_model': 'static_synapse', + 'kernel': P.epsilon, + 'weights': P.J_ex, + 'delays': P.delay}), + ('Inhibitory', 'Excitatory', + {'connection_type': 'convergent', + 'synapse_model': 'static_synapse', + 'kernel': P.epsilon, + 'weights': P.J_in, + 'delays': P.delay}), + ('Inhibitory', 'Excitatory', + {'connection_type': 'convergent', + 'synapse_model': 'static_synapse', + 'kernel': P.epsilon, + 'weights': P.J_in, + 'delays': P.delay}), + ('Multimeter', 'Excitatory', + {'connection_type': 'convergent'}), + ('Excitatory', 'SpikeDetector', + {'connection_type': 'convergent'}), + ('Inhibitory', 'SpikeDetector', + {'connection_type': 'convergent'}), + ('PoissonGenerator', 'Excitatory', + {'connection_type': 'convergent'})] + + def make_layers(self): + # First, we copy the models with custom specifications + # Neuron models + for model in self.models: + old_name, new_name, spec = model + nest.CopyModel(old_name, new_name, spec) + # Synapse models + for model in self.syn_models: + old_name, new_name, spec = model + nest.CopyModel(old_name, new_name, spec) + + # Next we make the layers + for l in self.layers: + name = l[0] + specs = l[1] + self.layer_dict.update({name: tp.CreateLayer(specs)}) + + def make_connections(self): + # Connect layers + for proj in self.projections: + pre_layer = self.layer_dict[proj[0]] + post_layer = self.layer_dict[proj[1]] + conn_specs = proj[2] + tp.ConnectLayers(pre_layer, post_layer, conn_specs) + + def simulate(self): + nest.Simulate(1000) + + def plot_positions(self): + ex_pos = self.layers[0][1]['positions'] + in_pos = self.layers[1][1]['positions'] + fig = plt.figure() + ax = Axes3D(fig) + for c, m, positions in [('b', 'o', ex_pos), ('r', '^', in_pos)]: + ax.scatter([x for x, y, z in positions], + [y for x, y, z in positions], + [z for x, y, z in positions], + c=c, marker=m) + + def get_results(self): + mm = (self.layer_dict['Multimeter'][0] + 1,) + sd = (self.layer_dict['SpikeDetector'][0] + 1,) + mm_status = nest.GetStatus(mm)[0] + sd_status = nest.GetStatus(sd)[0] + + nest.raster_plot.from_device(sd, hist=True) + + senders = mm_status['events']['senders'] + times = mm_status['events']['times'] + v_m = mm_status['events']['V_m'] + v_th = mm_status['events']['V_th'] + step = int(max(senders)/100 + 1) # Only plot results from some GIDs + + mm_events = [] + for i in range(1, max(senders) + 1, step): + if i in senders: + indices = np.argwhere(senders == i) + mm_events.append({'GID': i, + 'times': [times[n] for n in indices], + 'V_m': [v_m[n] for n in indices], + 'V_th': [v_th[n] for n in indices]}) + + return {'multimeter': mm_events, + 'spike_detector': nest.GetStatus(sd)[0]} + + +if __name__ == '__main__': + nest.ResetKernel() + + print('Making specifications') + brunel = Brunel3D() + brunel.make_layer_specs() + brunel.make_connection_specs() + + print('Making layers') + brunel.make_layers() + nest.topology.DumpLayerNodes([l[0] for l in brunel.layer_dict.values()][:2], + 'brunel_nodes.txt') + + print('Making connections') + brunel.make_connections() + + brunel.simulate() + + print('Getting results') + brunel.plot_positions() + results = brunel.get_results() + + for value in ['V_m', 'V_th']: + plt.figure() + for n in results['multimeter'][::20]: + plt.plot(n['times'], n[value], label='{}'.format(n['GID'])) + plt.legend() + plt.title(value) + plt.show() diff --git a/demos/brunel_simulation/nest_sim.py b/demos/brunel_simulation/nest_sim.py new file mode 100644 index 0000000000000000000000000000000000000000..65788db7fdfa3b6b407bc8f91ba08e04e1dc8dfc --- /dev/null +++ b/demos/brunel_simulation/nest_sim.py @@ -0,0 +1,94 @@ +#------------------------------------------------------------------------------- +# nest in situ vis +# +# Copyright (c) 2017-2018 RWTH Aachen University, Germany, +# Virtual Reality & Immersive Visualisation Group. +#------------------------------------------------------------------------------- +# License +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +#------------------------------------------------------------------------------- + +import sys +import nest +import numpy + +from PyQt5.QtWidgets import QApplication, QPushButton +from PyQt5.QtCore import QTimer + +import brunel_example + +class Simulation: + def __init__(self): + self.SetupSim() + + def SetupSim(self): + nest.ResetKernel() + + print('Making specifications') + self.brunel = brunel_example.Brunel3D() + self.brunel.make_layer_specs() + self.brunel.make_connection_specs() + + print('Making layers') + self.brunel.make_layers() + nest.topology.DumpLayerNodes([l[0] for l in self.brunel.layer_dict.values()][:2], + 'brunel_nodes.txt') + + print('Making connections') + self.brunel.make_connections() + + def Simulate(self, steps): + nest.Simulate(steps) + + +class MainWindow: + def __init__(self, screen_resolution): + self.screen_resolution = screen_resolution + self.SetupWindow() + self.simulation = Simulation() + + def SetupWindow(self): + self.simulate_button = QPushButton("nest.Simulate(1000)") + self.simulate_button.clicked.connect(self.SimulateButtonClicked) + + def SimulateButtonClicked(self): + self.simulate_button.setEnabled(False) + QApplication.processEvents() + + self.simulation.Simulate(1000) + + QApplication.processEvents() + self.simulate_button.setEnabled(True) + + def Show(self): + self.simulate_button.show() + button_geometry = self.simulate_button.geometry() + self.simulate_button.setGeometry( + self.screen_resolution.width() - button_geometry.width(), + self.screen_resolution.height() - button_geometry.height(), + button_geometry.width(), + button_geometry.height()) + + +def main(argv): + app = QApplication(argv) + screen_resolution = app.desktop().screenGeometry() + + w = MainWindow(screen_resolution) + w.Show() + + return app.exec_() + +if __name__ == "__main__": + main(sys.argv) diff --git a/demos/brunel_simulation/run_sim.sh.in b/demos/brunel_simulation/run_sim.sh.in new file mode 100644 index 0000000000000000000000000000000000000000..dd5c5c1b65105d5bd99b67e3b61314d2e362be64 --- /dev/null +++ b/demos/brunel_simulation/run_sim.sh.in @@ -0,0 +1,3 @@ +#!/bin/bash +source ${NEST_DIR}/nest_vars.sh +LD_LIBRARY_PATH=$NEST_MODULE_PATH:$LD_LIBRARY_PATH ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/nest_sim.py \ No newline at end of file diff --git a/recording_backend_nesci_contra.cpp b/recording_backend_nesci_contra.cpp deleted file mode 100644 index 57b97e96d44390f5afacace84631e3d9a7069efa..0000000000000000000000000000000000000000 --- a/recording_backend_nesci_contra.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* - * recording_backend_stream_niv.cpp - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST 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 2 of the License, or - * (at your option) any later version. - * - * NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#include "recording_backend_nesci_contra.h" - -#include "recording_device.h" - -#include <iostream> -#include <memory> -#include <sstream> - -streamingnest::RecordingBackendNesciContra::RecordingBackendNesciContra() - : num_buffered_steps_( 0 ), datum_(0, std::string{}, std::vector<double>{}) -{ - datum_.values.reserve(10); -} - -void -streamingnest::RecordingBackendNesciContra::enroll( const nest::RecordingDevice& device ) -{ - enroll( device, std::vector< Name >() ); -} - - -void -streamingnest::RecordingBackendNesciContra::enroll( const nest::RecordingDevice& device, - const std::vector< Name >& value_names ) -{ - if ( !is_enrolled_( device ) ) - { - do_enroll_( device, value_names ); - } -} - -bool -streamingnest::RecordingBackendNesciContra::is_enrolled_( const nest::RecordingDevice& device ) -{ - return recorders_.find( device.get_gid() ) != recorders_.end(); -} - -void -streamingnest::RecordingBackendNesciContra::do_enroll_( const nest::RecordingDevice& device, - const std::vector< Name >& value_names ) -{ - std::unique_ptr< nesci::producer::Device > recorder{ create_recorder_( - device, value_names ) }; - - - recorders_[ device.get_gid() ] = std::move( recorder ); -} - -std::unique_ptr< nesci::producer::Device > -streamingnest::RecordingBackendNesciContra::create_recorder_( - const nest::RecordingDevice& device, - const std::vector< Name >& value_names ) -{ - if ( device.get_type() == nest::RecordingDevice::MULTIMETER ) - { - const std::vector< std::string > converted_value_names{ convert_value_names( - value_names ) }; - return std::unique_ptr< nesci::producer::Device >( - new nesci::producer::NestMultimeter( - generate_device_identifier_( device ), converted_value_names ) ); - } - // Spike detector is currently not supported - // else if ( device.get_type() == nest::RecordingDevice::SPIKE_DETECTOR ) - // { - // return std::unique_ptr< nesci::producer::Device >( - // new nesci::producer::SpikeDetector( - // generate_device_identifier_( device ) ) ); - // } - return std::unique_ptr< nesci::producer::Device >( nullptr ); -} - -std::vector< std::string > -streamingnest::RecordingBackendNesciContra::convert_value_names( - const std::vector< Name >& value_names ) const -{ - std::vector< std::string > converted_value_names; - std::for_each( value_names.begin(), - value_names.end(), - [&converted_value_names]( const Name& name ) { - converted_value_names.push_back( name.toString() ); - } ); - return converted_value_names; -} - -std::string -streamingnest::RecordingBackendNesciContra::generate_device_identifier_( - const nest::RecordingDevice& device ) const -{ - if ( device.get_label().size() == 0 ) - { - std::stringstream device_identifier; - device_identifier << device.get_name(); - device_identifier << device.get_gid(); - return device_identifier.str(); - } - - return device.get_label(); -} - -void -streamingnest::RecordingBackendNesciContra::initialize() -{ - num_buffered_steps_ = 0; -} - -void -streamingnest::RecordingBackendNesciContra::finalize() -{ -} - -void -streamingnest::RecordingBackendNesciContra::synchronize() -{ -#pragma omp barrier -#pragma omp master - { - ++num_buffered_steps_; - if ( num_buffered_steps_ == 10 ) - { - send_and_reset_node_(); - num_buffered_steps_ = 0; - } - } -} - -void -streamingnest::RecordingBackendNesciContra::send_and_reset_node_() -{ - for ( const auto& indexRecorder : recorders_ ) - { - relay_.Send( indexRecorder.second->node() ); - indexRecorder.second->node().reset(); - } -} - -void -streamingnest::RecordingBackendNesciContra::write( const nest::RecordingDevice& device, - const nest::Event& event ) -{ - if ( !is_enrolled_( device ) ) - { - return; - } - - // nesci does currently not support spike detectors - // const auto time = event.get_stamp().get_ms() - event.get_offset(); - // auto& recorder = recorders_[ device.get_gid() ]; - // recorder->Record( - // niv::producer::SpikeDetector::Datum( time, event.get_sender_gid() ) ); -} - -void -streamingnest::RecordingBackendNesciContra::write( const nest::RecordingDevice& device, - const nest::Event& event, - const std::vector< double >& values ) -{ - if ( !is_enrolled_( device ) ) - { - return; - } - - const auto time = event.get_stamp().get_ms() - event.get_offset(); - auto& recorder = recorders_[ device.get_gid() ]; - datum_.time = time; - datum_.neuron_id = std::to_string(event.get_sender_gid()); - datum_.values = values; - recorder->Record( datum_ ); -} - -void -streamingnest::RecordingBackendNesciContra::set_status( const DictionaryDatum& d ) -{ - Parameters_ ptmp = P_; // temporary copy in case of errors - ptmp.set( *this, d ); // throws if BadProperty - - // if we get here, temporaries contain consistent set of properties - P_ = ptmp; -} - -void -streamingnest::RecordingBackendNesciContra::get_status( DictionaryDatum& d ) const -{ - P_.get( *this, d ); -} - -streamingnest::RecordingBackendNesciContra::Parameters_::Parameters_() - : stream_interval_( 10 ) -{ -} - -void -streamingnest::RecordingBackendNesciContra::Parameters_::get( - const RecordingBackendNesciContra&, - DictionaryDatum& d ) const -{ - ( *d )[ "stream_interval" ] = stream_interval_; -} - -void -streamingnest::RecordingBackendNesciContra::Parameters_::set( - const RecordingBackendNesciContra&, - const DictionaryDatum& d ) -{ - if ( updateValue< long >( d, "stream_interval", stream_interval_ ) ) - { - // do nothing for now - } -} diff --git a/recording_backend_nesci_contra.h b/recording_backend_nesci_contra.h deleted file mode 100644 index 70389b7a85439a8cbe5e17441141d1d4e9634f69..0000000000000000000000000000000000000000 --- a/recording_backend_nesci_contra.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * recording_backend_stream_niv.h - * - * This file is part of NEST. - * - * Copyright (C) 2004 The NEST Initiative - * - * NEST 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 2 of the License, or - * (at your option) any later version. - * - * NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>. - * - */ - -#ifndef RECORDING_BACKEND_STREAM_NIV_H -#define RECORDING_BACKEND_STREAM_NIV_H - -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "conduit/conduit_node.hpp" - -#include "nest_types.h" -#include "recording_backend.h" - -#include "contra/relay.hpp" -#include "contra/boost-shmem/shared_memory_transport.hpp" -#include "nesci/producer/device.hpp" -#include "nesci/producer/nest_multimeter.hpp" - -namespace streamingnest -{ - -class RecordingBackendNesciContra : public nest::RecordingBackend -{ -public: - RecordingBackendNesciContra(); - ~RecordingBackendNesciContra() throw() - { - } - - void enroll( const nest::RecordingDevice& device ); - void enroll( const nest::RecordingDevice& device, - const std::vector< Name >& value_names ); - void initialize(); - void finalize(); - void synchronize(); - void write( const nest::RecordingDevice& device, const nest::Event& event ); - void write( const nest::RecordingDevice& device, - const nest::Event& event, - const std::vector< double >& ); - - void set_status( const DictionaryDatum& ); - void get_status( DictionaryDatum& ) const; - -private: - bool is_enrolled_( const nest::RecordingDevice& device ); - void do_enroll_( const nest::RecordingDevice& device, - const std::vector< Name >& value_names ); - std::string generate_device_identifier_( - const nest::RecordingDevice& device ) const; - std::unique_ptr< nesci::producer::Device > create_recorder_( - const nest::RecordingDevice& device, - const std::vector< Name >& value_names ); - void send_and_reset_node_(); - - struct Parameters_ - - { - long stream_interval_; - - Parameters_(); - - void get( const RecordingBackendNesciContra&, DictionaryDatum& ) const; - void set( const RecordingBackendNesciContra&, const DictionaryDatum& ); - }; - - Parameters_ P_; - - std::size_t num_buffered_steps_; - - std::vector< std::string > convert_value_names( - const std::vector< Name >& value_names ) const; - - - contra::Relay< contra::SharedMemoryTransport > relay_; - std::map< nest::index, std::unique_ptr< nesci::producer::Device > > recorders_; - nesci::producer::NestMultimeter::Datum datum_; -}; -} - -#endif // RECORDING_BACKEND_STREAM_NIV_H diff --git a/sli/mymodule-init.sli b/sli/streamingmodule-init.sli similarity index 100% rename from sli/mymodule-init.sli rename to sli/streamingmodule-init.sli diff --git a/streaming_recording_backend.cpp b/streaming_recording_backend.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f6cf26da6dcd3eb83c68d0473b96bc68a737c5b3 --- /dev/null +++ b/streaming_recording_backend.cpp @@ -0,0 +1,139 @@ +/* + * recording_backend_stream_niv.cpp + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include "streaming_recording_backend.h" + +#include "recording_device.h" + +#include <iostream> +#include <memory> +#include <sstream> +#include <thread> + +namespace streamingnest { + +StreamingRecordingBackend::StreamingRecordingBackend() {} + +void StreamingRecordingBackend::initialize() { + // Called once + std::cout << "initialize()" << std::endl; +} + +void StreamingRecordingBackend::enroll( + const nest::RecordingDevice &device, + const std::vector<Name> &double_value_names, + const std::vector<Name> &long_value_names) { + // Called per thread + std::lock_guard<std::mutex> lock_guard(enroll_mutex_); + + std::vector<std::string> double_parameter_names; + double_parameter_names.reserve(double_value_names.size()); + for (const auto &value_name : double_value_names) { + double_parameter_names.push_back(value_name.toString()); + } + + std::vector<std::string> long_parameter_names; + long_parameter_names.reserve(long_value_names.size()); + for (const auto &value_name : long_value_names) { + long_parameter_names.push_back(value_name.toString()); + } + + if (device.get_type() == nest::RecordingDevice::Type::MULTIMETER) { + devices_[std::this_thread::get_id()][device.get_name()] = + std::make_unique<nesci::producer::NestMultimeter>( + device.get_name(), double_parameter_names, long_parameter_names); + } + + std::cout << std::this_thread::get_id() << ' '; + std::cout << device.get_name() << ' '; + std::cout << "double_value_names: "; + for (const auto &name : double_value_names) { + std::cout << name << ' '; + } + std::cout << ", long_value_names: "; + for (const auto &name : long_value_names) { + std::cout << name << ' '; + } + std::cout << std::endl; +} + +void StreamingRecordingBackend::write(const nest::RecordingDevice &device, + const nest::Event &event, + const std::vector<double> &double_values, + const std::vector<long> &long_values) { + // Called per thread + // std::lock_guard<std::mutex> lock_guard(write_mutex_); + // std::cout << std::this_thread::get_id() << ' '; + // std::cout << device.get_name() << ' '; + // std::cout << event.get_sender_gid() << ' '; + // std::cout << event.get_stamp() << ' '; + // for (const auto value : double_values) { + // std::cout << value << ' '; + // } + // std::cout << ' '; + // for (const auto value : long_values) { + // std::cout << value << ' '; + // } + // std::cout << std::endl; + + const auto thread_devices = devices_.find(std::this_thread::get_id()); + if (thread_devices == devices_.end()) { + // std::cout << "Error: no devices assigned to this thread!" << std::endl; + return; + } + + const auto thread_device = thread_devices->second.find(device.get_name()); + if (thread_device == thread_devices->second.end()) { + // std::cout << "Error: device not found in this thread (device = " + // << device.get_name() << ")" << std::endl; + + return; + } + + auto &nesci_device = thread_device->second; + + if (device.get_type() == nest::RecordingDevice::Type::MULTIMETER) { + auto multimeter = + static_cast<nesci::producer::NestMultimeter *>(nesci_device.get()); + multimeter->Record(event.get_stamp().get_ms(), event.get_sender_gid(), + double_values.data(), long_values.data()); + } +} + +void StreamingRecordingBackend::synchronize() { + // Called per thread + for (const auto &device : devices_.at(std::this_thread::get_id())) { + { + std::lock_guard<std::mutex> lock_guard(relay_mutex_); + relay_.Send(device.second->node(), false); + } + static_cast<nesci::producer::NestMultimeter *>(device.second.get()) + ->Clear(); + } +} + +void StreamingRecordingBackend::finalize() { + // Called once + std::cout << "finalize()" << std::endl; +} + +} // namespace streamingnest diff --git a/streaming_recording_backend.h b/streaming_recording_backend.h new file mode 100644 index 0000000000000000000000000000000000000000..ede20e6b3761b28fb4be86f4d6a153c2fae85778 --- /dev/null +++ b/streaming_recording_backend.h @@ -0,0 +1,71 @@ +/* + * recording_backend_stream_niv.h + * + * This file is part of NEST. + * + * Copyright (C) 2004 The NEST Initiative + * + * NEST 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 2 of the License, or + * (at your option) any later version. + * + * NEST 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 NEST. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#ifndef RECORDING_BACKEND_STREAM_NIV_H +#define RECORDING_BACKEND_STREAM_NIV_H + +#include <map> +#include <memory> +#include <mutex> +#include <string> +#include <vector> + +#include "nest_types.h" +#include "recording_backend.h" + +#include "contra/relay.hpp" +#include "contra/shared_memory/shared_memory_transport.hpp" +#include "nesci/producer/device.hpp" +#include "nesci/producer/nest_multimeter.hpp" + +namespace streamingnest { + +class StreamingRecordingBackend : public nest::RecordingBackend { + public: + StreamingRecordingBackend(); + ~StreamingRecordingBackend() throw() {} + + void enroll(const nest::RecordingDevice &, const std::vector<Name> &, + const std::vector<Name> &) override; + + void initialize() override; + + void finalize() override; + void synchronize() override; + + void write(const nest::RecordingDevice &, const nest::Event &, + const std::vector<double> &, const std::vector<long> &) override; + + private: + std::mutex relay_mutex_; + contra::Relay<contra::SharedMemoryTransport> relay_; + + std::mutex write_mutex_; + + std::map<std::thread::id, + std::map<std::string, std::unique_ptr<nesci::producer::Device>>> + devices_; + std::mutex enroll_mutex_; +}; +} // namespace streamingnest + +#endif // RECORDING_BACKEND_STREAM_NIV_H diff --git a/streamingmodule.cpp b/streamingmodule.cpp index 0b0a1948e0839237f4e35c6887dc8de9984b06fe..f5c95340db7ce0b102dbd5dbfc5ea168dbe4a2ad 100644 --- a/streamingmodule.cpp +++ b/streamingmodule.cpp @@ -26,7 +26,7 @@ #include "config.h" // include headers with your own stuff -#include "recording_backend_nesci_contra.h" +#include "streaming_recording_backend.h" // Includes from nestkernel: #include "connection_manager_impl.h" @@ -35,10 +35,10 @@ #include "exceptions.h" #include "genericmodel.h" #include "genericmodel_impl.h" +#include "io_manager_impl.h" #include "kernel_manager.h" #include "model.h" #include "model_manager_impl.h" -#include "io_manager_impl.h" #include "nestmodule.h" #include "target_identifier.h" @@ -70,45 +70,38 @@ * registration will take place in the file `static_modules.h`, which is * generated by cmake. */ -#if defined( LTX_MODULE ) | defined( LINKED_MODULE ) +#if defined(LTX_MODULE) | defined(LINKED_MODULE) streamingnest::StreamingModule streamingmodule_LTX_mod; #endif // -- DynModule functions ------------------------------------------------------ -streamingnest::StreamingModule::StreamingModule() -{ -#ifdef LINKED_MODULE +streamingnest::StreamingModule::StreamingModule() { +#if defined(LINKED_MODULE) && defined(HAVE_LIBLTDL) // register this module at the dynamic loader // this is needed to allow for linking in this module at compile time // all registered modules will be initialized by the main app's dynamic loader - nest::DynamicLoaderModule::registerLinkedModule( this ); + nest::DynamicLoaderModule::registerLinkedModule(this); #endif } -streamingnest::StreamingModule::~StreamingModule() -{ -} +streamingnest::StreamingModule::~StreamingModule() {} -const std::string -streamingnest::StreamingModule::name( void ) const -{ - return std::string( "Streaming NEST Module" ); // Return name of the module +const std::string streamingnest::StreamingModule::name(void) const { + return std::string("Streaming NEST Module"); // Return name of the module } -const std::string -streamingnest::StreamingModule::commandstring( void ) const -{ +const std::string streamingnest::StreamingModule::commandstring(void) const { // Instruct the interpreter to load streamingmodule-init.sli - return std::string( "(streamingmodule-init) run" ); + return std::string("(streamingmodule-init) run"); } //------------------------------------------------------------------------------------- -void -streamingnest::StreamingModule::init( SLIInterpreter* i ) -{ +void streamingnest::StreamingModule::init(SLIInterpreter *i) { // Register recording backend. - nest::kernel().io_manager.register_recording_backend< streamingnest::RecordingBackendNesciContra >( - "streaming" ); + nest::kernel() + .io_manager + .register_recording_backend<streamingnest::StreamingRecordingBackend>( + "streaming"); -} // StreamingModule::init() +} // StreamingModule::init() diff --git a/streamingmodule.h b/streamingmodule.h index bb1309340d476351783618fe548f4ff22a9d27e8..e06646c49b23d97b89cae5e84075ad665a00df70 100644 --- a/streamingmodule.h +++ b/streamingmodule.h @@ -28,16 +28,14 @@ #include "slimodule.h" // Put your stuff into your own namespace. -namespace streamingnest -{ +namespace streamingnest { /** * Class defining your model. * @note For each model, you must define one such class, with a unique name. */ -class StreamingModule : public SLIModule -{ -public: +class StreamingModule : public SLIModule { + public: // Interface functions ------------------------------------------ /** @@ -55,20 +53,20 @@ public: * Initialize module. * @param SLIInterpreter* SLI interpreter */ - void init( SLIInterpreter* ); + void init(SLIInterpreter *); /** * Return the name of your model. */ - const std::string name( void ) const; + const std::string name(void) const; /** * Return the name of a sli file to execute when streamingmodule is loaded. * This mechanism can be used to define SLI commands associated with your * module, in particular, set up type tries for functions you have defined. */ - const std::string commandstring( void ) const; + const std::string commandstring(void) const; }; -} // namespace streamingnest +} // namespace streamingnest #endif