Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
b7ee9f1
Inital implementation of ROS3 S3 read
oruebel Jul 13, 2026
a694d11
Fix bug in HDF5IO::canModifyObjects to work with ROS3
oruebel Jul 13, 2026
d8de75c
Add missing std include
oruebel Jul 13, 2026
a2dfcec
Fix linter
oruebel Jul 13, 2026
2c1a6dd
Renamed HDF5IO::openS3 and added user tutorial page
oruebel Jul 13, 2026
ced3d4e
Fix linter errors
oruebel Jul 13, 2026
bf40da8
Fix windows CI
oruebel Jul 13, 2026
f634ed2
Update example tp use findOwnedTypes instead
oruebel Jul 13, 2026
5d01fad
add draft ROS3 benchmark app
oruebel Jul 13, 2026
963092c
Add docs for the demo
oruebel Jul 13, 2026
ca345fa
Add ros3 demo to the github build
oruebel Jul 13, 2026
cb8c828
Change build-demo.yml to use ubuntu instead of macos for easier ROS3 …
oruebel Jul 13, 2026
ea8af55
Add python script for benchmark
oruebel Jul 13, 2026
7b7ed8a
Add python benmark to demo
oruebel Jul 13, 2026
571ef5b
Attempt to fix demo workflow
oruebel Jul 13, 2026
00179f7
Add missing package for python
oruebel Jul 13, 2026
578fa53
Add option to froce remfile in ros3 python benchmark
oruebel Jul 14, 2026
8ef78d6
Added new BaseIO::findObject and RegisteredType::findOwnedObject meth…
oruebel Jul 14, 2026
c507ebd
Add unit tests for the the new BaseIO::findObject and RegisteredType:…
oruebel Jul 14, 2026
f6d975e
Updated changelog
oruebel Jul 14, 2026
68296ea
Remove commented code from demo
oruebel Jul 14, 2026
0e5cff6
clean up benchmark example SizeArray usage
oruebel Jul 14, 2026
84991a0
Add remfile VFD support for reading remote files over HTTP(S)
bendichter Jul 14, 2026
8b4e8c4
Point remfile dependency at catalystneuro/remfile-cpp v0.1.0
bendichter Jul 14, 2026
6982d33
Bump remfile-cpp pin to v0.1.1
bendichter Jul 14, 2026
fb75f41
Add HDF5IO::findObject to improve performance of the search
oruebel Jul 14, 2026
4cd167d
Fix Ubuntu build by supporting H5_VERSION 1.12 iH5OVisit semantics
oruebel Jul 14, 2026
e5803b5
Bump remfile-cpp pin to v0.1.2
bendichter Jul 14, 2026
c9f1753
Update docs/pages/userdocs/reads3.dox
bendichter Jul 15, 2026
eb3d8fd
Merge branch 'add_ros3_benchmark_demo' into add_remfile_vfd
oruebel Jul 15, 2026
670011b
Replace std::strncpy with std::memcpy to avoid Windows build errors
oruebel Jul 15, 2026
f8d020a
Merge branch 'add_ros3' into add_ros3_benchmark_demo
oruebel Jul 15, 2026
ac0a319
Merge branch 'add_ros3_benchmark_demo' into add_remfile_vfd
oruebel Jul 15, 2026
05a537f
Add type hints and parameter docs to python benchmark script
oruebel Jul 16, 2026
b054384
Add propoer docs for demo/ros3_benchmark/main.cpp
oruebel Jul 16, 2026
da7f55d
Remove extra empty line
oruebel Jul 16, 2026
3b863bb
Remove redundant objectExist checks in the BaseIO::findObject impleme…
oruebel Jul 16, 2026
d732cbe
Clean up HDF5IO::findObject
oruebel Jul 16, 2026
157829e
Remove bad fix for in-source build of HDF5
oruebel Jul 16, 2026
4239eb3
Remove bad fix for in-source build of HDF5
oruebel Jul 16, 2026
9e3e257
Merge branch 'add_ros3' into add_ros3_benchmark_demo
oruebel Jul 16, 2026
0a22d23
Merge branch 'add_ros3_benchmark_demo' into add_remfile_vfd
oruebel Jul 16, 2026
d0e6295
Add basic unittesst for remfile read
oruebel Jul 16, 2026
cf474cc
Change default to not enable remfile by default
oruebel Jul 17, 2026
b37ee65
Enable remfile in unit tests
oruebel Jul 17, 2026
92e5eff
Added remfile example to docs
oruebel Jul 17, 2026
4c15f03
Clarify remote read docs
oruebel Jul 17, 2026
62e80c3
Fix demo workflow to enable remfile
oruebel Jul 17, 2026
22f3fea
Fix spelling in docs and move build warning on reads3.dox
oruebel Jul 17, 2026
d39f434
Merge pull request #309 from NeurodataWithoutBorders/add_remfile_vfd
oruebel Jul 17, 2026
7dc09d1
Updated changelog to group and clarify remote read changes
oruebel Jul 17, 2026
c9781c8
Fix spelling error
oruebel Jul 17, 2026
47548c1
Fix spelling error
oruebel Jul 17, 2026
80c5893
Merge pull request #308 from NeurodataWithoutBorders/add_ros3_benchma…
oruebel Jul 17, 2026
88aeda1
Apply suggestion from @oruebel
oruebel Jul 24, 2026
0896d0d
Change remfile gittag to main
oruebel Jul 24, 2026
6ced864
Fix old-style case in unit test
oruebel Jul 24, 2026
7cb6b2d
renamed ros3_benchmark to remote_read_benchmark
oruebel Jul 24, 2026
4723565
Fix demo build which was not updated when renaming the ros3_benchmark
oruebel Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 79 additions & 14 deletions .github/workflows/build-demo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,23 +21,29 @@ jobs:
strategy:
fail-fast: false
matrix:
os: [macos-latest]
os: [ubuntu-latest]

runs-on: ${{ matrix.os }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install dependencies - macos
if: matrix.os == 'macos-latest'
run: brew install hdf5 catch2
- name: Install dependencies - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libhdf5-dev libcurl4-openssl-dev
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout "v3.5.3"
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install

- name: Configure and build the main project
shell: pwsh
run: |
cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])"
cmake -B build -S .
cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])" -DAQNWB_USE_REMFILE=ON
cmake --build build --config Release -j 2

- name: Install aqnwb
Expand All @@ -55,28 +61,87 @@ jobs:
working-directory: build
run: ctest --output-on-failure --no-tests=error -C Release -j 2

- name: Build the inspect_electrical_series demo - macos
if: matrix.os == 'macos-latest'
- name: Set up Conda
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: aqnwb-demo
environment-file: demo/remote_read_benchmark/conda-env.yml
if: matrix.os == 'ubuntu-latest'

- name: Build the inspect_electrical_series demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/inspect_electrical_series
cmake -B build -S . -DCMAKE_PREFIX_PATH="${{ github.workspace }}/install"
cmake --build build --config Release -j 2

- name: Run the inspect_electrical_series demo - macos
if: matrix.os == 'macos-latest'
- name: Run the inspect_electrical_series demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/inspect_electrical_series/build/bin
./nwb_analysis_demo ../../../../build/tests/data/createElectricalSeries.nwb

- name: Build the labmetadata_extension_demo demo - macos
if: matrix.os == 'macos-latest'
- name: Build the labmetadata_extension_demo demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/labmetadata_extension_demo
cmake -B build -S . -DCMAKE_PREFIX_PATH="${{ github.workspace }}/install"
cmake --build build --config Release -j 2

- name: Run the labmetadata_extension_demo demo - macos
if: matrix.os == 'macos-latest'
- name: Run the labmetadata_extension_demo demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/labmetadata_extension_demo/build/bin
./labmetadata_extension_demo

- name: Build the remote_read_benchmark demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/remote_read_benchmark
cmake -B build -S . -DCMAKE_PREFIX_PATH="${{ github.workspace }}/install"
cmake --build build --config Release -j 2

- name: Run the remote_read_benchmark demo - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/remote_read_benchmark/build/bin
./remote_read_benchmark \
"https://dandiarchive.s3.amazonaws.com/blobs/fec/8a6/fec8a690-2ece-4437-8877-8a002ff8bd8a" \
"us-east-2" \
"ElectricalSeriesAp" \
"0,0" \
"10,1"

- name: Run the remote_read_benchmark demo with the remfile driver - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
cd demo/remote_read_benchmark/build/bin
./remote_read_benchmark \
"https://dandiarchive.s3.amazonaws.com/blobs/fec/8a6/fec8a690-2ece-4437-8877-8a002ff8bd8a" \
"us-east-2" \
"ElectricalSeriesAp" \
"0,0" \
"10,1" \
remfile

- name: Run the remote_read_benchmark Python benchmark (ROS3) - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
conda run -n aqnwb-demo python demo/remote_read_benchmark/benchmark.py \
"https://dandiarchive.s3.amazonaws.com/blobs/fec/8a6/fec8a690-2ece-4437-8877-8a002ff8bd8a" \
"us-east-2" \
"ElectricalSeriesAp" \
"0,0" \
"10,1"

- name: Run the remote_read_benchmark Python benchmark (remfile) - ubuntu
if: matrix.os == 'ubuntu-latest'
run: |
conda run -n aqnwb-demo python demo/remote_read_benchmark/benchmark.py \
"https://dandiarchive.s3.amazonaws.com/blobs/fec/8a6/fec8a690-2ece-4437-8877-8a002ff8bd8a" \
"us-east-2" \
"ElectricalSeriesAp" \
"0,0" \
"10,1" \
--force-remfile

16 changes: 8 additions & 8 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y libhdf5-dev
sudo apt-get install -y libhdf5-dev libcurl4-openssl-dev
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout "v3.5.3"
Expand All @@ -45,18 +45,18 @@ jobs:

- name: Install dependencies - macos
if: matrix.os == 'macos-latest'
run: brew install hdf5 catch2
run: brew install hdf5 catch2 curl

- name: Install dependencies - windows
if: matrix.os == 'windows-latest'
run: |
cd "${VCPKG_INSTALLATION_ROOT}"
vcpkg install hdf5[cpp]:x64-windows catch2:x64-windows
vcpkg install hdf5[cpp]:x64-windows catch2:x64-windows curl:x64-windows
vcpkg integrate install

- name: Configure
shell: pwsh
run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])"
run: cmake "--preset=ci-$("${{ matrix.os }}".split("-")[0])" -DAQNWB_USE_REMFILE=ON

- name: Build
run: cmake --build build --config Release -j 2
Expand Down Expand Up @@ -87,15 +87,15 @@ jobs:
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y libhdf5-dev
sudo apt-get install -y libhdf5-dev libcurl4-openssl-dev
git clone https://github.com/catchorg/Catch2.git
cd Catch2
git checkout "v3.5.3"
cmake -Bbuild -H. -DBUILD_TESTING=OFF
sudo cmake --build build/ --target install

- name: Configure
run: cmake --preset=ci-sanitize
run: cmake --preset=ci-sanitize -DAQNWB_USE_REMFILE=ON

- name: Build
run: cmake --build build/sanitize -j 2
Expand Down Expand Up @@ -157,11 +157,11 @@ jobs:
uses: actions/checkout@v4

- name: Install dependencies - macos
run: brew install hdf5 catch2
run: brew install hdf5 catch2 curl

- name: Configure (C++23)
shell: pwsh
run: cmake "--preset=ci-macos" -DAQNWB_CXX_STANDARD=23
run: cmake "--preset=ci-macos" -DAQNWB_CXX_STANDARD=23 -DAQNWB_USE_REMFILE=ON

- name: Build
run: cmake --build build --config Release -j 2
Expand Down
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).



## Upcoming (~June 2026)

### Added
* **Added support for streaming data read of remote NWB files:**
* Added `HDF5IO::openS3(...)` method to support opening an existing remote file in S3 in read-only mode using the HDF5 ROS3 driver. (@oruebel, [#307](https://github.com/NeurodataWithoutBorders/aqnwb/pull/307))
* Added `HDF5IO::openRemote()` method to read remote NWB files over HTTP(S) using the [remfile-cpp](https://github.com/catalystneuro/remfile-cpp) virtual file driver (a C++ port of the Python [remfile](https://github.com/magland/remfile) package), imported as an optional CMake dependency (`AQNWB_USE_REMFILE`, requires `libcurl`). Unlike ROS3, remfile does not require HDF5 to be built with ROS3 support and works with any HTTP(S) server that supports byte-range requests. (@bendichter, [#309](https://github.com/NeurodataWithoutBorders/aqnwb/pull/309))
* Added demo for benchmarking ROS3 and remfile performance and comparing with PyNWB S3 reads (`demo/ros3_benchmark`). (@oruebel, [#308](https://github.com/NeurodataWithoutBorders/aqnwb/pull/308); @bendichter, [#309](https://github.com/NeurodataWithoutBorders/aqnwb/pull/309))
* Added tutorial on using the ROS3 and remfile drivers to read NWB files in S3 (`docs/pages/userdocs/reads3.dox`)
* Added `ElectricalSeries::writeAllChannels` method and `IO::writeElectricalSeriesData` overload to simplify zero-copy interleaved multichannel writes. (@copilot, @oruebel, [#293](https://github.com/NeurodataWithoutBorders/aqnwb/pull/293))
* Added `ElectricalSeries::channelsAtSameSampleOffset` method to check if all channels are at the same sample offset, which is a requirement for using `writeAllChannels`. (@copilot, @oruebel, [#293](https://github.com/NeurodataWithoutBorders/aqnwb/pull/293))
* Added new `BaseIO::findObject` and `RegisteredType::findOwnedObject` methods to simplify searching for objects by name. Added `HDF5IO::findObject` override method to optimize the search for HDF5 objects. (@oruebel, [#308](https://github.com/NeurodataWithoutBorders/aqnwb/pull/308))

### Changed
* **[BREAKING]** Moved `disableSWMRMode` option from `HDF5IO` constructor to a new `HDF5IO::startRecording(bool disableSWMRMode)` overload. The `BaseIO`-compliant `startRecording()` override is preserved and defaults to SWMR enabled.
Expand All @@ -20,6 +25,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
* Updated nwbinspector validation tests in the CI to: 1) `--ignore=check_subject_exists` and 2) remove dependency on `sanitizer` tests to speed up CI (@oruebel, [#289](https://github.com/NeurodataWithoutBorders/aqnwb/pull/289))
* Fixed `get_utc_offset_seconds` to correctly account for daylight saving time using platform-specific APIs (`tm_gmtoff` on Unix/macOS; `_get_timezone` + `_get_dstbias` on Windows), preventing `session_start_time` from being written ~1 hour ahead of UTC during DST (@cboulay, [#295](https://github.com/NeurodataWithoutBorders/aqnwb/pull/295))
* Fixed bug in `HDF5IO::canModifyObjects` returning true when a file is opened in read-only. (@oruebel, [#307](https://github.com/NeurodataWithoutBorders/aqnwb/pull/307))
* Fixed `install-config.cmake` to propagate HDF5 include directories to downstream consumers of the `aqnwb::aqnwb` target, allowing them to locate HDF5 headers regardless of where HDF5 is installed on the system. (@oruebel, [#308](https://github.com/NeurodataWithoutBorders/aqnwb/pull/308))
* Updated `build-demo.yml` and `tests.yml` CI to support testing of the new ROS3 and remfile features and scripts (@oruebel, [#308](https://github.com/NeurodataWithoutBorders/aqnwb/pull/308))


## [0.3.0] - 2026-02-23
Expand Down
37 changes: 37 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,43 @@ set_target_properties(aqnwb_aqnwb PROPERTIES

target_compile_definitions(aqnwb_aqnwb PUBLIC AQNWB_CXX_STANDARD=${AQNWB_CXX_STANDARD})

# ---- Optional remfile VFD for reading remote files over HTTP(S) ----
# remfile provides an HDF5 virtual file driver that reads remote files with
# HTTP range requests and adaptive read-ahead caching. Unlike the ROS3 VFD,
# it does not require HDF5 to be built with ROS3 support.
set(aqnwb_use_remfile_default OFF)
option(AQNWB_USE_REMFILE "Enable reading remote files over HTTP(S) via the remfile VFD (requires libcurl)" ${aqnwb_use_remfile_default})

if(AQNWB_USE_REMFILE)
find_package(CURL QUIET)
if(NOT CURL_FOUND)
message(STATUS "remfile VFD disabled: libcurl not found")
set(AQNWB_USE_REMFILE OFF)
endif()
endif()

if(AQNWB_USE_REMFILE)
# Prefer an installed remfile package; otherwise fetch it from GitHub.
# When fetched, remfile's own install rules run as part of this project's
# install, so downstream consumers of the installed aqnwb package can
# resolve the remfile::remfile target via find_dependency(remfile).
find_package(remfile CONFIG QUIET)
if(remfile_FOUND)
message(STATUS "remfile VFD enabled (found installed remfile ${remfile_VERSION})")
else()
include(FetchContent)
FetchContent_Declare(
remfile
GIT_REPOSITORY https://github.com/catalystneuro/remfile-cpp.git
GIT_TAG main
)
FetchContent_MakeAvailable(remfile)
message(STATUS "remfile VFD enabled (fetched from GitHub)")
endif()
target_compile_definitions(aqnwb_aqnwb PUBLIC AQNWB_HAVE_REMFILE_VFD)
target_link_libraries(aqnwb_aqnwb PUBLIC remfile::remfile)
endif()

# ---- Additional libraries needed ----
find_package(HDF5 REQUIRED COMPONENTS CXX)

Expand Down
2 changes: 1 addition & 1 deletion CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@
{
"name": "ci-win64",
"inherits": ["flags-msvc", "ci-std"],
"generator": "Visual Studio 17 2022",
"generator": "Visual Studio 18 2026",
"architecture": "x64",
"cacheVariables": {
"CMAKE_TOOLCHAIN_FILE": "C:/vcpkg/scripts/buildsystems/vcpkg.cmake"
Expand Down
17 changes: 16 additions & 1 deletion cmake/install-config.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,19 @@ include(CMakeFindDependencyMacro)

find_dependency(HDF5 COMPONENTS CXX)

include("${CMAKE_CURRENT_LIST_DIR}/aqnwbTargets.cmake")
# When aqnwb was built with AQNWB_USE_REMFILE=ON, the exported target
# references remfile::remfile. remfile installs into the same prefix as
# aqnwb when it was fetched at build time, so this lookup is quiet and
# harmless when aqnwb was built without remfile support.
find_package(remfile CONFIG QUIET)

include("${CMAKE_CURRENT_LIST_DIR}/aqnwbTargets.cmake")

# The aqnwb_aqnwb target only propagates HDF5 include directories via
# $<BUILD_INTERFACE:...> (see the top-level CMakeLists.txt), so they are not
# part of the installed target's INTERFACE_INCLUDE_DIRECTORIES. Explicitly add
# the HDF5 include directories found above to the imported aqnwb::aqnwb target
# so that downstream consumers (e.g. via find_package(aqnwb)) can locate HDF5
# C/C++ headers regardless of where HDF5 is installed on the system.
target_include_directories(aqnwb::aqnwb SYSTEM INTERFACE ${HDF5_INCLUDE_DIRS})

25 changes: 25 additions & 0 deletions demo/remote_read_benchmark/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.15)
project(remote_read_benchmark VERSION 0.1.0 LANGUAGES CXX)

# Set C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Find aqnwb - this automatically brings in HDF5 as a transitive dependency
find_package(aqnwb REQUIRED)

# Add the executable
add_executable(remote_read_benchmark main.cpp)

# Link to aqnwb - HDF5 includes/libraries are provided transitively
target_link_libraries(remote_read_benchmark PRIVATE aqnwb::aqnwb)

# Set the output directory
set_target_properties(remote_read_benchmark PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin
)

# Install rules
install(TARGETS remote_read_benchmark
RUNTIME DESTINATION bin
)
Loading
Loading