Maintainers
Pricing
Enterprise
More
More
Documentation
Try Live
Rankings
Install
Blog
Docs7
Ask
New
Add Docs
Gadgetron
https://gadgetron.readthedocs.io/en/latest/
Admin
Gadgetron is an open source framework for medical image reconstruction.
Tokens:
20,074
Snippets:
132
Trust Score:
9.6
Update:
1 month ago
Context
Chat
Benchmark
Latest
Show doc for...
Code
Info
Show Results
Tokens:
Raw
Copy
Link
Tokens:
Raw
Copy
Link
### Start Gadgetron server and view startup output Source: https://gadgetron.readthedocs.io/en/latest/using.html Run the gadgetron command in a terminal to start the server. The output shows the server version, port 9002, and storage server port 9112, indicating it is ready to receive data. ```bash $ gadgetron 03-08 00:33:12.267 DEBUG [gadgetron_paths.cpp:107] Executable path: "/opt/conda/envs/gadgetron/bin/gadgetron" 03-08 00:33:12.267 DEBUG [gadgetron_paths.cpp:113] Default Gadgetron home: "/opt/conda/envs/gadgetron" 03-08 00:33:12.267 WARNING [initialization.cpp:38] Environment variable 'OMP_WAIT_POLICY' not set to 'PASSIVE'. 03-08 00:33:12.267 WARNING [initialization.cpp:39] Gadgetron may experience serious performance issues under heavy load (multiple simultaneous reconstructions, etc.) 03-08 00:33:12.267 INFO [main.cpp:76] Gadgetron 4.1.5 [NA] 03-08 00:33:12.267 INFO [main.cpp:77] Running on port 9002 03-08 00:33:12.731 INFO [storage.cpp:32] Running storage server on port 9112 03-08 00:33:12.732 INFO [Server.cpp:25] Gadgetron home directory: "/opt/conda/envs/gadgetron" 03-08 00:33:12.732 INFO [Server.cpp:26] Gadgetron working directory: "/tmp/gadgetron/" Configuring services, Running on port 9002 ``` -------------------------------- ### Validate Gadgetron installation with gadgetron --info Source: https://gadgetron.readthedocs.io/en/latest/using.html Displays version and build information for the installed Gadgetron. The output varies by setup, but error messages indicate installation problems. ```bash $ gadgetron --info Gadgetron Version Info -- Version : 4.1.5 -- Git SHA1 : NA -- System Memory size : 112705 MB -- Python Support : YES -- Julia Support : NO -- Matlab Support : NO -- CUDA Support : YES -- NVCC Flags : -gencode arch=compute_60,code=sm_60;-gencode arch=compute_61,code=sm_61;-gencode arch=compute_70,code=sm_70;-gencode arch=compute_75,code=sm_75;-gencode arch=compute_80,code=sm_80;-gencode arch=compute_86,code=sm_86 --std=c++17 * Number of CUDA capable devices: 1 - Device 0: Tesla P100-PCIE-16GB + CUDA Driver Version / Runtime Version: 11.6/11.6 + CUDA Capability Major / Minor version number: 6.0 + Total amount of global GPU memory: 16280 MB ``` -------------------------------- ### Start Gadgetron server Source: https://gadgetron.readthedocs.io/en/latest/_sources/using.md.txt Starts the Gadgetron server process, which listens on port 9002 by default. ```text $ gadgetron 03-08 00:33:12.267 DEBUG [gadgetron_paths.cpp:107] Executable path: "/opt/conda/envs/gadgetron/bin/gadgetron" 03-08 00:33:12.267 DEBUG [gadgetron_paths.cpp:113] Default Gadgetron home: "/opt/conda/envs/gadgetron" 03-08 00:33:12.267 WARNING [initialization.cpp:38] Environment variable 'OMP_WAIT_POLICY' not set to 'PASSIVE'. 03-08 00:33:12.267 WARNING [initialization.cpp:39] Gadgetron may experience serious performance issues under heavy load (multiple simultaneous reconstructions, etc.) 03-08 00:33:12.267 INFO [main.cpp:76] Gadgetron 4.1.5 [NA] 03-08 00:33:12.267 INFO [main.cpp:77] Running on port 9002 03-08 00:33:12.731 INFO [storage.cpp:32] Running storage server on port 9112 03-08 00:33:12.732 INFO [Server.cpp:25] Gadgetron home directory: "/opt/conda/envs/gadgetron" 03-08 00:33:12.732 INFO [Server.cpp:26] Gadgetron working directory: "/tmp/gadgetron/" Configuring services, Running on port 9002 ``` -------------------------------- ### Run Gadgetron Docker container Source: https://gadgetron.readthedocs.io/en/latest/using.html Starts a Gadgetron Docker container with GPU support and opens a terminal. Use this to get an environment where you can run the walkthrough commands. Requires Docker and the Gadgetron image from GitHub container registries. ```bash docker run --net=host -it --rm --gpus=all ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_cuda:latest /bin/bash ``` -------------------------------- ### Full SimpleRecon implementation Source: https://gadgetron.readthedocs.io/en/latest/gadget.html A complete example of a SimpleRecon class using ChannelGadget, including FFT and coil combination. ```cpp #include <gadgetron/Gadget.h> #include <gadgetron/hoNDFFT.h> #include <gadgetron/mri_core_utility.h> #include <gadgetron/ChannelAlgorithms.h> #include <gadgetron/log.h> #include <gadgetron/mri_core_coil_map_estimation.h> using namespace Gadgetron; using namespace Gadgetron::Core; using namespace Gadgetron::Core::Algorithm; class SimpleRecon : public ChannelGadget<Acquisition> { public: SimpleRecon(const Context& context, const GadgetProperties& params) : ChannelGadget<Acquisition>(params), header{context.header} { } void process(InputChannel<Acquisition>& in, OutputChannel& out){ auto recon_size = header.encoding[0].encodedSpace.matrixSize; ISMRMRD::AcquisitionHeader saved_header; auto split_condition = [](auto& message){ return std::get<ISMRMRD::AcquisitionHeader>(message).isFlagSet(ISMRMRD::ISMRMRD_ACQ_LAST_IN_ENCODE_STEP1); }; for (auto acquisitions : buffer(in,split_condition)) { auto data = hoNDArray<std::complex<float>>(recon_size.x,recon_size.y,recon_size.z,header.acquisitionSystemInformation->receiverChannels.get()); for ( auto [acq_header, acq_data, trajectories] : acquisitions){ saved_header = acq_header; data(slice,acq_header.idx.kspace_encode_step_1,0,slice) = acq_data; } hoNDFFT<float>::instance()->fft2c(data); auto coil_map = coil_map_Inati(data); data = coil_combine(data,coil_map,3); auto image_header = image_header_from_acquisition(saved_header,header,data); out.push(image_header,data); } } private: const ISMRMRD::IsmrmrdHeader header; }; GADGETRON_GADGET_EXPORT(SimpleRecon) ``` -------------------------------- ### Build Docker image with build-images.sh Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Builds a Docker image using the build-images.sh script. The example builds a CUDA development image. See --help for details. ```bash ./build-images --type dev --flavor cuda ``` -------------------------------- ### Iterate over InputChannel Source: https://gadgetron.readthedocs.io/en/latest/gadget.html Example of iterating over an InputChannel using a standard for loop to access acquisition components. ```cpp void process(InputChannel<Acquisition>& in, OutputChannel& out) override { for (auto acquisition : in ) { auto& header = std::get<ISMRMRD::AcquisitionHeader>(acquisition); auto& data = std::get<hoNDArray<std::complex<float>>>(acquisition); auto& trajectory = std::get<optional<hoNDArray<float>>>(acquisition); //Gather acquisitions here } } ``` -------------------------------- ### Run reconstruction using Docker Source: https://gadgetron.readthedocs.io/en/latest/using.html Invokes a reconstruction using the Gadgetron Docker container without local installation. ```bash ismrmrd_hdf5_to_stream --use-stdout -i testdata.h5 | docker run -i --gpus=all ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_cuda:latest --from_stream -c default.xml | ismrmrd_stream_to_hdf5 --use-stdin -o out.h5 ``` -------------------------------- ### Build Gadgetron with CMake and Ninja Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Clones the repository, creates a build directory, configures with CMake using Ninja and Release build type with MKL enabled, then builds and installs to the conda prefix. ```bash git clone https://github.com/gadgetron/gadgetron.git cd gadgetron mkdir -p build cd build cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=${CONDA_PREFIX} ../ ninja ninja install ``` -------------------------------- ### Create conda environment from environment.yml Source: https://gadgetron.readthedocs.io/en/latest/_sources/obtaining.md.txt Run this command to create the conda environment from the environment.yml file. After activation, verify the installation with 'gadgetron --info'. ```bash conda env create -f environment.yml ``` -------------------------------- ### SimpleRecon full implementation - ChannelGadget Source: https://gadgetron.readthedocs.io/en/latest/_sources/gadget.rst.txt Complete implementation of SimpleRecon with includes, constructor taking Context and GadgetProperties, and a process method that uses the header to get the encoded space matrix size. ```cpp #include <gadgetron/Gadget.h> #include <gadgetron/hoNDFFT.h> #include <gadgetron/mri_core_utility.h> #include <gadgetron/ChannelAlgorithms.h> #include <gadgetron/log.h> #include <gadgetron/mri_core_coil_map_estimation.h> using namespace Gadgetron; using namespace Gadgetron::Core; using namespace Gadgetron::Core::Algorithm; class SimpleRecon : public ChannelGadget<Acquisition> { public: SimpleRecon(const Context& context, const GadgetProperties& params) : ChannelGadget<Acquisition>(params), header{context.header} { } void process(InputChannel<Acquisition>& in, OutputChannel& out){ auto recon_size = header.encoding[0].encodedSpace.matrixSize; ``` -------------------------------- ### Create conda environment from environment.yml Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Creates a conda environment with dependencies defined in environment.yml. Requires conda to be installed. ```bash conda env create -f environment.yml ``` -------------------------------- ### ChannelGadget tuple type matching Source: https://gadgetron.readthedocs.io/en/latest/type_matching.html Equivalent to the simple type matching example using a tuple. ```cpp ChannelGadget<tuple<ISMRMRD::AcquisitionHeader, hoNDArray<std::complex<float>>>> ``` -------------------------------- ### ChannelGadget simple type matching Source: https://gadgetron.readthedocs.io/en/latest/type_matching.html Matches messages starting with an AcquisitionHeader followed by a hoNDArray. ```cpp ChannelGadget<ISMRMRD::AcquisitionHeader, hoNDArray<std::complex<float>>> ``` -------------------------------- ### Server terminal output during reconstruction Source: https://gadgetron.readthedocs.io/en/latest/using.html Expected log output from the Gadgetron server terminal when a reconstruction starts. It shows connection states, gadget loading, and processing steps. ```text 03-08 00:35:04.947 INFO [Server.cpp:38] Accepted connection from: ::ffff:127.0.0.1 03-08 00:35:04.948 INFO [ConfigConnection.cpp:131] Connection state: [CONFIG] 03-08 00:35:04.948 DEBUG [ConfigConnection.cpp:73] Reading config file: "/opt/conda/envs/gadgetron/share/gadgetron/config/default.xml" 03-08 00:35:04.949 INFO [HeaderConnection.cpp:84] Connection state: [HEADER] 03-08 00:35:04.949 DEBUG [RESTStorageClient.cpp:301] Using storage address: http://localhost:9112 03-08 00:35:04.949 INFO [StreamConnection.cpp:75] Connection state: [STREAM] 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget AccTrig of class AcquisitionAccumulateTriggerGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget Buff of class BucketToBufferGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget ImageFinish of class ImageFinishGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget SimpleRecon of class SimpleReconGadget from gadgetron_mricore 03-08 00:35:04.966 DEBUG [Stream.cpp:58] Loading Gadget RemoveROOversampling of class RemoveROOversamplingGadget from gadgetron_mricore 03-08 00:35:04.967 DEBUG [Stream.cpp:58] Loading Gadget ImageArraySplit of class ImageArraySplitGadget from gadgetron_mricore 03-08 00:35:04.969 DEBUG [RemoveROOversamplingGadget.cpp:43] RemoveROOversamplingGadget:omp_set_num_threads(1) ... 03-08 00:35:04.969 DEBUG [Stream.cpp:58] Loading Gadget Extract of class ExtractGadget from gadgetron_mricore 03-08 00:35:05.246 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (1) occurred, sending out 1 buckets 03-08 00:35:05.246 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.249 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.264 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (2) occurred, sending out 1 buckets 03-08 00:35:05.265 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.268 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.338 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (3) occurred, sending out 1 buckets 03-08 00:35:05.338 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.341 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.391 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (4) occurred, sending out 1 buckets 03-08 00:35:05.392 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.395 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.446 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (5) occurred, sending out 1 buckets 03-08 00:35:05.447 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.449 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.494 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (6) occurred, sending out 1 buckets 03-08 00:35:05.494 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.497 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.567 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (7) occurred, sending out 1 buckets 03-08 00:35:05.567 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.570 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.659 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (8) occurred, sending out 1 buckets 03-08 00:35:05.659 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.662 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.751 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (9) occurred, sending out 1 buckets 03-08 00:35:05.751 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.754 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.836 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.836 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (10) occurred, sending out 1 buckets 03-08 00:35:05.836 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.839 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.851 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.851 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.852 INFO [Core.cpp:77] Connection state: [FINISHED] ``` -------------------------------- ### ChannelGadget with simple type list Source: https://gadgetron.readthedocs.io/en/latest/_sources/type_matching.rst.txt Defines a ChannelGadget that accepts a message starting with an AcquisitionHeader followed by a hoNDArray of complex floats. Extra message parts are discarded. Equivalent to using a tuple. ```cpp ChannelGadget<ISMRMRD::AcquisitionHeader, hoNDArray<std::complex<float>>> ``` ```cpp ChannelGadget<tuple<ISMRMRD::AcquisitionHeader, hoNDArray<std::complex<float>>>> ``` -------------------------------- ### Gadgetron Server Mode Log Output Source: https://gadgetron.readthedocs.io/en/latest/_sources/using.md.txt A sample log showing the server accepting a connection, loading the default configuration, initializing various gadgets, and processing data buckets. ```text 03-08 00:35:04.947 INFO [Server.cpp:38] Accepted connection from: ::ffff:127.0.0.1 03-08 00:35:04.948 INFO [ConfigConnection.cpp:131] Connection state: [CONFIG] 03-08 00:35:04.948 DEBUG [ConfigConnection.cpp:73] Reading config file: "/opt/conda/envs/gadgetron/share/gadgetron/config/default.xml" 03-08 00:35:04.949 INFO [HeaderConnection.cpp:84] Connection state: [HEADER] 03-08 00:35:04.949 DEBUG [RESTStorageClient.cpp:301] Using storage address: http://localhost:9112 03-08 00:35:04.949 INFO [StreamConnection.cpp:75] Connection state: [STREAM] 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget AccTrig of class AcquisitionAccumulateTriggerGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget Buff of class BucketToBufferGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget ImageFinish of class ImageFinishGadget from gadgetron_mricore 03-08 00:35:04.965 DEBUG [Stream.cpp:58] Loading Gadget SimpleRecon of class SimpleReconGadget from gadgetron_mricore 03-08 00:35:04.966 DEBUG [Stream.cpp:58] Loading Gadget RemoveROOversampling of class RemoveROOversamplingGadget from gadgetron_mricore 03-08 00:35:04.967 DEBUG [Stream.cpp:58] Loading Gadget ImageArraySplit of class ImageArraySplitGadget from gadgetron_mricore 03-08 00:35:04.969 DEBUG [RemoveROOversamplingGadget.cpp:43] RemoveROOversamplingGadget:omp_set_num_threads(1) ... 03-08 00:35:04.969 DEBUG [Stream.cpp:58] Loading Gadget Extract of class ExtractGadget from gadgetron_mricore 03-08 00:35:05.246 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (1) occurred, sending out 1 buckets 03-08 00:35:05.246 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.249 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.264 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (2) occurred, sending out 1 buckets 03-08 00:35:05.265 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.268 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.338 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (3) occurred, sending out 1 buckets 03-08 00:35:05.338 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.341 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.391 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (4) occurred, sending out 1 buckets 03-08 00:35:05.392 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.395 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.446 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (5) occurred, sending out 1 buckets 03-08 00:35:05.447 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.449 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.494 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (6) occurred, sending out 1 buckets 03-08 00:35:05.494 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.497 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.567 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (7) occurred, sending out 1 buckets 03-08 00:35:05.567 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.570 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.659 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (8) occurred, sending out 1 buckets 03-08 00:35:05.659 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.662 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.751 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (9) occurred, sending out 1 buckets 03-08 00:35:05.751 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.754 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.836 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.836 DEBUG [AcquisitionAccumulateTriggerGadget.cpp:129] Trigger (10) occurred, sending out 1 buckets 03-08 00:35:05.836 DEBUG [BucketToBufferGadget.cpp:50] BUCKET_SIZE 256 ESPACE 0 03-08 00:35:05.839 DEBUG [BucketToBufferGadget.cpp:90] End of bucket reached, sending out 1 ReconData buffers 03-08 00:35:05.851 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.851 DEBUG [Gadget.h:130] Shutting down Gadget () 03-08 00:35:05.852 INFO [Core.cpp:77] Connection state: [FINISHED] ``` -------------------------------- ### Run Gadgetron in stream mode Source: https://gadgetron.readthedocs.io/en/latest/using.html Consumes the streaming format file 'test_out.dat' using the default configuration. ```bash gadgetron --from_stream -c default.xml -i test_out.dat -o img_out.dat ``` -------------------------------- ### Run gadgetron_ismrmrd_client Source: https://gadgetron.readthedocs.io/en/latest/_sources/using.md.txt Sends the testdata.h5 file to the running Gadgetron server for reconstruction. ```text $ gadgetron_ismrmrd_client -f testdata.h5 Gadgetron ISMRMRD client -- host : localhost -- port : 9002 -- hdf5 file in : testdata.h5 -- hdf5 group in : /dataset -- conf : default.xml -- loop : 1 -- hdf5 file out : out.h5 -- hdf5 group out : 2022-03-08 00:35:04 ``` -------------------------------- ### Consume intermediary data in different ways Source: https://gadgetron.readthedocs.io/en/latest/using.html Demonstrates two methods to consume the 'tmp.dat' file for further processing. ```bash gadgetron --from_stream -c stream_complex_to_float.xml -i tmp.dat | gadgetron --from_stream -c stream_float_to_short.xml | ismrmrd_stream_to_hdf5 --use-stdin -o out1.h5 cat tmp.dat | gadgetron --from_stream -c stream_complex_to_float.xml | gadgetron --from_stream -c stream_float_to_short.xml | ismrmrd_stream_to_hdf5 --use-stdin -o out2.h5 ``` -------------------------------- ### Run gadgetron with storage server address Source: https://gadgetron.readthedocs.io/en/latest/using.html Specify the storage server address as a command-line argument to gadgetron. This is recommended for production scenarios, especially in stream mode. ```bash gadgetron --storage-address https://my-storage-server:3333 ``` -------------------------------- ### Configure Storage Server Address via CLI Source: https://gadgetron.readthedocs.io/en/latest/_sources/using.md.txt Specify the storage server address using the --storage-address flag when launching Gadgetron. ```bash gadgetron --storage-address https://my-storage-server:3333 ``` -------------------------------- ### Send data to Gadgetron server with gadgetron_ismrmrd_client Source: https://gadgetron.readthedocs.io/en/latest/using.html Run this command in a second terminal to send the test data file to the running Gadgetron server. The output shows the client configuration, including host localhost, port 9002, input file testdata.h5, and output file out.h5. ```bash $ gadgetron_ismrmrd_client -f testdata.h5 Gadgetron ISMRMRD client -- host : localhost -- port : 9002 -- hdf5 file in : testdata.h5 -- hdf5 group in : /dataset -- conf : default.xml -- loop : 1 -- hdf5 file out : out.h5 -- hdf5 group out : 2022-03-08 00:35:04 ``` -------------------------------- ### Implement AutoScaleGadget logic Source: https://gadgetron.readthedocs.io/en/latest/gadget.html The implementation file for AutoScaleGadget, including the process_function and the GADGETRON_GADGET_EXPORT macro for dynamic loading. ```cpp #include "AutoScaleGadget.h" using namespace Gadgetron; using namespace Gadgetron::Core; namespace { template<class T> Image<T> autoscale(Image<T> &image, float max_value, unsigned int histogram_bins) { auto &header = std::get<ISMRMRD::ImageHeader>(image); auto &data = std::get<hoNDArray<T>>(image); auto &meta = std::get<optional<ISMRMRD::MetaContainer>>(image); if (header.image_type == ISMRMRD::ISMRMRD_IMTYPE_MAGNITUDE) { //Only scale magnitude images for now auto max = *std::max_element(data.begin(), data.end()); auto current_scale_ = 1.0; auto histogram_ = std::vector<size_t>(histogram_bins); std::fill(histogram_.begin(), histogram_.end(), 0); for (auto& d : data) { size_t bin = static_cast<size_t>(std::floor((d/max)*histogram_bins)); if (bin >= histogram_bins) { bin = histogram_bins-1; } histogram_[bin]++; } //Find 99th percentile long long cumsum = 0; size_t counter = 0; while (cumsum < (0.99*data.get_number_of_elements())) { cumsum += (long long)(histogram_[counter++]); } max = (counter+1)*(max/histogram_bins); current_scale_ = max_value/max; for (auto& d : data){ d *= current_scale_; } } return Image<T>(header,data,meta); } template<class T> Image<std::complex<T>> autoscale(Image<std::complex<T>> &image, float max_value, unsigned int histogram_bins) { GERROR("Autoscaling image is not well defined for complex images."); return image; } } namespace Gadgetron { AnyImage AutoScaleGadget::process_function(AnyImage image) const { return visit([&](auto &image) -> AnyImage { return autoscale(image, max_value, histogram_bins); }, image); } GADGETRON_GADGET_EXPORT(AutoScaleGadget); } ``` -------------------------------- ### Run end-to-end tests Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Downloads test data and runs integration tests with logging on failure, a 600-second timeout, and stats output to stats.csv. ```bash cd test/integration python get_data.py python run_tests.py --echo-log-on-failure --timeout=600 -F --stats stats.csv cases/* ``` -------------------------------- ### SimpleRecon gadget implementation Source: https://gadgetron.readthedocs.io/en/latest/_sources/gadget.rst.txt Defines a Gadgetron gadget class that processes acquisitions grouped by the LAST_IN_ENCODE_STEP1 flag. It reconstructs each group by filling a k-space array, performing a 2D FFT, coil map estimation and combination, then pushing the resulting image with a header. ```cpp ISMRMRD::AcquisitionHeader saved_header; auto split_condition = [](auto& message){ return std::get<ISMRMRD::AcquisitionHeader>(message).isFlagSet(ISMRMRD::ISMRMRD_ACQ_LAST_IN_ENCODE_STEP1); }; for (auto acquisitions : buffer(in,split_condition)) { auto data = hoNDArray<std::complex<float>>(recon_size.x,recon_size.y,recon_size.z,header.acquisitionSystemInformation->receiverChannels.get()); for ( auto [acq_header, acq_data, trajectories] : acquisitions){ saved_header = acq_header; data(slice,acq_header.idx.kspace_encode_step_1,0,slice) = acq_data; } hoNDFFT<float>::instance()->fft2c(data); auto coil_map = coil_map_Inati(data); data = coil_combine(data,coil_map,3); auto image_header = image_header_from_acquisition(saved_header,header,data); out.push(image_header,data); } } private: const ISMRMRD::IsmrmrdHeader header; }; GADGETRON_GADGET_EXPORT(SimpleRecon) ``` -------------------------------- ### Docker image names Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt List of Docker image names for development and runtime images with CUDA and no-CUDA flavors. ```text ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_dev_cuda:latest ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_dev_nocuda:latest ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_cuda:latest ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_nocuda:latest ``` -------------------------------- ### Generate test data with ismrmrd_generate_cartesian_shepp_logan Source: https://gadgetron.readthedocs.io/en/latest/using.html Run this command in a terminal to generate a test dataset named testdata.h5 in the current working directory with 8 coils and 10 repetitions. This step is unnecessary if you already have your own dataset. ```bash ismrmrd_generate_cartesian_shepp_logan -r 10 ``` -------------------------------- ### GenericPureGadget::process (final) Source: https://gadgetron.readthedocs.io/en/latest/core.html Final implementation of process for GenericPureGadget that processes data from the input channel. ```APIDOC ## GenericPureGadget::process (final) ### Description The function which processes the data coming from the InputChannel. Conceptually a coroutine. ### Method inline virtual void process(GenericInputChannel &in, OutputChannel &out) final ### Parameters - **in** (GenericInputChannel&) - Required - Channel from which messages are received from upstream - **out** (OutputChannel&) - Required - Channel in which messages are sent on downstream ### Returns void ``` -------------------------------- ### Inherit from ChannelGadget Source: https://gadgetron.readthedocs.io/en/latest/gadget.html Basic structure for creating a custom Gadget that inherits from ChannelGadget to process acquisitions. ```cpp using namespace Gadgetron; using namespace Gadgetron::Core; class SimpleRecon : public ChannelGadget<Acquisition>{ public: void process(InputChannel<Acquisition>& in, OutputChannel& out) override { ... } } ``` -------------------------------- ### Activate conda environment Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Activates the conda environment named 'gadgetron'. ```bash conda activate gadgetron ``` -------------------------------- ### Run Gadgetron Docker container Source: https://gadgetron.readthedocs.io/en/latest/_sources/building.md.txt Runs the GPU-enabled runtime Docker image, exposing port 9004 to host port 9002. ```bash docker run --gpus=all -ti -p 9004:9002 ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_cuda:latest ``` -------------------------------- ### Convert HDF5 to streaming format Source: https://gadgetron.readthedocs.io/en/latest/using.html Converts 'testdata.h5' to an intermediary streaming format file 'test_out.dat'. ```bash ismrmrd_hdf5_to_stream -i testdata.h5 -o test_out.dat ``` -------------------------------- ### Define conda environment for Gadgetron with dependencies Source: https://gadgetron.readthedocs.io/en/latest/_sources/obtaining.md.txt Create an environment.yml file to define the Gadgetron conda environment with required channels and dependencies, including gadgetron and siemens_to_ismrmrd. ```yaml name: gadgetron channels: - ismrmrd - gadgetron - nvidia/label/cuda-11.6.1 - conda-forge - bioconda - defaults - intel dependencies: - gadgetron>=4.4.3 - siemens_to_ismrmrd>=1.2.6 ``` -------------------------------- ### Chain complex reconstruction configurations Source: https://gadgetron.readthedocs.io/en/latest/using.html Chains multiple reconstruction configurations to process complex images into float and then short formats. ```bash ismrmrd_hdf5_to_stream -i testdata.h5 --use-stdout | gadgetron --from_stream -c Generic_Cartesian_Grappa_Complex.xml | gadgetron --from_stream -c stream_complex_to_float.xml | gadgetron --from_stream -c stream_float_to_short.xml | ismrmrd_stream_to_hdf5 --use-stdin -o out.h5 ``` -------------------------------- ### ChannelGadget::process (pure virtual) Source: https://gadgetron.readthedocs.io/en/latest/core.html The process function to be implemented when inheriting from ChannelGadget. Provides typed access to input data. ```APIDOC ## ChannelGadget::process (pure virtual) ### Description The process function to be implemented when inheriting from this class. ### Method virtual void process(InputChannel<TYPELIST...> &in, OutputChannel &out) = 0 ### Parameters - **in** (InputChannel<TYPELIST...>&) - Required - A channel of the types specified in TYPELIST - **out** (OutputChannel&) - Required - Channel of output ### Returns void ``` -------------------------------- ### Visualize output in Jupyter Notebook Source: https://gadgetron.readthedocs.io/en/latest/using.html Uses h5py and matplotlib to load and display the reconstructed image from 'out.h5'. ```python import h5py from matplotlib import pyplot as plt import numpy as np %matplotlib inline f = h5py.File('/workspaces/gadgetron/out.h5') image_series = list(f.keys()) data = np.array(f[image_series[0]]['image_0']['data']).squeeze() plt.imshow(data[0,:,:]) ``` -------------------------------- ### Buffer acquisitions with split condition Source: https://gadgetron.readthedocs.io/en/latest/gadget.html Using the buffer algorithm to group acquisitions based on a flag in the AcquisitionHeader. ```cpp void process(InputChannel<Acquisition>& in, OutputChannel& out) override { auto split_condition = [](auto& message){ return std::get<ISMRMRD::AcquisitionHeader>(message).isFlagSet(ISMRMRD::ISMRMRD_ACQ_LAST_IN_ENCODE_STEP1); }; for (auto acquisitions : buffer(in,split_condition)) { for (auto [header, data, trajectory] : acquisitions ) { //Gather acquisitions here } } ``` -------------------------------- ### Run GPU-enabled Gadgetron Docker container Source: https://gadgetron.readthedocs.io/en/latest/_sources/obtaining.md.txt This command runs the CUDA-enabled Gadgetron runtime image, exposing port 9004 mapping to container port 9002. Requires NVIDIA GPU and Docker with GPU support. ```bash docker run --gpus=all -ti -p 9004:9002 ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_rt_cuda:latest ``` -------------------------------- ### Acquisition type definition in Types.h Source: https://gadgetron.readthedocs.io/en/latest/type_matching.html Shows how Acquisition is defined using a tuple with an optional element. ```cpp using Acquisition = tuple<ISMRMRD::AcquisitionHeader, hoNDArray<std::complex<float>>,optional<hoNDArray<float>>>; ``` -------------------------------- ### Iterate with C++17 structured binding Source: https://gadgetron.readthedocs.io/en/latest/gadget.html Using C++17 structured bindings to simplify access to acquisition components within a loop. ```cpp void process(InputChannel<Acquisition>& in, OutputChannel& out) override { for (auto [header, data, trajectory] : in ) { //Gather acquisitions here } } ``` -------------------------------- ### Node::process Source: https://gadgetron.readthedocs.io/en/latest/core.html Pure virtual function that processes data from the input channel and sends messages to the output channel. Must be implemented by subclasses. ```APIDOC ## Node::process ### Description Processes the data coming from the InputChannel. Conceptually a coroutine. ### Method virtual void process(GenericInputChannel &in, OutputChannel &out) = 0 ### Parameters - **in** (GenericInputChannel&) - Required - Channel from which messages are received from upstream - **out** (OutputChannel&) - Required - Channel in which messages are sent on downstream ### Returns void ```