From 936fded51611295480cd9c7784f8588062b9588a Mon Sep 17 00:00:00 2001 From: Joe Naegele Date: Sat, 14 Dec 2024 10:10:20 -0500 Subject: [PATCH] Upgrade from ISMRMRD to MRDv2 Establish Pingvin streaming image reconstruction framework. * Upgrade all tested Gadgets/Toolboxes to use MRDv2 instead of ISMRMRD * Remove all socket networking code, including `gadgetron_ismrmrd_client` * Remove all Readers and Writers * Refactor end-to-end tests to use PyTest, removing Siemens dat conversion * Remove everything Windows-related * Port the CI pipeline to GitHub Actions * Rename from Gadgetron to Pingvin --- .devcontainer/.vscode/launch.json | 2 +- .devcontainer/.vscode/settings.json | 4 +- .devcontainer/bootstrap-vscode.sh | 2 +- .devcontainer/devcontainer.bashrc | 14 + .devcontainer/devcontainer.json | 15 +- .dockerignore | 7 +- .github/workflows/pingvin-ci.yml | 149 + CMakeLists.txt | 309 +- Dockerfile | 81 +- README.md | 3 +- apps/CMakeLists.txt | 7 +- apps/clients/CMakeLists.txt | 7 - .../gadgetron_ismrmrd_client/CMakeLists.txt | 21 - .../gadgetron_ismrmrd_client.cpp | 2044 ------------ apps/clients/utilities/CMakeLists.txt | 28 - .../clients/utilities/DependencyQueryReader.h | 100 - apps/clients/utilities/gt_alive.cpp | 68 - apps/clients/utilities/gt_query.cpp | 99 - apps/gadgetron/CMakeLists.txt | 110 - apps/gadgetron/Connection.cpp | 49 - apps/gadgetron/Connection.h | 15 - apps/gadgetron/Server.cpp | 42 - apps/gadgetron/Server.h | 19 - apps/gadgetron/StreamConsumer.h | 282 -- .../gadgetron/connection/ConfigConnection.cpp | 168 - apps/gadgetron/connection/ConfigConnection.h | 14 - apps/gadgetron/connection/Core.cpp | 89 - apps/gadgetron/connection/Handlers.cpp | 103 - apps/gadgetron/connection/Handlers.h | 53 - .../gadgetron/connection/HeaderConnection.cpp | 123 - apps/gadgetron/connection/HeaderConnection.h | 17 - apps/gadgetron/connection/Loader.cpp | 74 - apps/gadgetron/connection/Loader.h | 102 - apps/gadgetron/connection/SocketStreamBuf.cpp | 125 - apps/gadgetron/connection/SocketStreamBuf.h | 10 - .../gadgetron/connection/StreamConnection.cpp | 110 - apps/gadgetron/connection/StreamConnection.h | 19 - apps/gadgetron/connection/VoidConnection.cpp | 62 - apps/gadgetron/connection/VoidConnection.h | 17 - apps/gadgetron/connection/Writers.cpp | 34 - apps/gadgetron/connection/Writers.h | 17 - apps/gadgetron/connection/config/Config.h | 112 - .../connection/nodes/Distributed.cpp | 184 -- apps/gadgetron/connection/nodes/Distributed.h | 44 - apps/gadgetron/connection/nodes/External.cpp | 160 - apps/gadgetron/connection/nodes/External.h | 57 - .../connection/nodes/PureDistributed.cpp | 118 - .../connection/nodes/PureDistributed.h | 51 - .../connection/nodes/common/Closer.h | 21 - .../connection/nodes/common/Configuration.cpp | 74 - .../connection/nodes/common/Configuration.h | 24 - .../connection/nodes/common/Discovery.cpp | 109 - .../connection/nodes/common/Discovery.h | 12 - .../connection/nodes/common/External.cpp | 82 - .../connection/nodes/common/External.h | 34 - .../nodes/common/ExternalChannel.cpp | 105 - .../connection/nodes/common/ExternalChannel.h | 66 - .../connection/nodes/common/Serialization.cpp | 72 - .../connection/nodes/common/Serialization.h | 32 - .../connection/nodes/distributed/Pool.cpp | 63 - .../connection/nodes/distributed/Pool.h | 26 - .../connection/nodes/distributed/Worker.cpp | 159 - .../connection/nodes/distributed/Worker.h | 54 - .../connection/nodes/external/Julia.cpp | 62 - .../connection/nodes/external/Julia.h | 17 - .../connection/nodes/external/Matlab.cpp | 49 - .../connection/nodes/external/Matlab.h | 16 - .../connection/nodes/external/Python.cpp | 128 - .../connection/nodes/external/Python.h | 17 - apps/gadgetron/gadgetron_config.in | 14 - apps/gadgetron/main.cpp | 182 - apps/gadgetron/schema/gadgetron.xsd | 79 - apps/gadgetron/storage.cpp | 94 - apps/gadgetron/storage.h | 17 - apps/gadgetron/test/CMakeLists.txt | 26 - apps/gadgetron/test/socket_test.cpp | 107 - apps/gadgetron/test/storage_test.cpp | 302 -- apps/pingvin/CMakeLists.txt | 62 + .../connection/config => pingvin}/Config.cpp | 264 +- apps/pingvin/Config.h | 60 + .../Core.h => pingvin/ErrorHandler.h} | 67 +- apps/pingvin/Loader.cpp | 33 + apps/pingvin/Loader.h | 52 + apps/pingvin/StreamConsumer.h | 196 ++ .../{gadgetron => pingvin}/initialization.cpp | 4 +- apps/{gadgetron => pingvin}/initialization.h | 2 +- apps/pingvin/main.cpp | 133 + .../connection => pingvin}/nodes/Parallel.cpp | 20 +- .../connection => pingvin}/nodes/Parallel.h | 4 +- .../nodes/ParallelProcess.cpp | 2 +- .../nodes/ParallelProcess.h | 4 +- .../core => pingvin/nodes}/Processable.cpp | 2 +- .../core => pingvin/nodes}/Processable.h | 5 +- .../nodes/PureStream.cpp | 10 +- .../connection => pingvin}/nodes/PureStream.h | 6 +- .../connection => pingvin}/nodes/Stream.cpp | 48 +- .../connection => pingvin}/nodes/Stream.h | 10 +- apps/pingvin/pingvin_config.in | 13 + apps/pingvin/schema/gadgetron.xsd | 37 + apps/{gadgetron => pingvin}/system_info.cpp | 147 +- apps/{gadgetron => pingvin}/system_info.h | 15 +- apps/standalone/CMakeLists.txt | 9 - apps/standalone/cpu/CMakeLists.txt | 43 - .../cpu/denoising/2d/CMakeLists.txt | 18 - .../cpu/denoising/2d/denoise_TV.cpp | 117 - apps/standalone/cpu/denoising/CMakeLists.txt | 1 - apps/standalone/cpu/nfft/CMakeLists.txt | 20 - apps/standalone/cpu/nfft/nfft.cpp | 85 - .../cpu/registration/2d/CMakeLists.txt | 30 - .../cpu/registration/2d/register_CK_2d.cpp | 121 - .../cpu/registration/2d/register_HS_2d.cpp | 110 - .../cpu/registration/3d/CMakeLists.txt | 11 - .../cpu/registration/3d/register_CK_3d.cpp | 115 - .../cpu/registration/CMakeLists.txt | 3 - apps/standalone/gpu/CMakeLists.txt | 20 - .../gpu/deblurring/2d/CMakeLists.txt | 14 - apps/standalone/gpu/deblurring/2d/blur_2d.cpp | 111 - .../gpu/deblurring/2d/deblur_2d_cg.cpp | 108 - .../gpu/deblurring/2d/deblur_2d_sb.cpp | 129 - .../gpu/deblurring/3d/CMakeLists.txt | 13 - apps/standalone/gpu/deblurring/3d/blur_3d.cpp | 113 - .../gpu/deblurring/3d/deblur_3d_cg.cpp | 114 - .../gpu/deblurring/3d/deblur_3d_sb.cpp | 135 - apps/standalone/gpu/deblurring/CMakeLists.txt | 2 - .../gpu/denoising/2d/CMakeLists.txt | 13 - .../gpu/denoising/2d/denoise_TV.cpp | 154 - apps/standalone/gpu/denoising/CMakeLists.txt | 1 - apps/standalone/gpu/mri/CMakeLists.txt | 2 - .../standalone/gpu/mri/nfft/2d/CMakeLists.txt | 18 - apps/standalone/gpu/mri/nfft/2d/main_cg.cpp | 141 - apps/standalone/gpu/mri/nfft/2d/main_nfft.cpp | 144 - .../standalone/gpu/mri/nfft/2d/main_nffth.cpp | 145 - apps/standalone/gpu/mri/nfft/2d/main_sb.cpp | 175 - apps/standalone/gpu/mri/nfft/CMakeLists.txt | 2 - .../gpu/mri/nfft/ms2d/CMakeLists.txt | 9 - .../gpu/mri/nfft/ms2d/nfft_main.cpp | 150 - .../gpu/mri/nfft/ms2d/nffth_generic.cpp | 154 - .../gpu/mri/nfft/ms2d/nffth_main.cpp | 173 - apps/standalone/gpu/mri/sense/CMakeLists.txt | 2 - .../gpu/mri/sense/noncartesian/CMakeLists.txt | 11 - .../gpu/mri/sense/noncartesian/generic_cg.cpp | 193 -- .../radial/2d_golden_ratio/.gitignore | 1 - .../radial/2d_golden_ratio/CMakeLists.txt | 11 - .../radial/2d_golden_ratio/main_cg.cpp | 291 -- .../radial/2d_golden_ratio/main_gpbb.cpp | 287 -- .../radial/2d_golden_ratio/main_nlcg.cpp | 342 -- .../radial/2d_golden_ratio/main_sbc.cpp | 335 -- .../radial/2d_golden_ratio_gui/CMakeLists.txt | 30 - .../2d_golden_ratio_gui/GLReconWidget.cpp | 222 -- .../2d_golden_ratio_gui/GLReconWidget.h | 56 - .../radial/2d_golden_ratio_gui/UIconstants.h | 10 - .../radial/2d_golden_ratio_gui/main.cpp | 19 - .../radialSenseAppBaseMainWidget.ui | 572 ---- .../radialSenseAppMainWidget.cpp | 690 ---- .../radialSenseAppMainWidget.h | 134 - .../2d_golden_ratio_gui/reconBaseWidget.ui | 303 -- .../2d_golden_ratio_gui/reconWidget.cpp | 7 - .../radial/2d_golden_ratio_gui/reconWidget.h | 13 - .../radial/2d_golden_ratio_kt/CMakeLists.txt | 5 - .../radial/2d_golden_ratio_kt/main.cpp | 323 -- .../sense/noncartesian/radial/CMakeLists.txt | 10 - .../gpu/registration/2d/CMakeLists.txt | 43 - .../gpu/registration/2d/register_CGHS_2d.cpp | 134 - .../gpu/registration/2d/register_CK_2d.cpp | 129 - .../gpu/registration/2d/register_HS_2d.cpp | 122 - .../registration/2d/test_reg_sense_recon.cpp | 568 ---- .../gpu/registration/3d/CMakeLists.txt | 9 - .../gpu/registration/3d/register_CK_3d.cpp | 124 - .../gpu/registration/CMakeLists.txt | 7 - azure-pipelines.yml | 146 - chroot/CMakeLists.txt | 106 - chroot/README.rst | 35 - chroot/chroot-manual.txt | 156 - chroot/clean_gadgetron_data.sh | 61 - chroot/copy-cuda-lib.sh.in | 34 - chroot/copy_file_and_dependencies | 25 - chroot/create_chroot.sh | 85 - chroot/create_chroot_base.sh | 46 - chroot/create_chroot_from_base.sh | 117 - chroot/enter-chroot-env.sh.in | 3 - chroot/gadgetron-dependency-query.sh.in | 17 - chroot/gadgetron_chroot.conf | 26 - chroot/gadgetron_ismrmrd_client.sh.in | 18 - ...dgetron_ismrmrd_client_noise_summary.sh.in | 18 - chroot/generate_gadgetron_root | 45 - chroot/get_dependencies_for_binary | 12 - chroot/gt_alive.sh.in | 15 - chroot/install_chroot_image.sh | 173 - chroot/make_list_of_dependencies | 25 - chroot/mount.sh | 70 - chroot/mount_image.sh | 85 - chroot/mount_image.sh.in | 95 - chroot/nvidia-copy.sh | 93 - chroot/run-gadgetron-dependency-query.sh | 31 - chroot/run-gadgetron-dependency-query.sh.in | 44 - chroot/run-gadgetron_ismrmrd_client.sh | 32 - chroot/run-gadgetron_ismrmrd_client.sh.in | 45 - ...dgetron_ismrmrd_client_noise_summary.sh.in | 45 - chroot/run-gt_alive.sh | 49 - chroot/run-gt_alive.sh.in | 49 - chroot/run-siemens_to_ismrmrd.sh | 31 - chroot/run-siemens_to_ismrmrd.sh.in | 31 - chroot/siemens_to_ismrmrd.sh.in | 17 - chroot/start-env.sh | 18 - chroot/start-env.sh.in | 21 - chroot/start-gadgetron-from-image.sh | 49 - chroot/start-gadgetron-from-image.sh.in | 52 - chroot/start-gadgetron.sh.in | 18 - chroot/start.sh | 23 - chroot/start.sh.in | 27 - chroot/stop.sh | 62 - chroot/umount_image.sh | 55 - chroot/unique_lines_in_file | 14 - chroot/upstart-instructions.txt | 10 - cmake/CMakeLists.txt | 29 +- cmake/FindGLEW.cmake | 53 - cmake/FindPLplot.cmake | 50 - cmake/FindZFP.cmake | 42 - cmake/cpack_options.cmake.in | 22 +- cmake/cpack_options_dependency.cmake.in | 37 - cmake/cpack_options_web.cmake.in | 38 - cmake/debian/postinst | 18 - cmake/debian/prerm | 13 - cmake/debian_web/postinst | 7 - cmake/debian_web/prerm | 7 - cmake/gadgetron_sha1.h.in | 5 - cmake/gadgetron_web_cpack.cmake | 32 - ...onfig.cmake.in => pingvin-config.cmake.in} | 11 +- ...getron_cpack.cmake => pingvin_cpack.cmake} | 4 +- cmake/pingvin_sha1.h.in | 3 + conda/build.sh | 22 +- conda/environment.yml | 2 +- conda/meta.yaml | 45 +- conda/package.sh | 11 +- conda/run_test.sh | 12 +- conda/validate_versions.py | 4 +- core/CMakeLists.txt | 60 +- core/Channel.cpp | 4 +- core/Channel.h | 13 +- core/Context.h | 24 +- core/Gadget.h | 141 +- core/GadgetContainerMessage.h | 40 +- core/IsmrmrdContextVariables.cpp | 73 - core/IsmrmrdContextVariables.h | 41 - core/LegacyACE.cpp | 61 - core/LegacyACE.h | 113 - core/MPMCChannel.h | 8 +- core/Message.cpp | 1 - core/Message.h | 16 +- core/Message.hpp | 58 +- core/MessageID.h | 26 - core/Node.h | 17 +- core/Reader.h | 32 - core/Response.cpp | 5 - core/Response.h | 13 - core/Storage.cpp | 282 -- core/StorageSetup.h | 275 -- core/TypeTraits.h | 38 - core/Types.h | 50 - core/Types.hpp | 20 - core/Writer.h | 85 - core/Writer.hpp | 3 - core/config/distributed_default.xml | 138 - core/config/distributed_generic_default.xml | 137 - core/config/distributed_image_default.xml | 120 - core/distributed/AcquisitionDistributor.cpp | 56 - core/distributed/AcquisitionDistributor.h | 23 - core/distributed/BufferDistributor.cpp | 23 - core/distributed/BufferDistributor.h | 21 - core/distributed/CMakeLists.txt | 28 - core/distributed/ChannelCreator.h | 15 - core/distributed/Distributor.cpp | 6 - core/distributed/Distributor.h | 62 - core/gadgetron_paths.cpp | 138 - core/gadgetron_paths.h | 12 - core/io/adapt_struct.h | 16 - core/io/iostream_operators.h | 14 - core/io/ismrmrd_types.h | 123 - core/io/primitives.h | 31 +- core/io/primitives.hpp | 36 +- core/io/sfndam.h | 142 - core/io/sfndam_serializable.h | 13 - core/parallel/Branch.h | 1 + core/parallel/CMakeLists.txt | 20 +- core/parallel/Fanout.h | 6 +- core/parallel/Merge.h | 1 + core/readers/AcquisitionBucketReader.cpp | 117 - core/readers/AcquisitionBucketReader.h | 10 - core/readers/AcquisitionReader.cpp | 37 - core/readers/AcquisitionReader.h | 15 - core/readers/BufferReader.cpp | 23 - core/readers/BufferReader.h | 14 - core/readers/CMakeLists.txt | 29 - core/readers/ImageReader.cpp | 57 - core/readers/ImageReader.h | 14 - core/readers/IsmrmrdImageArrayReader.cpp | 18 - core/readers/IsmrmrdImageArrayReader.h | 10 - core/readers/TextReader.cpp | 19 - core/readers/TextReader.h | 14 - core/readers/WaveformReader.cpp | 30 - core/readers/WaveformReader.h | 11 - core/variant.hpp | 2813 ---------------- core/writers/AcquisitionBucketWriter.cpp | 168 - core/writers/AcquisitionBucketWriter.h | 15 - core/writers/AcquisitionWriter.cpp | 23 - core/writers/AcquisitionWriter.h | 22 - core/writers/BufferWriter.cpp | 29 - core/writers/BufferWriter.h | 14 - core/writers/CMakeLists.txt | 36 - core/writers/ImageWriter.cpp | 64 - core/writers/ImageWriter.h | 15 - core/writers/IsmrmrdImageArrayWriter.cpp | 14 - core/writers/IsmrmrdImageArrayWriter.h | 11 - core/writers/TextWriter.cpp | 16 - core/writers/TextWriter.h | 12 - core/writers/WaveformWriter.cpp | 20 - core/writers/WaveformWriter.h | 21 - doc/CMakeLists.txt | 2 +- doc/doxygen/CMakeLists.txt | 4 +- doc/doxygen/Doxyfile.in | 2929 +++++++++++------ doc/source/building.md | 64 +- doc/source/conf.py | 15 +- doc/source/core.rst | 13 +- doc/source/gadget.rst | 84 +- doc/source/index.rst | 6 +- doc/source/obtaining.md | 31 +- doc/source/type_matching.rst | 45 +- doc/source/using.md | 213 +- build-images.sh => docker/build-images.sh | 18 +- docker/entrypoint.sh | 4 +- environment.yml | 39 +- gadgets/CMakeLists.txt | 45 +- gadgets/T1/CMakeLists.txt | 28 - gadgets/T1/T1MocoGadget.cpp | 382 --- gadgets/T1/config/MOLLI_T1_Moco.xml | 230 -- gadgets/T1/config/MOLLI_T1_Moco_istore.xml | 236 -- gadgets/bart/BART_Recon.xml | 186 -- gadgets/bart/BART_Recon_cloud.xml | 202 -- gadgets/bart/BART_Recon_cloud_Standard.xml | 202 -- gadgets/bart/CMakeLists.txt | 69 - gadgets/bart/Sample_Grappa_Recon.sh | 49 - gadgets/bart/Sample_Grappa_Recon_Standard.sh | 49 - gadgets/bart/bart_helpers.cpp | 221 -- gadgets/bart/bart_helpers.h | 45 - gadgets/bart/bart_logger.cpp | 37 - gadgets/bart/bartgadget.cpp | 604 ---- gadgets/bart/bartgadget.h | 216 -- gadgets/cartesian/CMakeLists.txt | 33 - .../cartesian/CartesianToGenericGadget.cpp | 94 - gadgets/cartesian/CartesianToGenericGadget.h | 42 - .../cartesian/gadgetron_cartesian_export.h | 11 - gadgets/cmr/CMakeLists.txt | 99 +- .../CmrCartesianKSpaceBinningCineGadget.cpp | 160 +- .../cmr/CmrCartesianKSpaceBinningCineGadget.h | 65 +- gadgets/cmr/CmrParametricMappingGadget.cpp | 144 +- gadgets/cmr/CmrParametricMappingGadget.h | 19 +- .../cmr/CmrParametricT1SRMappingGadget.cpp | 128 +- gadgets/cmr/CmrParametricT1SRMappingGadget.h | 10 +- gadgets/cmr/CmrParametricT2MappingGadget.cpp | 136 +- gadgets/cmr/CmrParametricT2MappingGadget.h | 10 +- .../CmrRealTimeLAXCineAIAnalysisGadget.cpp | 124 +- .../cmr/CmrRealTimeLAXCineAIAnalysisGadget.h | 17 +- ...ureCmrCartesianKSpaceBinningCineGadget.cpp | 246 +- .../PureCmrCartesianKSpaceBinningCineGadget.h | 13 +- .../CMR_2DT_RTCine_KspaceBinning.xml | 43 +- .../CMR_2DT_RTCine_KspaceBinning_Cloud.xml | 311 -- ...R_2DT_RTCine_KspaceBinning_MultiSeries.xml | 43 +- ...RTCine_KspaceBinning_MultiSeries_Cloud.xml | 272 -- .../CMR_Image_Chain_RTCine_LAX_AI.xml | 4 +- .../LandmarkDetection/CMR_RTCine_LAX_AI.xml | 47 +- .../LandmarkDetection/CMR_RTCine_Recon.xml | 31 +- .../LandmarkDetection/stream_image_array.xml | 6 +- .../Mapping/CMR_2DT_T1Mapping_SASHA.xml | 49 +- gadgets/cmr/gadgetron_cmr_export.h | 14 - .../AcquisitionPassthroughGadget.cpp | 19 - .../debugging/AcquisitionPassthroughGadget.h | 24 - gadgets/debugging/CMakeLists.txt | 59 +- gadgets/debugging/CplxDumpGadget.cpp | 54 - gadgets/debugging/CplxDumpGadget.h | 23 - gadgets/debugging/ImageWriterGadget.cpp | 52 - gadgets/debugging/ImageWriterGadget.h | 50 - gadgets/debugging/PseudoReplicatorGadget.cpp | 68 +- gadgets/debugging/PseudoReplicatorGadget.h | 24 +- gadgets/debugging/RateLimitGadget.cpp | 37 +- gadgets/debugging/RateLimitGadget.h | 30 +- .../debugging/WhiteNoiseInjectorGadget.cpp | 69 +- gadgets/debugging/WhiteNoiseInjectorGadget.h | 13 +- .../debugging/gadgetron_debugging_export.h | 14 - gadgets/dicom/CMakeLists.txt | 102 - gadgets/dicom/DicomFinishGadget.cpp | 149 - gadgets/dicom/DicomFinishGadget.h | 188 -- gadgets/dicom/DicomImageWriter.cpp | 81 - gadgets/dicom/DicomImageWriter.h | 25 - gadgets/dicom/dicom.xml | 91 - gadgets/dicom/dicom_ismrmrd_utility.cpp | 972 ------ gadgets/dicom/dicom_ismrmrd_utility.h | 49 - gadgets/dicom/gadgetron_dicom_export.h | 15 - gadgets/epi/CMakeLists.txt | 34 +- gadgets/epi/CutXGadget.cpp | 54 +- gadgets/epi/CutXGadget.h | 11 +- gadgets/epi/EPICorrGadget.cpp | 72 +- gadgets/epi/EPICorrGadget.h | 20 +- gadgets/epi/EPIPackNavigatorGadget.cpp | 33 +- gadgets/epi/EPIPackNavigatorGadget.h | 11 +- gadgets/epi/EPIReconXGadget.cpp | 78 +- gadgets/epi/EPIReconXGadget.h | 11 +- gadgets/epi/FFTXGadget.cpp | 11 +- gadgets/epi/FFTXGadget.h | 9 +- gadgets/epi/OneEncodingGadget.cpp | 4 +- gadgets/epi/OneEncodingGadget.h | 8 +- gadgets/epi/epi.xml | 60 +- gadgets/epi/epi_gtplus_grappa.xml | 41 +- gadgets/epi/gadgetron_epi_export.h | 14 - .../examples/AcquisitionWaveformBranch.cpp | 13 +- gadgets/examples/AcquisitionWaveformBranch.h | 2 +- gadgets/examples/CMakeLists.txt | 34 +- gadgets/examples/ImageInverter.cpp | 27 +- gadgets/examples/ImageInverter.h | 7 +- gadgets/examples/ImageLayerer.cpp | 37 +- gadgets/examples/ImageLayerer.h | 1 - .../config/external_connect_example.xml | 32 - .../config/external_equivalent_example.xml | 60 - gadgets/examples/config/external_example.xml | 60 - .../external_julia_acquisition_example.xml | 29 - .../external_matlab_acquisition_example.xml | 33 - .../config/external_matlab_bucket_example.xml | 47 - .../config/external_matlab_buffer_example.xml | 51 - .../config/external_matlab_tiny_example.xml | 51 - .../external_python_acquisition_example.xml | 29 - .../config/external_python_bucket_example.xml | 45 - .../config/external_python_buffer_example.xml | 51 - .../config/parallel_bypass_example.xml | 38 +- .../config/stream_complex_to_float.xml | 2 +- .../examples/config/stream_float_to_short.xml | 2 +- .../config/stream_image_array_scaling.xml | 2 +- .../config/stream_image_array_split.xml | 2 +- gadgets/fatwater/CMakeLists.txt | 40 - gadgets/fatwater/FatWaterGadget.cpp | 240 -- gadgets/fatwater/FatWaterGadget.h | 61 - .../Generic_Cartesian_Grappa_FatWater.xml | 284 -- gadgets/fatwater/gadgetron_fatwater_export.h | 14 - gadgets/gpu/CMakeLists.txt | 22 +- gadgets/gpu/cuFFTGadget.cpp | 2 +- gadgets/gpu/cuFFTGadget.h | 7 +- gadgets/grappa/AcquisitionFanout.h | 3 - gadgets/grappa/CMakeLists.txt | 34 +- gadgets/grappa/ChannelReorderer.cpp | 39 +- gadgets/grappa/ChannelReorderer.h | 6 +- gadgets/grappa/ImageAccumulator.cpp | 24 +- gadgets/grappa/SliceAccumulator.cpp | 6 +- gadgets/grappa/SliceAccumulator.h | 1 - gadgets/grappa/Unmixing.cpp | 59 +- gadgets/grappa/Unmixing.h | 2 +- gadgets/grappa/WeightsCalculator.cpp | 50 +- gadgets/grappa/common/AcquisitionBuffer.cpp | 35 +- gadgets/grappa/common/AcquisitionBuffer.h | 1 - gadgets/grappa/common/AnnotatedAcquisition.h | 11 +- gadgets/grappa/common/grappa_common.h | 15 +- gadgets/grappa/config/grappa.xml | 44 +- gadgets/grappa/config/grappa_cpu.xml | 44 +- gadgets/grappa/config/grappa_float.xml | 40 +- gadgets/grappa/config/grappa_float_cpu.xml | 40 +- gadgets/grappa/config/grappa_unoptimized.xml | 38 +- .../config/grappa_unoptimized_float.xml | 34 +- gadgets/hyper/CMRT.xml | 52 - gadgets/hyper/CMRT3D.xml | 50 - gadgets/hyper/CMRT3DGadget.cpp | 264 -- gadgets/hyper/CMRT3DGadget.h | 48 - gadgets/hyper/CMRTGadget.cpp | 444 --- gadgets/hyper/CMRTGadget.h | 82 - gadgets/hyper/CMakeLists.txt | 45 - gadgets/hyper/CSIGadget.cpp | 297 -- gadgets/hyper/CSIGadget.h | 69 - gadgets/hyper/FS-CSI.xml | 104 - gadgets/hyper/NFFT2D.xml | 41 - gadgets/hyper/NFFT2DGadget.cpp | 334 -- gadgets/hyper/NFFT2DGadget.h | 57 - gadgets/hyper/gadgetron_hyper_export.h | 14 - gadgets/hyper/gpuCSICoilEstimationGadget.cpp | 276 -- gadgets/hyper/gpuCSICoilEstimationGadget.h | 60 - gadgets/interventional_mri/CMakeLists.txt | 32 +- .../DeviceChannelSplitterGadget.cpp | 85 +- .../DeviceChannelSplitterGadget.h | 24 +- .../gadgetron_interventional_mri_export.h | 14 - gadgets/interventional_mri/grappa_device.xml | 56 +- .../interventional_mri/grappa_device_cpu.xml | 56 +- gadgets/moco/CMakeLists.txt | 54 - gadgets/moco/RegistrationAveragingGadget.h | 273 -- gadgets/moco/RegistrationScatteringGadget.h | 318 -- gadgets/moco/config/CMakeLists.txt | 13 - .../config/cpureg_cartesian_averaging.xml | 127 - .../config/gpureg_cartesian_averaging.xml | 127 - .../moco/cpuRegistrationAveragingGadget.cpp | 44 - gadgets/moco/cpuRegistrationAveragingGadget.h | 25 - gadgets/moco/gadgetron_moco_export.h | 14 - .../moco/gpuRegistrationAveragingGadget.cpp | 50 - gadgets/moco/gpuRegistrationAveragingGadget.h | 26 - .../moco/gpuRegistrationScatteringGadget.cpp | 57 - .../moco/gpuRegistrationScatteringGadget.h | 26 - gadgets/mri_core/AccumulatorGadget.cpp | 128 +- gadgets/mri_core/AccumulatorGadget.h | 12 +- .../AcquisitionAccumulateTriggerGadget.cpp | 129 +- .../AcquisitionAccumulateTriggerGadget.h | 12 +- .../mri_core/AsymmetricEchoAdjustROGadget.cpp | 74 +- .../mri_core/AsymmetricEchoAdjustROGadget.h | 13 +- .../mri_core/AugmentImageMetadataGadget.cpp | 41 +- gadgets/mri_core/AugmentImageMetadataGadget.h | 16 +- gadgets/mri_core/AutoScaleGadget.cpp | 24 +- gadgets/mri_core/AutoScaleGadget.h | 7 +- gadgets/mri_core/BucketToBufferGadget.cpp | 624 ++-- gadgets/mri_core/BucketToBufferGadget.h | 46 +- gadgets/mri_core/CMakeLists.txt | 232 +- gadgets/mri_core/CoilComputationGadget.h | 11 +- gadgets/mri_core/CoilReductionGadget.cpp | 65 +- gadgets/mri_core/CoilReductionGadget.h | 11 +- gadgets/mri_core/CombineGadget.cpp | 40 +- gadgets/mri_core/CombineGadget.h | 7 +- gadgets/mri_core/ComplexToFloatGadget.cpp | 34 +- gadgets/mri_core/ComplexToFloatGadget.h | 13 +- gadgets/mri_core/CropAndCombineGadget.h | 10 +- gadgets/mri_core/DenoiseGadget.cpp | 15 +- gadgets/mri_core/DenoiseGadget.h | 13 +- gadgets/mri_core/ExtractGadget.cpp | 63 +- gadgets/mri_core/ExtractGadget.h | 9 +- gadgets/mri_core/FFTGadget.cpp | 109 +- gadgets/mri_core/FFTGadget.h | 14 +- gadgets/mri_core/FlagTriggerGadget.cpp | 418 +-- gadgets/mri_core/FlagTriggerGadget.h | 144 +- gadgets/mri_core/FloatToFixPointGadget.cpp | 59 +- gadgets/mri_core/FloatToFixPointGadget.h | 20 +- .../mri_core/FlowPhaseSubtractionGadget.cpp | 29 +- gadgets/mri_core/FlowPhaseSubtractionGadget.h | 13 +- gadgets/mri_core/GadgetMRIHeaders.h | 9 - gadgets/mri_core/ImageAccumulatorGadget.h | 7 +- gadgets/mri_core/ImageArraySendMixin.h | 27 +- gadgets/mri_core/ImageArraySendMixin.hpp | 146 +- gadgets/mri_core/ImageArraySplitGadget.cpp | 52 +- gadgets/mri_core/ImageArraySplitGadget.h | 9 +- gadgets/mri_core/ImageFFTGadget.h | 6 +- gadgets/mri_core/ImageFinishGadget.cpp | 21 - gadgets/mri_core/ImageFinishGadget.h | 22 - gadgets/mri_core/ImageIndexGadget.cpp | 12 +- gadgets/mri_core/ImageIndexGadget.h | 5 +- gadgets/mri_core/ImageResizingGadget.h | 6 +- gadgets/mri_core/ImageSortGadget.cpp | 39 +- gadgets/mri_core/ImageSortGadget.h | 11 +- gadgets/mri_core/IsmrmrdDumpGadget.cpp | 254 -- gadgets/mri_core/IsmrmrdDumpGadget.h | 52 - gadgets/mri_core/MaxwellCorrectionGadget.cpp | 85 +- gadgets/mri_core/MaxwellCorrectionGadget.h | 16 +- gadgets/mri_core/NoiseAdjustGadget.cpp | 196 +- gadgets/mri_core/NoiseAdjustGadget.h | 90 +- .../mri_core/NoiseAdjustGadget_unoptimized.h | 7 +- gadgets/mri_core/PCACoilGadget.cpp | 328 +- gadgets/mri_core/PCACoilGadget.h | 39 +- .../mri_core/PartialFourierAdjustROGadget.h | 3 +- .../mri_core/PhysioInterpolationGadget.cpp | 72 +- gadgets/mri_core/PhysioInterpolationGadget.h | 9 +- .../mri_core/RemoveROOversamplingGadget.cpp | 119 +- gadgets/mri_core/RemoveROOversamplingGadget.h | 9 +- gadgets/mri_core/ScaleGadget.cpp | 30 +- gadgets/mri_core/ScaleGadget.h | 3 +- gadgets/mri_core/SimpleReconGadget.cpp | 120 +- gadgets/mri_core/SimpleReconGadget.h | 21 +- gadgets/mri_core/config/NoiseSummary.xml | 23 - gadgets/mri_core/config/default.xml | 34 +- .../default_measurement_dependencies.xml | 21 +- ...asurement_dependencies_ismrmrd_storage.xml | 38 - gadgets/mri_core/config/default_optimized.xml | 71 +- gadgets/mri_core/config/default_short.xml | 97 - gadgets/mri_core/config/gtquery.xml | 33 - gadgets/mri_core/config/isalive.xml | 6 - gadgets/mri_core/config/ismrmrd_dump.xml | 22 - gadgets/mri_core/dependencyquery/Dependency.h | 7 - .../dependencyquery/DependencyQueryGadget.cpp | 179 - .../dependencyquery/DependencyQueryGadget.h | 56 - .../dependencyquery/DependencyQueryWriter.cpp | 28 - .../dependencyquery/DependencyQueryWriter.h | 30 - .../dependencyquery/NoiseSummaryGadget.cpp | 90 - .../dependencyquery/NoiseSummaryGadget.h | 40 - gadgets/mri_core/gadgetron_mricore_export.h | 14 - .../GenericImageReconArrayToImageGadget.h | 4 +- .../GenericImageReconGadget.cpp | 4 +- .../GenericImageReconGadget.h | 12 +- ...GenericReconAccumulateImageTriggerGadget.h | 24 +- .../GenericReconBase.cpp | 16 +- .../generic_recon_gadgets/GenericReconBase.h | 46 +- .../GenericReconCartesianFFTGadget.h | 8 +- .../GenericReconCartesianGrappaAIGadget.cpp | 129 +- .../GenericReconCartesianGrappaAIGadget.h | 16 +- .../GenericReconCartesianGrappaGadget.cpp | 210 +- .../GenericReconCartesianGrappaGadget.h | 18 +- ...ReconCartesianNonLinearSpirit2DTGadget.cpp | 52 +- ...icReconCartesianNonLinearSpirit2DTGadget.h | 14 +- ...nericReconCartesianReferencePrepGadget.cpp | 155 +- ...GenericReconCartesianReferencePrepGadget.h | 18 +- .../GenericReconCartesianSpiritGadget.cpp | 96 +- .../GenericReconCartesianSpiritGadget.h | 18 +- .../GenericReconEigenChannelGadget.cpp | 102 +- .../GenericReconEigenChannelGadget.h | 18 +- ...enericReconFieldOfViewAdjustmentGadget.cpp | 98 +- .../GenericReconFieldOfViewAdjustmentGadget.h | 12 +- .../GenericReconGadget.cpp | 407 +-- .../GenericReconGadget.h | 29 +- .../GenericReconImageArrayScalingGadget.cpp | 48 +- .../GenericReconImageArrayScalingGadget.h | 12 +- .../GenericReconImageToImageArrayGadget.h | 8 +- .../GenericReconKSpaceFilteringGadget.cpp | 154 +- .../GenericReconKSpaceFilteringGadget.h | 10 +- ...GenericReconNoiseStdMapComputingGadget.cpp | 67 +- .../GenericReconNoiseStdMapComputingGadget.h | 10 +- ...econPartialFourierHandlingFilterGadget.cpp | 4 +- ...nericReconPartialFourierHandlingGadget.cpp | 128 +- ...GenericReconPartialFourierHandlingGadget.h | 9 +- ...cReconPartialFourierHandlingPOCSGadget.cpp | 2 +- ...cReconReferenceKSpaceDelayedBufferGadget.h | 4 +- .../GenericReconStreamDef.h | 2 +- .../config/Generic_Cartesian_FFT.xml | 43 +- .../config/Generic_Cartesian_Grappa.xml | 43 +- .../config/Generic_Cartesian_Grappa_AI.xml | 43 +- .../Generic_Cartesian_Grappa_Cine_Denoise.xml | 50 +- .../Generic_Cartesian_Grappa_Complex.xml | 37 +- .../config/Generic_Cartesian_Grappa_EPI.xml | 47 +- .../Generic_Cartesian_Grappa_EPI_AVE.xml | 47 +- .../Generic_Cartesian_Grappa_ImageArray.xml | 29 +- .../Generic_Cartesian_Grappa_RealTimeCine.xml | 43 +- ...ic_Cartesian_Grappa_RealTimeCine_Cloud.xml | 242 -- .../config/Generic_Cartesian_Grappa_SNR.xml | 43 +- .../config/Generic_Cartesian_Grappa_T2W.xml | 43 +- .../Generic_Cartesian_Image_Chain_FFT.xml | 18 +- ...artesian_NonLinear_Spirit_RealTimeCine.xml | 45 +- ...an_NonLinear_Spirit_RealTimeCine_Cloud.xml | 270 -- ...Sampling_NonLinear_Spirit_RealTimeCine.xml | 45 +- ...ng_NonLinear_Spirit_RealTimeCine_Cloud.xml | 270 -- .../config/Generic_Cartesian_Spirit.xml | 43 +- .../Generic_Cartesian_Spirit_RealTimeCine.xml | 42 +- .../config/Generic_Cartesian_Spirit_SASHA.xml | 43 +- gadgets/mri_core/models/grappa_ai.py | 12 +- .../mri_core/readers/GadgetIsmrmrdReader.cpp | 154 - .../mri_core/readers/GadgetIsmrmrdReader.h | 42 - gadgets/mri_core/readers/MRIImageReader.cpp | 71 - gadgets/mri_core/readers/MRIImageReader.h | 28 - .../mri_core/writers/GadgetIsmrmrdWriter.cpp | 7 - .../mri_core/writers/GadgetIsmrmrdWriter.h | 9 - gadgets/mri_core/writers/MRIImageWriter.cpp | 12 - gadgets/mri_core/writers/MRIImageWriter.h | 12 - gadgets/mri_noncartesian/CMakeLists.txt | 71 - .../CPUGriddingReconGadget.cpp | 31 - .../mri_noncartesian/CPUGriddingReconGadget.h | 30 - .../mri_noncartesian/GriddingReconGadget.cpp | 21 - .../mri_noncartesian/GriddingReconGadget.h | 21 - .../GriddingReconGadgetBase.h | 55 - .../GriddingReconGadgetBase.hpp | 293 -- .../mri_noncartesian/NonCartesianTools.cpp | 134 - gadgets/mri_noncartesian/NonCartesianTools.h | 9 - .../config/Generic_CPU_Gridding_Recon.xml | 124 - .../config/Generic_Spiral.xml | 127 - .../config/Generic_Spiral_Flag.xml | 126 - .../config/Generic_Spiral_SNR.xml | 109 - .../gadgetron_mri_noncartesian_export.h | 14 - gadgets/plplot/CMakeLists.txt | 48 - .../Generic_Cartesian_Grappa_SNR_CoilQA.xml | 257 -- .../plplot/NoiseCovariancePlottingGadget.cpp | 290 -- .../plplot/NoiseCovariancePlottingGadget.h | 65 - gadgets/plplot/gadgetron_plplot_export.h | 16 - gadgets/pmri/CMakeLists.txt | 47 +- gadgets/pmri/GenericReconJob.h | 3 +- gadgets/pmri/config/CMakeLists.txt | 4 +- .../config/generic_gpu_ktsense_singleshot.xml | 54 +- gadgets/pmri/config/generic_gpusense_cg.xml | 58 +- .../config/generic_gpusense_cg_singleshot.xml | 58 +- .../generic_gpusense_nlcg_singleshot.xml | 58 +- .../config/generic_gpusense_sb_singleshot.xml | 56 +- gadgets/pmri/gadgetron_gpupmri_export.h | 14 - gadgets/pmri/gpuBufferSensePrepGadget.cpp | 97 +- gadgets/pmri/gpuBufferSensePrepGadget.h | 9 +- gadgets/pmri/gpuCgKtSenseGadget.cpp | 83 +- gadgets/pmri/gpuCgKtSenseGadget.h | 11 +- gadgets/pmri/gpuCgSenseGadget.cpp | 75 +- gadgets/pmri/gpuCgSenseGadget.h | 12 +- gadgets/pmri/gpuCgSpiritGadget.cpp | 33 +- gadgets/pmri/gpuCgSpiritGadget.h | 14 +- gadgets/pmri/gpuGenericSensePrepGadget.cpp | 420 ++- gadgets/pmri/gpuGenericSensePrepGadget.h | 57 +- gadgets/pmri/gpuLALMSenseGadget.cpp | 28 +- gadgets/pmri/gpuLALMSenseGadget.h | 9 +- gadgets/pmri/gpuNlcgSenseGadget.cpp | 47 +- gadgets/pmri/gpuNlcgSenseGadget.h | 9 +- gadgets/pmri/gpuOsSenseGadget.cpp | 27 +- gadgets/pmri/gpuOsSenseGadget.h | 9 +- gadgets/pmri/gpuSbSenseGadget.cpp | 34 +- gadgets/pmri/gpuSbSenseGadget.h | 13 +- gadgets/pmri/gpuSenseGadget.cpp | 52 +- gadgets/pmri/gpuSenseGadget.h | 6 +- gadgets/python/CMakeLists.txt | 29 - ...c_Cartesian_Grappa_RealTimeCine_Python.xml | 227 -- .../python/legacy/config/pseudoreplica.xml | 142 - .../python/legacy/config/python_buckets.xml | 88 - .../config/python_image_array_recon.xml | 87 - .../legacy/config/python_passthrough.xml | 244 -- gadgets/python/legacy/config/python_short.xml | 74 - .../legacy/gadgets/accumulate_and_recon.py | 79 - gadgets/python/legacy/gadgets/bucket_recon.py | 67 - .../legacy/gadgets/image_array_recon.py | 86 - .../image_array_recon_rtcine_plotting.py | 155 - gadgets/python/legacy/gadgets/passthrough.py | 13 - .../legacy/gadgets/passthrough_array_image.py | 32 - .../legacy/gadgets/pseudoreplicagather.py | 56 - .../legacy/gadgets/remove_2x_oversampling.py | 18 - .../python/legacy/gadgets/rms_coil_combine.py | 12 - gadgets/radial/CMakeLists.txt | 63 +- .../radial/RadialPhaseCorrectionGadget.cpp | 118 +- gadgets/radial/RadialPhaseCorrectionGadget.h | 24 +- gadgets/radial/config/CMakeLists.txt | 4 +- .../config/fixed_radial_mode0_gpu_ktsense.xml | 59 +- .../config/fixed_radial_mode0_gpusense_cg.xml | 59 +- ...d_radial_mode0_gpusense_cg_unoptimized.xml | 53 +- .../config/fixed_radial_mode0_gpusense_sb.xml | 59 +- ...d_radial_mode0_gpusense_sb_unoptimized.xml | 53 +- .../config/fixed_radial_mode0_realtime.xml | 64 +- .../config/fixed_radial_mode1_gpu_ktsense.xml | 65 +- .../config/fixed_radial_mode1_gpusense_cg.xml | 59 +- ...d_radial_mode1_gpusense_cg_unoptimized.xml | 53 +- .../config/fixed_radial_mode1_gpusense_sb.xml | 59 +- ...d_radial_mode1_gpusense_sb_unoptimized.xml | 53 +- .../config/fixed_radial_mode1_realtime.xml | 59 +- .../golden_radial_mode2_gpu_ktsense.xml | 59 +- .../golden_radial_mode2_gpusense_cg.xml | 59 +- ...n_radial_mode2_gpusense_cg_unoptimized.xml | 53 +- .../golden_radial_mode2_gpusense_nlcg.xml | 59 +- ...radial_mode2_gpusense_nlcg_unoptimized.xml | 59 +- .../golden_radial_mode2_gpusense_sb.xml | 59 +- ...n_radial_mode2_gpusense_sb_unoptimized.xml | 55 +- .../golden_radial_mode2_os_realtime.xml | 84 +- .../config/golden_radial_mode2_realtime.xml | 59 +- .../golden_radial_mode3_gpusense_cg.xml | 59 +- .../golden_radial_mode3_gpusense_sb.xml | 59 +- .../golden_radial_mode3_os_realtime.xml | 84 +- gadgets/radial/config/spirit.xml | 41 +- gadgets/radial/gadgetron_radial_export.h | 14 - gadgets/radial/gpuRadialPrepGadget.cpp | 118 +- gadgets/radial/gpuRadialPrepGadget.h | 18 +- gadgets/radial/gpuRadialSensePrepGadget.h | 17 +- gadgets/radial/gpuRadialSpiritPrepGadget.cpp | 4 +- gadgets/radial/gpuRadialSpiritPrepGadget.h | 17 +- .../radial/gpuRetroGatedSensePrepGadget.cpp | 123 +- gadgets/radial/gpuRetroGatedSensePrepGadget.h | 31 +- gadgets/spiral/CMakeLists.txt | 36 +- gadgets/spiral/SpiralToGenericGadget.cpp | 68 +- gadgets/spiral/SpiralToGenericGadget.h | 21 +- gadgets/spiral/config/CMakeLists.txt | 4 +- .../config/deblurring_recon_acctrig.xml | 30 +- .../spiral_flow_generic_gpusense_cg.xml | 70 +- .../spiral_flow_generic_gpusense_sb.xml | 70 +- .../spiral/config/spiral_flow_gpusense_cg.xml | 64 +- .../config/spiral_flow_gpusense_cg_ecg.xml | 70 +- .../spiral_flow_gpusense_cg_unoptimized.xml | 62 +- .../spiral/config/spiral_flow_gpusense_sb.xml | 68 +- .../spiral_flow_gpusense_sb_unoptimized.xml | 60 +- gadgets/spiral/config/spiral_interactive.xml | 60 +- gadgets/spiral/gadgetron_spiral_export.h | 3 - gadgets/spiral/gpuSpiralDeblurGadget.cpp | 202 +- gadgets/spiral/gpuSpiralDeblurGadget.h | 21 +- gadgets/spiral/gpuSpiralSensePrepGadget.cpp | 152 +- gadgets/spiral/gpuSpiralSensePrepGadget.h | 30 +- justfile | 25 + libmrd/CMakeLists.txt | 72 + libmrd/include/gadgetron-arrays.h | 290 ++ test/CMakeLists.txt | 177 +- test/IsmrmrdContextVariables_test.cpp | 369 --- test/StorageSpaces_test.cpp | 165 - test/core_primitive_io_test.cpp | 182 - test/core_test.cpp | 23 +- test/cuNDArray_utils_test.cpp | 8 +- test/e2e/.gitignore | 8 + test/e2e/README.md | 13 + test/e2e/cases/cmr_cine_binning.yml | 18 + test/e2e/cases/cmr_cine_binning_2slices.yml | 14 + test/e2e/cases/cmr_mapping_t1_sr.yml | 21 + test/e2e/cases/cpu_grappa_simple.yml | 16 + test/e2e/cases/epi_2d.yml | 19 + .../cases/generic_cartesian_cine_denoise.yml | 20 + .../cases/generic_cartesian_cine_python.yml | 22 + test/e2e/cases/generic_grappa2x1_3d.yml | 15 + test/e2e/cases/generic_grappa2x2_3d.yml | 15 + test/e2e/cases/generic_grappa_T2W.yml | 21 + test/e2e/cases/generic_grappa_epi_ave.yml | 14 + ...eneric_grappa_snr_R1_PEFOV100_PERes100.yml | 19 + ...a_snr_R1_PEFOV100_PERes100_compression.yml | 19 + ...eneric_grappa_snr_R1_PEFOV100_PERes120.yml | 19 + .../generic_grappa_snr_R1_PEFOV75_PERes75.yml | 19 + ...ic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml | 19 + ...nr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 19 + ...OV75_PERes75_PF6_8_AsymStrong_InterpON.yml | 19 + ...ipat_PEFOV75_PERes75_PEOverSampling120.yml | 19 + ..._ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 19 + ...c_grappa_snr_R2_spat_PEFOV100_PERes100.yml | 19 + ...c_grappa_snr_R2_spat_PEFOV100_PERes120.yml | 19 + ...ric_grappa_snr_R2_spat_PEFOV75_PERes75.yml | 19 + ...appa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml | 19 + ..._spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 19 + ...OV75_PERes75_PF6_8_AsymStrong_InterpON.yml | 19 + ...c_grappa_snr_R2_tpat_PEFOV100_PERes100.yml | 19 + ...ric_grappa_snr_R2_tpat_PEFOV75_PERes75.yml | 19 + ...appa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml | 19 + ..._tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml | 19 + ...spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml | 19 + ...c_grappa_snr_R3_tpat_PEFOV100_PERes120.yml | 21 + ...tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml | 19 + test/e2e/cases/generic_grappa_tse.yml | 19 + ...eric_nl_spirit_cartesian_sampling_cine.yml | 20 + ...generic_nl_spirit_random_sampling_cine.yml | 16 + test/e2e/cases/generic_rtcine_ai_landmark.yml | 22 + ...eneric_spirit_cartesian_sampling_spat2.yml | 16 + test/e2e/cases/gpu_fixed_radial_mode1_cg.yml | 16 + .../cases/gpu_fixed_radial_mode1_ktsense.yml | 16 + .../cases/gpu_fixed_radial_mode1_realtime.yml | 16 + test/e2e/cases/gpu_golden_radial_mode2_cg.yml | 16 + .../cases/gpu_golden_radial_mode2_ktsense.yml | 16 + .../gpu_golden_radial_mode2_realtime.yml | 16 + test/e2e/cases/gpu_golden_radial_mode2_sb.yml | 16 + test/e2e/cases/gpu_grappa_simple.yml | 19 + test/e2e/cases/gpu_spiral.yml | 16 + .../cases/gpu_spiral_realtime_deblurring.yml | 20 + test/e2e/cases/gpu_spiral_sb.yml | 15 + test/e2e/cases/parallel_bypass_example.yml | 16 + test/e2e/cases/simple_gre.yml | 16 + test/e2e/cases/simple_gre_3d.yml | 16 + test/e2e/cases/stream_image.yml | 21 + test/e2e/cases/stream_image_array.yml | 23 + test/e2e/conftest.py | 87 + test/e2e/test_e2e.py | 457 +++ test/from_string_test.cpp | 6 +- ... => AcquisitionAccumulateTrigger_test.cpp} | 12 +- test/gadgets/FlagTriggerParsing_test.cpp | 105 +- test/gadgets/setup_gadget.h | 61 +- test/integration/README.md | 9 + test/integration/bart_cases/bart.cfg | 17 - test/integration/cases/cmr_cine_binning.cfg | 19 +- .../cases/cmr_cine_binning_2slices.cfg | 11 +- test/integration/cases/cmr_mapping_t1_sr.cfg | 19 +- test/integration/cases/cpu_grappa_simple.cfg | 11 +- .../cases/distributed_simple_gre.cfg | 10 +- test/integration/cases/epi_2d.cfg | 19 +- .../cases/generic_cartesian_cine_denoise.cfg | 18 +- .../cases/generic_cartesian_cine_python.cfg | 16 +- .../cases/generic_grappa2x1_3d.cfg | 10 +- .../cases/generic_grappa2x2_3d.cfg | 10 +- test/integration/cases/generic_grappa_T2W.cfg | 18 +- .../cases/generic_grappa_epi_ave.cfg | 11 +- ...eneric_grappa_snr_R1_PEFOV100_PERes100.cfg | 18 +- ...a_snr_R1_PEFOV100_PERes100_compression.cfg | 20 +- ...eneric_grappa_snr_R1_PEFOV100_PERes120.cfg | 18 +- .../generic_grappa_snr_R1_PEFOV75_PERes75.cfg | 18 +- ...ic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.cfg | 18 +- ...nr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.cfg | 18 +- ...OV75_PERes75_PF6_8_AsymStrong_InterpON.cfg | 18 +- ...ipat_PEFOV75_PERes75_PEOverSampling120.cfg | 18 +- ..._ipat_PEFOV75_PERes75_PF6_8_AsymStrong.cfg | 18 +- ...c_grappa_snr_R2_spat_PEFOV100_PERes100.cfg | 18 +- ...c_grappa_snr_R2_spat_PEFOV100_PERes120.cfg | 18 +- ...ric_grappa_snr_R2_spat_PEFOV75_PERes75.cfg | 18 +- ...appa_snr_R2_spat_PEFOV75_PERes75_PF6_8.cfg | 18 +- ..._spat_PEFOV75_PERes75_PF6_8_AsymStrong.cfg | 18 +- ...OV75_PERes75_PF6_8_AsymStrong_InterpON.cfg | 18 +- ...c_grappa_snr_R2_tpat_PEFOV100_PERes100.cfg | 18 +- ...ric_grappa_snr_R2_tpat_PEFOV75_PERes75.cfg | 18 +- ...appa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.cfg | 18 +- ..._tpat_PEFOV75_PERes75_PF6_8_AsymStrong.cfg | 18 +- ...spat_PEFOV100_PERes75_PF6_8_AsymStrong.cfg | 18 +- ...c_grappa_snr_R3_tpat_PEFOV100_PERes120.cfg | 18 +- ...tpat_PEFOV100_PERes75_PF6_8_AsymStrong.cfg | 18 +- test/integration/cases/generic_grappa_tse.cfg | 18 +- ...eric_nl_spirit_cartesian_sampling_cine.cfg | 18 +- ...generic_nl_spirit_random_sampling_cine.cfg | 10 +- .../cases/generic_rtcine_ai_landmark.cfg | 9 +- ...eneric_spirit_cartesian_sampling_spat2.cfg | 10 +- .../cases/gpu_fixed_radial_mode1_cg.cfg | 10 +- .../cases/gpu_fixed_radial_mode1_ktsense.cfg | 10 +- .../cases/gpu_fixed_radial_mode1_realtime.cfg | 10 +- .../cases/gpu_golden_radial_mode2_cg.cfg | 10 +- .../cases/gpu_golden_radial_mode2_ktsense.cfg | 10 +- .../gpu_golden_radial_mode2_realtime.cfg | 10 +- .../cases/gpu_golden_radial_mode2_sb.cfg | 10 +- test/integration/cases/gpu_grappa_simple.cfg | 10 +- test/integration/cases/gpu_spiral.cfg | 10 +- .../cases/gpu_spiral_realtime_deblurring.cfg | 18 +- test/integration/cases/gpu_spiral_sb.cfg | 10 +- .../cases/parallel_bypass_example.cfg | 11 +- test/integration/cases/simple_gre.cfg | 10 +- test/integration/cases/simple_gre_3d.cfg | 10 +- test/integration/cases/stream_image.cfg | 2 +- test/integration/cases/stream_image_array.cfg | 5 +- .../cases/stream_snr_R1_PEFOV100_PERes100.cfg | 37 - .../ismrmrd_dump_gadget_test.template.xml | 8 +- test/integration/convert_test_data.py | 287 ++ test/integration/mem_watch.py | 507 --- test/integration/run_gadgetron_test.py | 834 ----- test/integration/run_tests.py | 341 -- test/integration/stats_to_junit.py | 30 - test/mri_core_stream_test.cpp | 219 +- test/performance/CMakeLists.txt | 28 - test/performance/benchmark_curvefitting.cpp | 256 -- test/python_converter_test.cpp | 697 ++-- test/read_writer_test.cpp | 214 -- test/threadpool_test.cpp | 1 + toolboxes/CMakeLists.txt | 75 +- toolboxes/T1/CMakeLists.txt | 36 - toolboxes/T1/t1fit.cpp | 606 ---- toolboxes/T1/t1fit.h | 106 - toolboxes/cmr/CMakeLists.txt | 99 +- toolboxes/cmr/cmr_analytical_strain.cpp | 4 +- toolboxes/cmr/cmr_analytical_strain.h | 4 +- toolboxes/cmr/cmr_export.h | 19 - toolboxes/cmr/cmr_image_container_util.cpp | 163 +- toolboxes/cmr/cmr_image_container_util.h | 21 +- toolboxes/cmr/cmr_ismrmrd_util.cpp | 347 -- toolboxes/cmr/cmr_ismrmrd_util.h | 40 - toolboxes/cmr/cmr_kspace_binning.cpp | 137 +- toolboxes/cmr/cmr_kspace_binning.h | 27 +- toolboxes/cmr/cmr_motion_correction.cpp | 63 +- toolboxes/cmr/cmr_motion_correction.h | 33 +- toolboxes/cmr/cmr_parametric_mapping.cpp | 22 +- toolboxes/cmr/cmr_parametric_mapping.h | 15 +- toolboxes/cmr/cmr_radial_thickening.cpp | 4 +- toolboxes/cmr/cmr_radial_thickening.h | 4 +- toolboxes/cmr/cmr_spirit_recon.cpp | 32 +- toolboxes/cmr/cmr_spirit_recon.h | 7 +- toolboxes/cmr/cmr_strain_analysis.cpp | 4 +- toolboxes/cmr/cmr_strain_analysis.h | 6 +- toolboxes/cmr/cmr_t1_mapping.cpp | 8 +- toolboxes/cmr/cmr_t1_mapping.h | 4 +- toolboxes/cmr/cmr_t2_mapping.cpp | 8 +- toolboxes/cmr/cmr_t2_mapping.h | 4 +- toolboxes/cmr/cmr_time_stamp.cpp | 26 +- toolboxes/cmr/cmr_time_stamp.h | 19 +- toolboxes/core/CMakeLists.txt | 8 +- toolboxes/core/GadgetronException.h | 33 - toolboxes/core/GadgetronTimer.h | 22 +- toolboxes/core/Gadgetron_enable_types.h | 17 - toolboxes/core/NDArray.h | 1212 ++++--- toolboxes/core/NDArray_utils.h | 138 +- toolboxes/core/cpu/CMakeLists.txt | 63 +- toolboxes/core/cpu/cpucore_export.h | 18 - toolboxes/core/cpu/dummy.cpp | 12 - toolboxes/core/cpu/hoMatrix.h | 3 +- toolboxes/core/cpu/hoMatrix.hxx | 106 +- toolboxes/core/cpu/hoNDArray.h | 21 +- toolboxes/core/cpu/hoNDArray.hxx | 66 +- toolboxes/core/cpu/hoNDInterpolatorLinear.hxx | 6 +- toolboxes/core/cpu/hoNDObjectArray.h | 30 +- toolboxes/core/cpu/hoNDPoint.h | 4 +- toolboxes/core/cpu/hostutils/CMakeLists.txt | 41 - .../core/cpu/hostutils/hostutils_export.h | 22 - .../core/cpu/hostutils/network_utils.cpp | 80 - toolboxes/core/cpu/hostutils/network_utils.h | 16 - .../core/cpu/hostutils/parameterparser.cpp | 337 -- .../core/cpu/hostutils/parameterparser.h | 81 - toolboxes/core/cpu/hostutils/url_encode.h | 47 - toolboxes/core/cpu/math/CMakeLists.txt | 84 +- toolboxes/core/cpu/math/cpp_blas.h | 174 +- .../core/cpu/math/hoNDArray_elemwise.cpp | 6 +- toolboxes/core/cpu/math/hoNDArray_linalg.cpp | 18 +- toolboxes/core/cpu/math/hoNDArray_linalg.h | 35 +- toolboxes/core/gpu/cuNDArray_elemwise.cu | 1410 ++++---- toolboxes/core/gpu/cuNDArray_operators.h | 66 +- toolboxes/deblur/CMakeLists.txt | 22 +- toolboxes/denoise/CMakeLists.txt | 28 +- toolboxes/denoise/denoise_export.h | 14 - toolboxes/denoise/non_local_means.h | 5 +- toolboxes/dwt/CMakeLists.txt | 4 +- toolboxes/dwt/cpu/CMakeLists.txt | 28 +- toolboxes/dwt/cpu/sessions_test.h | 19 - toolboxes/dwt/gpu/cuNDDWT.cu | 56 +- toolboxes/dwt/gpu/cuNDDWT.h | 14 +- toolboxes/fatwater/CMakeLists.txt | 40 - toolboxes/fatwater/ImageGraph.cpp | 18 - toolboxes/fatwater/ImageGraph.h | 397 --- toolboxes/fatwater/ImageGraph.hxx | 146 - toolboxes/fatwater/bounded_field_map.cpp | 140 - toolboxes/fatwater/bounded_field_map.h | 13 - .../fatwater/correct_frequency_shift.cpp | 84 - toolboxes/fatwater/correct_frequency_shift.h | 16 - toolboxes/fatwater/fatwater.cpp | 676 ---- toolboxes/fatwater/fatwater.h | 73 - toolboxes/fatwater/fatwater_export.h | 14 - toolboxes/fatwater/graph_cut.cpp | 184 -- toolboxes/fatwater/graph_cut.h | 13 - toolboxes/ffd/CMakeLists.txt | 26 +- toolboxes/fft/CMakeLists.txt | 4 +- toolboxes/fft/cpu/CMakeLists.txt | 31 +- toolboxes/fft/cpu/cpufft_export.h | 18 - toolboxes/fft/cpu/hoNDFFT.cpp | 4 +- toolboxes/fft/cpu/hoNDFFT.h | 3 +- toolboxes/fft/gpu/cuNDFFT.cpp | 4 +- toolboxes/fft/gpu/cuNDFFT.cu | 16 +- toolboxes/fft/gpu/cuNDFFT.h | 5 +- toolboxes/fft/gpu/gpufft_export.h | 18 - toolboxes/image/CMakeLists.txt | 9 +- toolboxes/image/cpu/CMakeLists.txt | 36 +- toolboxes/image/cpu/image_export.h | 19 - toolboxes/image/cpu/morphology.cpp | 26 +- toolboxes/image/cpu/morphology.h | 12 +- toolboxes/image_io/CMakeLists.txt | 23 +- toolboxes/image_io/ImageIOAnalyze.cpp | 4 +- toolboxes/image_io/ImageIOAnalyze.h | 56 +- toolboxes/image_io/ImageIOBase.h | 39 +- toolboxes/image_io/ImageIOExport.h | 16 - toolboxes/klt/CMakeLists.txt | 5 +- toolboxes/klt/cpu/CMakeLists.txt | 29 +- toolboxes/klt/cpu/cpuklt_export.h | 19 - toolboxes/klt/cpu/hoNDKLT.cpp | 16 +- toolboxes/klt/cpu/hoNDKLT.h | 3 +- toolboxes/log/CMakeLists.txt | 18 +- toolboxes/log/log.h | 34 +- toolboxes/log/log_export.h | 14 - toolboxes/mri/CMakeLists.txt | 5 +- toolboxes/mri/epi/CMakeLists.txt | 17 +- toolboxes/mri/epi/EPIExport.h | 16 - toolboxes/mri/epi/EPIReconXObject.h | 9 +- toolboxes/mri/epi/EPIReconXObjectFlat.h | 14 +- toolboxes/mri/epi/EPIReconXObjectTrapezoid.h | 27 +- toolboxes/mri/hyper/CMRTOperator.cpp | 21 - toolboxes/mri/hyper/CMRTOperator.h | 144 - toolboxes/mri/hyper/CSIOperator.cpp | 66 - toolboxes/mri/hyper/CSIOperator.h | 44 - toolboxes/mri/hyper/CSI_utils.cu | 177 - toolboxes/mri/hyper/CSI_utils.h | 38 - toolboxes/mri/hyper/CSfreqOperator.h | 53 - .../hyper/gadgetron_toolbox_hyper_export.h | 11 - toolboxes/mri/pmri/CMakeLists.txt | 1 - toolboxes/mri/pmri/gpu/b1_map.cu | 262 +- toolboxes/mri/pmri/gpu/b1_map.h | 15 +- toolboxes/mri/pmri/gpu/b1_map_NIH_Souheil.cu | 10 +- toolboxes/mri/pmri/gpu/b1map_test.cu | 96 +- toolboxes/mri/pmri/gpu/cuBuffer.cpp | 48 +- toolboxes/mri/pmri/gpu/cuBuffer.h | 19 +- .../mri/pmri/gpu/cuCartesianSenseOperator.cu | 38 +- .../mri/pmri/gpu/cuCartesianSenseOperator.h | 14 +- .../pmri/gpu/cuNonCartesianKtSenseOperator.cu | 20 +- .../pmri/gpu/cuNonCartesianKtSenseOperator.h | 12 +- .../pmri/gpu/cuNonCartesianSenseOperator.cu | 28 +- .../pmri/gpu/cuNonCartesianSenseOperator.h | 14 +- toolboxes/mri/pmri/gpu/cuSenseBuffer.cpp | 32 +- toolboxes/mri/pmri/gpu/cuSenseBuffer.h | 10 +- toolboxes/mri/pmri/gpu/cuSenseBufferCg.cpp | 36 +- toolboxes/mri/pmri/gpu/cuSenseBufferCg.h | 18 +- toolboxes/mri/pmri/gpu/cuSenseOperator.cu | 24 +- toolboxes/mri/pmri/gpu/cuSenseOperator.h | 13 +- toolboxes/mri/pmri/gpu/cuSpiritBuffer.cpp | 22 +- toolboxes/mri/pmri/gpu/cuSpiritBuffer.h | 16 +- toolboxes/mri/pmri/gpu/gpupmri_export.h | 19 - toolboxes/mri/pmri/gpu/htgrappa.cpp | 2 +- toolboxes/mri/pmri/gpu/htgrappa.cu | 4 +- toolboxes/mri/pmri/gpu/htgrappa.h | 17 +- toolboxes/mri/pmri/gpu/senseOperator.h | 9 +- toolboxes/mri/pmri/gpu/sense_utilities.cu | 60 +- toolboxes/mri/pmri/gpu/sense_utilities.h | 13 +- toolboxes/mri/pmri/gpu/spirit_calibration.h | 5 +- toolboxes/mri/sdc/CMakeLists.txt | 6 +- toolboxes/mri/sdc/cpu/CMakeLists.txt | 32 +- toolboxes/mri/spiral/CMakeLists.txt | 58 +- toolboxes/mri/spiral/TrajectoryParameters.cpp | 33 +- toolboxes/mri/spiral/TrajectoryParameters.h | 7 +- toolboxes/mri_core/CMakeLists.txt | 81 +- .../mri_core/mri_core_acquisition_bucket.h | 86 - .../mri_core/mri_core_coil_map_estimation.h | 5 +- toolboxes/mri_core/mri_core_data.cpp | 38 - toolboxes/mri_core/mri_core_data.h | 170 - toolboxes/mri_core/mri_core_def.h | 4 +- toolboxes/mri_core/mri_core_dependencies.cpp | 116 - toolboxes/mri_core/mri_core_dependencies.h | 30 - toolboxes/mri_core/mri_core_export.h | 7 - toolboxes/mri_core/mri_core_grappa.cpp | 116 +- toolboxes/mri_core/mri_core_grappa.h | 61 +- toolboxes/mri_core/mri_core_grappa_python.h | 3 +- toolboxes/mri_core/mri_core_kspace_filter.cpp | 170 +- toolboxes/mri_core/mri_core_kspace_filter.h | 57 +- .../mri_core/mri_core_partial_fourier.cpp | 28 +- toolboxes/mri_core/mri_core_partial_fourier.h | 5 +- toolboxes/mri_core/mri_core_python.cpp | 2 +- toolboxes/mri_core/mri_core_spirit.cpp | 52 +- toolboxes/mri_core/mri_core_spirit.h | 29 +- toolboxes/mri_core/mri_core_stream.cpp | 139 +- toolboxes/mri_core/mri_core_stream.h | 117 +- toolboxes/mri_core/mri_core_utility.cpp | 727 ++-- toolboxes/mri_core/mri_core_utility.h | 77 +- toolboxes/mri_image/CMakeLists.txt | 26 +- toolboxes/mri_image/hoMRImage.h | 66 +- toolboxes/mri_image/hoMRImage.hxx | 179 +- toolboxes/mri_image/mri_image_export.h | 14 - toolboxes/nfft/CMakeLists.txt | 9 +- toolboxes/nfft/NFFTOperator.h | 13 +- toolboxes/nfft/cpu/CMakeLists.txt | 33 +- toolboxes/nfft/cpu/hoGriddingConvolution.cpp | 3 - toolboxes/nfft/cpu/hoNFFTOperator.cpp | 13 +- toolboxes/nfft/gpu/ConvolverC2NC.cuh | 614 ++-- toolboxes/nfft/gpu/ConvolverNC2C_standard.cuh | 954 +++--- toolboxes/nfft/gpu/cuNFFT.cu | 590 ++-- toolboxes/nfft/gpu/cuNFFT.h | 264 +- toolboxes/nfft/nfft_export.h | 12 - toolboxes/operators/CMakeLists.txt | 18 +- toolboxes/operators/cpu/CMakeLists.txt | 89 +- toolboxes/operators/cpu/cpuOperatorExport.h | 8 - .../cpu/hoMotionCompensation2DTOperator.cpp | 12 +- .../cpu/hoMotionCompensation2DTOperator.h | 9 +- .../cpu/hoRedundantWaveletOperator.h | 7 +- .../operators/cpu/hoSPIRIT2DOperator.cpp | 10 +- toolboxes/operators/cpu/hoSPIRIT2DOperator.h | 6 +- .../cpu/hoSPIRIT2DTDataFidelityOperator.cpp | 4 +- .../cpu/hoSPIRIT2DTDataFidelityOperator.h | 6 +- .../operators/cpu/hoSPIRIT2DTOperator.cpp | 22 +- toolboxes/operators/cpu/hoSPIRIT2DTOperator.h | 6 +- .../operators/cpu/hoSPIRIT3DOperator.cpp | 10 +- toolboxes/operators/cpu/hoSPIRIT3DOperator.h | 6 +- toolboxes/operators/cpu/hoSPIRITOperator.cpp | 30 +- toolboxes/operators/cpu/hoSPIRITOperator.h | 7 +- .../operators/cpu/hoWavelet1DOperator.cpp | 8 +- toolboxes/operators/cpu/hoWavelet1DOperator.h | 12 +- .../operators/cpu/hoWavelet2DTOperator.cpp | 4 +- .../operators/cpu/hoWavelet2DTOperator.h | 6 +- .../operators/cpu/hoWavelet3DOperator.cpp | 4 +- toolboxes/operators/cpu/hoWavelet3DOperator.h | 6 +- toolboxes/operators/cpu/hoWaveletOperator.cpp | 8 +- toolboxes/operators/cpu/hoWaveletOperator.h | 7 +- .../operators/curveFittingCostFunction.h | 1 - toolboxes/operators/curveFittingOperator.h | 1 - .../operators/gpu/cuConvolutionOperator.cu | 46 +- .../operators/gpu/cuConvolutionOperator.h | 11 +- toolboxes/operators/gpu/cuLaplaceOperator.cu | 38 +- toolboxes/operators/gpu/cuLaplaceOperator.h | 11 +- .../gpu/cuPartialDerivativeOperator.cu | 98 +- .../gpu/cuPartialDerivativeOperator.h | 25 +- .../gpu/cuPartialDerivativeOperator2.cu | 50 +- .../gpu/cuPartialDerivativeOperator2.h | 3 +- toolboxes/operators/gpu/cuTv1dOperator.cu | 38 +- toolboxes/operators/gpu/cuTv1dOperator.h | 19 +- toolboxes/operators/gpu/cuTvOperator.cu | 38 +- toolboxes/operators/gpu/cuTvOperator.h | 7 +- toolboxes/operators/gpu/gpuoperators_export.h | 18 - toolboxes/pattern_recognition/CMakeLists.txt | 57 +- toolboxes/pattern_recognition/pr_export.h | 19 - toolboxes/pattern_recognition/pr_kmeans.cpp | 8 +- toolboxes/pattern_recognition/pr_kmeans.h | 7 +- toolboxes/plplot/CMakeLists.txt | 54 - toolboxes/plplot/GtPLplot.cpp | 654 ---- toolboxes/plplot/GtPLplot.h | 55 - toolboxes/plplot/PLplotExport.h | 16 - toolboxes/plplot/ut/CMakeLists.txt | 15 - toolboxes/plplot/ut/plplot_test.cpp | 186 -- toolboxes/plplot/ut/plplot_ut.cpp | 16 - toolboxes/python/CMakeLists.txt | 53 +- toolboxes/python/example/CMakeLists.txt | 10 - toolboxes/python/example/demo.cpp | 584 ---- toolboxes/python/example/test_python.cpp | 33 - .../python_IsmrmrdImageArray_converter.h | 127 - .../python_IsmrmrdReconData_converter.h | 172 - toolboxes/python/python_converters.h | 35 +- toolboxes/python/python_export.h | 14 - toolboxes/python/python_hoNDArray_converter.h | 256 +- toolboxes/python/python_ismrmrd_converter.h | 390 --- toolboxes/python/python_mrd_converters.h | 808 +++++ toolboxes/python/python_numpy_wrappers.h | 45 +- toolboxes/python/python_optional_converter.h | 49 + toolboxes/python/python_toolbox.cpp | 24 +- toolboxes/python/python_toolbox.h | 47 +- toolboxes/python/python_tuple_converter.h | 57 +- toolboxes/python/python_vector_converter.h | 319 +- toolboxes/registration/CMakeLists.txt | 4 +- toolboxes/registration/demons/CMakeLists.txt | 41 +- .../registration/optical_flow/CMakeLists.txt | 18 +- .../optical_flow/cpu/CMakeLists.txt | 46 +- .../optical_flow/cpu/cpureg_export.h | 14 - .../hoImageRegDissimilarityLocalCCR.h | 58 +- .../cpu/hoCKOpticalFlowSolver.cpp | 18 +- .../optical_flow/cpu/hoCKOpticalFlowSolver.h | 30 +- .../cpu/hoHSOpticalFlowSolver.cpp | 146 +- .../optical_flow/cpu/hoHSOpticalFlowSolver.h | 26 +- .../cpu/hoLinearResampleOperator.cpp | 86 +- .../cpu/hoLinearResampleOperator.h | 13 +- .../optical_flow/cpu/hoOpticalFlowSolver.cpp | 90 +- .../optical_flow/cpu/hoOpticalFlowSolver.h | 33 +- .../optical_flow/gpu/cuCKOpticalFlowSolver.cu | 18 +- .../optical_flow/gpu/cuCKOpticalFlowSolver.h | 30 +- .../optical_flow/gpu/cuHSOpticalFlowSolver.cu | 182 +- .../optical_flow/gpu/cuHSOpticalFlowSolver.h | 26 +- .../gpu/cuLinearResampleOperator.cu | 118 +- .../gpu/cuLinearResampleOperator.h | 10 +- .../optical_flow/gpu/cuOpticalFlowSolver.cu | 138 +- .../optical_flow/gpu/cuOpticalFlowSolver.h | 37 +- .../optical_flow/gpu/cuResampleOperator.cu | 72 +- .../optical_flow/gpu/cuResampleOperator.h | 15 +- .../optical_flow/gpu/gpureg_export.h | 14 - toolboxes/solvers/CMakeLists.txt | 17 +- toolboxes/solvers/cpu/CMakeLists.txt | 25 +- toolboxes/solvers/cpu/cpusolver_export.h | 19 - toolboxes/solvers/gpu/cuLbfgsSolver.h | 6 +- toolboxes/solvers/gpu/cuNlcgSolver.h | 3 +- toolboxes/solvers/gpu/cuSolverUtils.cu | 26 +- toolboxes/solvers/gpu/cuSolverUtils.h | 7 +- toolboxes/solvers/gpu/gpusolvers_export.h | 18 - 1201 files changed, 19257 insertions(+), 68138 deletions(-) create mode 100644 .devcontainer/devcontainer.bashrc create mode 100644 .github/workflows/pingvin-ci.yml delete mode 100644 apps/clients/CMakeLists.txt delete mode 100644 apps/clients/gadgetron_ismrmrd_client/CMakeLists.txt delete mode 100644 apps/clients/gadgetron_ismrmrd_client/gadgetron_ismrmrd_client.cpp delete mode 100644 apps/clients/utilities/CMakeLists.txt delete mode 100644 apps/clients/utilities/DependencyQueryReader.h delete mode 100644 apps/clients/utilities/gt_alive.cpp delete mode 100644 apps/clients/utilities/gt_query.cpp delete mode 100644 apps/gadgetron/CMakeLists.txt delete mode 100644 apps/gadgetron/Connection.cpp delete mode 100644 apps/gadgetron/Connection.h delete mode 100644 apps/gadgetron/Server.cpp delete mode 100644 apps/gadgetron/Server.h delete mode 100644 apps/gadgetron/StreamConsumer.h delete mode 100644 apps/gadgetron/connection/ConfigConnection.cpp delete mode 100644 apps/gadgetron/connection/ConfigConnection.h delete mode 100644 apps/gadgetron/connection/Core.cpp delete mode 100644 apps/gadgetron/connection/Handlers.cpp delete mode 100644 apps/gadgetron/connection/Handlers.h delete mode 100644 apps/gadgetron/connection/HeaderConnection.cpp delete mode 100644 apps/gadgetron/connection/HeaderConnection.h delete mode 100644 apps/gadgetron/connection/Loader.cpp delete mode 100644 apps/gadgetron/connection/Loader.h delete mode 100644 apps/gadgetron/connection/SocketStreamBuf.cpp delete mode 100644 apps/gadgetron/connection/SocketStreamBuf.h delete mode 100644 apps/gadgetron/connection/StreamConnection.cpp delete mode 100644 apps/gadgetron/connection/StreamConnection.h delete mode 100644 apps/gadgetron/connection/VoidConnection.cpp delete mode 100644 apps/gadgetron/connection/VoidConnection.h delete mode 100644 apps/gadgetron/connection/Writers.cpp delete mode 100644 apps/gadgetron/connection/Writers.h delete mode 100644 apps/gadgetron/connection/config/Config.h delete mode 100644 apps/gadgetron/connection/nodes/Distributed.cpp delete mode 100644 apps/gadgetron/connection/nodes/Distributed.h delete mode 100644 apps/gadgetron/connection/nodes/External.cpp delete mode 100644 apps/gadgetron/connection/nodes/External.h delete mode 100644 apps/gadgetron/connection/nodes/PureDistributed.cpp delete mode 100644 apps/gadgetron/connection/nodes/PureDistributed.h delete mode 100644 apps/gadgetron/connection/nodes/common/Closer.h delete mode 100644 apps/gadgetron/connection/nodes/common/Configuration.cpp delete mode 100644 apps/gadgetron/connection/nodes/common/Configuration.h delete mode 100644 apps/gadgetron/connection/nodes/common/Discovery.cpp delete mode 100644 apps/gadgetron/connection/nodes/common/Discovery.h delete mode 100644 apps/gadgetron/connection/nodes/common/External.cpp delete mode 100644 apps/gadgetron/connection/nodes/common/External.h delete mode 100644 apps/gadgetron/connection/nodes/common/ExternalChannel.cpp delete mode 100644 apps/gadgetron/connection/nodes/common/ExternalChannel.h delete mode 100644 apps/gadgetron/connection/nodes/common/Serialization.cpp delete mode 100644 apps/gadgetron/connection/nodes/common/Serialization.h delete mode 100644 apps/gadgetron/connection/nodes/distributed/Pool.cpp delete mode 100644 apps/gadgetron/connection/nodes/distributed/Pool.h delete mode 100644 apps/gadgetron/connection/nodes/distributed/Worker.cpp delete mode 100644 apps/gadgetron/connection/nodes/distributed/Worker.h delete mode 100644 apps/gadgetron/connection/nodes/external/Julia.cpp delete mode 100644 apps/gadgetron/connection/nodes/external/Julia.h delete mode 100644 apps/gadgetron/connection/nodes/external/Matlab.cpp delete mode 100644 apps/gadgetron/connection/nodes/external/Matlab.h delete mode 100644 apps/gadgetron/connection/nodes/external/Python.cpp delete mode 100644 apps/gadgetron/connection/nodes/external/Python.h delete mode 100644 apps/gadgetron/gadgetron_config.in delete mode 100644 apps/gadgetron/main.cpp delete mode 100644 apps/gadgetron/schema/gadgetron.xsd delete mode 100644 apps/gadgetron/storage.cpp delete mode 100644 apps/gadgetron/storage.h delete mode 100644 apps/gadgetron/test/CMakeLists.txt delete mode 100644 apps/gadgetron/test/socket_test.cpp delete mode 100644 apps/gadgetron/test/storage_test.cpp create mode 100644 apps/pingvin/CMakeLists.txt rename apps/{gadgetron/connection/config => pingvin}/Config.cpp (56%) create mode 100644 apps/pingvin/Config.h rename apps/{gadgetron/connection/Core.h => pingvin/ErrorHandler.h} (53%) create mode 100644 apps/pingvin/Loader.cpp create mode 100644 apps/pingvin/Loader.h create mode 100644 apps/pingvin/StreamConsumer.h rename apps/{gadgetron => pingvin}/initialization.cpp (90%) rename apps/{gadgetron => pingvin}/initialization.h (79%) create mode 100644 apps/pingvin/main.cpp rename apps/{gadgetron/connection => pingvin}/nodes/Parallel.cpp (90%) rename apps/{gadgetron/connection => pingvin}/nodes/Parallel.h (94%) rename apps/{gadgetron/connection => pingvin}/nodes/ParallelProcess.cpp (97%) rename apps/{gadgetron/connection => pingvin}/nodes/ParallelProcess.h (88%) rename apps/{gadgetron/connection/core => pingvin/nodes}/Processable.cpp (88%) rename apps/{gadgetron/connection/core => pingvin/nodes}/Processable.h (90%) rename apps/{gadgetron/connection => pingvin}/nodes/PureStream.cpp (81%) rename apps/{gadgetron/connection => pingvin}/nodes/PureStream.h (74%) rename apps/{gadgetron/connection => pingvin}/nodes/Stream.cpp (63%) rename apps/{gadgetron/connection => pingvin}/nodes/Stream.h (74%) create mode 100644 apps/pingvin/pingvin_config.in create mode 100644 apps/pingvin/schema/gadgetron.xsd rename apps/{gadgetron => pingvin}/system_info.cpp (58%) rename apps/{gadgetron => pingvin}/system_info.h (69%) delete mode 100644 apps/standalone/CMakeLists.txt delete mode 100644 apps/standalone/cpu/CMakeLists.txt delete mode 100644 apps/standalone/cpu/denoising/2d/CMakeLists.txt delete mode 100644 apps/standalone/cpu/denoising/2d/denoise_TV.cpp delete mode 100644 apps/standalone/cpu/denoising/CMakeLists.txt delete mode 100644 apps/standalone/cpu/nfft/CMakeLists.txt delete mode 100644 apps/standalone/cpu/nfft/nfft.cpp delete mode 100644 apps/standalone/cpu/registration/2d/CMakeLists.txt delete mode 100644 apps/standalone/cpu/registration/2d/register_CK_2d.cpp delete mode 100644 apps/standalone/cpu/registration/2d/register_HS_2d.cpp delete mode 100644 apps/standalone/cpu/registration/3d/CMakeLists.txt delete mode 100644 apps/standalone/cpu/registration/3d/register_CK_3d.cpp delete mode 100644 apps/standalone/cpu/registration/CMakeLists.txt delete mode 100644 apps/standalone/gpu/CMakeLists.txt delete mode 100644 apps/standalone/gpu/deblurring/2d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/deblurring/2d/blur_2d.cpp delete mode 100644 apps/standalone/gpu/deblurring/2d/deblur_2d_cg.cpp delete mode 100644 apps/standalone/gpu/deblurring/2d/deblur_2d_sb.cpp delete mode 100644 apps/standalone/gpu/deblurring/3d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/deblurring/3d/blur_3d.cpp delete mode 100644 apps/standalone/gpu/deblurring/3d/deblur_3d_cg.cpp delete mode 100644 apps/standalone/gpu/deblurring/3d/deblur_3d_sb.cpp delete mode 100644 apps/standalone/gpu/deblurring/CMakeLists.txt delete mode 100644 apps/standalone/gpu/denoising/2d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/denoising/2d/denoise_TV.cpp delete mode 100644 apps/standalone/gpu/denoising/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/nfft/2d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/nfft/2d/main_cg.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/2d/main_nfft.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/2d/main_nffth.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/2d/main_sb.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/nfft/ms2d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/nfft/ms2d/nfft_main.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/ms2d/nffth_generic.cpp delete mode 100644 apps/standalone/gpu/mri/nfft/ms2d/nffth_main.cpp delete mode 100644 apps/standalone/gpu/mri/sense/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/generic_cg.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/.gitignore delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_cg.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_gpbb.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_nlcg.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_sbc.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.h delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/UIconstants.h delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/main.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppBaseMainWidget.ui delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.h delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconBaseWidget.ui delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.h delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/CMakeLists.txt delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/main.cpp delete mode 100644 apps/standalone/gpu/mri/sense/noncartesian/radial/CMakeLists.txt delete mode 100644 apps/standalone/gpu/registration/2d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/registration/2d/register_CGHS_2d.cpp delete mode 100644 apps/standalone/gpu/registration/2d/register_CK_2d.cpp delete mode 100644 apps/standalone/gpu/registration/2d/register_HS_2d.cpp delete mode 100644 apps/standalone/gpu/registration/2d/test_reg_sense_recon.cpp delete mode 100644 apps/standalone/gpu/registration/3d/CMakeLists.txt delete mode 100644 apps/standalone/gpu/registration/3d/register_CK_3d.cpp delete mode 100644 apps/standalone/gpu/registration/CMakeLists.txt delete mode 100644 azure-pipelines.yml delete mode 100644 chroot/CMakeLists.txt delete mode 100644 chroot/README.rst delete mode 100644 chroot/chroot-manual.txt delete mode 100644 chroot/clean_gadgetron_data.sh delete mode 100644 chroot/copy-cuda-lib.sh.in delete mode 100755 chroot/copy_file_and_dependencies delete mode 100755 chroot/create_chroot.sh delete mode 100755 chroot/create_chroot_base.sh delete mode 100755 chroot/create_chroot_from_base.sh delete mode 100644 chroot/enter-chroot-env.sh.in delete mode 100644 chroot/gadgetron-dependency-query.sh.in delete mode 100644 chroot/gadgetron_chroot.conf delete mode 100644 chroot/gadgetron_ismrmrd_client.sh.in delete mode 100644 chroot/gadgetron_ismrmrd_client_noise_summary.sh.in delete mode 100755 chroot/generate_gadgetron_root delete mode 100755 chroot/get_dependencies_for_binary delete mode 100644 chroot/gt_alive.sh.in delete mode 100755 chroot/install_chroot_image.sh delete mode 100755 chroot/make_list_of_dependencies delete mode 100755 chroot/mount.sh delete mode 100755 chroot/mount_image.sh delete mode 100644 chroot/mount_image.sh.in delete mode 100755 chroot/nvidia-copy.sh delete mode 100755 chroot/run-gadgetron-dependency-query.sh delete mode 100644 chroot/run-gadgetron-dependency-query.sh.in delete mode 100755 chroot/run-gadgetron_ismrmrd_client.sh delete mode 100644 chroot/run-gadgetron_ismrmrd_client.sh.in delete mode 100644 chroot/run-gadgetron_ismrmrd_client_noise_summary.sh.in delete mode 100755 chroot/run-gt_alive.sh delete mode 100644 chroot/run-gt_alive.sh.in delete mode 100755 chroot/run-siemens_to_ismrmrd.sh delete mode 100644 chroot/run-siemens_to_ismrmrd.sh.in delete mode 100644 chroot/siemens_to_ismrmrd.sh.in delete mode 100755 chroot/start-env.sh delete mode 100644 chroot/start-env.sh.in delete mode 100755 chroot/start-gadgetron-from-image.sh delete mode 100755 chroot/start-gadgetron-from-image.sh.in delete mode 100644 chroot/start-gadgetron.sh.in delete mode 100755 chroot/start.sh delete mode 100644 chroot/start.sh.in delete mode 100755 chroot/stop.sh delete mode 100755 chroot/umount_image.sh delete mode 100755 chroot/unique_lines_in_file delete mode 100644 chroot/upstart-instructions.txt delete mode 100644 cmake/FindGLEW.cmake delete mode 100644 cmake/FindPLplot.cmake delete mode 100644 cmake/FindZFP.cmake delete mode 100644 cmake/cpack_options_dependency.cmake.in delete mode 100644 cmake/cpack_options_web.cmake.in delete mode 100644 cmake/debian/postinst delete mode 100644 cmake/debian/prerm delete mode 100644 cmake/debian_web/postinst delete mode 100644 cmake/debian_web/prerm delete mode 100644 cmake/gadgetron_sha1.h.in delete mode 100644 cmake/gadgetron_web_cpack.cmake rename cmake/{gadgetron-config.cmake.in => pingvin-config.cmake.in} (64%) rename cmake/{gadgetron_cpack.cmake => pingvin_cpack.cmake} (92%) create mode 100644 cmake/pingvin_sha1.h.in delete mode 100644 core/IsmrmrdContextVariables.cpp delete mode 100644 core/IsmrmrdContextVariables.h delete mode 100644 core/LegacyACE.cpp delete mode 100644 core/LegacyACE.h delete mode 100644 core/MessageID.h delete mode 100644 core/Reader.h delete mode 100644 core/Response.cpp delete mode 100644 core/Response.h delete mode 100644 core/Storage.cpp delete mode 100644 core/StorageSetup.h delete mode 100644 core/TypeTraits.h delete mode 100644 core/Types.h delete mode 100644 core/Types.hpp delete mode 100644 core/Writer.h delete mode 100644 core/Writer.hpp delete mode 100644 core/config/distributed_default.xml delete mode 100644 core/config/distributed_generic_default.xml delete mode 100644 core/config/distributed_image_default.xml delete mode 100644 core/distributed/AcquisitionDistributor.cpp delete mode 100644 core/distributed/AcquisitionDistributor.h delete mode 100644 core/distributed/BufferDistributor.cpp delete mode 100644 core/distributed/BufferDistributor.h delete mode 100644 core/distributed/CMakeLists.txt delete mode 100644 core/distributed/ChannelCreator.h delete mode 100644 core/distributed/Distributor.cpp delete mode 100644 core/distributed/Distributor.h delete mode 100644 core/gadgetron_paths.cpp delete mode 100644 core/gadgetron_paths.h delete mode 100644 core/io/adapt_struct.h delete mode 100644 core/io/iostream_operators.h delete mode 100644 core/io/ismrmrd_types.h delete mode 100644 core/io/sfndam.h delete mode 100644 core/io/sfndam_serializable.h delete mode 100644 core/readers/AcquisitionBucketReader.cpp delete mode 100644 core/readers/AcquisitionBucketReader.h delete mode 100644 core/readers/AcquisitionReader.cpp delete mode 100644 core/readers/AcquisitionReader.h delete mode 100644 core/readers/BufferReader.cpp delete mode 100644 core/readers/BufferReader.h delete mode 100644 core/readers/CMakeLists.txt delete mode 100644 core/readers/ImageReader.cpp delete mode 100644 core/readers/ImageReader.h delete mode 100644 core/readers/IsmrmrdImageArrayReader.cpp delete mode 100644 core/readers/IsmrmrdImageArrayReader.h delete mode 100644 core/readers/TextReader.cpp delete mode 100644 core/readers/TextReader.h delete mode 100644 core/readers/WaveformReader.cpp delete mode 100644 core/readers/WaveformReader.h delete mode 100644 core/variant.hpp delete mode 100644 core/writers/AcquisitionBucketWriter.cpp delete mode 100644 core/writers/AcquisitionBucketWriter.h delete mode 100644 core/writers/AcquisitionWriter.cpp delete mode 100644 core/writers/AcquisitionWriter.h delete mode 100644 core/writers/BufferWriter.cpp delete mode 100644 core/writers/BufferWriter.h delete mode 100644 core/writers/CMakeLists.txt delete mode 100644 core/writers/ImageWriter.cpp delete mode 100644 core/writers/ImageWriter.h delete mode 100644 core/writers/IsmrmrdImageArrayWriter.cpp delete mode 100644 core/writers/IsmrmrdImageArrayWriter.h delete mode 100644 core/writers/TextWriter.cpp delete mode 100644 core/writers/TextWriter.h delete mode 100644 core/writers/WaveformWriter.cpp delete mode 100644 core/writers/WaveformWriter.h rename build-images.sh => docker/build-images.sh (67%) delete mode 100644 gadgets/T1/CMakeLists.txt delete mode 100644 gadgets/T1/T1MocoGadget.cpp delete mode 100644 gadgets/T1/config/MOLLI_T1_Moco.xml delete mode 100644 gadgets/T1/config/MOLLI_T1_Moco_istore.xml delete mode 100644 gadgets/bart/BART_Recon.xml delete mode 100644 gadgets/bart/BART_Recon_cloud.xml delete mode 100644 gadgets/bart/BART_Recon_cloud_Standard.xml delete mode 100644 gadgets/bart/CMakeLists.txt delete mode 100755 gadgets/bart/Sample_Grappa_Recon.sh delete mode 100755 gadgets/bart/Sample_Grappa_Recon_Standard.sh delete mode 100644 gadgets/bart/bart_helpers.cpp delete mode 100644 gadgets/bart/bart_helpers.h delete mode 100644 gadgets/bart/bart_logger.cpp delete mode 100644 gadgets/bart/bartgadget.cpp delete mode 100644 gadgets/bart/bartgadget.h delete mode 100644 gadgets/cartesian/CMakeLists.txt delete mode 100644 gadgets/cartesian/CartesianToGenericGadget.cpp delete mode 100644 gadgets/cartesian/CartesianToGenericGadget.h delete mode 100644 gadgets/cartesian/gadgetron_cartesian_export.h delete mode 100644 gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_Cloud.xml delete mode 100644 gadgets/cmr/config/BinningCine/CMR_2DT_RTCine_KspaceBinning_MultiSeries_Cloud.xml delete mode 100644 gadgets/cmr/gadgetron_cmr_export.h delete mode 100644 gadgets/debugging/AcquisitionPassthroughGadget.cpp delete mode 100644 gadgets/debugging/AcquisitionPassthroughGadget.h delete mode 100644 gadgets/debugging/CplxDumpGadget.cpp delete mode 100644 gadgets/debugging/CplxDumpGadget.h delete mode 100644 gadgets/debugging/ImageWriterGadget.cpp delete mode 100644 gadgets/debugging/ImageWriterGadget.h delete mode 100644 gadgets/debugging/gadgetron_debugging_export.h delete mode 100644 gadgets/dicom/CMakeLists.txt delete mode 100644 gadgets/dicom/DicomFinishGadget.cpp delete mode 100644 gadgets/dicom/DicomFinishGadget.h delete mode 100644 gadgets/dicom/DicomImageWriter.cpp delete mode 100644 gadgets/dicom/DicomImageWriter.h delete mode 100644 gadgets/dicom/dicom.xml delete mode 100644 gadgets/dicom/dicom_ismrmrd_utility.cpp delete mode 100644 gadgets/dicom/dicom_ismrmrd_utility.h delete mode 100644 gadgets/dicom/gadgetron_dicom_export.h delete mode 100644 gadgets/epi/gadgetron_epi_export.h delete mode 100644 gadgets/examples/config/external_connect_example.xml delete mode 100644 gadgets/examples/config/external_equivalent_example.xml delete mode 100644 gadgets/examples/config/external_example.xml delete mode 100644 gadgets/examples/config/external_julia_acquisition_example.xml delete mode 100644 gadgets/examples/config/external_matlab_acquisition_example.xml delete mode 100644 gadgets/examples/config/external_matlab_bucket_example.xml delete mode 100644 gadgets/examples/config/external_matlab_buffer_example.xml delete mode 100644 gadgets/examples/config/external_matlab_tiny_example.xml delete mode 100644 gadgets/examples/config/external_python_acquisition_example.xml delete mode 100644 gadgets/examples/config/external_python_bucket_example.xml delete mode 100644 gadgets/examples/config/external_python_buffer_example.xml delete mode 100644 gadgets/fatwater/CMakeLists.txt delete mode 100644 gadgets/fatwater/FatWaterGadget.cpp delete mode 100644 gadgets/fatwater/FatWaterGadget.h delete mode 100644 gadgets/fatwater/config/Generic_Cartesian_Grappa_FatWater.xml delete mode 100644 gadgets/fatwater/gadgetron_fatwater_export.h delete mode 100644 gadgets/hyper/CMRT.xml delete mode 100644 gadgets/hyper/CMRT3D.xml delete mode 100644 gadgets/hyper/CMRT3DGadget.cpp delete mode 100644 gadgets/hyper/CMRT3DGadget.h delete mode 100644 gadgets/hyper/CMRTGadget.cpp delete mode 100644 gadgets/hyper/CMRTGadget.h delete mode 100644 gadgets/hyper/CMakeLists.txt delete mode 100644 gadgets/hyper/CSIGadget.cpp delete mode 100644 gadgets/hyper/CSIGadget.h delete mode 100644 gadgets/hyper/FS-CSI.xml delete mode 100644 gadgets/hyper/NFFT2D.xml delete mode 100644 gadgets/hyper/NFFT2DGadget.cpp delete mode 100644 gadgets/hyper/NFFT2DGadget.h delete mode 100644 gadgets/hyper/gadgetron_hyper_export.h delete mode 100644 gadgets/hyper/gpuCSICoilEstimationGadget.cpp delete mode 100644 gadgets/hyper/gpuCSICoilEstimationGadget.h delete mode 100644 gadgets/interventional_mri/gadgetron_interventional_mri_export.h delete mode 100644 gadgets/moco/CMakeLists.txt delete mode 100644 gadgets/moco/RegistrationAveragingGadget.h delete mode 100644 gadgets/moco/RegistrationScatteringGadget.h delete mode 100644 gadgets/moco/config/CMakeLists.txt delete mode 100644 gadgets/moco/config/cpureg_cartesian_averaging.xml delete mode 100644 gadgets/moco/config/gpureg_cartesian_averaging.xml delete mode 100644 gadgets/moco/cpuRegistrationAveragingGadget.cpp delete mode 100644 gadgets/moco/cpuRegistrationAveragingGadget.h delete mode 100644 gadgets/moco/gadgetron_moco_export.h delete mode 100644 gadgets/moco/gpuRegistrationAveragingGadget.cpp delete mode 100644 gadgets/moco/gpuRegistrationAveragingGadget.h delete mode 100644 gadgets/moco/gpuRegistrationScatteringGadget.cpp delete mode 100644 gadgets/moco/gpuRegistrationScatteringGadget.h delete mode 100644 gadgets/mri_core/GadgetMRIHeaders.h delete mode 100644 gadgets/mri_core/ImageFinishGadget.cpp delete mode 100644 gadgets/mri_core/ImageFinishGadget.h delete mode 100644 gadgets/mri_core/IsmrmrdDumpGadget.cpp delete mode 100644 gadgets/mri_core/IsmrmrdDumpGadget.h delete mode 100644 gadgets/mri_core/config/NoiseSummary.xml delete mode 100644 gadgets/mri_core/config/default_measurement_dependencies_ismrmrd_storage.xml delete mode 100644 gadgets/mri_core/config/default_short.xml delete mode 100644 gadgets/mri_core/config/gtquery.xml delete mode 100644 gadgets/mri_core/config/isalive.xml delete mode 100644 gadgets/mri_core/config/ismrmrd_dump.xml delete mode 100644 gadgets/mri_core/dependencyquery/Dependency.h delete mode 100644 gadgets/mri_core/dependencyquery/DependencyQueryGadget.cpp delete mode 100644 gadgets/mri_core/dependencyquery/DependencyQueryGadget.h delete mode 100644 gadgets/mri_core/dependencyquery/DependencyQueryWriter.cpp delete mode 100644 gadgets/mri_core/dependencyquery/DependencyQueryWriter.h delete mode 100644 gadgets/mri_core/dependencyquery/NoiseSummaryGadget.cpp delete mode 100644 gadgets/mri_core/dependencyquery/NoiseSummaryGadget.h delete mode 100644 gadgets/mri_core/gadgetron_mricore_export.h delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_Grappa_RealTimeCine_Cloud.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_NonLinear_Spirit_RealTimeCine_Cloud.xml delete mode 100644 gadgets/mri_core/generic_recon_gadgets/config/Generic_Cartesian_RandomSampling_NonLinear_Spirit_RealTimeCine_Cloud.xml delete mode 100644 gadgets/mri_core/readers/GadgetIsmrmrdReader.cpp delete mode 100644 gadgets/mri_core/readers/GadgetIsmrmrdReader.h delete mode 100644 gadgets/mri_core/readers/MRIImageReader.cpp delete mode 100644 gadgets/mri_core/readers/MRIImageReader.h delete mode 100644 gadgets/mri_core/writers/GadgetIsmrmrdWriter.cpp delete mode 100644 gadgets/mri_core/writers/GadgetIsmrmrdWriter.h delete mode 100644 gadgets/mri_core/writers/MRIImageWriter.cpp delete mode 100644 gadgets/mri_core/writers/MRIImageWriter.h delete mode 100644 gadgets/mri_noncartesian/CMakeLists.txt delete mode 100644 gadgets/mri_noncartesian/CPUGriddingReconGadget.cpp delete mode 100644 gadgets/mri_noncartesian/CPUGriddingReconGadget.h delete mode 100644 gadgets/mri_noncartesian/GriddingReconGadget.cpp delete mode 100644 gadgets/mri_noncartesian/GriddingReconGadget.h delete mode 100644 gadgets/mri_noncartesian/GriddingReconGadgetBase.h delete mode 100644 gadgets/mri_noncartesian/GriddingReconGadgetBase.hpp delete mode 100644 gadgets/mri_noncartesian/NonCartesianTools.cpp delete mode 100644 gadgets/mri_noncartesian/NonCartesianTools.h delete mode 100644 gadgets/mri_noncartesian/config/Generic_CPU_Gridding_Recon.xml delete mode 100644 gadgets/mri_noncartesian/config/Generic_Spiral.xml delete mode 100644 gadgets/mri_noncartesian/config/Generic_Spiral_Flag.xml delete mode 100644 gadgets/mri_noncartesian/config/Generic_Spiral_SNR.xml delete mode 100644 gadgets/mri_noncartesian/gadgetron_mri_noncartesian_export.h delete mode 100644 gadgets/plplot/CMakeLists.txt delete mode 100644 gadgets/plplot/Generic_Cartesian_Grappa_SNR_CoilQA.xml delete mode 100644 gadgets/plplot/NoiseCovariancePlottingGadget.cpp delete mode 100644 gadgets/plplot/NoiseCovariancePlottingGadget.h delete mode 100644 gadgets/plplot/gadgetron_plplot_export.h delete mode 100644 gadgets/pmri/gadgetron_gpupmri_export.h delete mode 100644 gadgets/python/CMakeLists.txt delete mode 100644 gadgets/python/config/Generic_Cartesian_Grappa_RealTimeCine_Python.xml delete mode 100644 gadgets/python/legacy/config/pseudoreplica.xml delete mode 100644 gadgets/python/legacy/config/python_buckets.xml delete mode 100644 gadgets/python/legacy/config/python_image_array_recon.xml delete mode 100644 gadgets/python/legacy/config/python_passthrough.xml delete mode 100644 gadgets/python/legacy/config/python_short.xml delete mode 100644 gadgets/python/legacy/gadgets/accumulate_and_recon.py delete mode 100644 gadgets/python/legacy/gadgets/bucket_recon.py delete mode 100644 gadgets/python/legacy/gadgets/image_array_recon.py delete mode 100644 gadgets/python/legacy/gadgets/image_array_recon_rtcine_plotting.py delete mode 100644 gadgets/python/legacy/gadgets/passthrough.py delete mode 100644 gadgets/python/legacy/gadgets/passthrough_array_image.py delete mode 100644 gadgets/python/legacy/gadgets/pseudoreplicagather.py delete mode 100644 gadgets/python/legacy/gadgets/remove_2x_oversampling.py delete mode 100644 gadgets/python/legacy/gadgets/rms_coil_combine.py delete mode 100644 gadgets/radial/gadgetron_radial_export.h delete mode 100644 gadgets/spiral/gadgetron_spiral_export.h create mode 100644 justfile create mode 100644 libmrd/CMakeLists.txt create mode 100644 libmrd/include/gadgetron-arrays.h delete mode 100644 test/IsmrmrdContextVariables_test.cpp delete mode 100644 test/StorageSpaces_test.cpp create mode 100644 test/e2e/.gitignore create mode 100644 test/e2e/README.md create mode 100644 test/e2e/cases/cmr_cine_binning.yml create mode 100644 test/e2e/cases/cmr_cine_binning_2slices.yml create mode 100644 test/e2e/cases/cmr_mapping_t1_sr.yml create mode 100644 test/e2e/cases/cpu_grappa_simple.yml create mode 100644 test/e2e/cases/epi_2d.yml create mode 100644 test/e2e/cases/generic_cartesian_cine_denoise.yml create mode 100644 test/e2e/cases/generic_cartesian_cine_python.yml create mode 100644 test/e2e/cases/generic_grappa2x1_3d.yml create mode 100644 test/e2e/cases/generic_grappa2x2_3d.yml create mode 100644 test/e2e/cases/generic_grappa_T2W.yml create mode 100644 test/e2e/cases/generic_grappa_epi_ave.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes100_compression.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV100_PERes120.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R1_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PEOverSampling120.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_ipat_PEFOV75_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes100.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV100_PERes120.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_spat_PEFOV75_PERes75_PF6_8_AsymStrong_InterpON.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV100_PERes100.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R2_tpat_PEFOV75_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R3_spat_PEFOV100_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes120.yml create mode 100644 test/e2e/cases/generic_grappa_snr_R3_tpat_PEFOV100_PERes75_PF6_8_AsymStrong.yml create mode 100644 test/e2e/cases/generic_grappa_tse.yml create mode 100644 test/e2e/cases/generic_nl_spirit_cartesian_sampling_cine.yml create mode 100644 test/e2e/cases/generic_nl_spirit_random_sampling_cine.yml create mode 100644 test/e2e/cases/generic_rtcine_ai_landmark.yml create mode 100644 test/e2e/cases/generic_spirit_cartesian_sampling_spat2.yml create mode 100644 test/e2e/cases/gpu_fixed_radial_mode1_cg.yml create mode 100644 test/e2e/cases/gpu_fixed_radial_mode1_ktsense.yml create mode 100644 test/e2e/cases/gpu_fixed_radial_mode1_realtime.yml create mode 100644 test/e2e/cases/gpu_golden_radial_mode2_cg.yml create mode 100644 test/e2e/cases/gpu_golden_radial_mode2_ktsense.yml create mode 100644 test/e2e/cases/gpu_golden_radial_mode2_realtime.yml create mode 100644 test/e2e/cases/gpu_golden_radial_mode2_sb.yml create mode 100644 test/e2e/cases/gpu_grappa_simple.yml create mode 100644 test/e2e/cases/gpu_spiral.yml create mode 100644 test/e2e/cases/gpu_spiral_realtime_deblurring.yml create mode 100644 test/e2e/cases/gpu_spiral_sb.yml create mode 100644 test/e2e/cases/parallel_bypass_example.yml create mode 100644 test/e2e/cases/simple_gre.yml create mode 100644 test/e2e/cases/simple_gre_3d.yml create mode 100644 test/e2e/cases/stream_image.yml create mode 100644 test/e2e/cases/stream_image_array.yml create mode 100644 test/e2e/conftest.py create mode 100644 test/e2e/test_e2e.py rename test/gadgets/{AcquisitionAccumulateTrigget_test.cpp => AcquisitionAccumulateTrigger_test.cpp} (76%) create mode 100644 test/integration/README.md delete mode 100644 test/integration/bart_cases/bart.cfg delete mode 100644 test/integration/cases/stream_snr_R1_PEFOV100_PERes100.cfg create mode 100644 test/integration/convert_test_data.py delete mode 100755 test/integration/mem_watch.py delete mode 100755 test/integration/run_gadgetron_test.py delete mode 100755 test/integration/run_tests.py delete mode 100644 test/integration/stats_to_junit.py delete mode 100644 test/performance/CMakeLists.txt delete mode 100644 test/performance/benchmark_curvefitting.cpp delete mode 100644 test/read_writer_test.cpp delete mode 100644 toolboxes/T1/CMakeLists.txt delete mode 100644 toolboxes/T1/t1fit.cpp delete mode 100644 toolboxes/T1/t1fit.h delete mode 100644 toolboxes/cmr/cmr_export.h delete mode 100644 toolboxes/cmr/cmr_ismrmrd_util.cpp delete mode 100644 toolboxes/cmr/cmr_ismrmrd_util.h delete mode 100644 toolboxes/core/GadgetronException.h delete mode 100644 toolboxes/core/Gadgetron_enable_types.h delete mode 100644 toolboxes/core/cpu/cpucore_export.h delete mode 100644 toolboxes/core/cpu/hostutils/CMakeLists.txt delete mode 100644 toolboxes/core/cpu/hostutils/hostutils_export.h delete mode 100644 toolboxes/core/cpu/hostutils/network_utils.cpp delete mode 100644 toolboxes/core/cpu/hostutils/network_utils.h delete mode 100644 toolboxes/core/cpu/hostutils/parameterparser.cpp delete mode 100644 toolboxes/core/cpu/hostutils/parameterparser.h delete mode 100644 toolboxes/core/cpu/hostutils/url_encode.h delete mode 100644 toolboxes/denoise/denoise_export.h delete mode 100644 toolboxes/dwt/cpu/sessions_test.h delete mode 100644 toolboxes/fatwater/CMakeLists.txt delete mode 100644 toolboxes/fatwater/ImageGraph.cpp delete mode 100644 toolboxes/fatwater/ImageGraph.h delete mode 100644 toolboxes/fatwater/ImageGraph.hxx delete mode 100644 toolboxes/fatwater/bounded_field_map.cpp delete mode 100644 toolboxes/fatwater/bounded_field_map.h delete mode 100644 toolboxes/fatwater/correct_frequency_shift.cpp delete mode 100644 toolboxes/fatwater/correct_frequency_shift.h delete mode 100644 toolboxes/fatwater/fatwater.cpp delete mode 100644 toolboxes/fatwater/fatwater.h delete mode 100644 toolboxes/fatwater/fatwater_export.h delete mode 100644 toolboxes/fatwater/graph_cut.cpp delete mode 100644 toolboxes/fatwater/graph_cut.h delete mode 100644 toolboxes/fft/cpu/cpufft_export.h delete mode 100644 toolboxes/fft/gpu/gpufft_export.h delete mode 100644 toolboxes/image/cpu/image_export.h delete mode 100644 toolboxes/image_io/ImageIOExport.h delete mode 100644 toolboxes/klt/cpu/cpuklt_export.h delete mode 100644 toolboxes/log/log_export.h delete mode 100644 toolboxes/mri/epi/EPIExport.h delete mode 100644 toolboxes/mri/hyper/CMRTOperator.cpp delete mode 100644 toolboxes/mri/hyper/CMRTOperator.h delete mode 100644 toolboxes/mri/hyper/CSIOperator.cpp delete mode 100644 toolboxes/mri/hyper/CSIOperator.h delete mode 100644 toolboxes/mri/hyper/CSI_utils.cu delete mode 100644 toolboxes/mri/hyper/CSI_utils.h delete mode 100644 toolboxes/mri/hyper/CSfreqOperator.h delete mode 100644 toolboxes/mri/hyper/gadgetron_toolbox_hyper_export.h delete mode 100644 toolboxes/mri/pmri/CMakeLists.txt delete mode 100644 toolboxes/mri/pmri/gpu/gpupmri_export.h delete mode 100644 toolboxes/mri_core/mri_core_acquisition_bucket.h delete mode 100644 toolboxes/mri_core/mri_core_data.cpp delete mode 100644 toolboxes/mri_core/mri_core_data.h delete mode 100644 toolboxes/mri_core/mri_core_dependencies.cpp delete mode 100644 toolboxes/mri_core/mri_core_dependencies.h delete mode 100644 toolboxes/mri_core/mri_core_export.h delete mode 100644 toolboxes/mri_image/mri_image_export.h delete mode 100644 toolboxes/nfft/nfft_export.h delete mode 100644 toolboxes/operators/cpu/cpuOperatorExport.h delete mode 100644 toolboxes/operators/gpu/gpuoperators_export.h delete mode 100644 toolboxes/pattern_recognition/pr_export.h delete mode 100644 toolboxes/plplot/CMakeLists.txt delete mode 100644 toolboxes/plplot/GtPLplot.cpp delete mode 100644 toolboxes/plplot/GtPLplot.h delete mode 100644 toolboxes/plplot/PLplotExport.h delete mode 100644 toolboxes/plplot/ut/CMakeLists.txt delete mode 100644 toolboxes/plplot/ut/plplot_test.cpp delete mode 100644 toolboxes/plplot/ut/plplot_ut.cpp delete mode 100644 toolboxes/python/example/CMakeLists.txt delete mode 100644 toolboxes/python/example/demo.cpp delete mode 100644 toolboxes/python/example/test_python.cpp delete mode 100644 toolboxes/python/python_IsmrmrdImageArray_converter.h delete mode 100644 toolboxes/python/python_IsmrmrdReconData_converter.h delete mode 100644 toolboxes/python/python_export.h delete mode 100644 toolboxes/python/python_ismrmrd_converter.h create mode 100644 toolboxes/python/python_mrd_converters.h create mode 100644 toolboxes/python/python_optional_converter.h delete mode 100644 toolboxes/registration/optical_flow/cpu/cpureg_export.h delete mode 100644 toolboxes/registration/optical_flow/gpu/gpureg_export.h delete mode 100644 toolboxes/solvers/cpu/cpusolver_export.h delete mode 100644 toolboxes/solvers/gpu/gpusolvers_export.h diff --git a/.devcontainer/.vscode/launch.json b/.devcontainer/.vscode/launch.json index 64e90623b..f0844b84b 100644 --- a/.devcontainer/.vscode/launch.json +++ b/.devcontainer/.vscode/launch.json @@ -8,7 +8,7 @@ "name": "(gdb) Launch", "type": "cppdbg", "request": "launch", - "program": "/opt/conda/envs/gadgetron/bin/gadgetron", + "program": "/opt/conda/envs/pingvin/bin/pingvin", "args": [], "stopAtEntry": false, "cwd": "${workspaceFolder}", diff --git a/.devcontainer/.vscode/settings.json b/.devcontainer/.vscode/settings.json index 86a4d294d..4c787403a 100644 --- a/.devcontainer/.vscode/settings.json +++ b/.devcontainer/.vscode/settings.json @@ -82,10 +82,10 @@ }, "cmake.configureOnOpen": true, "cmake.preferredGenerators": ["Ninja", "Unix Makefiles"], - "cmake.cmakePath": "/opt/conda/envs/gadgetron/bin/cmake", + "cmake.cmakePath": "/opt/conda/envs/pingvin/bin/cmake", "cmake.configureSettings": { "USE_CUDA": "ON", "USE_MKL": "ON", - "CMAKE_INSTALL_PREFIX": "/opt/conda/envs/gadgetron" + "CMAKE_INSTALL_PREFIX": "/opt/conda/envs/pingvin" } } \ No newline at end of file diff --git a/.devcontainer/bootstrap-vscode.sh b/.devcontainer/bootstrap-vscode.sh index 6f92155b3..857b65a32 100755 --- a/.devcontainer/bootstrap-vscode.sh +++ b/.devcontainer/bootstrap-vscode.sh @@ -9,5 +9,5 @@ else fi mkdir -p /home/vscode/.local/share/CMakeTools && \ - echo '[{"name":"GCC-CONDA","compilers":{"C":"/opt/conda/envs/gadgetron/bin/x86_64-conda_cos6-linux-gnu-gcc","CXX":"/opt/conda/envs/gadgetron/bin/x86_64-conda_cos6-linux-gnu-g++"}}]' > /home/vscode/.local/share/CMakeTools/cmake-tools-kits.json && \ + echo '[{"name":"GCC-CONDA","compilers":{"C":"/opt/conda/envs/pingvin/bin/x86_64-conda_cos6-linux-gnu-gcc","CXX":"/opt/conda/envs/pingvin/bin/x86_64-conda_cos6-linux-gnu-g++"}}]' > /home/vscode/.local/share/CMakeTools/cmake-tools-kits.json && \ chown vscode:conda /home/vscode/.local/share/CMakeTools/cmake-tools-kits.json \ No newline at end of file diff --git a/.devcontainer/devcontainer.bashrc b/.devcontainer/devcontainer.bashrc new file mode 100644 index 000000000..3f29c27cb --- /dev/null +++ b/.devcontainer/devcontainer.bashrc @@ -0,0 +1,14 @@ +#! /bin/bash +# shellcheck source=/dev/null + +source /opt/conda/etc/profile.d/conda.sh +conda activate pingvin + +if command -v just >/dev/null ; then + source <(just --completions bash) +fi + +if [[ "${BASH_ENV:-}" == "$(readlink -f "${BASH_SOURCE[0]:-}")" ]]; then + # We don't want subshells to unnecessarily source this again. + unset BASH_ENV +fi \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8befad66d..bacade0dc 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,10 +1,10 @@ { - "name": "Gadgetron", + "name": "Pingvin", "build": { "dockerfile": "../Dockerfile", - "target": "gadgetron_dev_cuda", + "target": "pingvin_dev_cuda", "context": "../", - "cacheFrom": "ghcr.io/gadgetron/gadgetron/gadgetron_ubuntu_dev_cuda:latest", + "cacheFrom": "ghcr.io/gadgetron/pingvin/ubuntu22.04_dev_cuda:latest", }, "containerEnv": { "DOCKER_BUILDKIT": "1", @@ -21,11 +21,11 @@ "Ninja", "Unix Makefiles" ], - "cmake.cmakePath": "/opt/conda/envs/gadgetron/bin/cmake", + "cmake.cmakePath": "/opt/conda/envs/pingvin/bin/cmake", "cmake.configureSettings": { "USE_CUDA": "ON", "USE_MKL": "ON", - "CMAKE_INSTALL_PREFIX": "/opt/conda/envs/gadgetron", + "CMAKE_INSTALL_PREFIX": "/opt/conda/envs/pingvin", "BUILD_DOCUMENTATION": "OFF" }, "indentRainbow.includedLanguages": [ "yaml", "python" ] @@ -34,6 +34,7 @@ // Add the IDs of extensions you want installed when the container is created. "extensions": [ "ms-vscode.cpptools", + "ms-vscode.cpptools-extension-pack", "ms-vscode.cmake-tools", "ms-vscode.live-server", "eamodio.gitlens", @@ -48,10 +49,8 @@ } }, - "runArgs": ["--init", "--network=host"], - // To enable your local GPUs in container if they are on enabled by default devcontainer will fail to start on hosts without GPU - // "runArgs": ["--init", "--network=host", "--gpus=all"], + "runArgs": ["--init", "--network=host", "--gpus=all"], "mounts": [ ], diff --git a/.dockerignore b/.dockerignore index c9699b614..211bdbf89 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,15 +6,18 @@ !apps/ !cmake/ !core/ +!doc/ !docker/ !gadgets/ +!justfile +!libmrd/ !test/ !toolboxes/ !environment.yml -!chroot/ -!doc/ +!.devcontainer/devcontainer.bashrc # but also ignore: test/integration/data/ +test/e2e/data/ *.Dockerfile docker/integration-test-image.sh \ No newline at end of file diff --git a/.github/workflows/pingvin-ci.yml b/.github/workflows/pingvin-ci.yml new file mode 100644 index 000000000..0c0a8c62d --- /dev/null +++ b/.github/workflows/pingvin-ci.yml @@ -0,0 +1,149 @@ +name: Pingvin CI + +on: + push: + branches: [main] + tags: ["v*.*.*"] + pull_request: + branches: [main] + workflow_dispatch: + +permissions: + id-token: write + contents: read + +env: + imageBaseName: ghcr.io/gadgetron/pingvin/ubuntu22.04 + +defaults: + run: + # See https://github.com/marketplace/actions/setup-miniconda#important + shell: bash -el {0} + +jobs: + build-and-test: + runs-on: ["self-hosted", "1ES.Pool=biomedsigproc-pingvin-NC6s_v3"] + strategy: + matrix: + flavor: [cuda, nocuda] + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + + - name: Check GPU availability + run: docker run --rm --gpus=all ghcr.io/gadgetron/gadgetron/cuda:12.3.0-base-ubuntu22.04 nvidia-smi + + - name: Build Docker images + run: ./docker/build-images.sh --type dev --type build --type rt --flavor ${{matrix.flavor}} --base-name "${{env.imageBaseName}}" + + - name: Unit Test + run: |- + image_name="${{env.imageBaseName}}_build_${{matrix.flavor}}" + test_command=". /opt/conda/etc/profile.d/conda.sh \ + && conda activate pingvin \ + && /opt/code/pingvin/build/test/test_all" + docker run --rm --gpus=all "${image_name}" /bin/bash -c "$test_command" + + - name: End-to-End Test + run: |- + image_name="${{env.imageBaseName}}_rt_${{matrix.flavor}}" + # Check Pingvin entrypoint + docker run --rm -i --gpus=all "${image_name}" --info + # Test Pingvin end-to-end + test_command=". /opt/conda/etc/profile.d/conda.sh \ + && conda activate pingvin \ + && cd /opt/e2e-test/ \ + && pytest --echo-log-on-failure" + docker run --rm --gpus=all --entrypoint /bin/bash "${image_name}" -c "$test_command" + + publish-docker-images: + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: [build-and-test] + runs-on: ["self-hosted", "1ES.Pool=biomedsigproc-pingvin-NC6s_v3"] + strategy: + matrix: + flavor: [cuda, nocuda] + permissions: + packages: write + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + + - name: Log into ghcr.io + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish Docker images + run: |- + PINGVIN_VERSION_MAJOR=$(grep -Po '(?<=set\(PINGVIN_VERSION_MAJOR )([^\)]+)' CMakeLists.txt) + PINGVIN_VERSION_MINOR=$(grep -Po '(?<=set\(PINGVIN_VERSION_MINOR )([^\)]+)' CMakeLists.txt) + PINGVIN_VERSION_PATCH=$(grep -Po '(?<=set\(PINGVIN_VERSION_PATCH )([^\)]+)' CMakeLists.txt) + PINGVIN_VERSION="${PINGVIN_VERSION_MAJOR}.${PINGVIN_VERSION_MINOR}.${PINGVIN_VERSION_PATCH}" + + ./docker/build-images.sh --type dev --type rt --flavor ${{matrix.flavor}} --base-name "${{env.imageBaseName}}" --tag "${PINGVIN_VERSION}" --push + ./docker/build-images.sh --type dev --type rt --flavor ${{matrix.flavor}} --base-name "${{env.imageBaseName}}" --tag latest --push + + + build-conda-package: + runs-on: ["self-hosted", "1ES.Pool=biomedsigproc-pingvin-NC6s_v3"] + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + + - name: Install Yardl + run: |- + YARDL_VERSION=$(grep -Po '(?<=YARDL_VERSION=)(.+)' Dockerfile) + mkdir -p "/tmp/yardl_${YARDL_VERSION}_linux_x86_64" + cd "/tmp/yardl_${YARDL_VERSION}_linux_x86_64" + wget --quiet "https://github.com/microsoft/yardl/releases/download/v${YARDL_VERSION}/yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" + tar -xzf "yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" + pwd >> $GITHUB_PATH + + - name: Setup Miniforge + uses: conda-incubator/setup-miniconda@v3 + with: + miniforge-version: latest + environment-file: conda/environment.yml + activate-environment: pingvin-build + + - name: Build conda package + run: ./conda/package.sh + + - name: Upload Conda package + uses: actions/upload-artifact@v4 + with: + name: conda-packages + path: conda/build_pkg/**/pingvin*.tar.bz2 + + publish-conda-package: + if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags') + needs: [build-conda-package] + runs-on: ["self-hosted", "1ES.Pool=biomedsigproc-pingvin-NC6s_v3"] + steps: + - name: checkout + uses: actions/checkout@v4.1.0 + + - name: Setup Miniforge + uses: conda-incubator/setup-miniconda@v3 + with: + miniforge-version: latest + environment-file: conda/environment.yml + activate-environment: pingvin-build + + - name: Download Conda package + uses: actions/download-artifact@v4 + with: + name: conda-packages + path: conda/build_pkg/ + + - name: Publish conda package + env: + ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} + run: | + for p in $(find conda/build_pkg -name pingvin*.tar.bz2) + do + ./conda/publish_package.sh -u gadgetron -t "$ANACONDA_TOKEN" -p "$p" + done diff --git a/CMakeLists.txt b/CMakeLists.txt index 64988e9ae..76a50a4d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ if (${CMAKE_VERSION} VERSION_LESS 3.17) else () cmake_policy(VERSION 3.17) endif() -project(GADGETRON LANGUAGES CXX C) +project(PINGVIN LANGUAGES CXX C) find_program(CCACHE_FOUND ccache) if (CCACHE_FOUND) @@ -16,9 +16,6 @@ endif (CCACHE_FOUND) if (EXISTS $ENV{CMAKE_PREFIX_PATH}) list(APPEND CMAKE_PREFIX_PATH $ENV{CMAKE_PREFIX_PATH}) endif () -if (EXISTS $ENV{ISMRMRD_HOME}) - list(APPEND CMAKE_PREFIX_PATH $ENV{ISMRMRD_HOME}) -endif () if (EXISTS $ENV{TORCH_HOME}) list(APPEND CMAKE_PREFIX_PATH $ENV{TORCH_HOME}) endif () @@ -34,58 +31,52 @@ if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion OUTPUT_VARIABLE CMAKE_CXX_COMPILER_VERSION) endif () if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - message("CXX COMPILER VERSION: ${CMAKE_CXX_COMPILER_ID} : ${CMAKE_CXX_COMPILER_VERSION}") - message(FATAL_ERROR "Gadgetron requires GCC version >= 6.0") + message(STATUS "CXX COMPILER VERSION: ${CMAKE_CXX_COMPILER_ID} : ${CMAKE_CXX_COMPILER_VERSION}") + message(FATAL_ERROR "Pingvin requires GCC version >= 6.0") endif () elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5) - message(FATAL_ERROR "Gadgetron requires Clang version >= 3.5") + message(FATAL_ERROR "Pingvin requires Clang version >= 3.5") endif () add_compile_definitions(BOOST_NO_CXX98_FUNCTION_BASE) elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 18.0) - message(FATAL_ERROR "Gadgetron requires MSVC 2013 or above ") + message(FATAL_ERROR "Pingvin requires MSVC 2013 or above ") endif () else () message(WARNING "Unsupported compiler!") endif () #VERSIONING AND INSTALL PATHS -set(GADGETRON_VERSION_MAJOR 4) -set(GADGETRON_VERSION_MINOR 7) -set(GADGETRON_VERSION_PATCH 2) -set(GADGETRON_VERSION_STRING ${GADGETRON_VERSION_MAJOR}.${GADGETRON_VERSION_MINOR}.${GADGETRON_VERSION_PATCH}) -set(GADGETRON_SOVERSION ${GADGETRON_VERSION_MAJOR}.${GADGETRON_VERSION_MINOR}) +set(PINGVIN_VERSION_MAJOR 0) +set(PINGVIN_VERSION_MINOR 1) +set(PINGVIN_VERSION_PATCH 0) +set(PINGVIN_VERSION_STRING ${PINGVIN_VERSION_MAJOR}.${PINGVIN_VERSION_MINOR}.${PINGVIN_VERSION_PATCH}) +set(PINGVIN_SOVERSION ${PINGVIN_VERSION_MAJOR}.${PINGVIN_VERSION_MINOR}) find_package(Git) if (GIT_FOUND) execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD WORKING_DIRECTORY - ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE GADGETRON_GIT_SHA1 ERROR_VARIABLE GADGETRON_GIT_STDERR) - string(STRIP "${GADGETRON_GIT_SHA1}" GADGETRON_GIT_SHA1) - string(LENGTH "${GADGETRON_GIT_SHA1}" GADGETRON_GIT_SHA1_LEN) - if (${GADGETRON_GIT_SHA1_LEN} LESS 40) - message(WARNING "Could not determine SHA-1 hash: ${GADGETRON_GIT_STDERR}") - set(GADGETRON_GIT_SHA1 "NA") + ${CMAKE_SOURCE_DIR} OUTPUT_VARIABLE PINGVIN_GIT_SHA1 ERROR_VARIABLE PINGVIN_GIT_STDERR) + string(STRIP "${PINGVIN_GIT_SHA1}" PINGVIN_GIT_SHA1) + string(LENGTH "${PINGVIN_GIT_SHA1}" PINGVIN_GIT_SHA1_LEN) + if (${PINGVIN_GIT_SHA1_LEN} LESS 40) + message(WARNING "Could not determine SHA-1 hash: ${PINGVIN_GIT_STDERR}") + set(PINGVIN_GIT_SHA1 "NA") endif () else () - set(GADGETRON_GIT_SHA1 "NA") -endif () -set(GADGETRON_INSTALL_CMAKE_PATH share/gadgetron/cmake) -set(GADGETRON_INSTALL_CONFIG_PATH share/gadgetron/config) -set(GADGETRON_INSTALL_PYTHON_MODULE_PATH share/gadgetron/python) -set(GADGETRON_INSTALL_SCHEMA_PATH share/gadgetron/schema) -set(GADGETRON_INSTALL_INCLUDE_PATH include/gadgetron) -set(GADGETRON_INSTALL_CHROOT_SCRIPTS_PATH share/gadgetron/chroot) -if (WIN32) - set(GADGETRON_VAR_DIR $ENV{APPDATA}/gadgetron CACHE PATH "Path where Gadgetron will store calibration data, etc" FORCE) -else () - set(GADGETRON_VAR_DIR /var/lib/gadgetron/ CACHE PATH "Path where Gadgetron will store calibration data, etc" FORCE) + set(PINGVIN_GIT_SHA1 "NA") endif () +set(PINGVIN_INSTALL_CMAKE_PATH share/pingvin/cmake) +set(PINGVIN_INSTALL_CONFIG_PATH share/pingvin/config) +set(PINGVIN_INSTALL_PYTHON_MODULE_PATH share/pingvin/python) +set(PINGVIN_INSTALL_SCHEMA_PATH share/pingvin/schema) +set(PINGVIN_INSTALL_INCLUDE_PATH include/pingvin) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) -# create the Gadgetron version header -configure_file("${CMAKE_SOURCE_DIR}/cmake/gadgetron_sha1.h.in" ${PROJECT_BINARY_DIR}/include/gadgetron_sha1.h @ONLY) +# create the Pingvin version header +configure_file("${CMAKE_SOURCE_DIR}/cmake/pingvin_sha1.h.in" ${PROJECT_BINARY_DIR}/include/pingvin_sha1.h @ONLY) include_directories(${PROJECT_BINARY_DIR}/include) -install(FILES ${PROJECT_BINARY_DIR}/include/gadgetron_sha1.h DESTINATION ${GADGETRON_INSTALL_INCLUDE_PATH} COMPONENT main) +install(FILES ${PROJECT_BINARY_DIR}/include/pingvin_sha1.h DESTINATION ${PINGVIN_INSTALL_INCLUDE_PATH} COMPONENT main) #Set the build type to Release if not specified @@ -97,155 +88,101 @@ endif () # build options for 64 bits system if (CMAKE_SIZEOF_VOID_P EQUAL 8) - message("64bit system is found") + message(STATUS "64bit system is found") set(HAS_64_BIT On CACHE BOOL "64bit build") else () - message("32bit system is found") + message(STATUS "32bit system is found") set(HAS_64_BIT Off CACHE BOOL "64bit build") endif () - -#set(CMAKE_MACOSX_RPATH 1) -set(CMAKE_INSTALL_RPATH ".:${CMAKE_INSTALL_PREFIX}/lib") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) -# whether to install dependencies -option(GADGETRON_INSTALL_DEPENDENCIES "Install gadgetron dependencies" Off) -option(DISABLE_FORK "Disables forking in release mode, causing Gadgetron to always run in a single process" Off) - -if (DISABLE_FORK) - add_definitions(-DGADGETRON_DISABLE_FORK) -endif() # build options for OpenMP support find_package(OpenMP) option(USE_OPENMP "Use OpenMP" On) if (OPENMP_FOUND) if (USE_OPENMP) - message("OpenMP multithreading enabled") + message(STATUS "OpenMP multithreading enabled") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") add_definitions(-DUSE_OMP) else () - message("OpenMP multithreading is supported, but disabled") + message(STATUS "OpenMP multithreading is supported, but disabled") endif () else () - message("OpenMP multithreading not supported") + message(STATUS "OpenMP multithreading not supported") endif () set(CMAKE_CXX_STANDARD 17) -if (WIN32) - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) - add_definitions(-DWIN32 -D_WIN32 -D_WINDOWS -DWIN -D_AMD64_) - add_definitions(-Zc:__cplusplus) - add_definitions(-DNOMINMAX) - #add_definitions(-DUNICODE -D_UNICODE) - add_definitions("/wd4251") #disable warnings, 4251: needs to have dll-interface to be used by clients/ - if (HAS_64_BIT) - add_definitions(-DWIN64 -D_WIN64) - endif () - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc /MP /bigobj /openmp:experimental /permissive- /FS /DNOGDI /we4667") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W1") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /EHsc /MP /bigobj /w1") - set(CMAKE_CXX_LINK_FLAGS "${CMAKE_CXX_LINK_FLAGS} /INCREMENTAL:NO") - set(CMAKE_C_LINK_FLAGS "${CMAKE_C_LINK_FLAGS} /INCREMENTAL:NO") - set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/debug /INCREMENTAL:NO") - set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/debug /INCREMENTAL:NO") - set(CMAKE_STATIC_LINKER_FLAGS_DEBUG "/debug /INCREMENTAL:NO") - set(CMAKE_MODULE_LINKER_FLAGS_DEBUG "/debug /INCREMENTAL:NO") - # The two flags below is to fix Windows problems in relation to multiple defined operators new/delete and some constructors that are defined in our headers - # set (CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /FORCE:MULTIPLE") - # set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /FORCE:MULTIPLE") -else () - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - include(CheckCXXCompilerFlag) - if (APPLE) - if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-array-bounds -Wno-switch -Wno-dynamic-class-memaccess -Wno-undefined-var-template -Wno-parentheses") - endif () - endif () - add_compile_options(-Werror) - check_cxx_compiler_flag(-Werror=return-type COMPILER_SUPPORTS_WRETURNTYPE) - if (COMPILER_SUPPORTS_WRETURNTYPE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type") - endif () - check_cxx_compiler_flag(-Werror=terminate COMPILER_SUPPORTS_WTERMINATE) - if (COMPILER_SUPPORTS_WTERMINATE) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=terminate") - endif () - check_cxx_compiler_flag(-Werror=non-virtual-dtor COMPILER_SUPPORT_WNON_VIRTUAL) - if (COMPILER_SUPPORT_WNON_VIRTUAL) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=non-virtual-dtor") +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +include(CheckCXXCompilerFlag) +if (APPLE) + if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -Wno-array-bounds -Wno-switch -Wno-dynamic-class-memaccess -Wno-undefined-var-template -Wno-parentheses") endif () +endif () - check_cxx_compiler_flag(-Werror=format-overflow COMPILER_SUPPORT_WOVERFLOW) - if (COMPILER_SUPPORT_WOVERFLOW) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=format-overflow") - endif() +add_compile_options(-Werror) +check_cxx_compiler_flag(-Werror=return-type COMPILER_SUPPORTS_WRETURNTYPE) +if (COMPILER_SUPPORTS_WRETURNTYPE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=return-type") +endif () +check_cxx_compiler_flag(-Werror=terminate COMPILER_SUPPORTS_WTERMINATE) +if (COMPILER_SUPPORTS_WTERMINATE) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=terminate") +endif () +check_cxx_compiler_flag(-Werror=non-virtual-dtor COMPILER_SUPPORT_WNON_VIRTUAL) +if (COMPILER_SUPPORT_WNON_VIRTUAL) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=non-virtual-dtor") endif () +check_cxx_compiler_flag(-Werror=format-overflow COMPILER_SUPPORT_WOVERFLOW) +if (COMPILER_SUPPORT_WOVERFLOW) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=format-overflow") +endif() + # whether to suppress compilation warnings option(BUILD_SUPPRESS_WARNINGS "Build package while suppressing warnings" Off) if (BUILD_SUPPRESS_WARNINGS) - if (WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W0") - elseif (WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") - endif () + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -w") endif () - set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED ON) set(Boost_USE_STATIC_RUNTIME OFF) -# necessary for Windows and RHEL <=6 systems - -if(WIN32) - add_definitions( -DHAVE_SNPRINTF) #Python decides to overwrite snprintf if this is not defined, because ofcourse it does. -endif() # We actually only use system and thread explicitly, but they require linking in date_time and chrono -if (WIN32) - find_package(Boost 1.80.0 COMPONENTS coroutine system date_time chrono program_options filesystem timer exception REQUIRED ) -else() - find_package(Boost 1.80.0 COMPONENTS coroutine system date_time program_options filesystem timer REQUIRED ) -endif() +find_package(Boost 1.80.0 COMPONENTS coroutine system date_time program_options filesystem timer REQUIRED ) add_definitions("-DBOOST_BIND_GLOBAL_PLACEHOLDERS") # To suppress messages in later versions of boost, in version 1.76.0 there are internal conflicts in boost add_definitions("-DBOOST_ALLOW_DEPRECATED_HEADERS") # To suppress messages in later versions of boost, in version 1.76.0 there are internal conflicts in boost if (NOT DEFINED Boost_VERSION_STRING) set(Boost_VERSION_STRING "${Boost_MAJOR_VERSION}.${Boost_MINOR_VERSION}.${Boost_SUBMINOR_VERSION}") endif() - option(USE_CUDA "Build with CUDA support" On) - if (USE_CUDA) find_package(CUDA_advanced) endif() - if (CUDA_FOUND AND USE_CUDA) - if (NOT CUDA_cublas_device_LIBRARY) list(REMOVE_ITEM CUDA_CUBLAS_LIBRARIES CUDA_cublas_device_LIBRARY-NOTFOUND) endif() add_definitions(-DUSE_CUDA) - set( GADGETRON_CUDA_FOUND_BOOL 1 ) + set( PINGVIN_CUDA_FOUND_BOOL 1 ) include_directories( ${CUDA_INCLUDE_DIRS} ) set(CUDA_PROPAGATE_HOST_FLAGS ON) set(CUDA_HOST_COMPILER ${CMAKE_CXX_COMPILER}) set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS} --std=c++17") set(CMAKE_CUDA_STANDARD 17) - # endif () - #set(CUDA_VERBOSE_BUILD ON) - # Compile kernels for compute models 1.0 and 2.0 as default for Cuda 4.1 # Support compute model 3.0 from Cuda 4.2 and up # Support compute model 3.5 from Cuda 5 and up - option(GADGETRON_CUDA_ALL_COMPUTE_MODEL "Build CUDA components for all computing models" OFF) - if (GADGETRON_CUDA_ALL_COMPUTE_MODEL) - message("Compiling CUDA components to support all compute model 3.5, 5.0, 5.2, 6.0, 6.1, 7.0") + option(PINGVIN_CUDA_ALL_COMPUTE_MODEL "Build CUDA components for all computing models" OFF) + if (PINGVIN_CUDA_ALL_COMPUTE_MODEL) + message(STATUS "Compiling CUDA components to support all compute model 3.5, 5.0, 5.2, 6.0, 6.1, 7.0") set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-gencode arch=compute_35,code=sm_35") set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-gencode arch=compute_50,code=sm_50") set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-gencode arch=compute_52,code=sm_52") @@ -257,17 +194,17 @@ if (CUDA_FOUND AND USE_CUDA) set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS} "-gencode arch=compute_86,code=sm_86") endif () - message("Compiling with ${CUDA_NVCC_FLAGS}") - message("CUDA libraries are ${CUDA_LIBRARIES}, ${CUDA_CUFFT_LIBRARIES}, ${CUDA_CUBLAS_LIBRARIES}, ${CUDA_CUSPARSE_LIBRARIES}") + message(STATUS "Compiling with ${CUDA_NVCC_FLAGS}") + message(STATUS "CUDA libraries are ${CUDA_LIBRARIES}, ${CUDA_CUFFT_LIBRARIES}, ${CUDA_CUBLAS_LIBRARIES}, ${CUDA_CUSPARSE_LIBRARIES}") else () - message("CUDA not found. CUDA components will not be compiled.") - set( GADGETRON_CUDA_FOUND_BOOL 0 ) + message(STATUS "CUDA not found. CUDA components will not be compiled.") + set( PINGVIN_CUDA_FOUND_BOOL 0 ) set( CUDA_NVCC_FLAGS "NA") endif () -option(REQUIRE_SIGNED_CONFIG "Force Gadgetron to accept only signed config files." Off) +option(REQUIRE_SIGNED_CONFIG "Force Pingvin to accept only signed config files." Off) if (REQUIRE_SIGNED_CONFIG) - message("Compile with signed config; GTBabylon is needed") + message(STATUS "Compile with signed config; GTBabylon is needed") add_definitions(-DUSE_GTBABYLON) find_package(GTBabylon REQUIRED) endif() @@ -276,24 +213,15 @@ find_package(Armadillo REQUIRED) add_library(armadillo INTERFACE) set_property(TARGET armadillo PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ARMADILLO_INCLUDE_DIR}) add_definitions(-DARMA_DONT_USE_WRAPPER -DARMA_USE_CXX11 -DARMA_64BIT_WORD) -install(TARGETS armadillo EXPORT gadgetron-export) +install(TARGETS armadillo EXPORT pingvin-export) -find_package(CURL REQUIRED) -find_package(PugiXML REQUIRED) -find_package(ISMRMRD CONFIG REQUIRED) - -if (CUDA_FOUND AND USE_CUDA) - # bart needs cuda - find_package(BART CONFIG QUIET) -endif() +add_subdirectory(libmrd) find_package(FFTW3 REQUIRED COMPONENTS single double) add_library(FFTW INTERFACE) target_link_libraries(FFTW INTERFACE ${FFTW3_LIBRARIES}) set_property(TARGET FFTW PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${FFTW3_INCLUDE_DIR}) -install(TARGETS FFTW EXPORT gadgetron-export) - -set(GADGETRON_BUILD_RPATH "") +install(TARGETS FFTW EXPORT pingvin-export) option(USE_MKL Off) if (USE_MKL) @@ -301,10 +229,9 @@ if (USE_MKL) list(APPEND CMAKE_PREFIX_PATH "/opt/intel/oneapi/mkl/latest") endif() find_package(MKL REQUIRED) - link_directories(GTBLAS BEFORE INTERFACE "${MKL_ROOT}/lib/intel64/") add_library(GTBLAS INTERFACE) + set_property(TARGET GTBLAS PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${MKL_INCLUDE_DIR}) set_property(TARGET GTBLAS PROPERTY INTERFACE_LINK_LIBRARIES ${MKL_LIBRARIES}) - message("MKL LIB DIR ${MKL_ROOT}/lib/intel64") add_definitions(-DUSE_MKL -DARMA_BLAS_LONG_LONG -DARMA_USE_BLAS -DARMA_USE_LAPACK) else () @@ -320,58 +247,48 @@ else () string(COMPARE EQUAL ${BLA_VENDOR} "OpenBLAS" USING_OPENBLAS) if (USING_OPENBLAS) - message("OpenBLAS detected; setting max number of OpenBLAS pthreads to one.") + message(STATUS "OpenBLAS detected; setting max number of OpenBLAS pthreads to one.") add_definitions(-DFORCE_LIMIT_OPENBLAS_NUM_THREADS) endif() endif () -install(TARGETS GTBLAS EXPORT gadgetron-export) +install(TARGETS GTBLAS EXPORT pingvin-export) if(EXISTS $ENV{TORCH_HOME}) find_package(Torch) if (TORCH_FOUND) add_definitions(-DUSE_TORCH) - message("Find Pytorch c++ library at ${TORCH_LIBRARIES}") + message(STATUS "Found Pytorch c++ library at ${TORCH_LIBRARIES}") else() - message("Do not find Pytorch c++ library") + message(STATUS "Did not find Pytorch c++ library") endif () else() - message("Do not find TORCH_HOME") + message(STATUS "Did not find TORCH_HOME") endif() option(BUILD_PYTHON_SUPPORT "Build Python gadgets etc" On) - if (BUILD_PYTHON_SUPPORT) find_package(Python3 COMPONENTS Development NumPy REQUIRED) find_package(Boost COMPONENTS python3${Python3_VERSION_MINOR} REQUIRED) - message("Found numpy : ${Python3_NumPy_INCLUDE_DIRS} ${Python3_NumPy_LIBRARIES} ${Python3_INCLUDE_DIRS} ${Python3_LIBRARIES}") + message(STATUS "Found NumPy:") + message(STATUS "NumPy include: ${Python3_NumPy_INCLUDE_DIRS}") + message(STATUS "NumPy libraries: ${Python3_NumPy_LIBRARIES}") + message(STATUS "Python3 libraries: ${Python3_LIBRARIES}") if (Python3_VERSION_MINOR LESS 7) - message(FATAL_ERROR "Gadgetron Python support requires Python 3.7 or newer. Found: ${Python3_VERSION}") + message(FATAL_ERROR "Pingvin Python support requires Python 3.7 or newer. Found: ${Python3_VERSION}") endif() - message("Boost Version: ${Boost_VERSION_STRING} (with Python ${Python3_VERSION})") - message("Secret: ${Boost_PYTHON3_TARGET}") + message(STATUS "Boost Version: ${Boost_VERSION_STRING} (with Python ${Python3_VERSION})") add_library(python INTERFACE) set_property(TARGET python PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${Python3_INCLUDE_DIRS} ${Python3_NumPy_INCLUDE_DIRS}) target_link_libraries(python INTERFACE Python3::Python Python3::NumPy Boost::python3${Python3_VERSION_MINOR}) - install(TARGETS python EXPORT gadgetron-export) -endif() - -message("Searching for OpenGL, GLEW, GLUT, and Qt. These libraries are only used in a single standalone application and are thus non-essential.") -if(WIN32) - message("For Windows users in particular, for ease of installation we do not recommend installing these libraries.") + install(TARGETS python EXPORT pingvin-export) endif() -find_package(OpenGL) -find_package(GLEW) -find_package(GLUT) -find_package(Qt4 4.6) -find_package(PLplot) - option(BUILD_TESTING "Enable test building" On) if (BUILD_TESTING) enable_testing() @@ -380,7 +297,7 @@ if (BUILD_TESTING) find_path(GTEST_SRC_DIR src/gtest.cc HINTS /usr/src/gtest) find_path(GTEST_INCLUDE_DIRS gtest.h HINTS /usr/include/gtest) if (GTEST_SRC_DIR AND GTEST_INCLUDE_DIRS) - message("GTest src package found. Compiling as part of Gadgetron.") + message(STATUS "GTest src package found. Compiling as part of Pingvin.") add_subdirectory(${GTEST_SRC_DIR} ${CMAKE_BINARY_DIR}/gtest ) include_directories(${GTEST_INCLUDE_DIRS}) set(GTEST_FOUND 1) @@ -390,17 +307,17 @@ if (BUILD_TESTING) endif () endif () - MESSAGE("GTEST FOUND: ${GTEST_FOUND}") + MESSAGE(STATUS "GTEST FOUND: ${GTEST_FOUND}") add_subdirectory(test) else() - MESSAGE("Testing not being built") + MESSAGE(STATUS "Testing not being built") endif() - +add_subdirectory(apps) +add_subdirectory(cmake) add_subdirectory(core) -add_subdirectory(toolboxes) add_subdirectory(gadgets) -add_subdirectory(apps) +add_subdirectory(toolboxes) option(BUILD_WITH_GPERFTOOLS_PROFILER "Build with the gperftools profiler." Off) if (BUILD_WITH_GPERFTOOLS_PROFILER) @@ -408,64 +325,46 @@ if (BUILD_WITH_GPERFTOOLS_PROFILER) find_package(Gperftools REQUIRED) endif() - -add_subdirectory(chroot) -add_subdirectory(cmake) - -option(BUILD_DOCUMENTATION "Build Gadgetron documentation." Off) +option(BUILD_DOCUMENTATION "Build Pingvin documentation." Off) if(BUILD_DOCUMENTATION) add_subdirectory(doc) endif() -# install dependencies for WIN32 -if (WIN32) - if (GADGETRON_INSTALL_DEPENDENCIES) - include(${CMAKE_SOURCE_DIR}/cmake/InstallWinDependencies.cmake) - endif () -endif () - -if (UNIX) - if (NOT APPLE) - if (GADGETRON_INSTALL_DEPENDENCIES) - include(${CMAKE_SOURCE_DIR}/cmake/InstallLinuxDependencies.cmake) - endif () - endif () -endif () # --- Main Library (end) ---- include(GNUInstallDirs) -install(EXPORT gadgetron-export - FILE gadgetron-targets.cmake +install(EXPORT pingvin-export + FILE pingvin-targets.cmake NAMESPACE - Gadgetron:: + Pingvin:: DESTINATION - ${CMAKE_INSTALL_LIBDIR}/cmake/gadgetron) + ${CMAKE_INSTALL_LIBDIR}/cmake/pingvin) include(CMakePackageConfigHelpers) configure_package_config_file( - ${CMAKE_SOURCE_DIR}/cmake/gadgetron-config.cmake.in - ${CMAKE_BINARY_DIR}/cmake/gadgetron-config.cmake - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/gadgetron - PATH_VARS GADGETRON_INSTALL_PYTHON_MODULE_PATH GADGETRON_INSTALL_CONFIG_PATH GADGETRON_INSTALL_SCHEMA_PATH) + ${CMAKE_SOURCE_DIR}/cmake/pingvin-config.cmake.in + ${CMAKE_BINARY_DIR}/cmake/pingvin-config.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pingvin + PATH_VARS PINGVIN_INSTALL_PYTHON_MODULE_PATH PINGVIN_INSTALL_CONFIG_PATH PINGVIN_INSTALL_SCHEMA_PATH) write_basic_package_version_file( - ${CMAKE_BINARY_DIR}/cmake/gadgetron-config-version.cmake - VERSION ${GADGETRON_VERSION_STRING} + ${CMAKE_BINARY_DIR}/cmake/pingvin-config-version.cmake + VERSION ${PINGVIN_VERSION_STRING} COMPATIBILITY AnyNewerVersion) install( FILES - ${CMAKE_BINARY_DIR}/cmake/gadgetron-config.cmake - ${CMAKE_BINARY_DIR}/cmake/gadgetron-config-version.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/gadgetron) + ${CMAKE_BINARY_DIR}/cmake/pingvin-config.cmake + ${CMAKE_BINARY_DIR}/cmake/pingvin-config-version.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pingvin) # Create package string(TOLOWER ${PROJECT_NAME} PROJECT_NAME_LOWER) -include(${CMAKE_SOURCE_DIR}/cmake/gadgetron_cpack.cmake) +include(${CMAKE_SOURCE_DIR}/cmake/pingvin_cpack.cmake) if(CPACK_GENERATOR) message(STATUS "Found CPack generators: ${CPACK_GENERATOR}") - configure_file("${CMAKE_SOURCE_DIR}/cmake/cpack_options.cmake.in" ${GADGETRON_CPACK_CFG_FILE} @ONLY) - set(CPACK_PROJECT_CONFIG_FILE ${GADGETRON_CPACK_CFG_FILE}) + configure_file("${CMAKE_SOURCE_DIR}/cmake/cpack_options.cmake.in" ${PINGVIN_CPACK_CFG_FILE} @ONLY) + set(CPACK_PROJECT_CONFIG_FILE ${PINGVIN_CPACK_CFG_FILE}) include(CPack) endif() diff --git a/Dockerfile b/Dockerfile index f0b1bab22..0b74d5b0b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,8 +3,8 @@ ARG USERNAME="vscode" ARG USER_UID=1000 ARG USER_GID=$USER_UID -FROM ghcr.io/gadgetron/gadgetron/ubuntu22.04 AS gadgetron_baseimage -LABEL org.opencontainers.image.source=https://github.com/gadgetron/gadgetron +FROM ghcr.io/gadgetron/gadgetron/ubuntu22.04 AS pingvin_baseimage +LABEL org.opencontainers.image.source=https://github.com/gadgetron/pingvin ARG USERNAME ARG USER_UID @@ -23,17 +23,17 @@ RUN groupadd --gid $USER_GID $USERNAME \ && echo $USERNAME ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/$USERNAME \ && chmod 0440 /etc/sudoers.d/$USERNAME -ARG MAMBAFORGE_VERSION=22.9.0-2 +ARG MINIFORGE_VERSION=24.3.0-0 ARG CONDA_GID=900 # Based on https://github.com/conda-forge/miniforge-images/blob/master/ubuntu/Dockerfile -RUN wget --no-hsts --quiet https://github.com/conda-forge/miniforge/releases/download/${MAMBAFORGE_VERSION}/Mambaforge-${MAMBAFORGE_VERSION}-Linux-$(uname -m).sh -O /tmp/miniforge.sh \ +RUN wget --no-hsts --quiet https://github.com/conda-forge/miniforge/releases/download/${MINIFORGE_VERSION}/Miniforge3-${MINIFORGE_VERSION}-Linux-$(uname -m).sh -O /tmp/miniforge.sh \ && /bin/bash /tmp/miniforge.sh -b -p /opt/conda \ && rm /tmp/miniforge.sh \ - && /opt/conda/bin/mamba clean --tarballs --index-cache --packages --yes \ + && /opt/conda/bin/conda clean --tarballs --index-cache --packages --yes \ && find /opt/conda -follow -type f -name '*.a' -delete \ && find /opt/conda -follow -type f -name '*.pyc' -delete \ - && /opt/conda/bin/mamba clean --force-pkgs-dirs --all --yes \ + && /opt/conda/bin/conda clean --force-pkgs-dirs --all --yes \ && groupadd -r conda --gid ${CONDA_GID} \ && usermod -aG conda ${USERNAME} \ && chown -R :conda /opt/conda \ @@ -47,92 +47,101 @@ COPY --chown=$USER_UID:conda environment.yml /tmp/build/ RUN mkdir -p /test && chown ${USER_UID}:${USER_GID} /test VOLUME /test +# Copy bashrc used to activate conda environment +COPY --chown=$USER_UID:conda .devcontainer/devcontainer.bashrc /opt/devcontainer/ + # Add a section to /etc/bash.bashrc that ensures that a section is present at the end of ~/.bashrc. # We can't just write to .bashrc from here because it will be overwritten if the vscode user has # opted to use their own dotfiles repo. The dotfiles repo is cloned after the postCreateCommand # in the devcontainer.json file is executed. RUN echo "\n\ -if ! grep -q \"^source /opt/conda/etc/profile.d/conda.sh\" ${HOME}/.bashrc; then\n\ - echo \"source /opt/conda/etc/profile.d/conda.sh\" >> ${HOME}/.bashrc\n\ - echo \"conda activate $(grep 'name:' /tmp/build/environment.yml | awk '{print $2}')\" >> ${HOME}/.bashrc\n\ +if ! grep -q \"^source /opt/devcontainer/devcontainer.bashrc\" \${HOME}/.bashrc; then\n\ + echo \"source /opt/devcontainer/devcontainer.bashrc\" >> \${HOME}/.bashrc\n\ fi\n" >> /etc/bash.bashrc -ENV TINI_VERSION v0.19.0 +ENV TINI_VERSION=v0.19.0 ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini RUN chmod +x /tini -FROM gadgetron_baseimage AS gadgetron_dev_cuda +# Install the yardl tool +ARG YARDL_VERSION=0.6.2 +RUN wget --quiet "https://github.com/microsoft/yardl/releases/download/v${YARDL_VERSION}/yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" \ + && tar -xzf "yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" \ + && mv yardl "/usr/local/bin/" \ + && rm "yardl_${YARDL_VERSION}_linux_x86_64.tar.gz" + +FROM pingvin_baseimage AS pingvin_dev_cuda ARG USER_UID ARG HOME USER ${USER_UID} RUN mkdir -p ${HOME}/.cache/conda/notices && sudo chown -R ${USER_UID}:conda ${HOME}/.cache/conda/notices RUN grep -v "#.*\" /tmp/build/environment.yml > /tmp/build/filtered_environment.yml -RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/mamba clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda USER root -FROM gadgetron_baseimage AS gadgetron_dev_nocuda +FROM pingvin_baseimage AS pingvin_dev_nocuda ARG USER_UID ARG HOME USER ${USER_UID} RUN mkdir -p ${HOME}/.cache/conda/notices && sudo chown -R ${USER_UID}:conda ${HOME}/.cache/conda/notices RUN grep -v "#.*\" /tmp/build/environment.yml > /tmp/build/filtered_environment.yml -RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/mamba clean -afy && sudo chown -R :conda /opt/conda +RUN umask 0002 && /opt/conda/bin/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda USER root -FROM gadgetron_dev_cuda AS gadgetron_cudabuild +FROM pingvin_dev_cuda AS pingvin_build_cuda ARG USER_UID USER ${USER_UID} WORKDIR /opt -RUN sudo chown $USER_UID:$USER_GID /opt && mkdir -p /opt/code/gadgetron && mkdir -p /opt/package -COPY --chown=$USER_UID:conda . /opt/code/gadgetron/ +RUN sudo chown $USER_UID:$USER_GID /opt && mkdir -p /opt/code/pingvin && mkdir -p /opt/package +COPY --chown=$USER_UID:conda . /opt/code/pingvin/ SHELL ["/bin/bash", "-c"] -RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate gadgetron && sh -x && \ - cd /opt/code/gadgetron && \ +RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin && sh -x && \ + cd /opt/code/pingvin && \ mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ ninja && \ ninja install -FROM gadgetron_dev_nocuda AS gadgetron_nocudabuild +FROM pingvin_dev_nocuda AS pingvin_build_nocuda ARG USER_UID USER ${USER_UID} WORKDIR /opt -RUN sudo chown $USER_UID:$USER_GID /opt && mkdir -p /opt/code/gadgetron && mkdir -p /opt/package -COPY --chown=$USER_UID:conda . /opt/code/gadgetron/ +RUN sudo chown $USER_UID:$USER_GID /opt && mkdir -p /opt/code/pingvin && mkdir -p /opt/package +COPY --chown=$USER_UID:conda . /opt/code/pingvin/ SHELL ["/bin/bash", "-c"] -RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate gadgetron && sh -x && \ - cd /opt/code/gadgetron && \ +RUN . /opt/conda/etc/profile.d/conda.sh && umask 0002 && conda activate pingvin && sh -x && \ + cd /opt/code/pingvin && \ mkdir build && \ cd build && \ cmake ../ -GNinja -DUSE_MKL=ON -DCMAKE_INSTALL_PREFIX=/opt/package && \ ninja && \ ninja install -FROM gadgetron_baseimage AS gadgetron_rt_cuda +FROM pingvin_baseimage AS pingvin_rt_cuda ARG USER_UID ARG HOME USER ${USER_UID} RUN mkdir -p ${HOME}/.cache/conda/notices && sudo chown -R ${USER_UID}:conda ${HOME}/.cache/conda/notices RUN grep -v "#.*\" /tmp/build/environment.yml > /tmp/build/filtered_environment.yml -RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/mamba clean -afy && sudo chown -R :conda /opt/conda -COPY --from=gadgetron_cudabuild --chown=$USER_UID:conda /opt/package /opt/conda/envs/gadgetron/ -COPY --from=gadgetron_cudabuild --chown=$USER_UID:conda /opt/code/gadgetron/docker/entrypoint.sh /opt/ +RUN umask 0002 && /opt/conda/bin/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +COPY --from=pingvin_build_cuda --chown=$USER_UID:conda /opt/package /opt/conda/envs/pingvin/ +COPY --from=pingvin_build_cuda --chown=$USER_UID:conda /opt/code/pingvin/docker/entrypoint.sh /opt/ RUN chmod +x /opt/entrypoint.sh -RUN sudo mkdir -p /opt/integration-test && sudo chown ${USER_GID}:${USER_UID} /opt/integration-test -COPY --from=gadgetron_cudabuild --chown=$USER_UID:conda /opt/code/gadgetron/test/integration /opt/integration-test/ +RUN sudo mkdir -p /opt/e2e-test && sudo chown ${USER_GID}:${USER_UID} /opt/e2e-test +COPY --from=pingvin_build_cuda --chown=$USER_UID:conda /opt/code/pingvin/test/e2e /opt/e2e-test/ ENTRYPOINT [ "/tini", "--", "/opt/entrypoint.sh" ] -FROM gadgetron_baseimage AS gadgetron_rt_nocuda +FROM pingvin_baseimage AS pingvin_rt_nocuda ARG USER_UID ARG HOME USER ${USER_UID} RUN mkdir -p ${HOME}/.cache/conda/notices && sudo chown -R ${USER_UID}:conda ${HOME}/.cache/conda/notices RUN grep -v "#.*\" /tmp/build/environment.yml > /tmp/build/filtered_environment.yml -RUN umask 0002 && /opt/conda/bin/mamba env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/mamba clean -afy && sudo chown -R :conda /opt/conda -COPY --from=gadgetron_nocudabuild --chown=$USER_UID:conda /opt/package /opt/conda/envs/gadgetron/ -COPY --from=gadgetron_nocudabuild --chown=$USER_UID:conda /opt/code/gadgetron/docker/entrypoint.sh /opt/ +RUN umask 0002 && /opt/conda/bin/conda env create -f /tmp/build/filtered_environment.yml && /opt/conda/bin/conda clean -afy && sudo chown -R :conda /opt/conda +COPY --from=pingvin_build_nocuda --chown=$USER_UID:conda /opt/package /opt/conda/envs/pingvin/ +COPY --from=pingvin_build_nocuda --chown=$USER_UID:conda /opt/code/pingvin/docker/entrypoint.sh /opt/ RUN chmod +x /opt/entrypoint.sh -RUN sudo mkdir -p /opt/integration-test && sudo chown ${USER_GID}:${USER_UID} /opt/integration-test -COPY --from=gadgetron_nocudabuild --chown=$USER_UID:conda /opt/code/gadgetron/test/integration /opt/integration-test/ +RUN sudo mkdir -p /opt/e2e-test && sudo chown ${USER_GID}:${USER_UID} /opt/e2e-test +COPY --from=pingvin_build_nocuda --chown=$USER_UID:conda /opt/code/pingvin/test/e2e /opt/e2e-test/ ENTRYPOINT [ "/tini", "--", "/opt/entrypoint.sh" ] diff --git a/README.md b/README.md index c69b2f11d..5e80b21d0 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,6 @@ # Pingvin Image Reconstruction Framework -Pingvin is a new prototype image reconstruction framework. - +Pingvin is a new prototype image reconstruction framework, inspired by the [Gadgetron](https://github.com/gadgetron/gadgetron). ## License diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index fcdd74931..f09b25327 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,6 +1 @@ -set(CMAKE_BUILD_RPATH ${GADGETRON_BUILD_RPATH}) - -add_subdirectory(gadgetron) - -add_subdirectory(clients) -add_subdirectory(standalone) +add_subdirectory(pingvin) diff --git a/apps/clients/CMakeLists.txt b/apps/clients/CMakeLists.txt deleted file mode 100644 index f59cfa821..000000000 --- a/apps/clients/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -#if(ACE_FOUND) -# add_subdirectory(utilities) -#endif() - -if(ISMRMRD_FOUND AND HDF5_FOUND) - add_subdirectory(gadgetron_ismrmrd_client) -endif() \ No newline at end of file diff --git a/apps/clients/gadgetron_ismrmrd_client/CMakeLists.txt b/apps/clients/gadgetron_ismrmrd_client/CMakeLists.txt deleted file mode 100644 index 04227a262..000000000 --- a/apps/clients/gadgetron_ismrmrd_client/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -find_package(ZFP) - - -if (ZFP_FOUND) - add_definitions(-DGADGETRON_COMPRESSION_ZFP) -endif() - -if (ZFP_FOUND) - include_directories(${ZFP_INCLUDE_DIR}) -endif() - - -add_executable(gadgetron_ismrmrd_client gadgetron_ismrmrd_client.cpp) -include_directories(${HDF5_INCLUDE_DIRS}) -target_link_libraries(gadgetron_ismrmrd_client ISMRMRD::ISMRMRD Boost::program_options gadgetron_mricore ) - -if (ZFP_FOUND) - target_link_libraries(gadgetron_ismrmrd_client ${ZFP_LIBRARIES}) -endif () - -install(TARGETS gadgetron_ismrmrd_client DESTINATION bin COMPONENT main) diff --git a/apps/clients/gadgetron_ismrmrd_client/gadgetron_ismrmrd_client.cpp b/apps/clients/gadgetron_ismrmrd_client/gadgetron_ismrmrd_client.cpp deleted file mode 100644 index b9bcd98ec..000000000 --- a/apps/clients/gadgetron_ismrmrd_client/gadgetron_ismrmrd_client.cpp +++ /dev/null @@ -1,2044 +0,0 @@ -/***************************************** -* Standalone ISMRMRD Gadgetron Client -* -* Author: Michael S. Hansen -* -* Dependencies: ISMRMRD and Boost -* -*****************************************/ - -//TODO: -// -Blobs (for DICOM image support) -// - First implementation is in, but testing needed -// -NIFTI and Analyze output -// -Check on potential threading problem with asio socket -// - having and reading and writing thread is supposedly not safe, but seems to work here -// -Static linking for standalone executable. - -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "NHLBICompression.h" -#include "GadgetronTimer.h" - -#if defined GADGETRON_COMPRESSION_ZFP -#include -#endif - -using namespace NHLBI; - -std::string get_date_time_string() -{ - time_t rawtime; - struct tm * timeinfo; - time ( &rawtime ); - timeinfo = localtime ( &rawtime ); - - std::stringstream str; - str << timeinfo->tm_year+1900 << "-" - << std::setw(2) << std::setfill('0') << timeinfo->tm_mon+1 << "-" - << std::setw(2) << std::setfill('0') << timeinfo->tm_mday << " " - << std::setw(2) << std::setfill('0') << timeinfo->tm_hour << ":" - << std::setw(2) << std::setfill('0') << timeinfo->tm_min << ":" - << std::setw(2) << std::setfill('0') << timeinfo->tm_sec; - - std::string ret = str.str(); - - return ret; -} - -struct NoiseStatistics -{ - bool status; - uint16_t channels; - float sigma_min; - float sigma_max; - float sigma_mean; - float noise_dwell_time_us; -}; - -#if defined GADGETRON_COMPRESSION_ZFP -size_t compress_zfp_tolerance(float* in, size_t samples, size_t coils, double tolerance, char* buffer, size_t buf_size) -{ - zfp_type type = zfp_type_float; - zfp_field* field = NULL; - zfp_stream* zfp = NULL; - bitstream* stream = NULL; - size_t zfpsize = 0; - - zfp = zfp_stream_open(NULL); - field = zfp_field_alloc(); - - zfp_field_set_pointer(field, in); - - zfp_field_set_type(field, type); - zfp_field_set_size_2d(field, samples, coils); - zfp_stream_set_accuracy(zfp, tolerance); - - if (zfp_stream_maximum_size(zfp, field) > buf_size) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Insufficient buffer space for compression"); - } - - stream = stream_open(buffer, buf_size); - if (!stream) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Cannot open compressed stream"); - } - zfp_stream_set_bit_stream(zfp, stream); - - if (!zfp_write_header(zfp, field, ZFP_HEADER_FULL)) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Unable to write compression header to stream"); - } - - zfpsize = zfp_compress(zfp, field); - if (zfpsize == 0) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Compression failed"); - } - - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - return zfpsize; -} - - -size_t compress_zfp_precision(float* in, size_t samples, size_t coils, unsigned int precision, char* buffer, size_t buf_size) -{ - zfp_type type = zfp_type_float; - zfp_field* field = NULL; - zfp_stream* zfp = NULL; - bitstream* stream = NULL; - size_t zfpsize = 0; - - zfp = zfp_stream_open(NULL); - field = zfp_field_alloc(); - - zfp_field_set_pointer(field, in); - - zfp_field_set_type(field, type); - zfp_field_set_size_2d(field, samples, coils); - zfp_stream_set_precision(zfp, precision); - - if (zfp_stream_maximum_size(zfp, field) > buf_size) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Insufficient buffer space for compression"); - } - - stream = stream_open(buffer, buf_size); - if (!stream) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Cannot open compressed stream"); - } - zfp_stream_set_bit_stream(zfp, stream); - - if (!zfp_write_header(zfp, field, ZFP_HEADER_FULL)) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Unable to write compression header to stream"); - } - - zfpsize = zfp_compress(zfp, field); - if (zfpsize == 0) { - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - throw std::runtime_error("Compression failed"); - } - - zfp_field_free(field); - zfp_stream_close(zfp); - stream_close(stream); - return zfpsize; -} -#endif //GADGETRON_COMPRESSION_ZFP - -namespace po = boost::program_options; -using boost::asio::ip::tcp; - - -enum GadgetronMessageID { - GADGET_MESSAGE_INT_ID_MIN = 0, - GADGET_MESSAGE_CONFIG_FILE = 1, - GADGET_MESSAGE_CONFIG_SCRIPT = 2, - GADGET_MESSAGE_PARAMETER_SCRIPT = 3, - GADGET_MESSAGE_CLOSE = 4, - GADGET_MESSAGE_TEXT = 5, - GADGET_MESSAGE_QUERY = 6, - GADGET_MESSAGE_RESPONSE = 7, - GADGET_MESSAGE_INT_ID_MAX = 999, - GADGET_MESSAGE_EXT_ID_MIN = 1000, - GADGET_MESSAGE_ACQUISITION = 1001, /**< DEPRECATED */ - GADGET_MESSAGE_NEW_MEASUREMENT = 1002, /**< DEPRECATED */ - GADGET_MESSAGE_END_OF_SCAN = 1003, /**< DEPRECATED */ - GADGET_MESSAGE_IMAGE_CPLX_FLOAT = 1004, /**< DEPRECATED */ - GADGET_MESSAGE_IMAGE_REAL_FLOAT = 1005, /**< DEPRECATED */ - GADGET_MESSAGE_IMAGE_REAL_USHORT = 1006, /**< DEPRECATED */ - GADGET_MESSAGE_EMPTY = 1007, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_ACQUISITION = 1008, - GADGET_MESSAGE_ISMRMRD_IMAGE_CPLX_FLOAT = 1009, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGE_REAL_FLOAT = 1010, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGE_REAL_USHORT = 1011, /**< DEPRECATED */ - GADGET_MESSAGE_DICOM = 1012, /**< DEPRECATED */ - GADGET_MESSAGE_CLOUD_JOB = 1013, - GADGET_MESSAGE_GADGETCLOUD_JOB = 1014, - GADGET_MESSAGE_ISMRMRD_IMAGEWITHATTRIB_CPLX_FLOAT = 1015, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGEWITHATTRIB_REAL_FLOAT = 1016, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGEWITHATTRIB_REAL_USHORT = 1017, /**< DEPRECATED */ - GADGET_MESSAGE_DICOM_WITHNAME = 1018, - GADGET_MESSAGE_DEPENDENCY_QUERY = 1019, - GADGET_MESSAGE_ISMRMRD_IMAGE_REAL_SHORT = 1020, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGEWITHATTRIB_REAL_SHORT = 1021, /**< DEPRECATED */ - GADGET_MESSAGE_ISMRMRD_IMAGE = 1022, - GADGET_MESSAGE_RECONDATA = 1023, - GADGET_MESSAGE_ISMRMRD_WAVEFORM = 1026, - GADGET_MESSAGE_EXT_ID_MAX = 4096 -}; - -std::mutex mtx; - -struct GadgetMessageIdentifier -{ - uint16_t id; -}; - -struct GadgetMessageConfigurationFile -{ - char configuration_file[1024]; -}; - -struct GadgetMessageScript -{ - uint32_t script_length; -}; - -class GadgetronClientException : public std::exception -{ - -public: - GadgetronClientException(std::string msg) - : msg_(msg) - { - - } - - virtual ~GadgetronClientException() throw() {} - - virtual const char* what() const throw() - { - return msg_.c_str(); - } - -protected: - std::string msg_; -}; - -class GadgetronClientMessageReader -{ -public: - virtual ~GadgetronClientMessageReader() {} - - /** - Function must be implemented to read a specific message. - */ - virtual void read(tcp::socket* s) = 0; - -}; - -class GadgetronClientResponseReader : public GadgetronClientMessageReader -{ - void read(tcp::socket *stream) override { - - uint64_t correlation_id = 0; - uint64_t response_length = 0; - - boost::asio::read(*stream, boost::asio::buffer(&correlation_id, sizeof(correlation_id))); - boost::asio::read(*stream, boost::asio::buffer(&response_length, sizeof(response_length))); - - std::vector response(response_length + 1,0); - - boost::asio::read(*stream, boost::asio::buffer(response.data(),response_length)); - - std::cout << response.data() << std::endl; - } -}; - -class GadgetronClientTextReader : public GadgetronClientMessageReader -{ - -public: - GadgetronClientTextReader() - { - - } - - virtual ~GadgetronClientTextReader() - { - - } - - virtual void read(tcp::socket* stream) - { - size_t recv_count = 0; - - typedef unsigned long long size_t_type; - uint32_t len(0); - boost::asio::read(*stream, boost::asio::buffer(&len, sizeof(uint32_t))); - - - char* buf = NULL; - try { - buf = new char[len+1]; - memset(buf, '\0', len+1); - } catch (std::runtime_error &err) { - std::cerr << "TextReader, failed to allocate buffer" << std::endl; - throw; - } - - if (boost::asio::read(*stream, boost::asio::buffer(buf, len)) != len) - { - delete [] buf; - throw GadgetronClientException("Incorrect number of bytes read for dependency query"); - } - - std::string s(buf); - std::cout << s; - delete[] buf; - } -}; - - -class GadgetronClientDependencyQueryReader : public GadgetronClientMessageReader -{ - -public: - GadgetronClientDependencyQueryReader(std::string filename) : number_of_calls_(0) , filename_(filename) - { - - } - - virtual ~GadgetronClientDependencyQueryReader() - { - - } - - virtual void read(tcp::socket* stream) - { - size_t recv_count = 0; - - typedef unsigned long long size_t_type; - size_t_type len(0); - boost::asio::read(*stream, boost::asio::buffer(&len, sizeof(size_t_type))); - - char* buf = NULL; - try { - buf = new char[len]; - memset(buf, '\0', len); - memcpy(buf, &len, sizeof(size_t_type)); - } catch (std::runtime_error &err) { - std::cerr << "DependencyQueryReader, failed to allocate buffer" << std::endl; - throw; - } - - - if (boost::asio::read(*stream, boost::asio::buffer(buf, len)) != len) - { - delete [] buf; - throw GadgetronClientException("Incorrect number of bytes read for dependency query"); - } - - std::ofstream outfile; - outfile.open (filename_.c_str(), std::ios::out|std::ios::binary); - - if (outfile.good()) { - outfile.write(buf, len); - outfile.close(); - number_of_calls_++; - } else { - delete[] buf; - throw GadgetronClientException("Unable to write dependency query to file"); - } - - delete[] buf; - } - - protected: - size_t number_of_calls_; - std::string filename_; -}; - - -class GadgetronClientImageMessageReader : public GadgetronClientMessageReader -{ - -public: - GadgetronClientImageMessageReader(std::string filename, std::string groupname) - : file_name_(filename) - , group_name_(groupname) - { - - } - - ~GadgetronClientImageMessageReader() { - } - - template - void read_data_attrib(tcp::socket* stream, const ISMRMRD::ImageHeader& h, ISMRMRD::Image& im) - { - im.setHead(h); - - typedef unsigned long long size_t_type; - - //Read meta attributes - size_t_type meta_attrib_length; - boost::asio::read(*stream, boost::asio::buffer(&meta_attrib_length, sizeof(size_t_type))); - - if (meta_attrib_length>0) - { - std::string meta_attrib(meta_attrib_length, 0); - boost::asio::read(*stream, boost::asio::buffer(const_cast(meta_attrib.c_str()), meta_attrib_length)); - im.setAttributeString(meta_attrib); - } - - //Read image data - boost::asio::read(*stream, boost::asio::buffer(im.getDataPtr(), im.getDataSize())); - { - if (!dataset_) { - - { - mtx.lock(); - dataset_ = std::shared_ptr(new ISMRMRD::Dataset(file_name_.c_str(), group_name_.c_str(), true)); // create if necessary - mtx.unlock(); - } - } - - std::stringstream st1; - st1 << "image_" << h.image_series_index; - std::string image_varname = st1.str(); - - { - mtx.lock(); - //TODO should this be wrapped in a try/catch? - dataset_->appendImage(image_varname, im); - mtx.unlock(); - } - } - } - - virtual void read(tcp::socket* stream) - { - //Read the image headerfrom the socket - ISMRMRD::ImageHeader h; - boost::asio::read(*stream, boost::asio::buffer(&h,sizeof(ISMRMRD::ImageHeader))); - - if (h.data_type == ISMRMRD::ISMRMRD_USHORT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_SHORT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_UINT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_INT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_FLOAT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_DOUBLE) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_CXFLOAT) - { - ISMRMRD::Image< std::complex > im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_CXDOUBLE) - { - ISMRMRD::Image< std::complex > im; - this->read_data_attrib(stream, h, im); - } - else - { - throw GadgetronClientException("Invalid image data type ... "); - } - } - -protected: - std::string group_name_; - std::string file_name_; - std::shared_ptr dataset_; -}; - -// ---------------------------------------------------------------- -// for the analyze image format -#ifdef DT_UNKNOWN - #undef DT_UNKNOWN -#endif // DT_UNKNOWN - -enum AnalyzeDataType -{ - DT_ANA_UNKNOWN=0, - - DT_NONE =0, - DT_UNKNOWN =0, /* what it says, dude */ - DT_BINARY =1, /* binary (1 bit/voxel) */ - DT_UNSIGNED_CHAR =2, /* unsigned char (8 bits/voxel) */ - DT_SIGNED_SHORT =4, /* signed short (16 bits/voxel) */ - DT_UNSIGNED_SHORT =5, - DT_SIGNED_INT =8, /* signed int (32 bits/voxel) */ - DT_UNSIGNED_INT =9, - DT_FLOAT =16, /* float (32 bits/voxel) */ - DT_COMPLEX =32, /* complex (64 bits/voxel) */ - DT_DOUBLE =64, /* double (64 bits/voxel) */ - DT_RGB =128, /* RGB triple (24 bits/voxel) */ - DT_ALL =255, /* not very useful (?) */ - - /*----- another set of names for the same ---*/ - DT_UINT8 =2, - DT_INT16 =4, - DT_INT32 =8, - DT_FLOAT32 =16, - DT_COMPLEX64 =32, - DT_FLOAT64 =64, - DT_RGB24 =128, - - /*------------------- new codes for NIFTI ---*/ - DT_INT8 =256, /* signed char (8 bits) */ - DT_UINT16 =512, /* unsigned short (16 bits) */ - DT_UINT32 =768, /* unsigned int (32 bits) */ - DT_INT64 =1024, /* long long (64 bits) */ - DT_UINT64 =1280, /* unsigned long long (64 bits) */ - DT_FLOAT128 =1536, /* long double (128 bits) */ - DT_COMPLEX128 =1792, /* double pair (128 bits) */ - DT_COMPLEX256 =2048, /* long double pair (256 bits) */ - DT_RGBA32 =2304, /* 4 byte RGBA (32 bits/voxel) */ -}; - -AnalyzeDataType getDataTypeFromRTTI(const std::string& name) -{ - AnalyzeDataType analyzeDT = DT_ANA_UNKNOWN; - - if ( name == typeid(unsigned char).name() ) - { - analyzeDT = DT_UNSIGNED_CHAR; - } - - if ( name == typeid(short).name() ) - { - analyzeDT = DT_SIGNED_SHORT; - } - - if ( name == typeid(unsigned short).name() ) - { - analyzeDT = DT_UINT16; - } - - if ( name == typeid(int).name() ) - { - analyzeDT = DT_SIGNED_INT; - } - - if ( name == typeid(unsigned int).name() ) - { - analyzeDT = DT_UINT32; - } - - if ( name == typeid(float).name() ) - { - analyzeDT = DT_FLOAT; - } - - if ( name == typeid(double).name() ) - { - analyzeDT = DT_DOUBLE; - } - - if ( name == typeid(long double).name() ) - { - analyzeDT = DT_FLOAT128; - } - - if ( name == typeid(std::complex).name() ) - { - analyzeDT = DT_COMPLEX; - } - - if ( name == typeid(std::complex).name() ) - { - analyzeDT = DT_COMPLEX128; - } - - if ( name == typeid(std::complex).name() ) - { - analyzeDT = DT_COMPLEX256; - } - - return analyzeDT; -} - -struct header_key -{ - int sizeof_hdr; - char data_type[10]; - char db_name[18]; - int extents; - short int session_error; - char regular; - char hkey_un0; -}; - -struct image_dimension -{ - short int dim[8]; - short int unused8; - short int unused9; - short int unused10; - short int unused11; - short int unused12; - short int unused13; - short int unused14; - short int datatype; - short int bitpix; - short int dim_un0; - float pixdim[8]; - float vox_offset; - float funused1; - float funused2; - float funused3; - float cal_max; - float cal_min; - float compressed; - float verified; - int glmax,glmin; -}; - -struct data_history -{ - char descrip[80]; - char aux_file[24]; - char orient; - char originator[10]; - char generated[10]; - char scannum[10]; - char patient_id[10]; - char exp_date[10]; - char exp_time[10]; - char hist_un0[3]; - int views; - int vols_added; - int start_field; - int field_skip; - int omax, omin; - int smax, smin; -}; - -// Analyze75 header has 348 bytes -struct dsr -{ - struct header_key hk; - struct image_dimension dime; - struct data_history hist; -}; - -class IOAnalyze -{ -public: - - typedef dsr HeaderType; - - IOAnalyze() {} - virtual ~IOAnalyze() {} - - template void array2Header(const std::vector& dim, const std::vector& pixelSize, HeaderType& header) - { - try - { - // set everything to zero - memset(&header, 0, sizeof(dsr)); - - // header_key - header.hk.sizeof_hdr = 348; - size_t i; - for (i=0; i<10; i++ ) header.hk.data_type[i] = 0; - for (i=0; i<18; i++ ) header.hk.db_name[i] = 0; - header.hk.extents = 16384; - header.hk.session_error = 0; - header.hk.regular = 'r'; - header.hk.hkey_un0 = 0; - - // image_dimension - size_t NDim = dim.size(); - - header.dime.dim[0] = (short)(NDim); - header.dime.dim[1] = (short)(dim[0]); - - if ( NDim > 1 ) - header.dime.dim[2] = (short)(dim[1]); - else - header.dime.dim[2] = 1; - - if ( NDim > 2 ) - header.dime.dim[3] = (short)(dim[2]); - else - header.dime.dim[3] = 1; - - if ( NDim > 3 ) - header.dime.dim[4] = (short)(dim[3]); - else - header.dime.dim[4] = 1; - - if ( NDim > 4 ) - header.dime.dim[5] = (short)(dim[4]); - else - header.dime.dim[5] = 1; - - if ( NDim > 5 ) - header.dime.dim[6] = (short)(dim[5]); - else - header.dime.dim[6] = 1; - - if ( NDim > 6 ) - header.dime.dim[7] = (short)(dim[6]); - else - header.dime.dim[7] = 1; - - if ( NDim > 7 ) - header.dime.unused8 = (short)(dim[7]); - else - header.dime.unused8 = 1; - - if ( NDim > 8 ) - header.dime.unused9 = (short)(dim[8]); - else - header.dime.unused9 = 1; - - if ( NDim > 9 ) - header.dime.unused10 = (short)(dim[9]); - else - header.dime.unused10 = 1; - - header.dime.unused11 = 0; - header.dime.unused12 = 0; - header.dime.unused13 = 0; - header.dime.unused14 = 0; - - std::string rttiID = std::string(typeid(T).name()); - header.dime.datatype = (short)getDataTypeFromRTTI(rttiID); - header.dime.bitpix = (short)(8*sizeof(T)); - header.dime.dim_un0 = 0; - - // since the NDArray does not carry the pixel spacing - header.dime.pixdim[0] = 0; - if ( pixelSize.size() > 0 ) - header.dime.pixdim[1] = pixelSize[0]; - if ( pixelSize.size() > 1 ) - header.dime.pixdim[2] = pixelSize[1]; - if ( pixelSize.size() > 2 ) - header.dime.pixdim[3] = pixelSize[2]; - if ( pixelSize.size() > 3 ) - header.dime.pixdim[4] = pixelSize[3]; - if ( pixelSize.size() > 4 ) - header.dime.pixdim[5] = pixelSize[4]; - if ( pixelSize.size() > 5 ) - header.dime.pixdim[6] = pixelSize[5]; - if ( pixelSize.size() > 6 ) - header.dime.pixdim[7] = pixelSize[6]; - - header.dime.vox_offset = 0; - header.dime.funused1 = 0; - header.dime.funused2 = 0; - header.dime.funused3 = 0; - header.dime.cal_max = 0; - header.dime.cal_min = 0; - header.dime.compressed = 0; - header.dime.verified = 0; - header.dime.glmax = 0; - header.dime.glmin = 0; - - // data history - for (i=0; i<80; i++ ) header.hist.descrip[i] = 0; - for (i=0; i<24; i++ ) header.hist.aux_file[i] = 0; - header.hist.orient = 0; - for (i=0; i<10; i++ ) header.hist.originator[i] = 0; - for (i=0; i<10; i++ ) header.hist.generated[i] = 0; - for (i=0; i<10; i++ ) header.hist.scannum[i] = 0; - for (i=0; i<10; i++ ) header.hist.patient_id[i] = 0; - for (i=0; i<10; i++ ) header.hist.exp_date[i] = 0; - for (i=0; i<10; i++ ) header.hist.exp_time[i] = 0; - for (i=0; i<3; i++ ) header.hist.hist_un0[i] = 0; - header.hist.views = 0; - header.hist.vols_added = 0; - header.hist.start_field = 0; - header.hist.field_skip = 0; - header.hist.omax = 0; - header.hist.omin = 0; - header.hist.smax = 0; - header.hist.smin = 0; - } - catch(...) - { - throw GadgetronClientException("Errors in IOAnalyze::array2Analyze(dim, header) ... "); - } - } -}; - -class GadgetronClientAnalyzeImageMessageReader : public GadgetronClientMessageReader -{ - -public: - - GadgetronClientAnalyzeImageMessageReader(const std::string& prefix = std::string("Image")) : prefix_(prefix) - { - - } - - ~GadgetronClientAnalyzeImageMessageReader() { - } - - template - void read_data_attrib(tcp::socket* stream, const ISMRMRD::ImageHeader& h, ISMRMRD::Image& im) - { - im.setHead(h); - - std::cout << "Receiving image : " << h.image_series_index << " - " << h.image_index << " - [" << h.matrix_size[0] << " " << h.matrix_size[1] << " " << h.matrix_size[2] << "]" << std::endl; - - typedef unsigned long long size_t_type; - - std::ostringstream ostr; - - if (!prefix_.empty()) - { - ostr << prefix_ << "_"; - } - - ostr << "SLC" << h.slice << "_" - << "CON" << h.contrast << "_" - << "PHS" << h.phase << "_" - << "REP" << h.repetition << "_" - << "SET" << h.set << "_" - << "AVE" << h.average << "_" - << h.image_index - << "_" << h.image_series_index; - - std::string filename = ostr.str(); - - //Read meta attributes - size_t_type meta_attrib_length; - boost::asio::read(*stream, boost::asio::buffer(&meta_attrib_length, sizeof(size_t_type))); - - if (meta_attrib_length > 0) - { - std::string meta_attrib(meta_attrib_length, 0); - boost::asio::read(*stream, boost::asio::buffer(const_cast(meta_attrib.c_str()), meta_attrib_length)); - - // deserialize the meta attribute - ISMRMRD::MetaContainer imgAttrib; - ISMRMRD::deserialize(meta_attrib.c_str(), imgAttrib); - - std::stringstream st3; - st3 << filename << ".attrib"; - std::string meta_varname = st3.str(); - - std::ofstream outfile; - outfile.open(meta_varname.c_str(), std::ios::out | std::ios::binary); - outfile.write(meta_attrib.c_str(), meta_attrib_length); - outfile.close(); - } - - //Read data - boost::asio::read(*stream, boost::asio::buffer(im.getDataPtr(), im.getDataSize())); - - // analyze header - std::stringstream st1; - st1 << filename << ".hdr"; - std::string head_varname = st1.str(); - - std::vector dim(4, 1); - dim[0] = h.matrix_size[0]; - dim[1] = h.matrix_size[1]; - dim[2] = h.matrix_size[2]; - dim[3] = h.channels; - - std::vector pixelSize(4, 1); - pixelSize[0] = h.field_of_view[0] / h.matrix_size[0]; - pixelSize[1] = h.field_of_view[1] / h.matrix_size[1]; - pixelSize[2] = h.field_of_view[2] / h.matrix_size[2]; - - IOAnalyze hdr; - dsr header; - hdr.array2Header(dim, pixelSize, header); - - std::ofstream outfileHeader; - outfileHeader.open(head_varname.c_str(), std::ios::out | std::ios::binary); - outfileHeader.write(reinterpret_cast(&header), sizeof(dsr)); - outfileHeader.close(); - - // data - std::stringstream st2; - st2 << filename << ".img"; - std::string img_varname = st2.str(); - - std::ofstream outfileData; - outfileData.open(img_varname.c_str(), std::ios::out | std::ios::binary); - outfileData.write(reinterpret_cast(im.getDataPtr()), sizeof(T)*dim[0] * dim[1] * dim[2] * dim[3]); - outfileData.close(); - } - - virtual void read(tcp::socket* stream) - { - //Read the image headerfrom the socket - ISMRMRD::ImageHeader h; - boost::asio::read(*stream, boost::asio::buffer(&h,sizeof(ISMRMRD::ImageHeader))); - - if (h.data_type == ISMRMRD::ISMRMRD_USHORT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_SHORT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_UINT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_INT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_FLOAT) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_DOUBLE) - { - ISMRMRD::Image im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_CXFLOAT) - { - ISMRMRD::Image< std::complex > im; - this->read_data_attrib(stream, h, im); - } - else if (h.data_type == ISMRMRD::ISMRMRD_CXDOUBLE) - { - ISMRMRD::Image< std::complex > im; - this->read_data_attrib(stream, h, im); - } - else - { - throw GadgetronClientException("Invalid image data type ... "); - } - } - -protected: - - std::string prefix_; -}; - -// ---------------------------------------------------------------- - -#define MAX_BLOBS_LOG_10 6 - -class GadgetronClientBlobMessageReader - : public GadgetronClientMessageReader -{ - -public: - GadgetronClientBlobMessageReader(std::string fileprefix, std::string filesuffix) - : number_of_calls_(0) - , file_prefix(fileprefix) - , file_suffix(filesuffix) - - { - - } - - virtual ~GadgetronClientBlobMessageReader() {} - - virtual void read(tcp::socket* socket) - { - - // MUST READ 32-bits - uint32_t nbytes; - boost::asio::read(*socket, boost::asio::buffer(&nbytes,sizeof(uint32_t))); - - std::vector data(nbytes,0); - boost::asio::read(*socket, boost::asio::buffer(&data[0],nbytes)); - - unsigned long long fileNameLen; - boost::asio::read(*socket, boost::asio::buffer(&fileNameLen,sizeof(unsigned long long))); - - std::string filenameBuf(fileNameLen,0); - boost::asio::read(*socket, boost::asio::buffer(const_cast(filenameBuf.c_str()),fileNameLen)); - - typedef unsigned long long size_t_type; - - size_t_type meta_attrib_length; - boost::asio::read(*socket, boost::asio::buffer(&meta_attrib_length, sizeof(size_t_type))); - - std::string meta_attrib; - if (meta_attrib_length > 0) - { - std::string meta_attrib_socket(meta_attrib_length, 0); - boost::asio::read(*socket, boost::asio::buffer(const_cast(meta_attrib_socket.c_str()), meta_attrib_length)); - meta_attrib = meta_attrib_socket; - } - - std::stringstream filename; - std::string filename_attrib; - - // Create the filename: (prefix_%06.suffix) - filename << file_prefix << "_"; - filename << std::setfill('0') << std::setw(MAX_BLOBS_LOG_10) << number_of_calls_; - filename_attrib = filename.str(); - filename << "." << file_suffix; - filename_attrib.append("_attrib.xml"); - - std::cout << "Writing image " << filename.str() << std::endl; - - std::ofstream outfile; - outfile.open(filename.str().c_str(), std::ios::out | std::ios::binary); - - std::ofstream outfile_attrib; - if (meta_attrib_length > 0) - { - outfile_attrib.open(filename_attrib.c_str(), std::ios::out | std::ios::binary); - } - - if (outfile.good()) - { - /* write 'size' bytes starting at 'data's pointer */ - outfile.write(&data[0], nbytes); - outfile.close(); - - if (meta_attrib_length > 0) - { - outfile_attrib.write(meta_attrib.c_str(), meta_attrib.length()); - outfile_attrib.close(); - } - - number_of_calls_++; - } - else - { - throw GadgetronClientException("Unable to write blob to output file\n"); - } - } - -protected: - size_t number_of_calls_; - std::string file_prefix; - std::string file_suffix; - -}; - -class GadgetronClientConnector -{ - -public: - GadgetronClientConnector() - : socket_(0) - , timeout_ms_(10000) - , uncompressed_bytes_sent_(0) - , compressed_bytes_sent_(0) - , header_bytes_sent_(0) - { - - } - - virtual ~GadgetronClientConnector() - { - if (socket_) { - socket_->close(); - delete socket_; - } - } - - double compression_ratio() - { - if (compressed_bytes_sent_ <= 0) { - return 1.0; - } - - return uncompressed_bytes_sent_/compressed_bytes_sent_; - } - - double get_bytes_transmitted() - { - if (compressed_bytes_sent_ <= 0) { - return header_bytes_sent_ + uncompressed_bytes_sent_; - } else { - return header_bytes_sent_ + compressed_bytes_sent_; - } - } - - void set_timeout(unsigned int t) - { - timeout_ms_ = t; - } - - void read_task() - { - if (!socket_) { - throw GadgetronClientException("Unable to create socket."); - } - - while (socket_->is_open()) { - - GadgetMessageIdentifier id; - boost::asio::read(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - - if (id.id == GADGET_MESSAGE_CLOSE) { - break; - } - - GadgetronClientMessageReader* r = find_reader(id.id); - - if (!r) { - std::cout << "Message received with ID: " << id.id << std::endl; - throw GadgetronClientException("Unknown Message ID"); - } else { - r->read(socket_); - } - } - } - - void wait() { - reader_thread_.join(); - } - - void connect(std::string hostname, std::string port) - { - tcp::resolver resolver(io_service); - // numeric_service flag is required to send data if the Linux machine has no internet connection (in this case the loopback device is the only network device with an address). - // https://stackoverflow.com/questions/5971242/how-does-boost-asios-hostname-resolution-work-on-linux-is-it-possible-to-use-n - // https://www.boost.org/doc/libs/1_65_0/doc/html/boost_asio/reference/ip__basic_resolver_query.html - tcp::resolver::query query(tcp::v4(), hostname.c_str(), port.c_str(), boost::asio::ip::resolver_query_base::numeric_service); - tcp::resolver::iterator endpoint_iterator = resolver.resolve(query); - tcp::resolver::iterator end; - - socket_ = new tcp::socket(io_service); - if (!socket_) { - throw GadgetronClientException("Unable to create socket."); - } - - std::condition_variable cv; - std::mutex cv_m; - - boost::system::error_code error = boost::asio::error::host_not_found; - std::thread t([&](){ - //TODO: - //For newer versions of Boost, we should use - // boost::asio::connect(*socket_, iterator); - while (error && endpoint_iterator != end) { - socket_->close(); - socket_->connect(*endpoint_iterator++, error); - } - cv.notify_all(); - }); - - { - std::unique_lock lk(cv_m); - if (std::cv_status::timeout == cv.wait_until(lk, std::chrono::system_clock::now() +std::chrono::milliseconds(timeout_ms_)) ) { - socket_->close(); - } - } - - t.join(); - if (error) - throw GadgetronClientException("Error connecting using socket."); - - reader_thread_ = std::thread([&](){this->read_task();}); - } - - void send_gadgetron_close() { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_CLOSE; - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - } - - void send_gadgetron_info_query(const std::string &query, uint64_t correlation_id = 0) { - GadgetMessageIdentifier id{ 6 }; // 6 = QUERY; Deal with it. - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(id))); - - uint64_t reserved = 0; - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&reserved, sizeof(reserved))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&correlation_id, sizeof(correlation_id))); - - uint64_t query_length = query.size(); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&query_length, sizeof(query_length))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(query)); - } - - void send_gadgetron_configuration_file(std::string config_xml_name) { - - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_CONFIG_FILE; - - GadgetMessageConfigurationFile ini; - memset(&ini,0,sizeof(GadgetMessageConfigurationFile)); - strncpy(ini.configuration_file, config_xml_name.c_str(),config_xml_name.size()); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&ini, sizeof(GadgetMessageConfigurationFile))); - - } - - void send_gadgetron_configuration_script(std::string xml_string) - { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_CONFIG_SCRIPT; - - GadgetMessageScript conf; - conf.script_length = (uint32_t)xml_string.size(); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&conf, sizeof(GadgetMessageScript))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(xml_string.c_str(), conf.script_length)); - } - - void send_gadgetron_parameters(std::string xml_string) - { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_PARAMETER_SCRIPT; - - GadgetMessageScript conf; - conf.script_length = (uint32_t)xml_string.size(); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&conf, sizeof(GadgetMessageScript))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(xml_string.c_str(), conf.script_length)); - } - - void send_ismrmrd_acquisition(ISMRMRD::Acquisition& acq) - { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_ISMRMRD_ACQUISITION;; - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getHead(), sizeof(ISMRMRD::AcquisitionHeader))); - - unsigned long trajectory_elements = acq.getHead().trajectory_dimensions*acq.getHead().number_of_samples; - unsigned long data_elements = acq.getHead().active_channels*acq.getHead().number_of_samples; - - if (trajectory_elements) { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getTrajPtr()[0], sizeof(float)*trajectory_elements)); - } - - - if (data_elements) { - uncompressed_bytes_sent_ +=boost::asio::write(*socket_, boost::asio::buffer(&acq.getDataPtr()[0], 2*sizeof(float)*data_elements)); - } - } - - - void send_ismrmrd_compressed_acquisition_precision(ISMRMRD::Acquisition& acq, unsigned int compression_precision) - { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_ISMRMRD_ACQUISITION; - - ISMRMRD::AcquisitionHeader h = acq.getHead(); //We will make a copy because we will be setting some flags - h.setFlag(ISMRMRD::ISMRMRD_ACQ_COMPRESSION2); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&h, sizeof(ISMRMRD::AcquisitionHeader))); - - unsigned long trajectory_elements = acq.getHead().trajectory_dimensions*acq.getHead().number_of_samples; - unsigned long data_elements = acq.getHead().active_channels*acq.getHead().number_of_samples; - - if (trajectory_elements) { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getTrajPtr()[0], sizeof(float)*trajectory_elements)); - } - - - if (data_elements) { - std::vector input_data((float*)&acq.getDataPtr()[0], (float*)&acq.getDataPtr()[0] + acq.getHead().active_channels*acq.getHead().number_of_samples*2); - - std::unique_ptr comp_buffer(CompressedFloatBuffer::createCompressedBuffer()); - comp_buffer->compress(input_data, -1.0, compression_precision); - std::vector serialized_buffer = comp_buffer->serialize(); - - compressed_bytes_sent_ += serialized_buffer.size(); - uncompressed_bytes_sent_ += data_elements*2*sizeof(float); - - uint32_t bs = (uint32_t)serialized_buffer.size(); - boost::asio::write(*socket_, boost::asio::buffer(&bs, sizeof(uint32_t))); - boost::asio::write(*socket_, boost::asio::buffer(&serialized_buffer[0], serialized_buffer.size())); - } - - } - - - void send_ismrmrd_compressed_acquisition_tolerance(ISMRMRD::Acquisition& acq, float compression_tolerance, NoiseStatistics& stat) - { - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_ISMRMRD_ACQUISITION; - - ISMRMRD::AcquisitionHeader h = acq.getHead(); //We will make a copy because we will be setting some flags - h.setFlag(ISMRMRD::ISMRMRD_ACQ_COMPRESSION2); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&h, sizeof(ISMRMRD::AcquisitionHeader))); - - unsigned long trajectory_elements = acq.getHead().trajectory_dimensions*acq.getHead().number_of_samples; - unsigned long data_elements = acq.getHead().active_channels*acq.getHead().number_of_samples; - - if (trajectory_elements) { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getTrajPtr()[0], sizeof(float)*trajectory_elements)); - } - - - if (data_elements) { - std::vector input_data((float*)&acq.getDataPtr()[0], (float*)&acq.getDataPtr()[0] + acq.getHead().active_channels* acq.getHead().number_of_samples*2); - - float local_tolerance = compression_tolerance; - float sigma = stat.sigma_min; //We use the minimum sigma of all channels to "cap" the error - if (stat.status && sigma > 0 && stat.noise_dwell_time_us && acq.getHead().sample_time_us) { - local_tolerance = local_tolerance*stat.sigma_min*acq.getHead().sample_time_us*std::sqrt(stat.noise_dwell_time_us/acq.getHead().sample_time_us); - } - - std::unique_ptr comp_buffer(CompressedFloatBuffer::createCompressedBuffer()); - comp_buffer->compress(input_data, local_tolerance); - std::vector serialized_buffer = comp_buffer->serialize(); - - compressed_bytes_sent_ += serialized_buffer.size(); - uncompressed_bytes_sent_ += data_elements*2*sizeof(float); - - uint32_t bs = (uint32_t)serialized_buffer.size(); - boost::asio::write(*socket_, boost::asio::buffer(&bs, sizeof(uint32_t))); - boost::asio::write(*socket_, boost::asio::buffer(&serialized_buffer[0], serialized_buffer.size())); - } - } - - void send_ismrmrd_zfp_compressed_acquisition_precision(ISMRMRD::Acquisition& acq, unsigned int compression_precision) - { - -#if defined GADGETRON_COMPRESSION_ZFP - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - //TODO: switch data type - id.id = GADGET_MESSAGE_ISMRMRD_ACQUISITION; - - ISMRMRD::AcquisitionHeader h = acq.getHead(); //We will make a copy because we will be setting some flags - h.setFlag(ISMRMRD::ISMRMRD_ACQ_COMPRESSION1); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&h, sizeof(ISMRMRD::AcquisitionHeader))); - - unsigned long trajectory_elements = acq.getHead().trajectory_dimensions*acq.getHead().number_of_samples; - unsigned long data_elements = acq.getHead().active_channels*acq.getHead().number_of_samples; - - if (trajectory_elements) { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getTrajPtr()[0], sizeof(float)*trajectory_elements)); - } - - - if (data_elements) { - size_t comp_buffer_size = 4*sizeof(float)*data_elements; - char* comp_buffer = new char[comp_buffer_size]; - size_t compressed_size = 0; - try { - compressed_size = compress_zfp_precision((float*)&acq.getDataPtr()[0], - acq.getHead().number_of_samples*2, acq.getHead().active_channels, - compression_precision, comp_buffer, comp_buffer_size); - - compressed_bytes_sent_ += compressed_size; - uncompressed_bytes_sent_ += data_elements*2*sizeof(float); - float compression_ratio = (1.0*data_elements*2*sizeof(float))/(float)compressed_size; - //std::cout << "Compression ratio: " << compression_ratio << std::endl; - - } catch (...) { - delete [] comp_buffer; - std::cout << "Compression failure caught" << std::endl; - throw; - } - - - //TODO: Write compressed buffer - uint32_t bs = (uint32_t)compressed_size; - boost::asio::write(*socket_, boost::asio::buffer(&bs, sizeof(uint32_t))); - boost::asio::write(*socket_, boost::asio::buffer(comp_buffer, compressed_size)); - - delete [] comp_buffer; - } - -#else //GADGETRON_COMPRESSION_ZFP - throw GadgetronClientException("Attempting to do ZFP compression, but ZFP not available"); -#endif //GADGETRON_COMPRESSION_ZFP - } - - void send_ismrmrd_zfp_compressed_acquisition_tolerance(ISMRMRD::Acquisition& acq, float compression_tolerance, NoiseStatistics& stat) - { -#if defined GADGETRON_COMPRESSION_ZFP - if (!socket_) { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - //TODO: switch data type - id.id = GADGET_MESSAGE_ISMRMRD_ACQUISITION; - - ISMRMRD::AcquisitionHeader h = acq.getHead(); //We will make a copy because we will be setting some flags - h.setFlag(ISMRMRD::ISMRMRD_ACQ_COMPRESSION1); - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&h, sizeof(ISMRMRD::AcquisitionHeader))); - - unsigned long trajectory_elements = acq.getHead().trajectory_dimensions*acq.getHead().number_of_samples; - unsigned long data_elements = acq.getHead().active_channels*acq.getHead().number_of_samples; - - if (trajectory_elements) { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&acq.getTrajPtr()[0], sizeof(float)*trajectory_elements)); - } - - float local_tolerance = compression_tolerance; - float sigma = stat.sigma_min; //We use the minimum sigma of all channels to "cap" the error - if (stat.status && sigma > 0 && stat.noise_dwell_time_us && acq.getHead().sample_time_us) { - local_tolerance = local_tolerance*stat.sigma_min*acq.getHead().sample_time_us*std::sqrt(stat.noise_dwell_time_us/acq.getHead().sample_time_us); - } - - if (data_elements) { - size_t comp_buffer_size = 4*sizeof(float)*data_elements; - char* comp_buffer = new char[comp_buffer_size]; - size_t compressed_size = 0; - try { - compressed_size = compress_zfp_tolerance((float*)&acq.getDataPtr()[0], - acq.getHead().number_of_samples*2, acq.getHead().active_channels, - local_tolerance, comp_buffer, comp_buffer_size); - - compressed_bytes_sent_ += compressed_size; - uncompressed_bytes_sent_ += data_elements*2*sizeof(float); - float compression_ratio = (1.0*data_elements*2*sizeof(float))/(float)compressed_size; - //std::cout << "Compression ratio: " << compression_ratio << std::endl; - - } catch (...) { - delete [] comp_buffer; - std::cout << "Compression failure caught" << std::endl; - throw; - } - - - //TODO: Write compressed buffer - uint32_t bs = (uint32_t)compressed_size; - boost::asio::write(*socket_, boost::asio::buffer(&bs, sizeof(uint32_t))); - boost::asio::write(*socket_, boost::asio::buffer(comp_buffer, compressed_size)); - - delete [] comp_buffer; - } -#else //GADGETRON_COMPRESSION_ZFP - throw GadgetronClientException("Attempting to do ZFP compression, but ZFP not available"); -#endif //GADGETRON_COMPRESSION_ZFP - - } - - void send_ismrmrd_waveform(ISMRMRD::Waveform& wav) - { - if (!socket_) - { - throw GadgetronClientException("Invalid socket."); - } - - GadgetMessageIdentifier id; - id.id = GADGET_MESSAGE_ISMRMRD_WAVEFORM;; - - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&id, sizeof(GadgetMessageIdentifier))); - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(&wav.head, sizeof(ISMRMRD::ISMRMRD_WaveformHeader))); - - unsigned long data_elements = wav.head.channels*wav.head.number_of_samples; - - if (data_elements) - { - header_bytes_sent_ += boost::asio::write(*socket_, boost::asio::buffer(wav.begin_data(), sizeof(uint32_t)*data_elements)); - } - } - - void register_reader(unsigned short slot, std::shared_ptr r) { - readers_[slot] = r; - } - -protected: - typedef std::map > maptype; - - GadgetronClientMessageReader* find_reader(unsigned short r) - { - GadgetronClientMessageReader* ret = 0; - - maptype::iterator it = readers_.find(r); - - if (it != readers_.end()) { - ret = it->second.get(); - } - - return ret; - } - - boost::asio::io_service io_service; - tcp::socket* socket_; - std::thread reader_thread_; - maptype readers_; - unsigned int timeout_ms_; - double header_bytes_sent_; - double uncompressed_bytes_sent_; - double compressed_bytes_sent_; -}; - - -class GadgetronClientQueryToStringReader : public GadgetronClientMessageReader -{ - -public: - GadgetronClientQueryToStringReader(std::string& result) : result_(result) - { - - } - - virtual ~GadgetronClientQueryToStringReader() - { - - } - - virtual void read(tcp::socket* stream) - { - size_t recv_count = 0; - - typedef unsigned long long size_t_type; - size_t_type len(0); - boost::asio::read(*stream, boost::asio::buffer(&len, sizeof(size_t_type))); - - std::vector temp(len,0); - if (boost::asio::read(*stream, boost::asio::buffer(temp.data(), len)) != len) - { - throw GadgetronClientException("Incorrect number of bytes read for dependency query"); - } - result_ = std::string(temp.data(),len); - - } - - protected: - std::string& result_; -}; - - -NoiseStatistics get_noise_statistics(std::string dependency_name, std::string host_name, std::string port, unsigned int timeout_ms) -{ - GadgetronClientConnector con; - con.set_timeout(timeout_ms); - std::string result; - NoiseStatistics stat; - - con.register_reader(GADGET_MESSAGE_DEPENDENCY_QUERY, std::make_shared(result)); - - std::string xml_config; - - xml_config += "\n"; - xml_config += " \n"; - xml_config += "\n"; - xml_config += " \n"; - xml_config += " 1019\n"; - xml_config += " gadgetron_mricore\n"; - xml_config += " DependencyQueryWriter\n"; - xml_config += " \n"; - xml_config += "\n"; - xml_config += " \n"; - xml_config += " NoiseSummary\n"; - xml_config += " gadgetron_mricore\n"; - xml_config += " NoiseSummaryGadget\n"; - xml_config += "\n"; - xml_config += " \n"; - xml_config += " noise_file\n"; - xml_config += " " + dependency_name + "\n"; - xml_config += " \n"; - xml_config += " \n"; - xml_config += "\n"; - xml_config += "\n"; - - try { - con.connect(host_name,port); - con.send_gadgetron_configuration_script(xml_config); - con.send_gadgetron_close(); - con.wait(); - } catch (...) { - std::cerr << "Unable to retrieve noise statistics from server" << std::endl; - stat.status = false; - } - - try { - ISMRMRD::MetaContainer meta; - ISMRMRD::deserialize(result.c_str(), meta); - stat.status = meta.as_str("status") == std::string("success"); - stat.channels = meta.as_long("channels"); - stat.sigma_min = meta.as_double("min_sigma"); - stat.sigma_max = meta.as_double("max_sigma"); - stat.sigma_mean = meta.as_double("mean_sigma"); - stat.noise_dwell_time_us = meta.as_double("noise_dwell_time_us"); - } catch (...) { - stat.status = false; - } - - return stat; -} - -void send_ismrmrd_acq(GadgetronClientConnector& con, ISMRMRD::Acquisition& acq_tmp, - unsigned int compression_precision, bool use_zfp_compression, float compression_tolerance, NoiseStatistics& noise_stats) -{ - try - { - if (compression_precision > 0) - { - if (use_zfp_compression) { - con.send_ismrmrd_zfp_compressed_acquisition_precision(acq_tmp, compression_precision); - } - else { - con.send_ismrmrd_compressed_acquisition_precision(acq_tmp, compression_precision); - } - } - else if (compression_tolerance > 0.0) - { - if (use_zfp_compression) { - con.send_ismrmrd_zfp_compressed_acquisition_tolerance(acq_tmp, compression_tolerance, noise_stats); - } - else { - con.send_ismrmrd_compressed_acquisition_tolerance(acq_tmp, compression_tolerance, noise_stats); - } - } - else - { - con.send_ismrmrd_acquisition(acq_tmp); - } - } - catch(...) - { - throw GadgetronClientException("send_ismrmrd_acq failed ... "); - } -} - -int main(int argc, char **argv) -{ - - std::string host_name; - std::string port; - std::string in_filename; - std::string out_filename; - std::string hdf5_in_group; - std::string hdf5_out_group; - std::string config_file; - std::string config_file_local; - std::string config_xml_local; - unsigned int loops; - unsigned int timeout_ms; - std::string out_fileformat; - bool open_input_file = true; - unsigned int compression_precision = 0; - float compression_tolerance = 0.0; - bool use_zfp_compression = false; - bool verbose = false; - Gadgetron::GadgetronTimer timer(false); - - po::options_description desc("Allowed options"); - - desc.add_options() - ("help,h", "Produce help message") - ("query,q", "Dependency query mode") - ("verbose,v", "Verbose mode") - ("info,Q", po::value(), "Query Gadgetron information") - ("port,p", po::value(&port)->default_value("9002"), "Port") - ("address,a", po::value(&host_name)->default_value("localhost"), "Address (hostname) of Gadgetron host") - ("filename,f", po::value(&in_filename), "Input file") - ("outfile,o", po::value(&out_filename)->default_value("out.h5"), "Output file") - ("in-group,g", po::value(&hdf5_in_group)->default_value("/dataset"), "Input data group") - ("out-group,G", po::value(&hdf5_out_group)->default_value(get_date_time_string()), "Output group name") - ("config,c", po::value(&config_file)->default_value("default.xml"), "Configuration file (remote)") - ("config-local,C", po::value(&config_file_local), "Configuration file (local)") - ("loops,l", po::value(&loops)->default_value(1), "Loops") - ("timeout,t", po::value(&timeout_ms)->default_value(10000), "Timeout [ms]") - ("outformat,F", po::value(&out_fileformat)->default_value("h5"), "Out format, h5 for hdf5 and hdr for analyze image") - ("precision,P", po::value(&compression_precision)->default_value(0), "Compression precision (bits)") - ("tolerance,T", po::value(&compression_tolerance)->default_value(0.0), "Compression tolerance (fraction of sigma, if no noise stats, assume sigma 1)") -#if defined GADGETRON_COMPRESSION_ZFP - ("ZFP,Z", po::value(&use_zfp_compression)->default_value(false), "Use ZFP library for compression"); -#endif //GADGETRON_COMPRESSION_ZFP - ; - - po::variables_map vm; - po::store(po::parse_command_line(argc, argv, desc), vm); - po::notify(vm); - - if (vm.count("help")) { - std::cout << desc << std::endl; - return 0; - } - - if (!vm.count("filename") && !vm.count("query") && !vm.count("info")) { - std::cout << std::endl << std::endl << "\tYou must supply a filename" << std::endl << std::endl; - std::cout << desc << std::endl; - return -1; - } - - if (vm.count("query") || vm.count("info")) { - open_input_file = false; - } - - if (vm.count("verbose")) { - verbose = true; - } - - if (vm.count("config-local")) { - std::ifstream t(config_file_local.c_str()); - if (t) { - //Read in the file. - config_xml_local = std::string((std::istreambuf_iterator(t)), - std::istreambuf_iterator()); - } else { - std::cout << "Unable to read local xml configuration: " << config_file_local << std::endl; - return -1; - } - } - - if (compression_precision > 0 && compression_tolerance > 0.0) { - std::cout << "You cannot supply both compression precision (P) and compression tolerance (T) at the same time" << std::endl; - return -1; - } - - //Let's check if the files exist: - std::string hdf5_xml_varname = std::string(hdf5_in_group) + std::string("/xml"); - std::string hdf5_data_varname = std::string(hdf5_in_group) + std::string("/data"); - std::string hdf5_waveform_varname = std::string(hdf5_in_group) + std::string("/waveform"); - - //TODO: - // Add check to see if input file exists - - //Let's open the input file - std::shared_ptr ismrmrd_dataset; - std::string xml_config; - if (open_input_file) { - ismrmrd_dataset = std::shared_ptr(new ISMRMRD::Dataset(in_filename.c_str(), hdf5_in_group.c_str(), false)); - // Read the header - ismrmrd_dataset->readHeader(xml_config); - } - - if (!vm.count("query") && !vm.count("info")) { - std::cout << "Gadgetron ISMRMRD client" << std::endl; - std::cout << " -- host : " << host_name << std::endl; - std::cout << " -- port : " << port << std::endl; - std::cout << " -- hdf5 file in : " << in_filename << std::endl; - std::cout << " -- hdf5 group in : " << hdf5_in_group << std::endl; - std::cout << " -- conf : " << config_file << std::endl; - std::cout << " -- loop : " << loops << std::endl; - std::cout << " -- hdf5 file out : " << out_filename << std::endl; - std::cout << " -- hdf5 group out : " << hdf5_out_group << std::endl; - } - - - //Let's figure out if this measurement has dependencies - NoiseStatistics noise_stats; noise_stats.status = false; - if (!vm.count("query") && !vm.count("info")) { - ISMRMRD::IsmrmrdHeader h; - ISMRMRD::deserialize(xml_config.c_str(),h); - - std::string noise_id; - if (h.measurementInformation.is_present() && - (h.measurementInformation().measurementDependency.size() > 0)) { - std::cout << "This measurement has dependent measurements" << std::endl; - for (auto d: h.measurementInformation().measurementDependency) { - std::cout << " " << d.dependencyType << " : " << d.measurementID << std::endl; - if (d.dependencyType == "Noise") { - noise_id = d.measurementID; - } - } - } - - if (!noise_id.empty()) { - std::cout << "Querying the Gadgetron instance for the dependent measurement: " << noise_id << std::endl; - noise_stats = get_noise_statistics(std::string("GadgetronNoiseCovarianceMatrix_") + noise_id, host_name, port, timeout_ms); - if (!noise_stats.status) { - std::cout << "WARNING: Dependent noise measurement not found on Gadgetron server. Was the noise data processed?" << std::endl; - if (compression_tolerance > 0.0) { - std::cout << " !!!!!! COMPRESSION TOLERANCE LEVEL SPECIFIED, BUT IT IS NOT POSSIBLE TO DETERMINE SIGMA. ASSIMUMING SIGMA == 1 !!!!!!" << std::endl; - } - } else { - std::cout << "Noise level: Min sigma = " << noise_stats.sigma_min << ", Mean sigma = " << noise_stats.sigma_mean << ", Max sigma = " << noise_stats.sigma_max << std::endl; - } - } - } - - GadgetronClientConnector con; - con.set_timeout(timeout_ms); - - if ( out_fileformat == "hdr" ) - { - con.register_reader(GADGET_MESSAGE_ISMRMRD_IMAGE, std::shared_ptr(new GadgetronClientAnalyzeImageMessageReader(hdf5_out_group))); - } - else - { - con.register_reader(GADGET_MESSAGE_ISMRMRD_IMAGE, std::shared_ptr(new GadgetronClientImageMessageReader(out_filename, hdf5_out_group))); - } - - con.register_reader(GADGET_MESSAGE_DICOM_WITHNAME, std::shared_ptr(new GadgetronClientBlobMessageReader(std::string(hdf5_out_group), std::string("dcm")))); - - con.register_reader(GADGET_MESSAGE_DEPENDENCY_QUERY, std::shared_ptr(new GadgetronClientDependencyQueryReader(std::string(out_filename)))); - con.register_reader(GADGET_MESSAGE_TEXT, std::shared_ptr(new GadgetronClientTextReader())); - con.register_reader(7, std::shared_ptr(new GadgetronClientResponseReader())); - - try - { - timer.start(); - con.connect(host_name,port); - - if (vm.count("info")) { - con.send_gadgetron_info_query(vm["info"].as()); - } - else if (vm.count("config-local")) - { - con.send_gadgetron_configuration_script(config_xml_local); - } - else - { - con.send_gadgetron_configuration_file(config_file); - } - - if (open_input_file) - { - con.send_gadgetron_parameters(xml_config); - - uint32_t acquisitions = 0; - { - mtx.lock(); - acquisitions = ismrmrd_dataset->getNumberOfAcquisitions(); - mtx.unlock(); - } - - uint32_t waveforms = 0; - { - mtx.lock(); - waveforms = ismrmrd_dataset->getNumberOfWaveforms(); - mtx.unlock(); - } - - if(verbose) - { - std::cout << "Find " << acquisitions << " ismrmrd acquisitions" << std::endl; - std::cout << "Find " << waveforms << " ismrmrd waveforms" << std::endl; - } - - ISMRMRD::Acquisition acq_tmp; - ISMRMRD::Waveform wav_tmp; - - uint32_t i(0), j(0); // i : index over the acquisition; j : index over the waveform - - if(waveforms>0) - { - { - std::lock_guard scoped_lock(mtx); - ismrmrd_dataset->readAcquisition(i, acq_tmp); - } - - { - std::lock_guard scoped_lock(mtx); - ismrmrd_dataset->readWaveform(j, wav_tmp); - } - - while(i Send out ismrmrd waveform : " << j << " - " << wav_tmp.head.scan_counter - << " - " << wav_tmp.head.time_stamp - << " - " << wav_tmp.head.channels - << " - " << wav_tmp.head.number_of_samples - << " - " << wav_tmp.head.waveform_id - << std::endl; - } - - j++; - - if(j scoped_lock(mtx); - ismrmrd_dataset->readWaveform(j, wav_tmp); - } - else - { - break; - } - } - - while (acq_tmp.getHead().acquisition_time_stamp <= wav_tmp.head.time_stamp) - { - send_ismrmrd_acq(con, acq_tmp, compression_precision, use_zfp_compression, compression_tolerance, noise_stats); - - if (verbose) - { - std::cout << "==> Send out ismrmrd acq : " << i << " - " << acq_tmp.getHead().scan_counter << " - " << acq_tmp.getHead().acquisition_time_stamp << std::endl; - } - - i++; - - if(i scoped_lock(mtx); - ismrmrd_dataset->readAcquisition(i, acq_tmp); - } - else - { - break; - } - } - - if(j==waveforms && i scoped_lock(mtx); - ismrmrd_dataset->readAcquisition(ia, acq_tmp); - } - - send_ismrmrd_acq(con, acq_tmp, compression_precision, use_zfp_compression, compression_tolerance, noise_stats); - } - } - - if (i==acquisitions && j scoped_lock(mtx); - ismrmrd_dataset->readWaveform(iw, wav_tmp); - } - - con.send_ismrmrd_waveform(wav_tmp); - } - } - } - } - else - { - for (i=0; i scoped_lock(mtx); - ismrmrd_dataset->readAcquisition(i, acq_tmp); - } - - send_ismrmrd_acq(con, acq_tmp, compression_precision, use_zfp_compression, compression_tolerance, noise_stats); - } - } - } - - if (compression_precision > 0 || compression_tolerance > 0.0) { - std::cout << "Compression ratio: " << con.compression_ratio() << std::endl; - } - - if (verbose) { - double transmission_time_s = timer.stop()/1e6; - double transmitted_mb = con.get_bytes_transmitted()/(1024*1024); - std::cout << "Time sending: " << transmission_time_s << "s" << std::endl; - std::cout << "Data sent: " << transmitted_mb << "MB" << std::endl; - std::cout << "Transmission rate: " << transmitted_mb/transmission_time_s << "MB/s" << std::endl; - } - - con.send_gadgetron_close(); - con.wait(); - } - catch (std::exception& ex) - { - std::cerr << "Error caught: " << ex.what() << std::endl; - return -1; - } - - return 0; -} diff --git a/apps/clients/utilities/CMakeLists.txt b/apps/clients/utilities/CMakeLists.txt deleted file mode 100644 index 2c80d8069..000000000 --- a/apps/clients/utilities/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -set(Boost_NO_BOOST_CMAKE ON) - -if(WIN32) - find_package(Boost COMPONENTS thread system date_time chrono REQUIRED) -else() - find_package(Boost COMPONENTS thread system REQUIRED) -endif() - -if(WIN32) - link_directories(${Boost_LIBRARY_DIRS}) -endif() - - -add_executable(gt_alive gt_alive.cpp) -add_executable(gtdependencyquery gt_query.cpp DependencyQueryReader.h) - -target_link_libraries(gt_alive gadgetron_toolbox_cpucore - gadgetron_toolbox_gadgettools - gadgetron_toolbox_log) - -target_link_libraries(gtdependencyquery gadgetron_toolbox_cpucore - gadgetron_toolbox_gadgettools - gadgetron_toolbox_log - boost - ) - -install(TARGETS gt_alive gtdependencyquery DESTINATION bin COMPONENT main) -install(FILES DependencyQueryReader.h DESTINATION ${GADGETRON_INSTALL_INCLUDE_PATH} COMPONENT main) diff --git a/apps/clients/utilities/DependencyQueryReader.h b/apps/clients/utilities/DependencyQueryReader.h deleted file mode 100644 index 67c697794..000000000 --- a/apps/clients/utilities/DependencyQueryReader.h +++ /dev/null @@ -1,100 +0,0 @@ - -/** \file DependencyQueryReader.h - \brief Implement the writer to write the dependency query reults into a file - \author Hui Xue -*/ - -#pragma once - -#include -#include - -#include "GadgetMessageInterface.h" -#include "ismrmrd/meta.h" - -namespace Gadgetron -{ - -class DependencyQueryReader : public GadgetMessageReader -{ - public: - - DependencyQueryReader(std::string filename) : number_of_calls_(0) , filename_(filename) - { - } - - virtual ~DependencyQueryReader() - { - } - - virtual ACE_Message_Block* read(ACE_SOCK_Stream* socket) - { - ssize_t recv_count = 0; - - typedef unsigned long long size_t_type; - - size_t_type len(0); - if ( ( recv_count = socket->recv_n( &len, sizeof(size_t_type)) ) <= 0 ) - { - GERROR("DependencyQueryReader, failed to read query results length\n"); - return 0; - } - - char* buf = NULL; - try - { - buf = new char[len]; - if ( buf == NULL ) - { - GERROR("DependencyQueryReader, failed to allocate buffer\n"); - return 0; - } - - memset(buf, '\0', len); - memcpy(buf, &len, sizeof(size_t_type)); - } - catch (std::runtime_error &err) - { - GEXCEPTION(err,"DependencyQueryReader, failed to allocate buffer\n"); - return 0; - } - - if ( ( recv_count = socket->recv_n( buf, len) ) <= 0 ) - { - GERROR("DependencyQueryReader, failed to read query results\n"); - delete [] buf; - return 0; - } - - std::ofstream outfile; - outfile.open (filename_.c_str(), std::ios::out|std::ios::binary); - - if (outfile.good()) - { - outfile.write(buf, len); - outfile.close(); - number_of_calls_++; - } - else - { - delete[] buf; - - GERROR_STREAM("File " << filename_ << " is not good for writing\n"); - return 0; - } - - delete[] buf; - - // The GadgetronConnector expects an ACE_Message_Block* (NOT NULL) - ACE_Message_Block *mb = new ACE_Message_Block(); - - return mb; - } - - protected: - - size_t number_of_calls_; - std::string filename_; -}; - -} // namespace Gadgetron diff --git a/apps/clients/utilities/gt_alive.cpp b/apps/clients/utilities/gt_alive.cpp deleted file mode 100644 index 4436ef9d3..000000000 --- a/apps/clients/utilities/gt_alive.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include "GadgetronConnector.h" -#include "GadgetMRIHeaders.h" -#include "GadgetContainerMessage.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -using namespace Gadgetron; - -int ACE_TMAIN(int argc, ACE_TCHAR *argv[] ) -{ - GadgetronConnector con; - - std::string host("localhost"); - std::string port("9002"); - - ACE_TCHAR hostname[1024]; - //We will do a little trick to figure out what the hostname would be according to ACE - ACE_SOCK_Acceptor listener (ACE_Addr::sap_any); - ACE_INET_Addr addr; - listener.get_local_addr (addr); - ACE_OS_String::strncpy(hostname, addr.get_host_name(), 1024); - - host = std::string(hostname); - - if (argc > 1) { - host = std::string(argv[1]); - } - - if (argc > 2) { - port = std::string(argv[2]); - } - - if (con.open(host,port) != 0) { - GERROR("Unable to connect to the Gadgetron host\n"); - return -1; - } - - //Tell Gadgetron which XML configuration to run. - if (con.send_gadgetron_configuration_file(std::string("isalive.xml")) != 0) { - GERROR("Unable to send XML configuration to the Gadgetron host\n"); - return -1; - } - - - GadgetContainerMessage* m1 = - new GadgetContainerMessage(); - - m1->getObjectPtr()->id = GADGET_MESSAGE_CLOSE; - - if (con.putq(m1) == -1) { - GERROR("Unable to put CLOSE package on queue\n"); - return -1; - } - - con.wait(); - - return 0; -} diff --git a/apps/clients/utilities/gt_query.cpp b/apps/clients/utilities/gt_query.cpp deleted file mode 100644 index a93b84258..000000000 --- a/apps/clients/utilities/gt_query.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "GadgetronConnector.h" -#include "GadgetMRIHeaders.h" -#include "GadgetContainerMessage.h" -#include "DependencyQueryReader.h" - -#include -#include -#include - -#include -#include -#include -#include - -using namespace Gadgetron; - -static void usage() -{ - using namespace std; - std::ostringstream outs; - - outs << "Query the gadgetron server for the stored dependency measurements" << endl; - outs << "gtdependencyquery -p (default 9002)" << endl; - outs << " -h (default localhost)" << endl; - outs << " -o (default dependency.xml)" << endl; - outs << std::ends; - - GDEBUG_STREAM(outs.str()); -} - -int ACE_TMAIN(int argc, ACE_TCHAR *argv[] ) -{ - GadgetronConnector con; - - std::string host("localhost"); - std::string port("9002"); - std::string out("dependency.xml"); - - static const ACE_TCHAR options[] = ACE_TEXT(":p:h:o:"); - - ACE_Get_Opt cmd_opts(argc, argv, options); - - int option; - while ((option = cmd_opts()) != EOF) - { - switch (option) { - case 'p': - port = std::string(cmd_opts.opt_arg()); - break; - case 'h': - host = std::string(cmd_opts.opt_arg()); - break; - case 'o': - out = std::string(cmd_opts.opt_arg()); - break; - case ':': - usage(); - GERROR("-%c requires an argument.\n", cmd_opts.opt_opt()); - return -1; - break; - default: - usage(); - GERROR("Command line parse error\n"); - return -1; - break; - } - } - - if (con.open(host,port) != 0) - { - GERROR("Unable to connect to the Gadgetron host\n"); - return -1; - } - - // need to register a reader - con.register_reader(GADGET_MESSAGE_DEPENDENCY_QUERY, new DependencyQueryReader(out)); - - //Tell Gadgetron which XML configuration to run. - if (con.send_gadgetron_configuration_file(std::string("gtquery.xml")) != 0) - { - GERROR("Unable to send XML configuration to the Gadgetron host\n"); - return -1; - } - - GadgetContainerMessage* m1 = - new GadgetContainerMessage(); - - m1->getObjectPtr()->id = GADGET_MESSAGE_CLOSE; - - if (con.putq(m1) == -1) - { - GERROR("Unable to put CLOSE package on queue\n"); - return -1; - } - - con.wait(); - - return 0; -} diff --git a/apps/gadgetron/CMakeLists.txt b/apps/gadgetron/CMakeLists.txt deleted file mode 100644 index 03913a915..000000000 --- a/apps/gadgetron/CMakeLists.txt +++ /dev/null @@ -1,110 +0,0 @@ -configure_file(gadgetron_config.in gadgetron_config.h) - -if (BUILD_TESTING) - add_subdirectory(test) -endif() - -add_executable(gadgetron - main.cpp - Server.cpp - Server.h - Connection.cpp - Connection.h - initialization.cpp - initialization.h - system_info.cpp - connection/config/Config.cpp - connection/config/Config.h - connection/ConfigConnection.cpp - connection/ConfigConnection.h - connection/StreamConnection.cpp - connection/StreamConnection.h - connection/Handlers.cpp - connection/Handlers.h - connection/Writers.cpp - connection/Writers.h - connection/VoidConnection.cpp - connection/VoidConnection.h - connection/HeaderConnection.cpp - connection/HeaderConnection.h - connection/Loader.cpp - connection/Loader.h - connection/Core.cpp - connection/Core.h - connection/SocketStreamBuf.cpp - connection/SocketStreamBuf.h - connection/nodes/Stream.cpp - connection/nodes/Stream.h - connection/nodes/Parallel.cpp - connection/nodes/Parallel.h - connection/nodes/Distributed.cpp - connection/nodes/Distributed.h - connection/nodes/External.cpp - connection/nodes/External.h - connection/core/Processable.h - connection/nodes/common/ExternalChannel.cpp - connection/nodes/common/ExternalChannel.h - connection/nodes/external/Matlab.cpp - connection/nodes/external/Matlab.h - connection/nodes/external/Julia.cpp - connection/nodes/external/Julia.h - connection/nodes/external/Python.cpp - connection/nodes/external/Python.h - connection/nodes/common/Discovery.cpp - connection/nodes/ParallelProcess.cpp - connection/nodes/ParallelProcess.h - connection/nodes/PureStream.cpp - connection/nodes/PureStream.h - connection/nodes/PureDistributed.cpp - connection/nodes/PureDistributed.h - connection/nodes/common/External.h - connection/nodes/common/External.cpp - connection/nodes/common/Serialization.cpp - connection/nodes/common/Serialization.h - connection/nodes/common/Configuration.cpp - connection/nodes/common/Configuration.h - connection/nodes/distributed/Pool.h - connection/nodes/distributed/Worker.cpp - connection/nodes/distributed/Worker.h - connection/nodes/common/Closer.h - connection/nodes/distributed/Pool.cpp - connection/core/Processable.cpp - storage.h - storage.cpp) - -target_link_libraries(gadgetron - gadgetron_core - gadgetron_core_writers - gadgetron_core_readers - gadgetron_toolbox_log - Boost::system - Boost::filesystem - Boost::program_options - ${CURL_LIBRARIES} - GTBLAS - ${CMAKE_DL_LIBS}) - -target_include_directories(gadgetron - PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_CURRENT_BINARY_DIR}) - - -if (REQUIRE_SIGNED_CONFIG) - target_link_libraries(gadgetron GTBabylon) -endif() - -if (BUILD_PYTHON_SUPPORT) - add_definitions("-DCOMPILING_WITH_PYTHON_SUPPORT") -endif () - -if (CUDA_FOUND) - target_link_libraries(gadgetron ${CUDA_LIBRARIES}) -endif () - -if (GPERFTOOLS_PROFILER) - message("Adding gperftools cpu profiler to gadgetron link assemblage.") - target_link_libraries(gadgetron ${GPERFTOOLS_PROFILER} ${GPERFTOOLS_TCMALLOC}) -endif () - -install(TARGETS gadgetron DESTINATION bin COMPONENT main) diff --git a/apps/gadgetron/Connection.cpp b/apps/gadgetron/Connection.cpp deleted file mode 100644 index dc060554d..000000000 --- a/apps/gadgetron/Connection.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Connection.h" -#include -#include - -#include "Context.h" - -#include "connection/Core.h" -#if !(_WIN32) -#include -#include -#include -#endif - -using namespace Gadgetron::Server::Connection; - -namespace Gadgetron::Server::Connection { - -#if _WIN32 || !NDEBUG || GADGETRON_DISABLE_FORK || __clang__ - - void handle( - const Gadgetron::Core::StreamContext::Paths& paths, - const Gadgetron::Core::StreamContext::Args& args, - const std::string& storage_address, - std::unique_ptr stream - ) { - auto thread = std::thread(handle_connection, std::move(stream), paths, args, storage_address); - thread.detach(); - } - -#else - - void handle( - const Gadgetron::Core::StreamContext::Paths& paths, - const Gadgetron::Core::StreamContext::Args& args, - const Gadgetron::Core::StreamContext::StorageAddress& storage_address, - std::unique_ptr stream - ) { - auto pid = fork(); - if (pid == 0) { - handle_connection(std::move(stream), paths, args, storage_address); - std::quick_exit(0); - } - auto listen_for_close = [](auto pid) {int status; waitpid(pid,&status,0);}; - std::thread t(listen_for_close,pid); - t.detach(); - } - -#endif -} diff --git a/apps/gadgetron/Connection.h b/apps/gadgetron/Connection.h deleted file mode 100644 index ca3d978c6..000000000 --- a/apps/gadgetron/Connection.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include -#include - -#include "Context.h" - -namespace Gadgetron::Server::Connection { - void handle( - const Gadgetron::Core::StreamContext::Paths &paths, - const Gadgetron::Core::StreamContext::Args &args, - const std::string& storage, - std::unique_ptr stream - ); -} diff --git a/apps/gadgetron/Server.cpp b/apps/gadgetron/Server.cpp deleted file mode 100644 index 157de1594..000000000 --- a/apps/gadgetron/Server.cpp +++ /dev/null @@ -1,42 +0,0 @@ - -#include - -#include - -#include "log.h" - -#include "Server.h" -#include "Connection.h" -#include "connection/SocketStreamBuf.h" -#include "system_info.h" - -using namespace boost::filesystem; -using namespace Gadgetron::Server; - - -Server::Server( - const boost::program_options::variables_map &args, - std::string address -) : args(args), storage_address(std::move(address)) {} - -[[noreturn]] void Server::serve() { - - Gadgetron::Core::Context::Paths paths{args["home"].as(), args["dir"].as()}; - GINFO_STREAM("Gadgetron home directory: " << paths.gadgetron_home); - GINFO_STREAM("Gadgetron working directory: " << paths.working_folder); - - boost::asio::io_context executor; - boost::asio::ip::tcp::endpoint local(Info::tcp_protocol(), args["port"].as()); - boost::asio::ip::tcp::acceptor acceptor(executor, local); - - acceptor.set_option(boost::asio::socket_base::reuse_address(true)); - - while(true) { - auto socket = std::make_unique(executor); - acceptor.accept(*socket); - - GINFO_STREAM("Accepted connection from: " << socket->remote_endpoint().address()); - - Connection::handle(paths, args, storage_address, Gadgetron::Connection::stream_from_socket(std::move(socket))); - } -} diff --git a/apps/gadgetron/Server.h b/apps/gadgetron/Server.h deleted file mode 100644 index 40a5727e7..000000000 --- a/apps/gadgetron/Server.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include -#include -#include - -namespace Gadgetron::Server { - - class Server { - public: - Server(const boost::program_options::variables_map &args, std::string storage_address); - - [[noreturn]] void serve(); - - private: - const boost::program_options::variables_map &args; - const std::string storage_address; - }; -} diff --git a/apps/gadgetron/StreamConsumer.h b/apps/gadgetron/StreamConsumer.h deleted file mode 100644 index 238260872..000000000 --- a/apps/gadgetron/StreamConsumer.h +++ /dev/null @@ -1,282 +0,0 @@ -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "Channel.h" -#include "connection/Core.h" -#include "connection/Loader.h" - -#include "MessageID.h" -#include "Reader.h" -#include "readers/AcquisitionBucketReader.h" -#include "readers/AcquisitionReader.h" -#include "readers/ImageReader.h" -#include "readers/IsmrmrdImageArrayReader.h" -#include "readers/WaveformReader.h" -#include "readers/TextReader.h" -#include "writers/AcquisitionBucketWriter.h" -#include "writers/ImageWriter.h" -#include "writers/IsmrmrdImageArrayWriter.h" -#include "writers/TextWriter.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Server; - -namespace -{ - -class ErrorThrower : public Connection::ErrorReporter -{ - public: - void operator()(const std::string& location, const std::string& message) override { - throw std::runtime_error(("[" + location + "] ERROR: " + message)); - } -}; - -std::filesystem::path find_config_path(const std::string& home_dir, const std::string& config_xml) -{ - auto config_path = std::filesystem::path(home_dir) / std::filesystem::path("share/gadgetron/config") / - std::filesystem::path(config_xml); - - if (!std::filesystem::is_regular_file(config_path)) { - throw std::runtime_error("Failed to find gadgetron configuration at the expected path: " + - config_path.string()); - } - - return config_path; -} - -} // namespace - -class StreamConsumer -{ -public: - StreamConsumer(const boost::program_options::variables_map& args, std::string storage_address) - : args_(args), storage_address_(storage_address) {} - ~StreamConsumer() {} - - void consume(std::istream& input_stream, std::ostream& output_stream, std::string config_xml_name) - { - Context::Paths paths{ - args_["home"].as().string(), - args_["dir"].as().string()}; - - ISMRMRD::IsmrmrdHeader hdr = consume_ismrmrd_header(input_stream, output_stream); - auto storage_spaces = setup_storage_spaces(storage_address_, hdr); - - auto context = StreamContext(hdr, paths, args_, storage_address_, storage_spaces); - auto loader = Connection::Loader(context); - auto config_path = find_config_path(args_["home"].as().string(), config_xml_name); - - std::ifstream file(config_path, std::ios::in | std::ios::binary); - if (!file.is_open()) { - throw std::runtime_error("Failed to open file at path: " + config_path.string()); - } - - auto config = Connection::parse_config(file); - file.close(); - - auto stream = loader.load(config.stream); - auto input_channel = make_channel(); - auto output_channel = make_channel(); - std::atomic processing = true; - - auto process_future = std::async(std::launch::async, [&]() { - try - { - ErrorThrower error_thrower; - Connection::ErrorHandler error_handler(error_thrower, std::string(__FILE__)); - stream->process(std::move(input_channel.input), std::move(output_channel.output), error_handler); - processing = false; - } - catch (const std::exception& exc) - { - { - // Induce a ChannelClosed exception upon readers of the channel. - auto destruct_me = std::move(output_channel.output); - } - processing = false; - throw; - } - }); - - auto input_future = std::async(std::launch::async, [&]() { - try - { - consume_input_messages(input_stream, input_channel); - } - catch(std::ios_base::failure& exc) - { - // Induce a ChannelClosed exception upon readers of the channel. - auto destruct_me = std::move(input_channel.output); - } - }); - - auto output_future = std::async(std::launch::async, [&]() - { - process_output_messages(output_channel, output_stream); - }); - - // Clean up and propagate exceptions if they occurred - input_future.get(); - output_future.get(); - process_future.get(); - } - - private: - - ISMRMRD::IsmrmrdHeader consume_ismrmrd_header(std::istream& input_stream, std::ostream& output_stream) - { - ISMRMRD::IsmrmrdHeader hdr; - MessageID id = MessageID::CLOSE; - input_stream.read(reinterpret_cast(&id), sizeof(MessageID)); - output_stream.write(reinterpret_cast(&id), sizeof(MessageID)); - - switch(id) - { - case MessageID::HEADER: - { - uint32_t hdr_size = 0; - input_stream.read(reinterpret_cast(&hdr_size), sizeof(uint32_t)); - output_stream.write(reinterpret_cast(&hdr_size), sizeof(uint32_t)); - - if(hdr_size > 0) - { - std::vector data(hdr_size); - - input_stream.read(data.data(), hdr_size); - output_stream.write(data.data(), hdr_size); - ISMRMRD::deserialize(std::string(data.data(), data.size()).c_str(), hdr); - } - else - { - throw std::runtime_error("Expected size > 0, got: " + std::to_string(hdr_size)); - } - - break; - } - default: - { - throw std::runtime_error("Expected HEADER enumeration, got: " + std::to_string(id)); - } - } - - return hdr; - } - - void consume_input_messages(std::istream& input_stream, ChannelPair& input_channel) - { - input_stream.exceptions(std::istream::failbit | std::istream::badbit | std::istream::eofbit); - - auto acq_reader = Readers::AcquisitionReader(); - auto wav_reader = Readers::WaveformReader(); - auto img_reader = Readers::ImageReader(); - auto img_array_reader = Readers::IsmrmrdImageArrayReader(); - auto acq_bucket_reader = Readers::AcquisitionBucketReader(); - auto text_reader = Readers::TextReader(); - bool closed = false; - - while (!input_stream.eof() && !closed) - { - MessageID id = MessageID::ERROR; - input_stream.read(reinterpret_cast(&id), sizeof(MessageID)); - - switch(id) - { - case MessageID::GADGET_MESSAGE_ISMRMRD_ACQUISITION: - { - input_channel.output.push_message(acq_reader.read(input_stream)); - break; - } - case MessageID::GADGET_MESSAGE_ISMRMRD_WAVEFORM: - { - input_channel.output.push_message(wav_reader.read(input_stream)); - break; - } - case MessageID::GADGET_MESSAGE_ISMRMRD_IMAGE: - { - input_channel.output.push_message(img_reader.read(input_stream)); - break; - } - case MessageID::GADGET_MESSAGE_ISMRMRD_IMAGE_ARRAY: - { - input_channel.output.push_message(img_array_reader.read(input_stream)); - break; - } - case MessageID::GADGET_MESSAGE_BUCKET: - { - input_channel.output.push_message(acq_bucket_reader.read(input_stream)); - break; - } - case MessageID::TEXT: - { - input_channel.output.push_message(text_reader.read(input_stream)); - break; - } - case MessageID::ERROR: - { - throw std::runtime_error("Got error while processing input stream"); - } - case MessageID::CLOSE: - { - auto destruct_me = std::move(input_channel.output); - closed = true; - break; - } - default: - { - throw std::runtime_error("Unsupported message ID: " + std::to_string(id)); - } - } - } - } - - void process_output_messages(ChannelPair& output_channel, std::ostream& output_stream) - { - auto writer = Writers::ImageWriter(); - auto img_array_writer = Writers::IsmrmrdImageArrayWriter(); - auto acq_bucket_writer = Writers::AcquisitionBucketWriter(); - auto text_writer = Writers::TextWriter(); - - while (true) - { - try - { - auto message = output_channel.input.pop(); - - if (convertible_to(message) ) - { - acq_bucket_writer.write(output_stream, std::move(message)); - } - else if (convertible_to(message) ) - { - img_array_writer.write(output_stream, std::move(message)); - } - else if (convertible_to(message) ) - { - text_writer.write(output_stream, std::move(message)); - } - else - { - writer.write(output_stream, std::move(message)); - } - } - catch (const ChannelClosed& exc) - { - break; - } - } - - MessageID close_id = MessageID::CLOSE; - output_stream.write(reinterpret_cast(&close_id), sizeof(MessageID)); - } - - boost::program_options::variables_map args_; - std::string storage_address_; -}; diff --git a/apps/gadgetron/connection/ConfigConnection.cpp b/apps/gadgetron/connection/ConfigConnection.cpp deleted file mode 100644 index f9550c7a3..000000000 --- a/apps/gadgetron/connection/ConfigConnection.cpp +++ /dev/null @@ -1,168 +0,0 @@ - -#include "ConfigConnection.h" - -#include -#include - -#include "gadgetron_config.h" - -#include "Handlers.h" -#include "HeaderConnection.h" -#include "config/Config.h" - -#include "io/primitives.h" -#include "Context.h" -#include "MessageID.h" -#include "Types.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Core::IO; -using namespace Gadgetron::Server::Connection; -using namespace Gadgetron::Server::Connection::Handlers; - -#ifdef USE_GTBABYLON -#include - - static std::unique_ptr open_and_verify_config(const std::string& filename) - { - auto filestream = std::ifstream(filename); - auto config_string = std::string(std::istreambuf_iterator(filestream),{}); - auto decoded = GTBabylon::decode_message(config_string); - return std::make_unique(decoded); - } -#else - static std::unique_ptr open_and_verify_config(const std::string& filename) - { - return std::make_unique(filename); - } -#endif - -namespace { - - using Header = Gadgetron::Core::StreamContext::Header; - - std::string read_filename_from_stream(std::istream &stream) { - auto buffer = read>(stream); - return std::string(buffer.data()); - } - - class ConfigHandler : public Handler { - public: - explicit ConfigHandler(std::function callback) - : callback(std::move(callback)) {} - - void handle_callback(std::istream &config_stream) { - - callback(parse_config(config_stream)); - } - - private: - std::function callback; - }; - - class ConfigReferenceHandler : public ConfigHandler { - public: - ConfigReferenceHandler( - std::function &&callback, - const StreamContext::Paths &paths - ) : ConfigHandler(callback), paths(paths) {} - - void handle(std::istream &stream, Gadgetron::Core::OutputChannel&) override { - auto recon_name = read_filename_from_stream(stream); - - // Look up if there is an environment variable with that name - if (getenv(recon_name.c_str())) { - recon_name = std::string(getenv(recon_name.c_str())); - } - - boost::filesystem::path filename = paths.gadgetron_home / GADGETRON_CONFIG_PATH / recon_name; - - GDEBUG_STREAM("Reading config file: " << filename); - - auto config_stream = open_and_verify_config(filename.string()); - handle_callback(*config_stream); - } - - private: - const StreamContext::Paths &paths; - }; - - class ConfigStringHandler : public ConfigHandler { - public: - explicit ConfigStringHandler(std::function &&callback) - : ConfigHandler(callback) {} - - void handle(std::istream &stream, Gadgetron::Core::OutputChannel& ) override { - std::stringstream config_stream(read_string_from_stream(stream)); - handle_callback(config_stream); - } - }; - - class ConfigStreamContext { - public: - Gadgetron::Core::optional config; - const StreamContext::Paths paths; - }; - - std::map> prepare_handlers( - std::function close, - ConfigStreamContext &context - ) { - std::map> handlers{}; - - auto config_callback = [=, &context](Config config) { - context.config = config; - close(); - }; - - handlers[FILENAME] = std::make_unique(config_callback, context.paths); - handlers[CONFIG] = std::make_unique(config_callback); - handlers[HEADER] = std::make_unique("Received ISMRMRD header before config file."); - handlers[QUERY] = std::make_unique(); - handlers[CLOSE] = std::make_unique(close); - - return handlers; - } -}; - - -namespace Gadgetron::Server::Connection::ConfigConnection { - - void process( - std::iostream &stream, - const Core::StreamContext::Paths &paths, - const Core::StreamContext::Args &args, - const Core::StreamContext::StorageAddress& sessions_address, - ErrorHandler &error_handler - ) { - GINFO_STREAM("Connection state: [CONFIG]"); - - ConfigStreamContext context{ - Core::none, - paths - }; - - auto channel = make_channel(); - - std::thread input_thread = start_input_thread( - stream, - std::move(channel.output), - [&](auto close) { return prepare_handlers(close, context); }, - error_handler - ); - - std::thread output_thread = start_output_thread( - stream, - std::move(channel.input), - default_writers, - error_handler - ); - - input_thread.join(); - output_thread.join(); - - if (context.config) { - HeaderConnection::process(stream, paths, args, sessions_address, context.config.value(), error_handler); - } - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/ConfigConnection.h b/apps/gadgetron/connection/ConfigConnection.h deleted file mode 100644 index 1f5d47df2..000000000 --- a/apps/gadgetron/connection/ConfigConnection.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include "Core.h" -#include "Context.h" - -namespace Gadgetron::Server::Connection::ConfigConnection { - void process( - std::iostream &stream, - const Core::StreamContext::Paths &paths, - const Core::StreamContext::Args &args, - const Core::StreamContext::StorageAddress& session_address, - ErrorHandler &error_handler - ); -} diff --git a/apps/gadgetron/connection/Core.cpp b/apps/gadgetron/connection/Core.cpp deleted file mode 100644 index d515f9981..000000000 --- a/apps/gadgetron/connection/Core.cpp +++ /dev/null @@ -1,89 +0,0 @@ - -#include "Core.h" - -#include "ConfigConnection.h" -#include "Writers.h" - -namespace { - - using namespace Gadgetron::Core; - using namespace Gadgetron::Server::Connection; - - class ErrorSender : public ErrorReporter { - public: - - - void operator()(const std::string &location, const std::string &message) override { - std::string error("[" + location + "] ERROR: " + message); - GERROR_STREAM(error); - { - std::lock_guard guard(error_lock); - errors.push_back(error); - } - } - - - void send_error_to_client(std::iostream &stream) { - Writers::TextWriter writer{}; - - for (auto &error : errors) { - writer.serialize(stream, error); - } - } - - private: - - std::mutex error_lock; - std::vector errors; - - }; - - - void send_close(std::iostream &stream) { - uint16_t close = 4; - stream.write(reinterpret_cast(&close), sizeof(close)); - } - -} - - -namespace Gadgetron::Server::Connection { - - void handle_connection( - std::unique_ptr stream, - Gadgetron::Core::StreamContext::Paths paths, - Gadgetron::Core::StreamContext::Args args, - Gadgetron::Core::StreamContext::StorageAddress storage_address - ) { - - stream->exceptions(std::istream::failbit | std::istream::badbit | std::istream::eofbit); - ErrorSender sender; - - ErrorHandler error_handler(sender, "Connection Main Thread"); - - error_handler.handle([&]() { - ConfigConnection::process(*stream, paths, args, storage_address, error_handler); - }); - - try { - sender.send_error_to_client(*stream); - send_close(*stream); - } - catch (std::runtime_error &e) { - GERROR_STREAM("Finalizing connection to client failed with the following error: " << e.what()); - } - catch (...) {} - - GINFO_STREAM("Connection state: [FINISHED]"); - } - - std::vector> default_writers() { - std::vector> writers{}; - - writers.emplace_back(std::make_unique()); - writers.emplace_back(std::make_unique()); - // TODO: writers.emplace_back(std::make_unique()); - - return std::move(writers); - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/Handlers.cpp b/apps/gadgetron/connection/Handlers.cpp deleted file mode 100644 index 4077f4eb2..000000000 --- a/apps/gadgetron/connection/Handlers.cpp +++ /dev/null @@ -1,103 +0,0 @@ - -#include -#include "Handlers.h" - -#include "system_info.h" - -#include "io/primitives.h" -#include "Response.h" - -namespace { - - using namespace Gadgetron::Server; - - std::string gadgetron_info() { - std::stringstream stream; - Info::print_system_information(stream); - return stream.str(); - } - - std::vector for_each_device(std::function fn) { - std::vector results{}; - for (int device = 0; device < Info::CUDA::cuda_device_count(); device++) { - results.push_back(fn(device)); - } - return results; - } - - std::string cuda_capabilities() { - return boost::algorithm::join(for_each_device(Info::CUDA::cuda_device_capabilities), ";"); - } - - std::string cuda_memory() { - return boost::algorithm::join( - for_each_device( - [](int device) { - return std::to_string(Info::CUDA::cuda_device_memory(device)); - } - ), - ";" - ); - } - - void initialize_with_default_queries(std::map> &answers) { - answers["ismrmrd::version"] = Info::ismrmrd_version; - answers["gadgetron::version"] = Info::gadgetron_version; - answers["gadgetron::build"] = Info::gadgetron_build; - answers["gadgetron::info"] = gadgetron_info; - answers["gadgetron::info::memory"] = []() { return std::to_string(Info::system_memory()); }; - answers["gadgetron::info::python"] = []() { return std::to_string(Info::python_support()); }; - answers["gadgetron::info::matlab"] = []() { return std::to_string(Info::matlab_support()); }; - answers["gadgetron::info::cuda"] = []() { return std::to_string(Info::CUDA::cuda_support()); }; - answers["gadgetron::cuda::devices"] = []() { return std::to_string(Info::CUDA::cuda_device_count()); }; - answers["gadgetron::cuda::driver"] = Info::CUDA::cuda_driver_version; - answers["gadgetron::cuda::runtime"] = Info::CUDA::cuda_runtime_version; - answers["gadgetron::cuda::memory"] = cuda_memory; - answers["gadgetron::cuda::capabilities"] = cuda_capabilities; - } -} - -namespace Gadgetron::Server::Connection::Handlers { - - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::IO; - - QueryHandler::QueryHandler() { - initialize_with_default_queries(answers); - } - - void QueryHandler::handle(std::istream &stream, Gadgetron::Core::OutputChannel& channel) { - - auto reserved = read(stream); - auto corr_id = read(stream); - auto query = read_string_from_stream(stream); - - if (reserved) { - throw std::runtime_error("Unsupported value in reserved bytes."); - } - - if (answers.count(query)) - channel.push(Response(corr_id, answers.at(query)())); - else - channel.push(Response(corr_id,"Unknown query")); - } - - - ErrorProducingHandler::ErrorProducingHandler(std::string message) - : message(std::move(message)) {} - - - void ErrorProducingHandler::handle(std::istream &, Gadgetron::Core::OutputChannel&) { - throw std::runtime_error(message); - } - - CloseHandler::CloseHandler(std::function callback) : callback(std::move(callback)) {} - - void CloseHandler::handle(std::istream &stream, Gadgetron::Core::OutputChannel& ) { callback(); } - - void TextLoggerHandler::handle(std::istream &stream, Gadgetron::Core::OutputChannel& ) { - auto msg = read_string_from_stream(stream); - GDEBUG_STREAM("TEXT MESSAGE RECEIVED: " << std::endl << msg); - } -} - diff --git a/apps/gadgetron/connection/Handlers.h b/apps/gadgetron/connection/Handlers.h deleted file mode 100644 index b00aef451..000000000 --- a/apps/gadgetron/connection/Handlers.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Channel.h" - -namespace Gadgetron::Server::Connection::Handlers { - - - class Handler { - public: - virtual void handle(std::istream &stream, Gadgetron::Core::OutputChannel &channel) = 0; - - virtual ~Handler() = default; - }; - - class QueryHandler : public Handler { - public: - QueryHandler(); - - void handle(std::istream &stream, Gadgetron::Core::OutputChannel &channel) override; - - std::map> answers; - }; - - class ErrorProducingHandler : public Handler { - public: - explicit ErrorProducingHandler(std::string message); - - void handle(std::istream &stream, Gadgetron::Core::OutputChannel &channel) override; - - private: - std::string message; - }; - - class CloseHandler : public Handler { - public: - explicit CloseHandler(std::function callback); - - void handle(std::istream &stream, Gadgetron::Core::OutputChannel &channel) override; - - private: - std::function callback; - }; - - class TextLoggerHandler : public Handler { - public: - void handle(std::istream &stream, Gadgetron::Core::OutputChannel& ) override; - }; -} - diff --git a/apps/gadgetron/connection/HeaderConnection.cpp b/apps/gadgetron/connection/HeaderConnection.cpp deleted file mode 100644 index 950ab986b..000000000 --- a/apps/gadgetron/connection/HeaderConnection.cpp +++ /dev/null @@ -1,123 +0,0 @@ - -#include "HeaderConnection.h" - -#include -#include - -#include "storage.h" -#include "Handlers.h" -#include "StreamConnection.h" -#include "VoidConnection.h" -#include "config/Config.h" - -#include "io/primitives.h" -#include "Context.h" -#include "MessageID.h" - -#define CONFIG_ERROR "Received second config file. Only one allowed." - -namespace { - - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::IO; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Handlers; - - using Header = Gadgetron::Core::StreamContext::Header; - - class HeaderHandler : public Handler { - public: - explicit HeaderHandler( - std::function header_callback - ) : header_callback(std::move(header_callback)) {} - - void handle(std::istream &stream, OutputChannel&) override { - std::string raw_header(read_string_from_stream(stream)); - - ISMRMRD::IsmrmrdHeader header{}; - ISMRMRD::deserialize(raw_header.c_str(), header); - - header_callback(header); - } - - private: - std::function header_callback; - }; - - class HeaderContext { - public: - Gadgetron::Core::optional
header; - const StreamContext::Paths paths; - }; - - std::map> prepare_handlers( - std::function close, - HeaderContext &context - ) { - std::map> handlers{}; - - auto header_callback = [=, &context](Header header) { - context.header = header; - close(); - }; - - handlers[FILENAME] = std::make_unique(CONFIG_ERROR); - handlers[CONFIG] = std::make_unique(CONFIG_ERROR); - handlers[HEADER] = std::make_unique(header_callback); - handlers[TEXT] = std::make_unique(); - handlers[QUERY] = std::make_unique(); - handlers[CLOSE] = std::make_unique(close); - - return handlers; - } -} - -namespace Gadgetron::Server::Connection::HeaderConnection { - - void process( - std::iostream &stream, - const Core::StreamContext::Paths &paths, - const Core::StreamContext::Args &args, - const Core::StreamContext::StorageAddress& storage_address, - const Config &config, - ErrorHandler &error_handler - ) { - GINFO_STREAM("Connection state: [HEADER]"); - - HeaderContext context{ - Core::none, - paths - }; - - auto channel = make_channel(); - - std::thread input_thread = start_input_thread( - stream, - std::move(channel.output), - [&](auto close) { return prepare_handlers(close, context); }, - error_handler - ); - - std::thread output_thread = start_output_thread( - stream, - std::move(channel.input), - default_writers, - error_handler - ); - - input_thread.join(); - output_thread.join(); - - auto header = context.header.value_or(Header()); - StreamContext stream_context{ - header, - paths, - args, - storage_address, - setup_storage_spaces(storage_address, header) - }; - - auto process = context.header ? StreamConnection::process : VoidConnection::process; - process(stream, stream_context, config, error_handler); - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/HeaderConnection.h b/apps/gadgetron/connection/HeaderConnection.h deleted file mode 100644 index 642ad1bbc..000000000 --- a/apps/gadgetron/connection/HeaderConnection.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Core.h" -#include "config/Config.h" - -#include "Context.h" - -namespace Gadgetron::Server::Connection::HeaderConnection { - void process( - std::iostream &stream, - const Core::StreamContext::Paths &paths, - const Core::StreamContext::Args &args, - const Core::StreamContext::StorageAddress& address, - const Config &config, - ErrorHandler &error_handler - ); -} diff --git a/apps/gadgetron/connection/Loader.cpp b/apps/gadgetron/connection/Loader.cpp deleted file mode 100644 index fa379a740..000000000 --- a/apps/gadgetron/connection/Loader.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "Loader.h" - -#include - -#include "nodes/Stream.h" - -namespace { - using namespace Gadgetron::Core; - - using reader_factory = std::unique_ptr(); - using writer_factory = std::unique_ptr(); -} - -namespace Gadgetron::Server::Connection { - - Loader::Loader(const StreamContext &context) : context(context) {} - - boost::dll::shared_library Loader::load_library(const std::string &shared_library_name) { - try - { - auto lib = boost::dll::shared_library( - shared_library_name, - boost::dll::load_mode::append_decorations | - boost::dll::load_mode::rtld_global | - boost::dll::load_mode::search_system_folders - ); - libraries.push_back(lib); - return lib; - } - catch( const std::exception & ex ) - { - std::cerr << ex.what() << std::endl; - throw; - } - } - - std::unique_ptr Loader::load(const Config::Reader &conf) { - auto factory = load_factory("reader_factory_export_", conf.classname, conf.dll); - return factory(); - } - - std::unique_ptr Loader::load(const Config::Writer &conf) { - auto factory = load_factory("writer_factory_export_", conf.classname, conf.dll); - return factory(); - } - - std::unique_ptr Loader::load(const Config::Stream &conf) { - return std::make_unique(conf, context, *this); - } - - std::map> Loader::load_readers(const std::vector &configs) { - - std::map> readers{}; - - for (auto &config : configs) { - auto reader = load(config); - uint16_t slot = config.slot.value_or(reader->slot()); - readers[slot] = std::move(reader); - } - - return readers; - } - - std::vector> Loader::load_writers(const std::vector &configs) { - - std::vector> writers{}; - - for (auto &writer_config : configs) { - writers.emplace_back(load(writer_config)); - } - - return std::move(writers); - } -} diff --git a/apps/gadgetron/connection/Loader.h b/apps/gadgetron/connection/Loader.h deleted file mode 100644 index b784fbe1d..000000000 --- a/apps/gadgetron/connection/Loader.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once - -#include -#include - -#include "config/Config.h" -#include "nodes/Stream.h" - -#include "Context.h" -#include "Reader.h" -#include "Writer.h" - -namespace Gadgetron::Server::Connection::Nodes { - class Stream; -} - -namespace Gadgetron::Server::Connection { - - class Loader { - using Context = Core::Context; - using Reader = Gadgetron::Core::Reader; - using Writer = Gadgetron::Core::Writer; - using Stream = Gadgetron::Server::Connection::Nodes::Stream; - - using GadgetProperties = Core::GadgetProperties; - public: - explicit Loader(const Core::StreamContext &); - - std::unique_ptr load(const Config::Reader &); - std::unique_ptr load(const Config::Writer &); - std::unique_ptr load(const Config::Stream &); - - template - using generic_factory = std::unique_ptr( - const Context &, - const GadgetProperties & - ); - - template - FACTORY& load_factory(const std::string &prefix, const std::string &classname, const std::string &dll) { - GINFO_STREAM("loading " << prefix << " - " << classname << " from the dll " << dll); - auto library = load_library(dll); - return library.get_alias(prefix + classname); - } - - std::map> load_readers(const std::vector &); - std::vector> load_writers(const std::vector &); - - template - std::map> load_readers(CONFIG config) { - return load_readers(config.readers); - } - - template - std::map> load_default_or_custom_readers(CONFIG config) { - - static const std::vector default_readers{ - Config::Reader { "gadgetron_core_readers", "AcquisitionReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "WaveformReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "ImageReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "BufferReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "IsmrmrdImageArrayReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "AcquisitionBucketReader", Core::none }, - Config::Reader { "gadgetron_core_readers", "TextReader", Core::none } - }; - - if (config.readers.empty()) - return load_readers(default_readers); - return load_readers(config.readers); - } - - template - std::vector> load_writers(CONFIG config) { - return load_writers(config.writers); - } - - template - std::vector> load_default_or_custom_writers(CONFIG config) { - - static const std::vector default_writers{ - Config::Writer { "gadgetron_core_writers", "AcquisitionWriter" }, - Config::Writer { "gadgetron_core_writers", "WaveformWriter" }, - Config::Writer { "gadgetron_core_writers", "ImageWriter" }, - Config::Writer { "gadgetron_core_writers", "BufferWriter" }, - Config::Writer { "gadgetron_core_writers", "IsmrmrdImageArrayWriter" }, - Config::Writer { "gadgetron_core_writers", "AcquisitionBucketWriter" } - }; - - if (config.writers.empty()) - return load_writers(default_writers); - return load_writers(config.writers); - } - - private: - boost::dll::shared_library load_library(const std::string &shared_library_name); - - const Core::StreamContext context; - - std::vector libraries = std::vector(); - }; -} - diff --git a/apps/gadgetron/connection/SocketStreamBuf.cpp b/apps/gadgetron/connection/SocketStreamBuf.cpp deleted file mode 100644 index eb2af385d..000000000 --- a/apps/gadgetron/connection/SocketStreamBuf.cpp +++ /dev/null @@ -1,125 +0,0 @@ -// -// Created by dchansen on 3/25/19. -// - -#include "SocketStreamBuf.h" - -#include - -#include "Types.h" - -#include -namespace { - using boost::asio::ip::tcp; - - std::unique_ptr connect_socket( - const std::string& host, const std::string& service, boost::asio::io_service& context) { - tcp::resolver resolver{ context }; - boost::system::error_code ec; - for (int remaining_attemps = 10; remaining_attemps > 0; remaining_attemps--) { - if (ec.failed()) { - GDEBUG_STREAM("Waiting to retry after receiving error when connecting to service " << service << " on host " << host << ": " << ec.message()); - std::this_thread::sleep_for(std::chrono::seconds(2)); - ec.clear(); - } - - auto result = resolver.resolve(host, service, ec); - if (ec.failed()) { - continue; - } - - auto socket = std::make_unique(context); - auto endpoint = *result; - socket->connect(endpoint, ec); - if (ec.failed()) { - continue; - } - return std::move(socket); - } - - throw std::runtime_error("Failed to connect to service " + service + " on host " + host + ": " + ec.message()); - } - - class SocketStreamBuf : public std::streambuf { - public: - explicit SocketStreamBuf(std::unique_ptr socket, size_t buffer_size = 1024); - - protected: - std::streamsize xsputn(const char_type* data, std::streamsize length) override; - - int sync() override; - int underflow() override; - int overflow(int ch = traits_type::eof()) override; - - private: - std::unique_ptr socket; - std::vector input_buffer; - std::vector output_buffer; - - /* Other members */ - }; - - int SocketStreamBuf::sync() { - return this->overflow() != traits_type::eof() ? 0 : -1; - } - int SocketStreamBuf::underflow() { - - auto elements_read = socket->read_some(boost::asio::buffer(this->eback(), input_buffer.size())); - - this->setg(this->eback(), this->eback(), this->eback() + elements_read); - return traits_type::to_int_type(*this->gptr()); - } - int SocketStreamBuf::overflow(int ch) { - if (this->pptr() != this->pbase()) { - boost::asio::write(*socket, boost::asio::buffer(this->pbase(), std::distance(this->pbase(), this->pptr()))); - this->setp(this->pbase(), this->epptr()); - } - if (ch != traits_type::eof()) { - this->sputc(ch); - } - - return 0; - } - - std::streamsize SocketStreamBuf::xsputn(const char* data, std::streamsize length) { - this->overflow(); - return boost::asio::write(*socket, boost::asio::buffer(data, length)); - } - SocketStreamBuf::SocketStreamBuf(std::unique_ptr socket, size_t buffer_size) - : socket(std::move(socket)), input_buffer(buffer_size), output_buffer(buffer_size) { - this->setg(input_buffer.data(), input_buffer.data() + buffer_size, input_buffer.data() + buffer_size); - this->setp(output_buffer.data(), output_buffer.data() + buffer_size); - } - - using namespace Gadgetron::Connection; - class SocketStream : public std::iostream { - public: - explicit SocketStream(std::unique_ptr socket) - : std::iostream(new SocketStreamBuf(std::move(socket))) { - buffer = std::unique_ptr(static_cast(this->rdbuf())); - } - - SocketStream(const std::string& host, const std::string& service, - std::shared_ptr io_service = std::make_shared()) - : SocketStream(connect_socket(host, service, *io_service)) { - this->io_service = io_service; - } - - ~SocketStream() override = default; - - private: - std::shared_ptr io_service; - std::unique_ptr buffer; - }; -} - - -std::unique_ptr Gadgetron::Connection::stream_from_socket( - std::unique_ptr socket) { - return std::make_unique(std::move(socket)); -} - -std::unique_ptr Gadgetron::Connection::remote_stream( - const std::string& host, const std::string& service) { - return std::make_unique(host, service); -} diff --git a/apps/gadgetron/connection/SocketStreamBuf.h b/apps/gadgetron/connection/SocketStreamBuf.h deleted file mode 100644 index 8a37202a4..000000000 --- a/apps/gadgetron/connection/SocketStreamBuf.h +++ /dev/null @@ -1,10 +0,0 @@ - -#pragma once -#include -#include - -namespace Gadgetron::Connection { - - std::unique_ptr stream_from_socket(std::unique_ptr socket); - std::unique_ptr remote_stream(const std::string & host, const std::string& service); -} \ No newline at end of file diff --git a/apps/gadgetron/connection/StreamConnection.cpp b/apps/gadgetron/connection/StreamConnection.cpp deleted file mode 100644 index 12e2d111c..000000000 --- a/apps/gadgetron/connection/StreamConnection.cpp +++ /dev/null @@ -1,110 +0,0 @@ - -#include - -#include "StreamConnection.h" - -#include "Handlers.h" -#include "Writers.h" -#include "Loader.h" - -#include "io/primitives.h" -#include "Reader.h" -#include "Channel.h" -#include "Context.h" -#include "MessageID.h" - -static constexpr const char* CONFIG_ERROR = "Received second config file. Only one allowed."; -static constexpr const char* HEADER_ERROR = "Received second ISMRMRD header. Only one allowed."; - -namespace { - - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::IO; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Writers; - using namespace Gadgetron::Server::Connection::Handlers; - - class ReaderHandler : public Handler { - public: - ReaderHandler(std::unique_ptr &&reader) - : reader(std::move(reader)) {} - - void handle(std::istream &stream, OutputChannel &channel) override { - channel.push_message(reader->read(stream)); - } - - std::unique_ptr reader; - std::shared_ptr channel; - }; - - std::map> prepare_handlers( - std::function close, - std::map> &readers - ) { - std::map> handlers{}; - - handlers[FILENAME] = std::make_unique(CONFIG_ERROR); - handlers[CONFIG] = std::make_unique(CONFIG_ERROR); - handlers[HEADER] = std::make_unique(HEADER_ERROR); - handlers[TEXT] = std::make_unique(); - handlers[QUERY] = std::make_unique(); - handlers[CLOSE] = std::make_unique(close); - - for (auto &pair : readers) { - handlers[pair.first] = std::make_unique(std::move(pair.second)); - } - - return handlers; - } - - std::vector> prepare_writers(std::vector> &writers) { - auto ws = default_writers(); - for (auto &writer : writers) { ws.emplace_back(std::move(writer)); } - return ws; - } -} - - -namespace Gadgetron::Server::Connection::StreamConnection { - - void process( - std::iostream &stream, - const StreamContext &context, - const Config &config, - ErrorHandler &error_handler - ) { - GINFO_STREAM("Connection state: [STREAM]"); - - Loader loader{context}; - - auto ichannel = make_channel(); - auto ochannel = make_channel(); - - auto readers = loader.load_readers(config); - auto writers = loader.load_writers(config); - - std::thread input_thread = start_input_thread( - stream, - std::move(ichannel.output), - [&](auto close) { return prepare_handlers(close, readers); }, - error_handler - ); - - std::thread output_thread = start_output_thread( - stream, - std::move(ochannel.input), - [&]() { return prepare_writers(writers); }, - error_handler - ); - - auto processable = loader.load(config.stream); - processable->process( - std::move(ichannel.input), - std::move(ochannel.output), - error_handler - ); - - input_thread.join(); - output_thread.join(); - } -} diff --git a/apps/gadgetron/connection/StreamConnection.h b/apps/gadgetron/connection/StreamConnection.h deleted file mode 100644 index 69c01d44a..000000000 --- a/apps/gadgetron/connection/StreamConnection.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "Core.h" -#include "config/Config.h" - -#include "Context.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection::StreamConnection { - void process( - std::iostream &stream, - const StreamContext &context, - const Config &config, - ErrorHandler &error_handler - ); -} - - diff --git a/apps/gadgetron/connection/VoidConnection.cpp b/apps/gadgetron/connection/VoidConnection.cpp deleted file mode 100644 index 9e953b670..000000000 --- a/apps/gadgetron/connection/VoidConnection.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "VoidConnection.h" - -#include "Handlers.h" -#include "Writers.h" -#include "Loader.h" - -#include "io/primitives.h" -#include "Reader.h" -#include "Channel.h" -#include "Context.h" - - -namespace { - - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::IO; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Writers; - using namespace Gadgetron::Server::Connection::Handlers; - - std::vector> prepare_writers(std::vector> &writers) { - auto ws = default_writers(); - - for (auto &writer : writers) { ws.emplace_back(std::move(writer)); } - - return std::move(ws); - } -} - -namespace Gadgetron::Server::Connection::VoidConnection { - - void process( - std::iostream &stream, - const Core::StreamContext &context, - const Config &config, - ErrorHandler &error_handler - ) { - GINFO_STREAM("Connection state: [VOID]"); - - Loader loader{context}; - - auto ochannel = make_channel(); - auto ichannel = make_channel(); - - auto node = loader.load(config.stream); - auto writers = loader.load_writers(config); - - std::thread output_thread = start_output_thread( - stream, - std::move(ochannel.input), - [&writers]() { return prepare_writers(writers); }, - error_handler - ); - - { // This.... this is not nice. - OutputChannel removed = std::move(ichannel.output); - } - - node->process(std::move(ichannel.input), std::move(ochannel.output), error_handler); - output_thread.join(); - } -} diff --git a/apps/gadgetron/connection/VoidConnection.h b/apps/gadgetron/connection/VoidConnection.h deleted file mode 100644 index 5d179ac25..000000000 --- a/apps/gadgetron/connection/VoidConnection.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Core.h" -#include "config/Config.h" - -#include "Context.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection::VoidConnection { - void process( - std::iostream &stream, - const StreamContext &context, - const Config &config, - ErrorHandler &error_handler - ); -} diff --git a/apps/gadgetron/connection/Writers.cpp b/apps/gadgetron/connection/Writers.cpp deleted file mode 100644 index b94710aff..000000000 --- a/apps/gadgetron/connection/Writers.cpp +++ /dev/null @@ -1,34 +0,0 @@ - - -#include "Writers.h" - -namespace Gadgetron::Server::Connection::Writers { - - void ResponseWriter::serialize( - std::ostream &stream, - const Gadgetron::Core::Response& response - ) { - uint16_t message_id = 7; - uint64_t correlation_id = response.correlation_id; - uint64_t response_length = response.response.size(); - - stream.write(reinterpret_cast(&message_id), sizeof(message_id)); - stream.write(reinterpret_cast(&correlation_id), sizeof(correlation_id)); - stream.write(reinterpret_cast(&response_length), sizeof(response_length)); - stream.write(response.response.c_str(), response.response.size()); - } - - - void TextWriter::serialize( - std::ostream &stream, - const std::string& message - ) { - uint16_t message_id = 5; - - auto length = uint32_t(message.size()); - - stream.write(reinterpret_cast(&message_id), sizeof(message_id)); - stream.write(reinterpret_cast(&length), sizeof(length)); - stream.write(message.data(), length); - } -} diff --git a/apps/gadgetron/connection/Writers.h b/apps/gadgetron/connection/Writers.h deleted file mode 100644 index 4aa6feb36..000000000 --- a/apps/gadgetron/connection/Writers.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "Writer.h" -#include "Response.h" - -namespace Gadgetron::Server::Connection::Writers { - - class ResponseWriter : public Core::TypedWriter { - public: - void serialize(std::ostream &, const Core::Response& ) override; - }; - - class TextWriter : public Core::TypedWriter { - public: - void serialize(std::ostream &, const std::string&) override; - }; -} diff --git a/apps/gadgetron/connection/config/Config.h b/apps/gadgetron/connection/config/Config.h deleted file mode 100644 index 1d68fc50f..000000000 --- a/apps/gadgetron/connection/config/Config.h +++ /dev/null @@ -1,112 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Types.h" - -namespace Gadgetron::Server::Connection { - - struct Config { - - struct Gadget; - struct External; - struct Parallel; - struct Distributed; - struct ParallelProcess; - struct PureDistributed; - using Node = Core::variant; - - template - static std::string name(CONFIG config) { - return config.name.empty() ? config.classname : config.name; - } - - struct Reader { - std::string dll, classname; - Core::optional slot; - }; - - struct Writer { - std::string dll, classname; - }; - - struct Stream { - std::string key; - std::vector nodes; - }; - - struct PureStream{ - std::vector gadgets; - }; - - struct Gadget { - std::string name, dll, classname; - std::unordered_map properties; - Gadget(std::string name, std::string dll, std::string classname, std::unordered_map properties): - name(std::move(name)), dll(std::move(dll)), classname(std::move(classname)), properties(std::move(properties)) - { - - } - }; - - struct Execute { - std::string name, type; - Core::optional target; - }; - - struct Connect { - std::string address, port; - }; - - using Action = Core::variant; - - struct External { - Action action; - - struct Configuration; - std::shared_ptr configuration; - - std::vector readers; - std::vector writers; - }; - - struct Branch : Gadget { using Gadget::Gadget;}; - struct Merge : Gadget { using Gadget::Gadget;}; - - struct Parallel { - Branch branch; - Merge merge; - std::vector streams; - }; - - struct PureDistributed { - std::vector readers; - std::vector writers; - PureStream stream; - }; - - struct ParallelProcess { - size_t workers = 0; - PureStream stream; - }; - - struct Distributor : Gadget { using Gadget::Gadget;}; - - struct Distributed { - std::vector readers; - std::vector writers; - Distributor distributor; - Stream stream; - }; - - std::vector readers; - std::vector writers; - Stream stream; - }; - - Config parse_config(std::istream &stream); - std::string serialize_config(const Config& config); - std::string serialize_config(const Config::External& external_config); -} diff --git a/apps/gadgetron/connection/nodes/Distributed.cpp b/apps/gadgetron/connection/nodes/Distributed.cpp deleted file mode 100644 index 926fadfbe..000000000 --- a/apps/gadgetron/connection/nodes/Distributed.cpp +++ /dev/null @@ -1,184 +0,0 @@ - -#include -#include - -#include "Distributed.h" - -#include "common/Closer.h" -#include "common/Discovery.h" -#include "common/ExternalChannel.h" - -#include "io/iostream_operators.h" - -namespace { - using namespace Gadgetron; - using namespace Gadgetron::Core; - using namespace Gadgetron::Core::Distributed; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Nodes; - - class ChannelWrapper { - public: - ChannelWrapper( - const Address &peer, - std::shared_ptr serialization, - std::shared_ptr configuration - ); - - void process_input(GenericInputChannel input); - void process_output(OutputChannel output); - - private: - std::shared_ptr external; - }; - - ChannelWrapper::ChannelWrapper( - const Address &peer, - std::shared_ptr serialization, - std::shared_ptr configuration - ) { - GINFO_STREAM("Connecting to peer: " << peer); - external = std::make_shared( - connect(peer, configuration), - std::move(serialization), - std::move(configuration) - ); - } - - void ChannelWrapper::process_input(GenericInputChannel input) { - auto closer = make_closer(external); - for (auto message : input) { - external->push_message(std::move(message)); - } - } - - void ChannelWrapper::process_output(OutputChannel output) { - while(true) { - output.push_message(external->pop()); - GDEBUG_STREAM("Pushed message to distributed output."); - } - } - - class ChannelCreatorImpl : public ChannelCreator { - public: - OutputChannel create() override; - void join(); - - ChannelCreatorImpl( - std::shared_ptr serialization, - std::shared_ptr configuration, - OutputChannel output_channel, - ErrorHandler& error_handler - ); - - private: - Address next_peer(); - - OutputChannel output; - - std::shared_ptr serialization; - std::shared_ptr configuration; - - std::list
peers; - std::list threads; - - ErrorHandler error_handler; - }; - - ChannelCreatorImpl::ChannelCreatorImpl( - std::shared_ptr serialization, - std::shared_ptr configuration, - OutputChannel output_channel, - ErrorHandler &error_handler - ) : serialization(std::move(serialization)), - configuration(std::move(configuration)), - output(std::move(output_channel)), - error_handler(error_handler, "Distributed") { - - auto ps = discover_peers(); - std::copy(ps.begin(), ps.end(), std::back_inserter(peers)); - } - - OutputChannel ChannelCreatorImpl::create() { - - auto pair = Core::make_channel(); - - auto channel = std::make_shared( - next_peer(), - serialization, - configuration - ); - - threads.push_back(error_handler.run( - [=](auto in) { channel->process_input(std::move(in)); }, - std::move(pair.input) - )); - threads.push_back(error_handler.run( - [=](auto out) { channel->process_output(std::move(out)); }, - Core::split(output) - )); - - return std::move(pair.output); - } - - void ChannelCreatorImpl::join() { - for (auto &thread : threads) thread.join(); - } - - Address ChannelCreatorImpl::next_peer() { - auto peer = peers.front(); peers.pop_front(); - peers.push_back(peer); - return peer; - } -} - -namespace { - std::unique_ptr load_distributor( - Loader &loader, - const Core::Context& context, - const Config::Distributor& conf - ) { - auto factory = loader.load_factory>( - "distributor_factory_export_", conf.classname, conf.dll); - return factory(context, conf.properties); - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - void Distributed::process( - Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler& error_handler - ) { - auto channel_creator = ChannelCreatorImpl { - serialization, - configuration, - Core::split(output), - error_handler - }; - - distributor->process(std::move(input), channel_creator, std::move(output)); - channel_creator.join(); - } - - Distributed::Distributed( - const Config::Distributed& config, - const Core::StreamContext& context, - Loader& loader - ) : serialization(std::make_shared( - loader.load_readers(config), - loader.load_writers(config) - )), - configuration(std::make_shared( - context, - config - )), - distributor(load_distributor(loader, context, config.distributor)) {} - - const std::string& Distributed::name() { - static const std::string n = "Distributed"; - return n; - } -} - diff --git a/apps/gadgetron/connection/nodes/Distributed.h b/apps/gadgetron/connection/nodes/Distributed.h deleted file mode 100644 index 54a66382c..000000000 --- a/apps/gadgetron/connection/nodes/Distributed.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#include "common/Configuration.h" -#include "common/Serialization.h" -#include "distributed/Distributor.h" - -#include "connection/core/Processable.h" - -#include "Channel.h" -#include "Stream.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class Distributed : public Processable { - public: - Distributed( - const Config::Distributed &, - const Core::StreamContext &, - Loader & - ); - - void process( - Core::GenericInputChannel input, - Core::OutputChannel output, - ErrorHandler &error_handler - ) override; - - const std::string &name() override; - - private: - std::unique_ptr distributor; - - const std::shared_ptr serialization; - const std::shared_ptr configuration; - }; -} - - - diff --git a/apps/gadgetron/connection/nodes/External.cpp b/apps/gadgetron/connection/nodes/External.cpp deleted file mode 100644 index 0e06db920..000000000 --- a/apps/gadgetron/connection/nodes/External.cpp +++ /dev/null @@ -1,160 +0,0 @@ -#include "External.h" - -#include "common/Closer.h" -#include "common/ExternalChannel.h" - -#include "connection/SocketStreamBuf.h" -#include "connection/config/Config.h" - -#include "external/Python.h" -#include "external/Matlab.h" -#include "external/Julia.h" - -#include -#include -#include "system_info.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Server::Connection; -using namespace Gadgetron::Server::Connection::Nodes; - -using tcp = boost::asio::ip::tcp; - -namespace { - - const std::map> modules{ - {"python", start_python_module}, - {"matlab", start_matlab_module}, - {"julia", start_julia_module} - - }; - - void process_input(GenericInputChannel input, std::shared_ptr external, OutputChannel bypass ) { - auto closer = make_closer(external); - for (auto message : input) { - if (external->accepts(message)) { - external->push_message(std::move(message)); - } else { - bypass.push_message(std::move(message)); - } - } - } - - void process_output(OutputChannel output, std::shared_ptr external) { - while(true) { - output.push_message(external->pop()); - } - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - void External::monitor_child( - std::shared_ptr child, - std::shared_ptr acceptor - ) { - child->wait(); - io_service.dispatch([=]() { acceptor->close(); }); - } - - std::shared_ptr External::open_connection(Config::Connect connect, const StreamContext &context) { - GINFO_STREAM("Connecting to external module on address: " << connect.address << ":" << connect.port); - return std::make_shared( - Gadgetron::Connection::remote_stream(connect.address, connect.port), - serialization, - configuration - ); - } - - std::shared_ptr External::open_connection(Config::Execute execute, const StreamContext &context) { - - tcp::endpoint endpoint(Info::tcp_protocol(), 0); - auto acceptor = std::make_shared(io_service, endpoint); - - auto port = acceptor->local_endpoint().port(); - boost::algorithm::to_lower(execute.type); - - GINFO_STREAM("Waiting for external module '" << execute.name << "' on port: " << port); - - auto child = std::make_shared(modules.at(execute.type)(execute, port, context)); - - monitors.child = std::async( - std::launch::async, - [=](auto child, auto acceptor) { monitor_child(std::move(child), std::move(acceptor)); }, - child, - acceptor - ); - - auto socket = std::make_unique(io_service); - auto future_socket = acceptor->async_accept(*socket, boost::asio::use_future); - - io_service.run(); - future_socket.get(); - - GINFO_STREAM("Connected to external module '" << execute.name << "' on port: " << port); - - auto stream = Gadgetron::Connection::stream_from_socket(std::move(socket)); - auto external_channel = std::make_shared( - std::move(stream), - serialization, - configuration - ); - - return external_channel; - } - - std::shared_ptr External::open_external_channel( - const Config::External &config, - const StreamContext &context - ) { - return Core::visit( - [&, this](auto action) { return this->open_connection(action, context); }, - config.action - ); - } - - External::External( - const Config::External &config, - const Core::StreamContext &context, - Loader &loader - ) : serialization(std::make_shared( - loader.load_default_or_custom_readers(config), - loader.load_default_or_custom_writers(config) - )), - configuration(std::make_shared( - context, - config - )) { - channel = std::async( - std::launch::async, - [=](auto config, auto context) { return open_external_channel(config, context); }, - config, - context - ); - } - - void External::process( - InputChannel input, - OutputChannel output, - ErrorHandler &error_handler - ) { - std::shared_ptr external = channel.get(); - - auto input_thread = error_handler.run( - [=](auto input, auto output) { ::process_input(std::move(input), external, std::move(output)); }, - std::move(input), split(output) - ); - - auto output_thread = error_handler.run( - [=](auto output) { ::process_output(std::move(output), external); }, - std::move(output) - ); - - input_thread.join(); output_thread.join(); - } - - const std::string &External::name() { - static const std::string name = "external"; - return name; - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/External.h b/apps/gadgetron/connection/nodes/External.h deleted file mode 100644 index d52b47db3..000000000 --- a/apps/gadgetron/connection/nodes/External.h +++ /dev/null @@ -1,57 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "connection/config/Config.h" - -#include "Stream.h" -#include "connection/core/Processable.h" - -#include "common/ExternalChannel.h" -#include "common/Serialization.h" -#include "common/Configuration.h" - -#include "parallel/Branch.h" -#include "parallel/Merge.h" - -#include "Channel.h" -#include "Context.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class External : public Processable { - public: - using InputChannel = Core::GenericInputChannel; - using OutputChannel = Core::OutputChannel; - - External(const Config::External &, const Core::StreamContext &, Loader &); - - void process( - InputChannel input, - OutputChannel output, - ErrorHandler &error_handler - ) override; - - const std::string& name() override; - - private: - std::shared_ptr open_connection(Config::Execute, const Core::StreamContext &); - std::shared_ptr open_connection(Config::Connect, const Core::StreamContext &); - std::shared_ptr open_external_channel(const Config::External &, const Core::StreamContext &); - - void monitor_child(std::shared_ptr, std::shared_ptr); - - std::future> channel; - std::shared_ptr serialization; - std::shared_ptr configuration; - - boost::asio::io_service io_service; - - struct { - std::future child; - } monitors; - - }; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/PureDistributed.cpp b/apps/gadgetron/connection/nodes/PureDistributed.cpp deleted file mode 100644 index 1d17fc8ff..000000000 --- a/apps/gadgetron/connection/nodes/PureDistributed.cpp +++ /dev/null @@ -1,118 +0,0 @@ - -#include "PureDistributed.h" - -#include "common/Discovery.h" -#include "common/Closer.h" - -#include "distributed/Worker.h" -#include "distributed/Pool.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Server::Connection; -using namespace Gadgetron::Server::Connection::Nodes; - - -namespace { - - std::unique_ptr connect_to_peer( - Address address, - std::shared_ptr serialization, - std::shared_ptr configuration - ) { - return std::make_unique(std::move(address), std::move(serialization), std::move(configuration)); - } - - std::list>> begin_connecting_to_peers( - std::future> addresses, - std::shared_ptr serialization, - std::shared_ptr configuration - ) { - std::list>> workers; - for (auto address : addresses.get()) { - workers.emplace_back(std::async(std::launch::async, connect_to_peer, address, serialization, configuration)); - } - return std::move(workers); - } - - std::list> finish_connecting_to_peers( - std::list>> pending_workers - ) { - std::list> workers; - for (auto &pending_worker : pending_workers) { - auto status = pending_worker.wait_for(std::chrono::seconds(60)); - if (status == std::future_status::ready) { - try { - workers.emplace_back(pending_worker.get()); - } - catch (std::exception &e) { - GWARN_STREAM("Failed connecting to worker with error: " << e.what()); - } - } - } - - if (workers.empty()) throw std::runtime_error("Could not connect to ANY workers; cannot distribute work."); - - return std::move(workers); - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - - void PureDistributed::process_outbound(GenericInputChannel input, std::shared_ptr jobs) { - - auto closer = make_closer(jobs); - - auto workers = Pool(finish_connecting_to_peers(std::move(pending_workers))); - - for (auto message : input) { - jobs->push(workers.push(std::move(message))); - } - } - - void PureDistributed::process_inbound(OutputChannel output, std::shared_ptr jobs) { - while (true) { - output.push_message(jobs->pop().get()); - } - } - - void PureDistributed::process(GenericInputChannel input, - OutputChannel output, - ErrorHandler& error_handler - ) { - auto queue = std::make_shared(); - - auto outbound = error_handler.run( - [&](auto input) { process_outbound(std::move(input), queue); }, - std::move(input) - ); - - auto inbound = error_handler.run( - [&](auto output) { process_inbound(std::move(output), queue); }, - std::move(output) - ); - - outbound.join(); inbound.join(); - } - - PureDistributed::PureDistributed( - const Config::PureDistributed& config, - const Core::StreamContext& context, - Loader& loader - ) : serialization(std::make_shared( - loader.load_readers(config), - loader.load_writers(config) - )), - configuration(std::make_shared( - context, - config - )) { - pending_workers = begin_connecting_to_peers(std::async(discover_peers), serialization, configuration); - } - - - const std::string& Gadgetron::Server::Connection::Nodes::PureDistributed::name() { - const static std::string n = "PureDistributed"; - return n; - } -} diff --git a/apps/gadgetron/connection/nodes/PureDistributed.h b/apps/gadgetron/connection/nodes/PureDistributed.h deleted file mode 100644 index 0973748e5..000000000 --- a/apps/gadgetron/connection/nodes/PureDistributed.h +++ /dev/null @@ -1,51 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Reader.h" -#include "Writer.h" -#include "connection/core/Processable.h" - -#include "connection/Loader.h" -#include "connection/config/Config.h" - -#include "common/Serialization.h" -#include "common/Configuration.h" - -#include "distributed/Worker.h" -#include "distributed/Pool.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class PureDistributed : public Processable { - - public: - PureDistributed( - const Config::PureDistributed &, - const Core::StreamContext &, - Loader & - ); - - void process( - Core::GenericInputChannel, - Core::OutputChannel, - ErrorHandler & - ) override; - - const std::string& name() override; - - private: - using Job = std::future; - using Queue = Core::MPMCChannel; - - void process_outbound(Core::GenericInputChannel, std::shared_ptr); - void process_inbound(Core::OutputChannel, std::shared_ptr); - - std::shared_ptr serialization; - std::shared_ptr configuration; - - std::list>> pending_workers; - }; -} diff --git a/apps/gadgetron/connection/nodes/common/Closer.h b/apps/gadgetron/connection/nodes/common/Closer.h deleted file mode 100644 index 73ba3987f..000000000 --- a/apps/gadgetron/connection/nodes/common/Closer.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -#include "log.h" - -namespace Gadgetron::Server::Connection::Nodes { - - template - class Closer{ - public: - ~Closer() { closed->close(); }; - explicit Closer(CLOSED& closed) : closed(closed) {} - private: - CLOSED& closed; - }; - - template - static Closer make_closer(CLOSED& cls) { return Closer(cls); } - -} diff --git a/apps/gadgetron/connection/nodes/common/Configuration.cpp b/apps/gadgetron/connection/nodes/common/Configuration.cpp deleted file mode 100644 index 15fbbd80d..000000000 --- a/apps/gadgetron/connection/nodes/common/Configuration.cpp +++ /dev/null @@ -1,74 +0,0 @@ -#include "Configuration.h" - -#include -#include - -#include "io/primitives.h" -#include "MessageID.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection::Nodes { - - using Serializable = Core::variant; - - static void send_header(std::iostream &stream, const Context::Header &header) { - std::stringstream strstream; - ISMRMRD::serialize(header, strstream); - - IO::write(stream, HEADER); - IO::write_string_to_stream(stream, strstream.str()); - } - - static void send_config(std::iostream &stream, const Serializable &config) { - Core::visit( - [&stream](auto &config) { - IO::write(stream, CONFIG); - IO::write_string_to_stream(stream, serialize_config(config)); - }, - config - ); - } - - void Configuration::send(std::iostream &stream) const { - send_config(stream, config); - send_header(stream, context.header); - } - - Configuration::Configuration( - Core::StreamContext context, - Config config - ) : context(std::move(context)), config{config} {} - - Configuration::Configuration( - Core::StreamContext context, - Config::External config - ) : context(std::move(context)), config{config} {} - - Configuration::Configuration( - Core::StreamContext context, - Config::Distributed config - ) : Configuration( - std::move(context), - Config{ - config.readers, - config.writers, - config.stream - } - ) {} - - Configuration::Configuration( - Core::StreamContext context, - Config::PureDistributed config - ) : Configuration( - std::move(context), - Config{ - config.readers, - config.writers, - Config::Stream { - "PureStream", - std::vector(config.stream.gadgets.begin(), config.stream.gadgets.end()) - } - } - ) {} -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/Configuration.h b/apps/gadgetron/connection/nodes/common/Configuration.h deleted file mode 100644 index 445c90c1b..000000000 --- a/apps/gadgetron/connection/nodes/common/Configuration.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "connection/config/Config.h" - -#include "Context.h" -#include "Types.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class Configuration { - public: - const Core::StreamContext context; - - void send(std::iostream &stream) const; - - Configuration(Core::StreamContext context, Config config); - Configuration(Core::StreamContext context, Config::External config); - Configuration(Core::StreamContext context, Config::Distributed config); - Configuration(Core::StreamContext context, Config::PureDistributed config); - - private: - Core::variant config; - }; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/Discovery.cpp b/apps/gadgetron/connection/nodes/common/Discovery.cpp deleted file mode 100644 index 77dad16e9..000000000 --- a/apps/gadgetron/connection/nodes/common/Discovery.cpp +++ /dev/null @@ -1,109 +0,0 @@ -#include "Discovery.h" - -#include - -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include - -BOOST_FUSION_ADAPT_STRUCT( - Gadgetron::Server::Connection::Nodes::Remote, - (std::string, address)(std::string, port) -) - -namespace { - using namespace Gadgetron::Server; - using namespace Gadgetron::Server::Connection::Nodes; - - std::vector
parse_remote_workers(std::string input) - { - namespace qi = boost::spirit::qi; - namespace ascii = boost::spirit::ascii; - using ascii::space; - using qi::_1; - using qi::char_; - using qi::double_; - using qi::lexeme; - using qi::phrase_parse; - - auto first = input.begin(), last = input.end(); - - qi::rule ipv6 = '[' >> lexeme[+(char_ - ']')] >> ']'; - qi::rule address_rule = - '"' >> - (lexeme[+(char_ - (lexeme[':'] | lexeme[']'] | lexeme['[']))] | ipv6) >> - ':' >> - (lexeme[+(char_ - '"')]) >> - '"'; - - auto result = std::vector
{}; - bool r = phrase_parse( - first, - last, - ( '[' >> address_rule % ',' >> ']' ), - space, - result - ); - - if (first != last || !r ) { - GWARN_STREAM("Failed to parse worker list from discovery command: " << input); - return std::vector
{}; - } - - return result; - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - std::vector
discover_remote_peers() - { - auto worker_discovery_command = std::getenv("GADGETRON_REMOTE_WORKER_COMMAND"); - if (!worker_discovery_command) return std::vector
{}; - - GDEBUG_STREAM("Worker discovery command: " << worker_discovery_command); - - std::error_code error_code; - std::future output; - Process::system( - worker_discovery_command, - boost::process::std_out > output, - boost::process::std_err > boost::process::null, - boost::asio::io_service{}, - error_code - ); - - if (error_code) { - GWARN_STREAM("Failed executing remote worker command: " << error_code.message()); - return std::vector
(); - } - - return parse_remote_workers(output.get()); - } - - std::vector
discover_peers() { - - auto workers = discover_remote_peers(); - - if (workers.empty()) { - GWARN_STREAM( - "Remote worker list empty; adding local worker. " << - "This machine will perform reconstructions. " << - "This is probably not what you intended." - ) - workers.emplace_back(Local{}); - } - - return workers; - } -} diff --git a/apps/gadgetron/connection/nodes/common/Discovery.h b/apps/gadgetron/connection/nodes/common/Discovery.h deleted file mode 100644 index 10a27bd8f..000000000 --- a/apps/gadgetron/connection/nodes/common/Discovery.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once - -#include "External.h" - -#include "Types.h" - -namespace Gadgetron::Server::Connection::Nodes { - std::vector
discover_remote_peers(); - std::vector
discover_peers(); -} - - diff --git a/apps/gadgetron/connection/nodes/common/External.cpp b/apps/gadgetron/connection/nodes/common/External.cpp deleted file mode 100644 index 37e7990e7..000000000 --- a/apps/gadgetron/connection/nodes/common/External.cpp +++ /dev/null @@ -1,82 +0,0 @@ -#include "External.h" - -#include - -#include - -#include "system_info.h" - -#include "connection/SocketStreamBuf.h" -#include "log.h" - -namespace { - - std::string make_error_message(const std::list& errors) { - std::stringstream error_maker; - error_maker << "Errors received: " << std::endl; - for (auto& error : errors) { - error_maker << error << std::endl; - } - return error_maker.str(); - } -} - -namespace { - using namespace Gadgetron::Server::Connection::Nodes; - - Remote as_remote(Local, const std::shared_ptr &configuration) { - return Remote { - "localhost", - std::to_string(configuration->context.args["port"].as()) - }; - } - - Remote as_remote(Remote remote, const std::shared_ptr &) { - return remote; - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - RemoteError::RemoteError(std::list messages) : std::runtime_error(make_error_message(messages)), messages(messages) {} - - std::ostream & operator<<(std::ostream &stream, const Local &l) { stream << to_string(l); return stream; } - std::ostream & operator<<(std::ostream &stream, const Remote &r) { stream << to_string(r); return stream; } - - std::string to_string(const Local &) { - return "Local"; - } - - std::string to_string(const Remote &remote) { - return remote.address + ":" + remote.port; - } - - std::unique_ptr listen(unsigned short port) { - - boost::asio::io_service service; - boost::asio::ip::tcp::endpoint peer; - boost::asio::ip::tcp::endpoint local(Gadgetron::Server::Info::tcp_protocol(), port); - boost::asio::ip::tcp::acceptor acceptor(service, local); - - auto socket = std::make_unique(service); - - acceptor.accept(*socket, peer); - acceptor.close(); - - GINFO_STREAM("Accepted connection from " << peer.address()); - - return Gadgetron::Connection::stream_from_socket(std::move(socket)); - } - - std::unique_ptr connect(const std::string &address, const std::string &port) { - return Gadgetron::Connection::remote_stream(address, port); - } - - std::unique_ptr connect(const Remote &remote) { - return connect(remote.address, remote.port); - } - - std::unique_ptr connect(const Address &address, std::shared_ptr configuration) { - return connect(Core::visit([&](auto address) { return as_remote(address, configuration); }, address)); - } -} diff --git a/apps/gadgetron/connection/nodes/common/External.h b/apps/gadgetron/connection/nodes/common/External.h deleted file mode 100644 index efd4816e4..000000000 --- a/apps/gadgetron/connection/nodes/common/External.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include - -#include "Serialization.h" -#include "Configuration.h" - -#include "Channel.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class RemoteError : public std::runtime_error { - public: - explicit RemoteError(std::list messages); - private: - const std::list messages; - }; - - struct Local {}; - struct Remote { std::string address, port; }; - - using Address = Core::variant; - - std::ostream & operator<<(std::ostream &, const Local &); - std::ostream & operator<<(std::ostream &, const Remote &); - - std::string to_string(const Local &); - std::string to_string(const Remote &); - - std::unique_ptr listen(std::string port); - std::unique_ptr connect(const std::string &address, const std::string &port); - std::unique_ptr connect(const Remote &remote); - std::unique_ptr connect(const Address &address, std::shared_ptr configuration); -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/ExternalChannel.cpp b/apps/gadgetron/connection/nodes/common/ExternalChannel.cpp deleted file mode 100644 index ed8b5854f..000000000 --- a/apps/gadgetron/connection/nodes/common/ExternalChannel.cpp +++ /dev/null @@ -1,105 +0,0 @@ - -#include "ExternalChannel.h" - -#include "Serialization.h" -#include "Configuration.h" -#include "External.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection::Nodes { - - class ExternalChannel::Outbound::Closed : public ExternalChannel::Outbound { - void push(Core::Message message) override { throw Core::ChannelClosed(); } - void close() override {} - }; - - class ExternalChannel::Inbound::Closed : public ExternalChannel::Inbound { - Core::Message pop() override { throw Core::ChannelClosed(); } - void close() override {} - }; - - class ExternalChannel::Outbound::Open : public ExternalChannel::Outbound { - public: - explicit Open(ExternalChannel *channel) : channel(channel) {} - - void push(Core::Message message) override { - std::lock_guard guard{channel->mutex}; - channel->serialization->write(*channel->stream, std::move(message)); - } - - void close() override { - std::lock_guard guard{channel->mutex}; - channel->serialization->close(*channel->stream); - channel->outbound = std::make_unique(); - } - private: - ExternalChannel * const channel; - }; - - class ExternalChannel::Inbound::Open : public ExternalChannel::Inbound { - public: - explicit Open(ExternalChannel *channel) : channel(channel) {} - - Core::Message pop() override { - return channel->serialization->read( - *channel->stream, - [&]() { - auto &c_remote_errors = channel->remote_errors; - channel->inbound->close(); - - if (c_remote_errors.empty()) throw ChannelClosed(); else throw RemoteError(c_remote_errors); - }, - [&](auto message) { - channel->outbound->close(); - channel->remote_errors.push_back(message); - } - ); - } - - void close() override { - std::lock_guard guard{channel->mutex}; - channel->inbound = std::make_unique(); - } - private: - ExternalChannel * const channel; - }; -} - -namespace Gadgetron::Server::Connection::Nodes { - - ExternalChannel::ExternalChannel( - std::unique_ptr stream, - std::shared_ptr serialization - ) : remote_errors(), - stream(std::move(stream)), - serialization(std::move(serialization)) { - - inbound = std::make_unique(this); - outbound = std::make_unique(this); - } - - ExternalChannel::ExternalChannel( - std::unique_ptr stream, - std::shared_ptr serialization, - std::shared_ptr configuration - ) : ExternalChannel(std::move(stream), std::move(serialization)) { - configuration->send(*this->stream); - } - - Core::Message ExternalChannel::pop() { - return inbound->pop(); - } - - void ExternalChannel::push_message(Core::Message message) { - outbound->push(std::move(message)); - } - - void ExternalChannel::close() { - outbound->close(); - } - - bool ExternalChannel::accepts(const Message& message){ - return serialization->accepts(message); - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/ExternalChannel.h b/apps/gadgetron/connection/nodes/common/ExternalChannel.h deleted file mode 100644 index c5642ddba..000000000 --- a/apps/gadgetron/connection/nodes/common/ExternalChannel.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include -#include - -#include "connection/config/Config.h" - -#include "Context.h" -#include "Channel.h" -#include "Reader.h" -#include "Writer.h" - -#include "Serialization.h" -#include "Configuration.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class ExternalChannel { - public: - ExternalChannel( - std::unique_ptr stream, - std::shared_ptr serialization - ); - - ExternalChannel( - std::unique_ptr stream, - std::shared_ptr serialization, - std::shared_ptr configuration - ); - - Core::Message pop(); - void push_message(Core::Message message); - void close(); - bool accepts(const Core::Message& message); - - private: - std::unique_ptr stream; - std::list remote_errors; - - std::shared_ptr serialization; - - class Outbound { - public: - virtual ~Outbound() = default; - virtual void push(Core::Message message) = 0; - virtual void close() = 0; - - class Open; class Closed; - }; - - class Inbound { - public: - virtual ~Inbound() = default; - virtual Core::Message pop() = 0; - virtual void close() = 0; - - class Open; class Closed; - }; - - friend Outbound; friend Inbound; - - std::mutex mutex; - std::unique_ptr outbound; - std::unique_ptr inbound; - }; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/Serialization.cpp b/apps/gadgetron/connection/nodes/common/Serialization.cpp deleted file mode 100644 index b2293fb20..000000000 --- a/apps/gadgetron/connection/nodes/common/Serialization.cpp +++ /dev/null @@ -1,72 +0,0 @@ - -#include - -#include "Serialization.h" - -#include "io/primitives.h" -#include "MessageID.h" - -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection::Nodes { - - Serialization::Serialization( - Readers readers, - Writers writers - ) : readers(std::move(readers)), writers(std::move(writers)) {} - - void Serialization::write(std::iostream &stream, Core::Message message) const { - - auto writer = std::find_if( - writers.begin(), - writers.end(), - [&](auto& writer) { return writer->accepts(message); } - ); - - if (writer == writers.end()) - throw std::runtime_error("Could not find appropriate writer for message."); - - (*writer)->write(stream, std::move(message)); - } - - Core::Message Serialization::read( - std::iostream &stream, - std::function on_close, - std::function on_error - ) const { - - auto id = IO::read(stream); - auto illegal_message = [&](auto &) { - throw std::runtime_error("Received illegal message id from external peer: " + std::to_string(id)); - }; - - const std::map> handlers{ - {FILENAME, illegal_message}, - {CONFIG, illegal_message}, - {HEADER, illegal_message}, - {CLOSE, [&](auto &) { on_close(); }}, - {TEXT, illegal_message}, - {QUERY, illegal_message}, - {RESPONSE, illegal_message}, - {ERROR, [&](auto &stream) { on_error(IO::read_string_from_stream(stream)); }} - }; - - for (; handlers.count(id); id = IO::read(stream)) handlers.at(id)(stream); - if (!readers.count(id)) illegal_message(stream); - return readers.at(id)->read(stream); - } - - void Serialization::close(std::iostream &stream) const { - IO::write(stream, CLOSE); - } - - bool Serialization::accepts(const Message &message) { - auto writer = std::find_if( - writers.begin(), - writers.end(), - [&](auto& writer) { return writer->accepts(message); } - ); - if (writer == writers.end()) return false; - return true; - } -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/common/Serialization.h b/apps/gadgetron/connection/nodes/common/Serialization.h deleted file mode 100644 index 1a0783cbb..000000000 --- a/apps/gadgetron/connection/nodes/common/Serialization.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "Reader.h" -#include "Writer.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class Serialization { - public: - using Readers = std::map>; - using Writers = std::vector>; - Serialization(Readers readers, Writers writers); - - void close(std::iostream &stream) const; - void write(std::iostream &stream, Core::Message message) const; - Core::Message read( - std::iostream &stream, - std::function on_close, - std::function on_error - ) const; - - bool accepts(const Core::Message& message); - - private: - const Readers readers; - const Writers writers; - }; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/distributed/Pool.cpp b/apps/gadgetron/connection/nodes/distributed/Pool.cpp deleted file mode 100644 index d202e1b67..000000000 --- a/apps/gadgetron/connection/nodes/distributed/Pool.cpp +++ /dev/null @@ -1,63 +0,0 @@ - -#include "Pool.h" - -#include "connection/nodes/common/Discovery.h" - -#include "log.h" -#include "io/iostream_operators.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Server::Connection::Nodes; -using namespace Gadgetron; - -namespace { - - bool compare_load(const std::unique_ptr &a, const std::unique_ptr &b) { - return a->current_load() < b->current_load(); - } - - std::unique_ptr &select_best_worker(std::list> &workers) { - return *std::min_element(workers.begin(), workers.end(), compare_load); - } - - Message send_to_best_worker( - Message message, - std::shared_ptr>> workers, - size_t retries - ) { - - if (!retries) throw std::runtime_error("Multiple workers failed processing job; aborting."); - - auto &worker = select_best_worker(*workers); - - try { - auto response = worker->push(message.clone()); - GDEBUG_STREAM("Pushed message; waiting for response from worker " << worker->address); - auto response_message = response.get(); - GDEBUG_STREAM("Response gotten from worker " << worker->address); - return std::move(response_message); - } - catch (const std::exception &e) { - GWARN_STREAM("Worker " << worker->address << " failed processing job. The job will be retried. [" << e.what() << "]"); - return send_to_best_worker(std::move(message), std::move(workers), retries - 1); - } - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - Pool::Pool( - std::list> workers - ) : workers(std::make_shared>>(std::move(workers))) {} - - std::future Pool::push(Message message) { - return std::async( - std::launch::async, - send_to_best_worker, - std::move(message), - workers, - 3 - ); - } -} - diff --git a/apps/gadgetron/connection/nodes/distributed/Pool.h b/apps/gadgetron/connection/nodes/distributed/Pool.h deleted file mode 100644 index dcfa8c788..000000000 --- a/apps/gadgetron/connection/nodes/distributed/Pool.h +++ /dev/null @@ -1,26 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -#include "connection/nodes/common/External.h" - -#include "Worker.h" - -#include "Message.h" - - -namespace Gadgetron::Server::Connection::Nodes { - - class Pool { - public: - explicit Pool(std::list> workers); - std::future push(Core::Message message); - - private: - std::shared_ptr>> workers; - }; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/distributed/Worker.cpp b/apps/gadgetron/connection/nodes/distributed/Worker.cpp deleted file mode 100644 index c256107f0..000000000 --- a/apps/gadgetron/connection/nodes/distributed/Worker.cpp +++ /dev/null @@ -1,159 +0,0 @@ - -#include "Worker.h" - -#include -#include - -#include "connection/nodes/common/External.h" -#include "connection/nodes/common/ExternalChannel.h" - -#include "io/iostream_operators.h" - -using namespace Gadgetron::Core; -using namespace Gadgetron::Server::Connection::Nodes; - -namespace { - - template - std::chrono::milliseconds time_since(std::chrono::time_point instance) { - return std::chrono::duration_cast( - std::chrono::steady_clock::now() - instance - ); - } -} - -namespace Gadgetron::Server::Connection::Nodes { - - struct Worker::Job { - std::chrono::time_point start; - std::promise response; - }; - - struct Module { - Worker& worker; - explicit Module(Worker &worker) : worker(worker) {} - virtual ~Module() = default; - }; - - struct Worker::PushModule : public Module { - using Module::Module; - - virtual std::future push(Message message) { - GDEBUG_STREAM("Pushing message to remote worker " << worker.address); - - Job job { - std::chrono::steady_clock::now(), - std::promise() - }; - - auto future = job.response.get_future(); - worker.channel->push_message(std::move(message)); - worker.jobs.push_back(std::move(job)); - return future; - }; - }; - - struct Worker::LoadModule : public Module { - using Module::Module; - - virtual long long current_load() { - auto current_job_duration_estimate = std::max( - worker.timing.latest.count(), - time_since(worker.jobs.front().start).count() - ); - - return current_job_duration_estimate * worker.jobs.size(); - }; - }; - - struct Worker::ClosedPushModule : public Worker::PushModule { - using Worker::PushModule::PushModule; - std::future push(Message message) override { - throw std::runtime_error("Cannot push message to closed/failed worker."); - } - }; - - struct Worker::ClosedLoadModule : public Worker::LoadModule { - using Worker::LoadModule::LoadModule; - long long current_load() override { return std::numeric_limits::max(); } - }; -} - - -namespace Gadgetron::Server::Connection::Nodes { - - Worker::~Worker() { - channel->close(); - inbound_thread.join(); - } - - Worker::Worker( - Address address, - std::shared_ptr serialization, - std::shared_ptr configuration - ) : address(std::move(address)) { - GDEBUG_STREAM("Creating worker " << this->address); - - channel = std::make_unique( - connect(this->address, configuration), - std::move(serialization), - std::move(configuration) - ); - - load_module = std::make_unique(*this); - push_module = std::make_unique(*this); - - inbound_thread = std::thread([=]() { handle_inbound_messages(); }); - } - - long long Worker::current_load() const { - std::lock_guard guard(mutex); - return load_module->current_load(); - } - - std::future Worker::push(Message message) { - std::lock_guard guard(mutex); - return push_module->push(std::move(message)); - } - - void Worker::close() { - std::lock_guard guard(mutex); - channel->close(); - } - - void Worker::handle_inbound_messages() { - try { - while(true) process_inbound_message(channel->pop()); - } - catch (const ChannelClosed &) {} - catch (const std::exception &e) { - GWARN_STREAM("Worker " << address << " failed: " << e.what()); - fail_pending_messages(std::current_exception()); - } - switch_to_closed_modules(); - } - - void Worker::process_inbound_message(Core::Message message) { - GDEBUG_STREAM("Received message from remote worker " << address); - - std::lock_guard guard(mutex); - - auto job = std::move(jobs.front()); jobs.pop_front(); - timing.latest = time_since(job.start); - job.response.set_value(std::move(message)); - } - - void Worker::fail_pending_messages(const std::exception_ptr &e) { - std::lock_guard guard(mutex); - - for (auto &job : jobs) { - job.response.set_exception(e); - } - } - - void Worker::switch_to_closed_modules() { - std::lock_guard guard(mutex); - load_module = std::make_unique(*this); - push_module = std::make_unique(*this); - } -} diff --git a/apps/gadgetron/connection/nodes/distributed/Worker.h b/apps/gadgetron/connection/nodes/distributed/Worker.h deleted file mode 100644 index 02500abae..000000000 --- a/apps/gadgetron/connection/nodes/distributed/Worker.h +++ /dev/null @@ -1,54 +0,0 @@ -#pragma once - -#include -#include -#include - -#include "connection/Core.h" -#include "connection/nodes/common/Serialization.h" -#include "connection/nodes/common/Configuration.h" -#include "connection/nodes/common/ExternalChannel.h" -#include "connection/nodes/common/Discovery.h" - -#include "Message.h" - -namespace Gadgetron::Server::Connection::Nodes { - - class Worker { - public: - const Address address; - - ~Worker(); - Worker( - Address address, - std::shared_ptr serialization, - std::shared_ptr configuration - ); - - std::future push(Core::Message message); - long long current_load() const; - void close(); - - private: - mutable std::mutex mutex; - - std::thread inbound_thread; - - struct Timing { - std::chrono::milliseconds latest = std::chrono::seconds(5); - } timing; - - struct Job; - std::list jobs; - std::unique_ptr channel; - - struct PushModule; struct LoadModule; struct ClosedPushModule; struct ClosedLoadModule; - std::unique_ptr push_module; - std::unique_ptr load_module; - void switch_to_closed_modules(); - - void handle_inbound_messages(); - void process_inbound_message(Core::Message message); - void fail_pending_messages(const std::exception_ptr &e); - }; -} diff --git a/apps/gadgetron/connection/nodes/external/Julia.cpp b/apps/gadgetron/connection/nodes/external/Julia.cpp deleted file mode 100644 index 967b5e576..000000000 --- a/apps/gadgetron/connection/nodes/external/Julia.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "Python.h" - -#include -#include "Process.h" - -#include "connection/config/Config.h" - -#include - -#include "log.h" -#include - -namespace Gadgetron::Server::Connection::Nodes { - - using namespace Gadgetron::Core; - - - boost::process::child start_julia_module( - const Config::Execute &execute, - unsigned short port, - const StreamContext &context - ) { - if (!execute.target) throw std::invalid_argument("Target must be specified for Julia modules"); - - std::list args{ - "-e", "import Gadgetron; Gadgetron.External.main()", - std::to_string(port), - execute.name, *execute.target - }; - namespace bp = boost::process; - //Workaround for bug in Boost process - auto env = boost::this_process::environment(); - - env.set("GADGETRON_STORAGE_ADDRESS",context.storage_address); - - auto module = Process::child( - boost::process::search_path("julia"), - boost::process::args = args, - env, - boost::process::limit_handles, - boost::process::std_out > stdout, - boost::process::std_err > stderr - ); - - GINFO_STREAM("Started external Julia module (pid: " << module.id() << ")."); - return std::move(module); - } - - bool julia_available() noexcept { - try { - return !Process::system( - boost::process::search_path("julia"), - boost::process::args={"-e", "using Gadgetron"}, - boost::process::std_out > boost::process::null, - boost::process::std_err > boost::process::null - ); - } - catch (...) { - return false; - } - } -} diff --git a/apps/gadgetron/connection/nodes/external/Julia.h b/apps/gadgetron/connection/nodes/external/Julia.h deleted file mode 100644 index c9de4ab9d..000000000 --- a/apps/gadgetron/connection/nodes/external/Julia.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include "connection/config/Config.h" - -#include "Context.h" - -namespace Gadgetron::Server::Connection::Nodes { - boost::process::child start_julia_module( - const Config::Execute &, - unsigned short port, - const Gadgetron::Core::StreamContext & - ); - bool julia_available() noexcept; -} - diff --git a/apps/gadgetron/connection/nodes/external/Matlab.cpp b/apps/gadgetron/connection/nodes/external/Matlab.cpp deleted file mode 100644 index 79c71e024..000000000 --- a/apps/gadgetron/connection/nodes/external/Matlab.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Matlab.h" - -#include -#include "Process.h" -#include "connection/config/Config.h" - -#include "log.h" - -namespace Gadgetron::Server::Connection::Nodes { - - boost::process::child start_matlab_module( - const Config::Execute &execute, - unsigned short port, - const Gadgetron::Core::StreamContext &context - ) { - - auto env = boost::this_process::environment(); - env.set("GADGETRON_EXTERNAL_PORT",std::to_string(port)); - env.set("GADGETRON_EXTERNAL_MODULE",execute.name); - env.set("GADGETRON_STORAGE_ADDRESS", context.storage_address); - - auto module = Process::child( - boost::process::search_path("matlab"), - boost::process::args={"-batch", "gadgetron.external.main"}, - env, - boost::process::limit_handles, - boost::process::std_out > stdout, - boost::process::std_err > stderr - ); - - GINFO_STREAM("Started external MATLAB module (pid: " << module.id() << ")."); - - return std::move(module); - } - - bool matlab_available() noexcept { - try { - return !Process::system( - boost::process::search_path("matlab"), - boost::process::args={"-batch", "gadgetron.external.test_available"}, - boost::process::std_out > boost::process::null, - boost::process::std_err > boost::process::null - ); - } - catch (...) { - return false; - } - } -} diff --git a/apps/gadgetron/connection/nodes/external/Matlab.h b/apps/gadgetron/connection/nodes/external/Matlab.h deleted file mode 100644 index efc789423..000000000 --- a/apps/gadgetron/connection/nodes/external/Matlab.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#include "connection/config/Config.h" - -#include "Context.h" - -namespace Gadgetron::Server::Connection::Nodes { - boost::process::child start_matlab_module( - const Config::Execute &, - unsigned short port, - const Gadgetron::Core::StreamContext & - ); - bool matlab_available() noexcept; -} \ No newline at end of file diff --git a/apps/gadgetron/connection/nodes/external/Python.cpp b/apps/gadgetron/connection/nodes/external/Python.cpp deleted file mode 100644 index 7a1e18156..000000000 --- a/apps/gadgetron/connection/nodes/external/Python.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "Python.h" - -#include -#include "Process.h" - -#include "connection/config/Config.h" - -#include - -#include "log.h" -#include - -namespace Gadgetron::Server::Connection::Nodes { - - using namespace Gadgetron::Core; - - namespace { - - std::tuple parse_version(const std::string& versionstring) { - - auto version_rules = std::regex(R"(.*?([0-9]+)\.([0-9]+)\.([0-9]+))"); - std::smatch matches; - auto found = std::regex_search(versionstring, matches, version_rules); - - if (!found) - return {0, 0, 0}; - - int major_version = std::stoi(matches[1].str()); - int minor_version = std::stoi(matches[2].str()); - int patch_version = std::stoi(matches[3].str()); - - return {major_version, minor_version, patch_version}; - } - - bool is_valid_python3(const std::string& pythonname){ - try { - std::future output_stream; - Process::system( - boost::process::search_path(pythonname), - boost::process::args={"--version"}, - boost::process::std_out > output_stream, - boost::process::std_err > boost::process::null - ); - - - auto output = output_stream.get(); - - - auto [major, minor, patch] = parse_version(output); - - if ((major == 3) && (minor > 5)) - return true; - - - } - catch (...){ - return false; - } - return false; - - - }; - - std::string get_python_executable() { - auto possible_names = std::vector{"python", "python3"}; - for (auto &name : possible_names) { - if (is_valid_python3(name)) { - return name; - } - } - throw std::runtime_error("Could not find valid python installation"); - } - - } - - boost::process::child start_python_module( - const Config::Execute &execute, - unsigned short port, - const StreamContext &context - ) { - auto python_path = (context.paths.gadgetron_home / "share" / "gadgetron" / "python").string(); - - std::list args{ - "-m", "gadgetron", - std::to_string(port), - execute.name - }; - - if(execute.target) args.push_back(execute.target.value()); - - namespace bp = boost::process; - //Workaround for bug in Boost process - auto env = boost::this_process::environment(); - auto orig_python_path = std::getenv("PYTHONPATH"); - if (orig_python_path) - env.set("PYTHONPATH",std::string(orig_python_path) + ":" + python_path); - else - env.set("PYTHONPATH",python_path); - - env.set("GADGETRON_STORAGE_ADDRESS",context.storage_address); - - auto module = Process::child( - boost::process::search_path(get_python_executable()), - boost::process::args = args, - env, - boost::process::limit_handles, - boost::process::std_out > stdout, - boost::process::std_err > stderr - ); - - GINFO_STREAM("Started external Python module (pid: " << module.id() << ")."); - return std::move(module); - } - - bool python_available() noexcept { - try { - return !Process::system( - boost::process::search_path(get_python_executable()), - boost::process::args={"-m", "gadgetron"}, - boost::process::std_out > boost::process::null, - boost::process::std_err > boost::process::null - ); - } - catch (...) { - return false; - } - } -} diff --git a/apps/gadgetron/connection/nodes/external/Python.h b/apps/gadgetron/connection/nodes/external/Python.h deleted file mode 100644 index 3a89214a7..000000000 --- a/apps/gadgetron/connection/nodes/external/Python.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include "connection/config/Config.h" - -#include "Context.h" - -namespace Gadgetron::Server::Connection::Nodes { - boost::process::child start_python_module( - const Config::Execute &, - unsigned short port, - const Gadgetron::Core::StreamContext & - ); - bool python_available() noexcept; -} - diff --git a/apps/gadgetron/gadgetron_config.in b/apps/gadgetron/gadgetron_config.in deleted file mode 100644 index 9e6b3bbe9..000000000 --- a/apps/gadgetron/gadgetron_config.in +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef GADGETRON_CONFIG_H -#define GADGETRON_CONFIG_H - -#define GADGETRON_VERSION_MAJOR @GADGETRON_VERSION_MAJOR@ -#define GADGETRON_VERSION_MINOR @GADGETRON_VERSION_MINOR@ -#define GADGETRON_VERSION_PATCH @GADGETRON_VERSION_PATCH@ -#define GADGETRON_VERSION_STRING "@GADGETRON_VERSION_STRING@" -#define GADGETRON_CONFIG_PATH "@GADGETRON_INSTALL_CONFIG_PATH@" -#define GADGETRON_PYTHON_PATH "@GADGETRON_INSTALL_PYTHON_MODULE_PATH@" -#define GADGETRON_GIT_SHA1_HASH "@GADGETRON_GIT_SHA1@" -#define GADGETRON_CUDA_NVCC_FLAGS "@CUDA_NVCC_FLAGS@" -#define GADGETRON_VAR_DIR "@GADGETRON_VAR_DIR@" - -#endif //GADGETRON_CONFIG_H diff --git a/apps/gadgetron/main.cpp b/apps/gadgetron/main.cpp deleted file mode 100644 index 8f9d47996..000000000 --- a/apps/gadgetron/main.cpp +++ /dev/null @@ -1,182 +0,0 @@ -#include - -#include -#include - -#include "log.h" -#include "gadgetron_paths.h" -#include "initialization.h" -#include "storage.h" - -#include "system_info.h" -#include "gadgetron_config.h" - -#include "Server.h" -#include "StreamConsumer.h" - - -using namespace boost::filesystem; -using namespace boost::program_options; -using namespace Gadgetron::Server; - -using gadget_parameter = std::pair; - -std::istream& operator>>(std::istream& in, gadget_parameter& param) { - std::string token; - in >> token; - // parse = into a gadget_parameter - auto pos = token.find('='); - if (pos == std::string::npos) { - throw std::runtime_error("Invalid gadget parameter: " + token); - } - param.first = token.substr(0, pos); - param.second = token.substr(pos + 1); - return in; -} - -std::ostream& operator<<(std::ostream& out, const gadget_parameter& param) { - out << param.first << "=" << param.second; - return out; -} - -int main(int argc, char *argv[]) { - options_description gadgetron_options("Allowed options:"); - - - gadgetron_options.add_options() - ("help,h", "Prints this help message.") - ("info", "Prints build info about the Gadgetron.") - ("dir,W", - value()->default_value(default_working_folder()), - "Set the Gadgetron working directory.") - ("home,G", - value()->default_value(default_gadgetron_home()), - "Set the Gadgetron home directory.") - ("port,p", - value()->default_value(9002), - "Listen for incoming connections on this port.") - ("from_stream, s", - "Perform reconstruction from a local data stream") - ("input_path,i", - value(), - "Input file for binary data to perform a local reconstruction with") - ("output_path,o", - value(), - "Output file for binary data as a result of a local reconstruction") - ("config_name,c", - value(), - "Filename of the desired gadgetron reconstruction config.") - ("parameter", - value>(), - "Parameter to be passed to the gadgetron reconstruction config. Multiple parameters can be passed." - "Format: --parameter = --parameter = ..."); - - - options_description storage_options("Storage options"); - storage_options.add_options() - ("disable_storage,d", - value()->default_value(false), - "Disable storage server access. Used for testing cases where storage is not available.") - ("storage_address,E", - value(), - "External address of a storage server. If not provided, a storage server will be started.") - ("storage_port,s", - value(), - "Port on which to run the storage server. " - "If no port is provided, a port offset from the port argument (-p) is selected.") - ("database_dir,D", - value()->default_value(default_database_folder()), - "Directory in which to store the storage server database.") - ("storage_dir,S", - value()->default_value(default_storage_folder()), - "Directory in which to store data blobs."); - - options_description desc; - desc - .add(gadgetron_options) - .add(storage_options); - - variables_map args; - store(parse_command_line(argc, argv, desc), args); - notify(args); - - try { - check_environment_variables(); - configure_blas_libraries(); - set_locale(); - - if (args.count("help")) { - GINFO_STREAM(desc); - return 0; - } - - if (args.count("info")) { - std::stringstream str; - Info::print_system_information(str); - GINFO(str.str().c_str()); - return 0; - } - - GINFO("Gadgetron %s [%s]\n", GADGETRON_VERSION_STRING, GADGETRON_GIT_SHA1_HASH); - - // Ensure working directory exists. - create_directories(args["dir"].as()); - - // We do not currently allow the user to specify parameters unless in streaming mode. - if (args.count("parameter") && !args.count("from_stream")) { - GERROR_STREAM("Parameters can only be specified in streaming mode."); - return 1; - } - - auto [storage_address, storage_server] = ensure_storage_server(args); - - if(!args.count("from_stream")) - { - GINFO("Running on port %d\n", args["port"].as()); - Server server(args, storage_address); - server.serve(); - } - else - { - auto cfg = args["config_name"].as(); - StreamConsumer consumer(args, storage_address); - - if(args.count("input_path") && args.count("output_path")) - { - auto input_stream = std::ifstream(args["input_path"].as()); - auto output_stream = std::ofstream(args["output_path"].as()); - consumer.consume(input_stream, output_stream, cfg); - output_stream.close(); - } - else if(args.count("input_path")) - { - auto input_stream = std::ifstream(args["input_path"].as()); - consumer.consume(input_stream, std::cout, cfg); - std::flush(std::cout); - } - else if(args.count("output_path")) - { - auto output_stream = std::ofstream(args["output_path"].as()); - consumer.consume(std::cin, output_stream, cfg); - output_stream.close(); - } - else - { - consumer.consume(std::cin, std::cout, cfg); - std::flush(std::cout); - } - } - } - catch (std::exception &e) - { - GERROR_STREAM(e.what() << std::endl); - std::exit(EXIT_FAILURE); - } - catch(...) - { - GERROR_STREAM("Unhandled exception, exiting" << std::endl); - std::exit(EXIT_FAILURE); - } - - return 0; -} diff --git a/apps/gadgetron/schema/gadgetron.xsd b/apps/gadgetron/schema/gadgetron.xsd deleted file mode 100644 index f74a9cebd..000000000 --- a/apps/gadgetron/schema/gadgetron.xsd +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/apps/gadgetron/storage.cpp b/apps/gadgetron/storage.cpp deleted file mode 100644 index adcc03da4..000000000 --- a/apps/gadgetron/storage.cpp +++ /dev/null @@ -1,94 +0,0 @@ - -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -#include "IsmrmrdContextVariables.h" -#include "Process.h" -#include "gadgetron_paths.h" -#include "log.h" - -#include "storage.h" - -using namespace Gadgetron::Storage; -using namespace boost::filesystem; -using namespace boost::program_options; - -namespace Gadgetron::Server { - -void invoke_storage_server_health_check(std::string base_address) { - GINFO_STREAM("Verifying connectivity to storage server...") - StorageClient c(base_address); - for (int i = 0;; i++) { - auto err = c.health_check(); - if (!err.has_value()) { - GINFO_STREAM("Received successful response from storage server."); - break; - } - - if (i == 49) { - throw std::runtime_error(*err); - } - - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - } -} - -std::tuple> ensure_storage_server(const variables_map& args) { - if (args.count("disable_storage") && args["disable_storage"].as()) { - return {"", std::nullopt}; - } - - if (args.count("storage_address")) { - auto uri = args["storage_address"].as(); - invoke_storage_server_health_check(uri); - return {uri, std::nullopt}; - } - - auto port = args["storage_port"].empty() ? args["port"].as() + 110 - : args["storage_port"].as(); - auto environment = boost::this_process::environment(); - environment.set("MRD_STORAGE_SERVER_PORT", std::to_string(port)); - environment.set("MRD_STORAGE_SERVER_DATABASE_CONNECTION_STRING", - (args["database_dir"].as() / "metadata.db").string()); - environment.set("MRD_STORAGE_SERVER_STORAGE_CONNECTION_STRING", (args["storage_dir"].as()).string()); - - auto storage_executable = boost::process::search_path("mrd-storage-server"); - if (storage_executable.empty()) { - throw std::runtime_error("Failed to find MRD Storage Server.\n" - "Please ensure 'mrd-storage-server' is found on your PATH.\n" - "See: https://github.com/ismrmrd/mrd-storage-server/"); - } - - GDEBUG_STREAM("Found storage server: " + storage_executable.string()) - GINFO_STREAM("Starting storage server on port " + environment.get("MRD_STORAGE_SERVER_PORT")) - - auto uri = "http://localhost:" + environment.get("MRD_STORAGE_SERVER_PORT"); - auto process = - Process::child(storage_executable, "--require-parent-pid", // have child process exit if parent crashes - std::to_string(boost::this_process::get_id()), - boost::process::std_out > boost::process::null, boost::process::std_err > stderr, environment); - - invoke_storage_server_health_check(uri); - - return {uri, std::move(process)}; -} - -StorageSpaces setup_storage_spaces(const std::string& address, const ISMRMRD::IsmrmrdHeader& header) { - auto client = std::make_shared(address); - IsmrmrdContextVariables variables(header); - auto ttl = std::chrono::hours(48); - - return {std::make_shared(client, variables, ttl), - std::make_shared(client, variables, ttl), - std::make_shared(client, variables, ttl)}; -} -} // namespace Gadgetron::Server diff --git a/apps/gadgetron/storage.h b/apps/gadgetron/storage.h deleted file mode 100644 index 271f80b39..000000000 --- a/apps/gadgetron/storage.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include - -#include - -#include -#include - -#include "StorageSetup.h" - -namespace Gadgetron::Server { -std::tuple> -ensure_storage_server(const boost::program_options::variables_map& args); - -StorageSpaces setup_storage_spaces(const std::string& address, const ISMRMRD::IsmrmrdHeader& header); -} // namespace Gadgetron::Server diff --git a/apps/gadgetron/test/CMakeLists.txt b/apps/gadgetron/test/CMakeLists.txt deleted file mode 100644 index dafd92af6..000000000 --- a/apps/gadgetron/test/CMakeLists.txt +++ /dev/null @@ -1,26 +0,0 @@ -enable_testing() - -add_executable(server_tests - storage_test.cpp - socket_test.cpp - ../connection/SocketStreamBuf.cpp) - -add_library(storage OBJECT - ../storage.cpp) - -target_link_libraries(storage - gadgetron_core - ${CURL_LIBRARIES} - Boost::filesystem - Boost::program_options) - -target_link_libraries(server_tests - storage - gadgetron_core - gadgetron_toolbox_log - GTest::GTest - GTest::Main - GTest::gtest - GTest::gtest_main - ) - diff --git a/apps/gadgetron/test/socket_test.cpp b/apps/gadgetron/test/socket_test.cpp deleted file mode 100644 index 1e187320f..000000000 --- a/apps/gadgetron/test/socket_test.cpp +++ /dev/null @@ -1,107 +0,0 @@ -// -// Created by dchansen on 9/10/19. -// -#include - -#include -#include - -#include "../connection/SocketStreamBuf.h" -#include "log.h" - - -namespace ba = boost::asio; -using tcp = boost::asio::ip::tcp; -using namespace Gadgetron; - - -class SocketTest : public ::testing::Test { - -public: - SocketTest() : ::testing::Test() { - auto endpoint = tcp::endpoint(tcp::v6(), 0); - acceptor = std::make_unique(tcp::acceptor(ios, endpoint)); - - auto port = acceptor->local_endpoint().port(); - auto socketF = std::async([&]() { - tcp::socket socket{ ios }; - acceptor->accept(socket); - return socket; - }); - - socketstream = Connection::remote_stream("localhost", std::to_string(port)); - - server_socket = std::make_unique(socketF.get()); - } - - - ba::io_service ios{}; - std::unique_ptr acceptor; - std::unique_ptr socketstream; - std::unique_ptr server_socket; - -}; - -TEST_F(SocketTest, read_test) { - - auto data = std::vector(19,42); - ba::write(*server_socket,ba::buffer(data.data(),data.size())); - - auto data2 = std::vector(19); - - socketstream->read(data2.data(),data2.size()); - - ASSERT_EQ(data,data2); -} - -TEST_F(SocketTest, write_test) { - - auto data = std::vector(1u << 22,42); - - auto thread = std::thread([&](){socketstream->write(data.data(),data.size());}); - - auto data2 = std::vector(data.size()); - ba::read(*server_socket,ba::buffer(data2.data(),data2.size())); - - ASSERT_EQ(data,data2); - thread.join(); -} - - -TEST_F(SocketTest, stringstream_test) { - const std::string name = "Albatros"; - std::stringstream sstream; - sstream << name; - *socketstream << sstream.rdbuf(); - - - - std::vector ref(name.size()); - ba::read(*server_socket,ba::buffer(ref.data(),ref.size())); - - std::string name2(ref.begin(),ref.end()); - ASSERT_EQ(name,name2); -} - - - -TEST_F(SocketTest, nulltest) { - auto data = std::vector(1u << 22,0); - std::mt19937_64 engine; - std::uniform_int_distribution distribution(0); - for (auto& d : data) d = distribution(engine); - - GINFO_STREAM(std::to_string(data.size()) << std::endl); - std::stringstream sstream; - sstream.write(data.data(),data.size()); - - auto thread = std::thread([&](){ *socketstream << sstream.rdbuf(); *socketstream << sstream.rdbuf();}); - - - - std::vector ref(data.size()); - ba::read(*server_socket,ba::buffer(ref.data(),ref.size())); - - ASSERT_EQ(ref,data); - thread.join(); -} diff --git a/apps/gadgetron/test/storage_test.cpp b/apps/gadgetron/test/storage_test.cpp deleted file mode 100644 index 0af161f7c..000000000 --- a/apps/gadgetron/test/storage_test.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "storage.h" - -using namespace Gadgetron::Storage; -using namespace Gadgetron; - -using namespace boost::filesystem; -using namespace boost::program_options; - -class StorageTest : public ::testing::Test { - protected: - static void SetUpTestSuite() { - - temp_dir = boost::filesystem::temp_directory_path() / "gadgetron_session_test"; - boost::filesystem::remove_all(temp_dir); - boost::filesystem::create_directory(temp_dir); - - options_description desc("Storage options"); - // clang-format off - desc.add_options() - ("storage_port", value()->default_value(26589)) - ("database_dir,D", value()->default_value(temp_dir)) - ("storage_dir,S", value()->default_value(temp_dir)); - // clang-format on - - variables_map args; - store(parse_environment(desc, "GADGETRON_STORAGE_TEST_"), args); - notify(args); - - auto [address, process] = Server::ensure_storage_server(args); - - ISMRMRD::IsmrmrdHeader header; - header.subjectInformation = ISMRMRD::SubjectInformation{{}, {}, {}, std::string("mypatient"), {}, {}}; - header.studyInformation = ISMRMRD::StudyInformation{{}, {}, std::string("mystudy")}; - - storage_address = address; - server = std::move(*process); - storage = Gadgetron::Server::setup_storage_spaces(address, header); - } - - static void TearDownTestSuite() { - boost::filesystem::remove_all(temp_dir); - server.terminate(); - server.wait(); - } - - inline static std::string storage_address; - inline static StorageSpaces storage; - inline static boost::process::child server; - inline static boost::filesystem::path temp_dir; -}; - -std::vector generate_random_vector(size_t size) { - std::vector data(size, 0); - std::random_device rd; - std::mt19937 gen(rd()); - std::uniform_int_distribution<> distrib(0, 255); - for (size_t n = 0; n < data.size(); n++) { - data[n] = (char)distrib(gen); - } - return data; -} - -TEST_F(StorageTest, storage_client_should_return_inserted_data_and_all_meta_tags) { - StorageClient storage_client(storage_address); - auto data = generate_random_vector(256); - auto datastream = std::stringstream(std::string(data.begin(), data.end())); - std::string session_id = "my&session3"; - auto tags = StorageItemTags::Builder("my&patient") - .with_device("my&device") - .with_session(session_id) - .with_name("my&variable1") - .with_custom_tag("tagone", "first&") - .with_custom_tag("tagtwo", "second&") - .with_custom_tag("multival", "value1&") - .with_custom_tag("multival", "value2&") - .build(); - - auto resp = storage_client.store_item(tags, datastream); - auto out = storage_client.get_latest_item(tags); - std::vector out_bytes; - std::copy(std::istreambuf_iterator(*out), std::istreambuf_iterator(), std::back_inserter(out_bytes)); - EXPECT_EQ(data, out_bytes); - auto outByUrl = storage_client.get_item_by_url(resp.data); - std::vector outBytesByUrl; - std::copy(std::istreambuf_iterator(*outByUrl), std::istreambuf_iterator(), - std::back_inserter(outBytesByUrl)); - EXPECT_EQ(data, outBytesByUrl); - - // using ampersands in the tag values to ensure that they are properly escaped - - // Get the list of items - auto list = storage_client.list_items( - StorageItemTags::Builder("my&patient").with_session(session_id).with_name("my&variable1").build()); - EXPECT_TRUE(list.complete); - EXPECT_EQ(list.items.size(), 1); - - // check tags - EXPECT_EQ(list.items[0].tags.subject, "my&patient"); - EXPECT_EQ(list.items[0].tags.device, "my&device"); - EXPECT_EQ(list.items[0].tags.session, session_id); - EXPECT_EQ(list.items[0].tags.name, "my&variable1"); - EXPECT_EQ(list.items[0].tags.custom_tags.find("tagone")->second, "first&"); - EXPECT_EQ(list.items[0].tags.custom_tags.find("tagtwo")->second, "second&"); - auto multival_iterators = list.items[0].tags.custom_tags.equal_range("multival"); - std::vector multival_values; - std::transform(multival_iterators.first, multival_iterators.second, std::back_inserter(multival_values), - [](auto p) { return p.second; }); - ASSERT_THAT(multival_values, testing::ElementsAre("value1&", "value2&")); -} - -TEST_F(StorageTest, storage_client_supports_paging) { - StorageClient storage_client(storage_address); - auto data = generate_random_vector(256); - auto datastream = std::stringstream(std::string(data.begin(), data.end()), std::ios::binary); - std::string session_id = "mysession4"; - auto tags = StorageItemTags::Builder("mypatient") - .with_device("mydevice") - .with_session(session_id) - .with_name("myvariable1") - .build(); - - const int items_to_insert = 20; - for (int i = 0; i < items_to_insert; i++) { - storage_client.store_item(tags, datastream); - } - - auto list = storage_client.list_items(tags, 5); - EXPECT_FALSE(list.complete); - EXPECT_EQ(list.items.size(), 5); - - for (int i = 0; i < 3; i++) { - list = storage_client.get_next_page_of_items(list); - EXPECT_EQ(list.items.size(), 5); - EXPECT_EQ(list.complete, i == 2); - } - - list = storage_client.list_items(tags, items_to_insert); - EXPECT_TRUE(list.complete); - EXPECT_EQ(list.items.size(), items_to_insert); - - list = storage_client.get_next_page_of_items(list); - EXPECT_TRUE(list.complete); - EXPECT_EQ(list.items.size(), 0); -} - -TEST_F(StorageTest, storage_client_should_store_items_and_return_list) { - StorageClient storage_client(storage_address); - auto data = generate_random_vector(256); - auto datastream = std::stringstream(std::string(data.begin(), data.end()), std::ios::binary); - std::string session_id = "mysession5"; - - auto tags1 = StorageItemTags::Builder("mypatient") - .with_device("mydevice") - .with_session(session_id) - .with_name("myvariable1") - .build(); - - auto tags2 = StorageItemTags::Builder("mypatient") - .with_device("mydevice") - .with_session(session_id) - .with_name("myvariable2") - .build(); - - auto tags_session = StorageItemTags::Builder("mypatient").with_device("mydevice").with_session(session_id).build(); - - auto resp = storage_client.store_item(tags1, datastream); - - datastream.clear(); - datastream.seekg(0); - resp = storage_client.store_item(tags1, datastream); - - datastream.clear(); - datastream.seekg(0); - resp = storage_client.store_item(tags1, datastream); - - datastream.clear(); - datastream.seekg(0); - resp = storage_client.store_item(tags2, datastream); - - datastream.clear(); - datastream.seekg(0); - resp = storage_client.store_item(tags2, datastream); - - auto list = storage_client.list_items(tags_session); - EXPECT_EQ(list.items.size(), 5); - list = storage_client.list_items(tags1); - EXPECT_EQ(list.items.size(), 3); - list = storage_client.list_items(tags2); - EXPECT_EQ(list.items.size(), 2); -} - -TEST_F(StorageTest, storage_client_supports_time_to_live) { - StorageClient storage_client(storage_address); - auto data = generate_random_vector(256); - auto datastream = std::stringstream(std::string(data.begin(), data.end()), std::ios::binary); - std::string session_id = "mysession6"; - - auto tags = StorageItemTags::Builder("mypatient") - .with_device("mydevice") - .with_session(session_id) - .with_name("myname") - .build(); - - auto resp = storage_client.store_item(tags, datastream, std::chrono::seconds(10)); - ASSERT_TRUE(resp.expires.has_value()); - - resp = storage_client.store_item(tags, datastream); - ASSERT_FALSE(resp.expires.has_value()); -} - -TEST_F(StorageTest, storage_client_should_return_empty_ptr_when_not_found) { - StorageClient storage_client(storage_address); - std::string session_id = "mysession7"; - auto tags = StorageItemTags::Builder("mypatient") - .with_device("mydevice") - .with_session(session_id) - .with_name("myvariable1") - .build(); - - ASSERT_FALSE(storage_client.get_latest_item(tags)); - ASSERT_FALSE(storage_client.get_item_by_url(storage_address + "/foo"));; -} - -TEST_F(StorageTest, storage_client_exception_contains_server_error_message) { - StorageClient storage_client(storage_address); - auto tags = StorageItemTags::Builder("") - .build(); - - auto datastream = std::stringstream("abc"); - EXPECT_THROW( - try{ - storage_client.store_item(tags, datastream); - } catch (std::runtime_error const& e) { - EXPECT_THAT(e.what(), testing::HasSubstr("InvalidSubject")); - throw; - }, - std::runtime_error - ); -} - -TEST_F(StorageTest, storage_client_handles_trailing_slash_in_address) { - StorageClient storage_client(storage_address + "/"); - ASSERT_FALSE(storage_client.health_check().has_value()); -} - -TEST_F(StorageTest, storage_client_healthcheck_returns_error_when_address_invalid) { - StorageClient storage_client(storage_address + "/foobar"); - ASSERT_TRUE(storage_client.health_check().has_value()); -} - -TEST_F(StorageTest, storage_spaces_basic) { - hoNDArray x(10); - std::fill(x.begin(), x.end(), 23); - storage.session->store("stuff", x); - - auto item = storage.session->get_latest>("stuff"); - ASSERT_TRUE(item.has_value()); - ASSERT_EQ(x, *item); - - hoNDArray y(2, 2); - std::fill(y.begin(), y.end(), 23); - storage.session->store("stuff", y); - - item = storage.session->get_latest>("stuff"); - ASSERT_TRUE(item.has_value()); - ASSERT_EQ(y, *item); -} - -TEST_F(StorageTest, storage_spaces_larger_data) { - hoNDArray x(1024 * 255); - std::fill(x.begin(), x.end(), 23); - storage.session->store("larger_storage_test", x); - - auto item = storage.session->get_latest>("larger_storage_test"); - ASSERT_EQ(x, *item); -} - -TEST_F(StorageTest, storage_spaces_image_data) { - Core::Image image; - - auto& [header, data, meta] = image; - - data = hoNDArray(2, 2, 1, 4); - std::fill(data.begin(), data.end(), 3); - storage.session->store("image", image); - - auto item = storage.session->get_latest>("image"); - - auto [stored_header, stored_data, stored_meta] = *item; - ASSERT_EQ(data, stored_data); -} diff --git a/apps/pingvin/CMakeLists.txt b/apps/pingvin/CMakeLists.txt new file mode 100644 index 000000000..6a829bd9a --- /dev/null +++ b/apps/pingvin/CMakeLists.txt @@ -0,0 +1,62 @@ +find_package(PugiXML REQUIRED) + +configure_file(pingvin_config.in pingvin_config.h) + +add_executable(pingvin + main.cpp + initialization.cpp + initialization.h + system_info.cpp + + Loader.cpp + Loader.h + + Config.cpp + Config.h + + ErrorHandler.h + + nodes/Processable.h + nodes/Processable.cpp + + nodes/Stream.cpp + nodes/Stream.h + nodes/Parallel.cpp + nodes/Parallel.h + nodes/ParallelProcess.cpp + nodes/ParallelProcess.h + nodes/PureStream.cpp + nodes/PureStream.h + ) + +target_link_libraries(pingvin + pingvin_core + pingvin_toolbox_log + pingvin_toolbox_mri_core + Boost::system + Boost::filesystem + Boost::program_options + ${PUGIXML_LIBRARIES} + GTBLAS + ${CMAKE_DL_LIBS}) + +target_include_directories(pingvin + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR}) + + +if (REQUIRE_SIGNED_CONFIG) + target_link_libraries(pingvin GTBabylon) +endif() + +if (CUDA_FOUND) + target_link_libraries(pingvin ${CUDA_LIBRARIES}) +endif () + +if (GPERFTOOLS_PROFILER) + message("Adding gperftools cpu profiler to Pingvin link assemblage.") + target_link_libraries(pingvin ${GPERFTOOLS_PROFILER} ${GPERFTOOLS_TCMALLOC}) +endif () + +install(TARGETS pingvin DESTINATION bin COMPONENT main) diff --git a/apps/gadgetron/connection/config/Config.cpp b/apps/pingvin/Config.cpp similarity index 56% rename from apps/gadgetron/connection/config/Config.cpp rename to apps/pingvin/Config.cpp index f0db121b7..980a606cf 100644 --- a/apps/gadgetron/connection/config/Config.cpp +++ b/apps/pingvin/Config.cpp @@ -13,20 +13,8 @@ #include "log.h" #include "Config.h" -#include "Types.h" -using namespace Gadgetron::Server::Connection; -using namespace Gadgetron::Core; - -namespace Gadgetron::Server::Connection { - struct Config::External::Configuration { - pugi::xml_document document; - - explicit Configuration(const pugi::xml_node &configuration_node) : document() { - document.append_copy(configuration_node); - } - }; -} +using namespace Gadgetron::Main; namespace { @@ -38,8 +26,8 @@ namespace { private: static std::string make_message(const std::string &message, const pugi::xml_node &node) { std::stringstream stream; - stream << message << " "; - node.print(stream, "", pugi::format_raw); + stream << message << "\n"; + node.print(stream); return stream.str(); } }; @@ -47,12 +35,6 @@ namespace { template constexpr const char *xml_name(); - template<> - constexpr const char *xml_name() { return "reader"; } - - template<> - constexpr const char *xml_name() { return "writer"; } - template<> constexpr const char *xml_name() { return "gadget"; } @@ -62,9 +44,6 @@ namespace { template<> constexpr const char *xml_name() { return "merge"; } - template<> - constexpr const char *xml_name() { return "distributor"; } - struct XMLSerializer { template @@ -84,18 +63,6 @@ namespace { return child_node; } - static pugi::xml_node add_readers(const std::vector &readers, pugi::xml_node &node) { - auto readers_node = node.append_child("readers"); - for (auto &reader : readers) add_basenode(reader, readers_node); - return readers_node; - } - - static pugi::xml_node add_writers(const std::vector &writers, pugi::xml_node &node) { - auto writers_node = node.append_child("writers"); - for (auto &writer : writers) add_basenode(writer, writers_node); - return writers_node; - } - static void add_property(const std::pair &property, pugi::xml_node &node) { auto property_node = node.append_child("property"); property_node.append_attribute("name").set_value(property.first.c_str()); @@ -120,44 +87,6 @@ namespace { return parallel_node; } - static pugi::xml_node add_node(const Config::Distributed &distributed, pugi::xml_node &node) { - auto distributed_node = node.append_child("distributed"); - add_readers(distributed.readers, distributed_node); - add_writers(distributed.writers, distributed_node); - add_node(distributed.distributor, distributed_node); - add_node(distributed.stream, distributed_node); - - return distributed_node; - } - - static pugi::xml_node add_node(const Config::Execute &execute, pugi::xml_node &node) { - auto execute_node = node.append_child("execute"); - execute_node.append_attribute("name").set_value(execute.name.c_str()); - execute_node.append_attribute("type").set_value(execute.type.c_str()); - return execute_node; - } - - static pugi::xml_node add_node(const Config::Connect &connect, pugi::xml_node &node) { - auto connect_node = node.append_child("connect"); - connect_node.append_attribute("port").set_value(connect.port.c_str()); - return connect_node; - } - - static pugi::xml_node add_node(const Config::External &external, pugi::xml_node &node) { - - auto external_node = node.append_child("external"); - - add_readers(external.readers, external_node); - add_writers(external.writers, external_node); - visit( - [&](auto action) { add_node(action, external_node); }, - external.action - ); - external_node.append_copy(external.configuration->document); - - return external_node; - } - static pugi::xml_node add_node(const Config::Stream &stream, pugi::xml_node &node) { auto stream_node = node.append_child("stream"); stream_node.append_attribute("key").set_value(stream.key.c_str()); @@ -181,14 +110,6 @@ namespace { } return purestream_node; } - - static pugi::xml_node add_node(const Config::PureDistributed& distributed, pugi::xml_node& node){ - auto puredistributed_node = node.append_child("puredistributed"); - add_readers(distributed.readers,puredistributed_node); - add_writers(distributed.writers,puredistributed_node); - add_node(distributed.stream,puredistributed_node); - return puredistributed_node; - } }; struct Property { @@ -238,15 +159,15 @@ namespace { template - optional make_property(const pugi::xml_node &node) { - if (!Source::accepts(node)) return none; + std::optional make_property(const pugi::xml_node &node) { + if (!Source::accepts(node)) return std::nullopt; return Property{Source::name(node), Source::value(node)}; } template Property parse_property(const pugi::xml_node &node) { - std::vector> potentials = {make_property(node)...}; + std::vector> potentials = {make_property(node)...}; auto to_bool = [](auto &potential) { return bool(potential); }; auto n_valid = boost::count_if(potentials, to_bool); @@ -282,46 +203,20 @@ namespace { return value_string; } - static Config::Reader parse_reader(const pugi::xml_node &reader_node) { - - std::string slot_str = reader_node.child_value("slot"); - - optional slot = none; - if (!slot_str.empty()) - slot = static_cast(std::stoi(slot_str)); - - return Config::Reader{reader_node.child_value("dll"), - reader_node.child_value("classname"), - slot}; - } + template + NODE parse_node(const pugi::xml_node &gadget_node) { + std::string name(gadget_node.child_value("name")); + std::string dll(gadget_node.child_value("dll")); + std::string classname(gadget_node.child_value("classname")); - static std::vector parse_readers(const pugi::xml_node &reader_root) { - std::vector readers{}; - for (const auto &node : reader_root.children("reader")) { - readers.push_back(parse_reader(node)); + if (dll.empty()) { + throw ConfigNodeError("Missing dll for gadget " + name, gadget_node); } - return readers; - } - - static Config::Writer parse_writer(const pugi::xml_node &writer_node) { - return Config::Writer{writer_node.child_value("dll"), - writer_node.child_value("classname")}; - } - - static std::vector parse_writers(const pugi::xml_node &writer_root) { - std::vector writers{}; - for (const auto &node : writer_root.children("writer")) { - writers.push_back(parse_writer(node)); + if (classname.empty()) { + throw ConfigNodeError("Missing classname for gadget " + name, gadget_node); } - return writers; - } - template - NODE parse_node(const pugi::xml_node &gadget_node) { - return NODE{gadget_node.child_value("name"), - gadget_node.child_value("dll"), - gadget_node.child_value("classname"), - parse_properties(gadget_node)}; + return NODE{name, dll, classname, parse_properties(gadget_node)}; } private: @@ -370,33 +265,6 @@ namespace { } }; - bool is_legacy_python_gadget(const Config::Gadget &gadget) { - return gadget.dll == "gadgetron_python" && gadget.classname == "PythonGadget"; - } - - Config::Node transform_legacy_python_gadget(Config::Gadget gadget) { - GDEBUG_STREAM("Legacy Python Gadget detected: " << gadget.name) - - pugi::xml_document document; - auto configuration = document.append_child("configuration"); - - for (auto &property : gadget.properties) { - GDEBUG_STREAM("Appending property to configuration: " << property.first << ": " << property.second) - XMLSerializer::add_property(property, configuration); - } - - return Config::External{ - Config::Execute{ - gadget.properties.at("python_module"), - "python", - gadget.properties.at("python_class") - }, - std::make_shared(configuration), - std::vector(), - std::vector() - }; - } - class Legacy : public Parser { public: @@ -405,11 +273,7 @@ namespace { auto parser = Legacy(config); pugi::xml_node root = config.child("gadgetronStreamConfiguration"); - return Config{ - parse_readers(root), - parse_writers(root), - parser.parse_stream(root) - }; + return Config{ parser.parse_stream(root) }; } static bool accepts(const pugi::xml_document &config) { @@ -421,7 +285,6 @@ namespace { const std::list, std::function>> node_transformations{ - std::make_pair(is_legacy_python_gadget, transform_legacy_python_gadget), std::make_pair([](auto _) { return true; }, [=](auto c) { return Config::Node(c); }) }; @@ -463,11 +326,7 @@ namespace { auto parser = V2(config); auto root = config.child("configuration"); - return Config{ - parse_readers(root.child("readers")), - parse_writers(root.child("writers")), - parser.parse_stream(root.child("stream")) - }; + return Config{ parser.parse_stream(root.child("stream")) }; } static bool accepts(const pugi::xml_document &config) { @@ -480,10 +339,7 @@ namespace { explicit V2(const pugi::xml_document &doc) : Parser(doc) { node_parsers["gadget"] = [&](const pugi::xml_node &n) { return this->parse_node(n); }; node_parsers["parallel"] = [&](const pugi::xml_node &n) { return this->parse_parallel(n); }; - node_parsers["external"] = [&](const pugi::xml_node &n) { return this->parse_external(n); }; - node_parsers["distributed"] = [&](const pugi::xml_node &n) { return this->parse_distributed(n); }; node_parsers["parallelprocess"] = [&](const pugi::xml_node &n) { return this->parse_parallelprocess(n); }; - node_parsers["puredistributed"] = [&](const pugi::xml_node &n) { return this->parse_puredistributed(n); }; } std::unordered_map> node_parsers; @@ -500,24 +356,6 @@ namespace { return Config::Parallel{branch, merge, streams}; } - Config::External parse_external(const pugi::xml_node &external_node) { - - return Config::External{ - parse_action(external_node), - parse_action_configuration(external_node), - parse_readers(external_node.child("readers")), - parse_writers(external_node.child("writers")) - }; - } - - Config::Distributed parse_distributed(const pugi::xml_node &distributed_node) { - auto distributor = parse_node(distributed_node.child("distributor")); - auto stream = parse_stream(distributed_node.child("stream")); - auto readers = parse_readers(distributed_node.child("readers")); - auto writers = parse_writers(distributed_node.child("writers")); - return {readers,writers,distributor,stream}; - } - Config::Stream parse_stream(const pugi::xml_node &stream_node) { std::vector nodes; for (auto &node : stream_node.children()) { @@ -539,64 +377,12 @@ namespace { return Config::ParallelProcess{workers,parse_purestream(parallelprocess_node.child("purestream"))}; } - Config::PureDistributed parse_puredistributed(const pugi::xml_node& puredistributedprocess_node){ - - auto purestream = parse_purestream(puredistributedprocess_node.child("purestream")); - auto readers = parse_readers(puredistributedprocess_node.child("readers")); - auto writers = parse_writers(puredistributedprocess_node.child("writers")); - return {readers,writers,purestream}; - } - - static optional parse_target(std::string s) { - if (s.empty()) return none; - return s; - } - - static Config::Execute parse_execute(const pugi::xml_node &execute_node) { - return Config::Execute { - execute_node.attribute("name").value(), - execute_node.attribute("type").value(), - parse_target(execute_node.attribute("target").value()) - }; - } - - static std::string address_or_localhost(const std::string &s) { - return s.empty() ? "localhost" : s; - } - - static Config::Connect parse_connect(const pugi::xml_node &connect_node) { - return Config::Connect { - address_or_localhost(connect_node.attribute("address").value()), - connect_node.attribute("port").value() - }; - } - - std::map> action_parsers { - {"execute", parse_execute}, - {"connect", parse_connect} - }; - - Config::Action parse_action(const pugi::xml_node &external_node) { - - for (pugi::xml_node child : external_node) { - if (action_parsers.count(child.name())) { - return action_parsers.at(child.name())(child); - } - } - - throw ConfigNodeError("Unable to parse valid action for external node", external_node); - } - - std::shared_ptr - parse_action_configuration(const pugi::xml_node &external_node) { - return std::make_shared(external_node.child("configuration")); - } }; } -namespace Gadgetron::Server::Connection { +namespace Gadgetron::Main { - Config parse_config(std::istream &stream) { + Config Config::parse(std::istream &stream) { auto parsers = { std::make_pair(Legacy::accepts, Legacy::parse), @@ -616,22 +402,14 @@ namespace Gadgetron::Server::Connection { return std::get<1>(*parser)(doc); } - std::string serialize_config(const Config &config) { + std::string Config::serialize(const Config &config) { pugi::xml_document doc{}; auto config_node = doc.append_child("configuration"); config_node.append_child("version").text().set(2); - XMLSerializer::add_readers(config.readers, config_node); - XMLSerializer::add_writers(config.writers, config_node); XMLSerializer::add_node(config.stream, config_node); std::stringstream stream; doc.save(stream); return stream.str(); } - - std::string serialize_config(const Config::External& external_config) { - std::stringstream stream; - external_config.configuration->document.save(stream); - return stream.str(); - } } diff --git a/apps/pingvin/Config.h b/apps/pingvin/Config.h new file mode 100644 index 000000000..c9522a134 --- /dev/null +++ b/apps/pingvin/Config.h @@ -0,0 +1,60 @@ +#pragma once + +#include +#include +#include +#include + + +namespace Gadgetron::Main { + + struct Config { + + struct Gadget; + struct Parallel; + struct ParallelProcess; + using Node = std::variant; + + template + static std::string name(CONFIG config) { + return config.name.empty() ? config.classname : config.name; + } + + struct Stream { + std::string key; + std::vector nodes; + }; + + struct PureStream{ + std::vector gadgets; + }; + + struct Gadget { + std::string name, dll, classname; + std::unordered_map properties; + Gadget(std::string name, std::string dll, std::string classname, std::unordered_map properties): + name(std::move(name)), dll(std::move(dll)), classname(std::move(classname)), properties(std::move(properties)) + { + } + }; + + struct Branch : Gadget { using Gadget::Gadget;}; + struct Merge : Gadget { using Gadget::Gadget;}; + + struct Parallel { + Branch branch; + Merge merge; + std::vector streams; + }; + + struct ParallelProcess { + size_t workers = 0; + PureStream stream; + }; + + Stream stream; + + static Config parse(std::istream &stream); + static std::string serialize(const Config& config); + }; +} diff --git a/apps/gadgetron/connection/Core.h b/apps/pingvin/ErrorHandler.h similarity index 53% rename from apps/gadgetron/connection/Core.h rename to apps/pingvin/ErrorHandler.h index cbe45c74f..fc7a4eade 100644 --- a/apps/gadgetron/connection/Core.h +++ b/apps/pingvin/ErrorHandler.h @@ -6,11 +6,10 @@ #include "io/primitives.h" -#include "Writer.h" #include "Channel.h" #include "Context.h" -namespace Gadgetron::Server::Connection { +namespace Gadgetron::Main { class ErrorReporter { public: @@ -87,68 +86,4 @@ namespace Gadgetron::Server::Connection { const std::string location; ErrorReporter &push_error; }; - - template - void process_input(std::iostream &stream, Core::OutputChannel channel, F handler_factory) { - - bool closed = false; - auto handlers = handler_factory([&]() { closed = true; }); - - while (!closed) { - auto id = Core::IO::read(stream); - handlers.at(id)->handle(stream, channel); - } - } - - template - void process_output(std::iostream &stream, Core::GenericInputChannel messages, F writer_factory) { - - auto writers = writer_factory(); - - for (auto message : messages) { - - auto writer = std::find_if(writers.begin(), writers.end(), - [&](auto &writer) { return writer->accepts(message); } - ); - - if (writer != writers.end()) { - (*writer)->write(stream, std::move(message)); - } - } - } - - std::vector> default_writers(); - - template - std::thread start_input_thread( - std::iostream &stream, - Core::OutputChannel channel, - F handler_factory, - ErrorHandler &error_handler - ) { - - return ErrorHandler(error_handler,"Connection Input Thread").run( - [&stream](auto c, auto h) { process_input(stream, std::move(c), h); }, - std::move(channel), handler_factory); - } - - template - std::thread start_output_thread( - std::iostream &stream, - Core::GenericInputChannel channel, - F writer_factory, - ErrorHandler &error_handler - ) { - return ErrorHandler(error_handler,"Connection Output Thread").run( - [&stream](auto c, auto w) { process_output(stream, std::move(c), w); }, - std::move(channel), writer_factory - ); - } - - void handle_connection( - std::unique_ptr stream, - Core::StreamContext::Paths paths, - Core::StreamContext::Args args, - Core::StreamContext::StorageAddress storage_address - ); } \ No newline at end of file diff --git a/apps/pingvin/Loader.cpp b/apps/pingvin/Loader.cpp new file mode 100644 index 000000000..227f591c5 --- /dev/null +++ b/apps/pingvin/Loader.cpp @@ -0,0 +1,33 @@ +#include "Loader.h" + +#include + +#include "nodes/Stream.h" + +namespace Gadgetron::Main { + + Loader::Loader(const Core::StreamContext &context) : context(context) {} + + boost::dll::shared_library Loader::load_library(const std::string &shared_library_name) { + try + { + auto lib = boost::dll::shared_library( + shared_library_name, + boost::dll::load_mode::append_decorations | + boost::dll::load_mode::rtld_global | + boost::dll::load_mode::search_system_folders + ); + libraries.push_back(lib); + return lib; + } + catch( const std::exception & ex ) + { + std::cerr << ex.what() << std::endl; + throw; + } + } + + std::unique_ptr Loader::load(const Config::Stream &conf) { + return std::make_unique(conf, context, *this); + } +} diff --git a/apps/pingvin/Loader.h b/apps/pingvin/Loader.h new file mode 100644 index 000000000..494a537b2 --- /dev/null +++ b/apps/pingvin/Loader.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include + +#include "Config.h" +#include "nodes/Stream.h" + +#include "PropertyMixin.h" +#include "Context.h" + +#include + +namespace Gadgetron::Main::Nodes { + class Stream; +} + +namespace Gadgetron::Main { + + class Loader { + using Context = Core::Context; + using Stream = Gadgetron::Main::Nodes::Stream; + + using GadgetProperties = Core::GadgetProperties; + public: + explicit Loader(const Core::StreamContext &); + + std::unique_ptr load(const Config::Stream &); + + template + using generic_factory = std::unique_ptr( + const Context &, + const std::string &, + const GadgetProperties & + ); + + template + FACTORY& load_factory(const std::string &prefix, const std::string &classname, const std::string &dll) { + GINFO_STREAM("loading " << prefix << " - " << classname << " from the dll " << dll); + auto library = load_library(dll); + return library.get_alias(prefix + classname); + } + + private: + boost::dll::shared_library load_library(const std::string &shared_library_name); + + const Core::StreamContext context; + + std::vector libraries = std::vector(); + }; +} + diff --git a/apps/pingvin/StreamConsumer.h b/apps/pingvin/StreamConsumer.h new file mode 100644 index 000000000..1c4c983ab --- /dev/null +++ b/apps/pingvin/StreamConsumer.h @@ -0,0 +1,196 @@ +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "Channel.h" +#include "ErrorHandler.h" +#include "Loader.h" + +using namespace Gadgetron::Core; +using namespace Gadgetron::Main; + +namespace +{ + +class ErrorThrower : public ErrorReporter +{ + public: + void operator()(const std::string& location, const std::string& message) override { + throw std::runtime_error(("[" + location + "] ERROR: " + message)); + } +}; + +std::filesystem::path find_config_path(const std::string& home_dir, const std::string& config_xml) +{ + auto config_path = std::filesystem::path(home_dir) / std::filesystem::path(PINGVIN_CONFIG_PATH) / + std::filesystem::path(config_xml); + + if (!std::filesystem::is_regular_file(config_path)) { + throw std::runtime_error("Failed to find Pingvin configuration at the expected path: " + + config_path.string()); + } + + return config_path; +} + +} // namespace + +class StreamConsumer +{ +public: + StreamConsumer(const boost::program_options::variables_map& args) + : args_(args) {} + ~StreamConsumer() {} + + void consume(std::istream& input_stream, std::ostream& output_stream, std::string config_xml_name) + { + Context::Paths paths{ + args_["home"].as().string() + }; + + mrd::binary::MrdReader mrd_reader(input_stream); + mrd::binary::MrdWriter mrd_writer(output_stream); + + mrd::Header hdr = consume_mrd_header(mrd_reader, mrd_writer); + + auto context = StreamContext(hdr, paths, args_); + auto loader = Loader(context); + auto config_path = find_config_path(args_["home"].as().string(), config_xml_name); + + GINFO_STREAM("Loading configuration from: " << config_path.string()); + std::ifstream file(config_path, std::ios::in | std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Failed to open file at path: " + config_path.string()); + } + + auto config = Config::parse(file); + file.close(); + + auto stream = loader.load(config.stream); + auto input_channel = make_channel(); + auto output_channel = make_channel(); + std::atomic processing = true; + + auto process_future = std::async(std::launch::async, [&]() { + try + { + ErrorThrower error_thrower; + ErrorHandler error_handler(error_thrower, std::string(__FILE__)); + stream->process(std::move(input_channel.input), std::move(output_channel.output), error_handler); + processing = false; + } + catch (const std::exception& exc) + { + { + // Induce a ChannelClosed exception upon readers of the channel. + auto destruct_me = std::move(output_channel.output); + } + processing = false; + throw; + } + }); + + auto input_future = std::async(std::launch::async, [&]() { + try + { + consume_input_stream(mrd_reader, input_channel); + } + catch(std::ios_base::failure& exc) + { + // Induce a ChannelClosed exception upon readers of the channel. + auto destruct_me = std::move(input_channel.output); + } + }); + + auto output_future = std::async(std::launch::async, [&]() + { + process_output_stream(output_channel, mrd_writer); + }); + + // Clean up and propagate exceptions if they occurred + input_future.get(); + output_future.get(); + process_future.get(); + } + + private: + + mrd::Header consume_mrd_header(mrd::binary::MrdReader& mrd_reader, mrd::binary::MrdWriter& mrd_writer) + { + std::optional hdr; + + mrd_reader.ReadHeader(hdr); + mrd_writer.WriteHeader(hdr); + + if (!hdr.has_value()) { + GADGET_THROW("Failed to read ISMRMRD header"); + } + return hdr.value(); + } + + void consume_input_stream(mrd::binary::MrdReader& mrd_reader, ChannelPair& input_channel) + { + mrd::StreamItem stream_item; + while (mrd_reader.ReadData(stream_item)) { + std::visit([&](auto&& arg) { + Message msg(std::move(arg)); + input_channel.output.push_message(std::move(msg)); + }, stream_item); + } + + mrd_reader.Close(); + auto destruct_me = std::move(input_channel.output); + } + + void process_output_stream(ChannelPair& output_channel, mrd::binary::MrdWriter& mrd_writer) + { + while (true) { + try { + auto message = output_channel.input.pop(); + + if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else if (convertible_to(message) ) { + mrd_writer.WriteData(force_unpack(std::move(message))); + } else { + GADGET_THROW("Unsupported Message type for MrdWriter! Check that the last Gadget emits a valid MRD type."); + } + } catch (const ChannelClosed& exc) { + break; + } + } + + mrd_writer.EndData(); + mrd_writer.Close(); + } + + boost::program_options::variables_map args_; +}; diff --git a/apps/gadgetron/initialization.cpp b/apps/pingvin/initialization.cpp similarity index 90% rename from apps/gadgetron/initialization.cpp rename to apps/pingvin/initialization.cpp index aec432875..ea39ce959 100644 --- a/apps/gadgetron/initialization.cpp +++ b/apps/pingvin/initialization.cpp @@ -11,7 +11,7 @@ #include #endif #include -namespace Gadgetron::Server { +namespace Gadgetron::Main { void configure_blas_libraries() { @@ -36,7 +36,7 @@ namespace Gadgetron::Server { if ("passive" != get_policy()) { GWARN_STREAM("Environment variable 'OMP_WAIT_POLICY' not set to 'PASSIVE'."); - GWARN_STREAM("Gadgetron may experience serious performance issues under heavy load " << + GWARN_STREAM("Pingvin may experience serious performance issues under heavy load " << "(multiple simultaneous reconstructions, etc.)") } } diff --git a/apps/gadgetron/initialization.h b/apps/pingvin/initialization.h similarity index 79% rename from apps/gadgetron/initialization.h rename to apps/pingvin/initialization.h index dcbe17089..d3edfe984 100644 --- a/apps/gadgetron/initialization.h +++ b/apps/pingvin/initialization.h @@ -1,6 +1,6 @@ #pragma once -namespace Gadgetron::Server { +namespace Gadgetron::Main { void configure_blas_libraries(); void check_environment_variables(); diff --git a/apps/pingvin/main.cpp b/apps/pingvin/main.cpp new file mode 100644 index 000000000..0757ff5bf --- /dev/null +++ b/apps/pingvin/main.cpp @@ -0,0 +1,133 @@ +#include + +#include +#include + +#include "log.h" +#include "initialization.h" + +#include "system_info.h" +#include "pingvin_config.h" + +#include "StreamConsumer.h" + + +using namespace boost::filesystem; +using namespace boost::program_options; +using namespace Gadgetron::Main; + +using gadget_parameter = std::pair; + +std::istream& operator>>(std::istream& in, gadget_parameter& param) { + std::string token; + in >> token; + // parse = into a gadget_parameter + auto pos = token.find('='); + if (pos == std::string::npos) { + throw std::runtime_error("Invalid gadget parameter: " + token); + } + param.first = token.substr(0, pos); + param.second = token.substr(pos + 1); + return in; +} + +std::ostream& operator<<(std::ostream& out, const gadget_parameter& param) { + out << param.first << "=" << param.second; + return out; +} + +int main(int argc, char *argv[]) { + options_description gadgetron_options("Allowed options:"); + gadgetron_options.add_options() + ("help,h", "Prints this help message.") + ("info", "Prints build info about Pingvin.") + ("home,G", + value()->default_value(Info::default_pingvin_home()), + "Set the Pingvin home directory.") + ("input,i", + value(), + "Input file for binary data to perform a local reconstruction with") + ("output,o", + value(), + "Output file for binary data as a result of a local reconstruction") + ("config,c", + value(), + "Filename of the desired Pingvin reconstruction config.") + ("parameter", + value>(), + "Parameter to be passed to the Pingvin reconstruction config. Multiple parameters can be passed." + "Format: --parameter = --parameter = ..."); + + options_description desc; + desc.add(gadgetron_options); + + variables_map args; + store(parse_command_line(argc, argv, desc), args); + notify(args); + + try { + check_environment_variables(); + configure_blas_libraries(); + set_locale(); + + if (args.count("help")) { + GINFO_STREAM(desc); + return 0; + } + + if (args.count("info")) { + std::stringstream str; + Info::print_system_information(str); + GINFO(str.str().c_str()); + return 0; + } + + GINFO("Pingvin %s [%s]\n", PINGVIN_VERSION_STRING, PINGVIN_GIT_SHA1_HASH); + + if (!args.count("config")) + { + GERROR_STREAM("No config file provided. Use --config/-c"); + return 1; + } + + auto cfg = args["config"].as(); + StreamConsumer consumer(args); + + std::unique_ptr input_file; + if (args.count("input")) { + input_file = std::make_unique(args["input"].as()); + if (!input_file->good()) { + GERROR_STREAM("Could not open input file: " << args["input"].as()); + return 1; + } + } + + std::unique_ptr output_file; + if (args.count("output")) { + output_file = std::make_unique(args["output"].as()); + if (!output_file->good()) { + GERROR_STREAM("Could not open output file: " << args["output"].as()); + return 1; + } + } + + std::istream& input = input_file ? *input_file : std::cin; + std::ostream& output = output_file ? *output_file : std::cout; + consumer.consume(input, output, cfg); + std::flush(output); + + GDEBUG_STREAM("Finished consuming stream"); + } + catch (std::exception &e) + { + GERROR_STREAM(e.what() << std::endl); + std::exit(EXIT_FAILURE); + } + catch(...) + { + GERROR_STREAM("Unhandled exception, exiting" << std::endl); + std::exit(EXIT_FAILURE); + } + + return 0; +} diff --git a/apps/gadgetron/connection/nodes/Parallel.cpp b/apps/pingvin/nodes/Parallel.cpp similarity index 90% rename from apps/gadgetron/connection/nodes/Parallel.cpp rename to apps/pingvin/nodes/Parallel.cpp index 1fe4fcd6a..5909380fe 100644 --- a/apps/gadgetron/connection/nodes/Parallel.cpp +++ b/apps/pingvin/nodes/Parallel.cpp @@ -3,7 +3,7 @@ #include #include -#include "connection/Loader.h" +#include "Loader.h" #include "Channel.h" #include "Context.h" @@ -11,23 +11,23 @@ namespace { using namespace Gadgetron::Core; using namespace Gadgetron::Core::Parallel; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Nodes; + using namespace Gadgetron::Main; + using namespace Gadgetron::Main::Nodes; - using DecoratedBranch = Gadgetron::Server::Connection::Nodes::Parallel::DecoratedBranch; - using DecoratedMerge = Gadgetron::Server::Connection::Nodes::Parallel::DecoratedMerge; + using DecoratedBranch = Gadgetron::Main::Nodes::Parallel::DecoratedBranch; + using DecoratedMerge = Gadgetron::Main::Nodes::Parallel::DecoratedMerge; using branch_factory = Loader::generic_factory; using merge_factory = Loader::generic_factory; std::unique_ptr load_branch(const Config::Branch &conf, const Context &context, Loader &loader) { auto factory = loader.load_factory("branch_factory_export_", conf.classname, conf.dll); - return std::make_unique(factory(context, conf.properties), Config::name(conf)); + return std::make_unique(factory(context, Config::name(conf), conf.properties), Config::name(conf)); } std::unique_ptr load_merge(const Config::Merge &conf, const Context &context, Loader &loader) { auto factory = loader.load_factory("merge_factory_export_", conf.classname, conf.dll); - return std::make_unique(factory(context, conf.properties), Config::name(conf)); + return std::make_unique(factory(context, Config::name(conf), conf.properties), Config::name(conf)); } template @@ -44,8 +44,8 @@ namespace { namespace { using namespace Gadgetron::Core; using namespace Gadgetron::Core::Parallel; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Nodes; + using namespace Gadgetron::Main; + using namespace Gadgetron::Main::Nodes; ChannelPair split(const ChannelPair &in) { return ChannelPair{ split(in.input), split(in.output) }; @@ -66,7 +66,7 @@ namespace { } } -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { Parallel::Parallel( const Config::Parallel &config, diff --git a/apps/gadgetron/connection/nodes/Parallel.h b/apps/pingvin/nodes/Parallel.h similarity index 94% rename from apps/gadgetron/connection/nodes/Parallel.h rename to apps/pingvin/nodes/Parallel.h index 491bf75b7..45d358fe7 100644 --- a/apps/gadgetron/connection/nodes/Parallel.h +++ b/apps/pingvin/nodes/Parallel.h @@ -1,7 +1,7 @@ #pragma once #include "Stream.h" -#include "connection/core/Processable.h" +#include "Processable.h" #include "parallel/Branch.h" #include "parallel/Merge.h" @@ -9,7 +9,7 @@ #include "Channel.h" #include "Context.h" -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { class Parallel : public Processable { using Channel = Core::Channel; diff --git a/apps/gadgetron/connection/nodes/ParallelProcess.cpp b/apps/pingvin/nodes/ParallelProcess.cpp similarity index 97% rename from apps/gadgetron/connection/nodes/ParallelProcess.cpp rename to apps/pingvin/nodes/ParallelProcess.cpp index b0ab4b787..5b65d2697 100644 --- a/apps/gadgetron/connection/nodes/ParallelProcess.cpp +++ b/apps/pingvin/nodes/ParallelProcess.cpp @@ -4,7 +4,7 @@ using namespace Gadgetron::Core; -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { void ParallelProcess::process_input(GenericInputChannel input, Queue &queue) { diff --git a/apps/gadgetron/connection/nodes/ParallelProcess.h b/apps/pingvin/nodes/ParallelProcess.h similarity index 88% rename from apps/gadgetron/connection/nodes/ParallelProcess.h rename to apps/pingvin/nodes/ParallelProcess.h index 69acd9e85..21d8a527e 100644 --- a/apps/gadgetron/connection/nodes/ParallelProcess.h +++ b/apps/pingvin/nodes/ParallelProcess.h @@ -1,11 +1,11 @@ #pragma once #include "PureStream.h" -#include "connection/core/Processable.h" +#include "Processable.h" #include -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { class ParallelProcess : public Processable { public: diff --git a/apps/gadgetron/connection/core/Processable.cpp b/apps/pingvin/nodes/Processable.cpp similarity index 88% rename from apps/gadgetron/connection/core/Processable.cpp rename to apps/pingvin/nodes/Processable.cpp index a85729cfe..547cb7367 100644 --- a/apps/gadgetron/connection/core/Processable.cpp +++ b/apps/pingvin/nodes/Processable.cpp @@ -1,7 +1,7 @@ #include "Processable.h" -std::thread Gadgetron::Server::Connection::Processable::process_async( +std::thread Gadgetron::Main::Processable::process_async( std::shared_ptr processable, Core::GenericInputChannel input, Core::OutputChannel output, diff --git a/apps/gadgetron/connection/core/Processable.h b/apps/pingvin/nodes/Processable.h similarity index 90% rename from apps/gadgetron/connection/core/Processable.h rename to apps/pingvin/nodes/Processable.h index 5a87b7d40..76a6b69c6 100644 --- a/apps/gadgetron/connection/core/Processable.h +++ b/apps/pingvin/nodes/Processable.h @@ -1,12 +1,13 @@ #pragma once +#include "ErrorHandler.h" #include "Channel.h" #include "Context.h" + #include #include -#include "connection/Core.h" -namespace Gadgetron::Server::Connection { +namespace Gadgetron::Main { class Processable { public: diff --git a/apps/gadgetron/connection/nodes/PureStream.cpp b/apps/pingvin/nodes/PureStream.cpp similarity index 81% rename from apps/gadgetron/connection/nodes/PureStream.cpp rename to apps/pingvin/nodes/PureStream.cpp index 30f51a65f..815ca93a0 100644 --- a/apps/gadgetron/connection/nodes/PureStream.cpp +++ b/apps/pingvin/nodes/PureStream.cpp @@ -2,13 +2,13 @@ namespace { using namespace Gadgetron::Core; - using namespace Gadgetron::Server::Connection; + using namespace Gadgetron::Main; std::unique_ptr load_pure_gadget(const Config::Gadget& conf, const Context& context, Loader& loader) { auto factory = loader.load_factory>("gadget_factory_export_", conf.classname, conf.dll); - auto gadget = factory(context, conf.properties); + auto gadget = factory(context, Config::name(conf), conf.properties); if (dynamic_cast(gadget.get())) { return std::unique_ptr(dynamic_cast(gadget.release())); @@ -30,13 +30,13 @@ namespace { } } -Gadgetron::Server::Connection::Nodes::PureStream::PureStream( - const Gadgetron::Server::Connection::Config::PureStream& conf, +Gadgetron::Main::Nodes::PureStream::PureStream( + const Gadgetron::Main::Config::PureStream& conf, const Gadgetron::Core::Context& context, Loader& loader ) : pure_gadgets{ load_pure_gadgets(conf.gadgets, context, loader) } {} -Gadgetron::Core::Message Gadgetron::Server::Connection::Nodes::PureStream::process_function( +Gadgetron::Core::Message Gadgetron::Main::Nodes::PureStream::process_function( Gadgetron::Core::Message message ) const { return std::accumulate( diff --git a/apps/gadgetron/connection/nodes/PureStream.h b/apps/pingvin/nodes/PureStream.h similarity index 74% rename from apps/gadgetron/connection/nodes/PureStream.h rename to apps/pingvin/nodes/PureStream.h index fce9febb6..c861271d0 100644 --- a/apps/gadgetron/connection/nodes/PureStream.h +++ b/apps/pingvin/nodes/PureStream.h @@ -1,10 +1,10 @@ #pragma once #include "Message.h" #include "PureGadget.h" -#include "connection/Loader.h" -#include "connection/config/Config.h" +#include "Loader.h" +#include "Config.h" -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { class PureStream { public: PureStream(const Config::PureStream&, const Core::Context&, Loader&); diff --git a/apps/gadgetron/connection/nodes/Stream.cpp b/apps/pingvin/nodes/Stream.cpp similarity index 63% rename from apps/gadgetron/connection/nodes/Stream.cpp rename to apps/pingvin/nodes/Stream.cpp index 8f054855e..fbdebb995 100644 --- a/apps/gadgetron/connection/nodes/Stream.cpp +++ b/apps/pingvin/nodes/Stream.cpp @@ -1,34 +1,19 @@ #include "Stream.h" -#include "Distributed.h" -#include "External.h" #include "Parallel.h" #include "ParallelProcess.h" -#include "PureDistributed.h" -#include "connection/core/Processable.h" +#include "Processable.h" -#include "connection/Loader.h" +#include "Loader.h" #include "Node.h" namespace { using namespace Gadgetron::Core; - using namespace Gadgetron::Server::Connection; - using namespace Gadgetron::Server::Connection::Nodes; + using namespace Gadgetron::Main; + using namespace Gadgetron::Main::Nodes; using namespace std::string_literals; - std::string print_action(const Config::Execute& execute){ - return "Execute block with name "s + execute.name + " of type " + execute.type; - } - - std::string print_action(const Config::Connect& connect){ - return "Connect block on port "s + connect.port; - } - - std::string print_action(const Config::Action& action){ - return visit([](auto& ac){return print_action(ac);}, action); - } - class NodeProcessable : public Processable { public: NodeProcessable(std::function()> factory, std::string name) : factory(std::move(factory)), name_(std::move(name)) {} @@ -55,8 +40,8 @@ namespace { conf.dll); return std::make_shared( [=]() { - GDEBUG("Loading Gadget %s of class %s from %s\n", conf.name.c_str(), conf.classname.c_str(), conf.dll.c_str()); - return factory(context, conf.properties); + GDEBUG("Loading Gadget %s (class %s) from %s\n", conf.name.c_str(), conf.classname.c_str(), conf.dll.c_str()); + return factory(context, Config::name(conf), conf.properties); }, Config::name(conf) ); @@ -67,33 +52,18 @@ namespace { return std::make_shared(conf, context, loader); } - std::shared_ptr load_node(const Config::External &conf, const StreamContext &context, Loader &loader) { - GDEBUG("Loading External %s \n", print_action(conf.action).c_str()); - return std::make_shared(conf, context, loader); - } - - std::shared_ptr load_node(const Config::Distributed &conf, const StreamContext &context, Loader &loader) { - GDEBUG("Loading Distributed block\n"); - return std::make_shared(conf, context, loader); - } - std::shared_ptr load_node(const Config::ParallelProcess& conf, const StreamContext& context, Loader& loader){ GDEBUG("Loading ParalleProcess block\n"); return std::make_shared(conf,context,loader); } - - std::shared_ptr load_node(const Config::PureDistributed& conf, const StreamContext& context, Loader& loader){ - GDEBUG("Loading PureDistributed block\n"); - return std::make_shared(conf,context,loader); - } } -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { Stream::Stream(const Config::Stream &config, const Core::StreamContext &context, Loader &loader) : key(config.key) { for (auto &node_config : config.nodes) { nodes.emplace_back( - Core::visit([&](auto n) { return load_node(n, context, loader); }, node_config) + std::visit([&](auto n) { return load_node(n, context, loader); }, node_config) ); } } @@ -136,7 +106,7 @@ namespace Gadgetron::Server::Connection::Nodes { bool Stream::empty() const { return nodes.empty(); } } -const std::string &Gadgetron::Server::Connection::Nodes::Stream::name() { +const std::string &Gadgetron::Main::Nodes::Stream::name() { static const std::string name = "Stream"; return key.empty() ? name : key; } diff --git a/apps/gadgetron/connection/nodes/Stream.h b/apps/pingvin/nodes/Stream.h similarity index 74% rename from apps/gadgetron/connection/nodes/Stream.h rename to apps/pingvin/nodes/Stream.h index 56ece4936..cbeb35ca9 100644 --- a/apps/gadgetron/connection/nodes/Stream.h +++ b/apps/pingvin/nodes/Stream.h @@ -3,19 +3,19 @@ #include -#include "connection/Loader.h" -#include "connection/config/Config.h" +#include "Loader.h" +#include "Config.h" -#include "connection/core/Processable.h" +#include "Processable.h" #include "Channel.h" #include "Context.h" -namespace Gadgetron::Server::Connection { +namespace Gadgetron::Main { class Loader; } -namespace Gadgetron::Server::Connection::Nodes { +namespace Gadgetron::Main::Nodes { class Stream : public Processable { public: diff --git a/apps/pingvin/pingvin_config.in b/apps/pingvin/pingvin_config.in new file mode 100644 index 000000000..eead2bbfd --- /dev/null +++ b/apps/pingvin/pingvin_config.in @@ -0,0 +1,13 @@ +#ifndef PINGVIN_CONFIG_H +#define PINGVIN_CONFIG_H + +#define PINGVIN_VERSION_MAJOR @PINGVIN_VERSION_MAJOR@ +#define PINGVIN_VERSION_MINOR @PINGVIN_VERSION_MINOR@ +#define PINGVIN_VERSION_PATCH @PINGVIN_VERSION_PATCH@ +#define PINGVIN_VERSION_STRING "@PINGVIN_VERSION_STRING@" +#define PINGVIN_CONFIG_PATH "@PINGVIN_INSTALL_CONFIG_PATH@" +#define PINGVIN_PYTHON_PATH "@PINGVIN_INSTALL_PYTHON_MODULE_PATH@" +#define PINGVIN_GIT_SHA1_HASH "@PINGVIN_GIT_SHA1@" +#define PINGVIN_CUDA_NVCC_FLAGS "@CUDA_NVCC_FLAGS@" + +#endif //PINGVIN_CONFIG_H diff --git a/apps/pingvin/schema/gadgetron.xsd b/apps/pingvin/schema/gadgetron.xsd new file mode 100644 index 000000000..6b9602a37 --- /dev/null +++ b/apps/pingvin/schema/gadgetron.xsd @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/gadgetron/system_info.cpp b/apps/pingvin/system_info.cpp similarity index 58% rename from apps/gadgetron/system_info.cpp rename to apps/pingvin/system_info.cpp index a4373ad47..c7ac99f61 100644 --- a/apps/gadgetron/system_info.cpp +++ b/apps/pingvin/system_info.cpp @@ -1,25 +1,18 @@ #include "system_info.h" -#include "gadgetron_config.h" -#include "connection/nodes/external/Python.h" -#include "connection/nodes/external/Matlab.h" -#include "connection/nodes/external/Julia.h" +#include "pingvin_config.h" #include "log.h" #include "Process.h" - -#if defined(_WIN32) -#include -#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) - #include #include #include +#include #include +#include #include -#endif #if defined(BSD) #include #endif @@ -30,27 +23,18 @@ #include #endif -namespace Gadgetron::Server::Info { - std::string ismrmrd_version() { - return "0.0.0-alpha"; - } +namespace Gadgetron::Main::Info { - std::string gadgetron_version() { - return GADGETRON_VERSION_STRING; + std::string pingvin_version() { + return PINGVIN_VERSION_STRING; } - std::string gadgetron_build() { - return GADGETRON_GIT_SHA1_HASH; + std::string pingvin_build() { + return PINGVIN_GIT_SHA1_HASH; } size_t system_memory() { -#if defined(_WIN32) - MEMORYSTATUSEX status; - status.dwLength = sizeof(status); - GlobalMemoryStatusEx( &status ); - return (size_t)status.ullTotalPhys; -#else //Unix variant #if defined(CTL_HW) && (defined(HW_MEMSIZE) || defined(HW_PHYSMEM64)) //Mac int mib[2]; @@ -74,24 +58,11 @@ namespace Gadgetron::Server::Info { #endif //Mac -#endif //WIN32 return 0L; } - bool python_support() { - return Gadgetron::Server::Connection::Nodes::python_available(); - } - - bool matlab_support() { - return Gadgetron::Server::Connection::Nodes::matlab_available(); - } - bool julia_support() { - return Gadgetron::Server::Connection::Nodes::julia_available(); - } - -#if defined USE_CUDA namespace CUDA { - +#if defined USE_CUDA std::string format_version(int version) { std::stringstream stream; stream << (version / 1000) << "." << (version % 100) / 10; @@ -150,20 +121,17 @@ namespace Gadgetron::Server::Info { int device_count = CUDA::cuda_device_count(); os << " -- CUDA Support : YES" << std::endl; - os << " -- NVCC Flags : " << GADGETRON_CUDA_NVCC_FLAGS << std::endl; - os << " * Number of CUDA capable devices: " << device_count << std::endl; + os << " -- NVCC Flags : " << PINGVIN_CUDA_NVCC_FLAGS << std::endl; + os << " -- CUDA Device count : " << device_count << std::endl; for (int dev = 0; dev < device_count; dev++) { os << " - Device " << dev << ": " << CUDA::cuda_device_name(dev) << std::endl; os << " + CUDA Driver Version / Runtime Version: " << CUDA::cuda_driver_version() << "/" << CUDA::cuda_runtime_version() << std::endl; os << " + CUDA Capability Major / Minor version number: " << CUDA::cuda_device_capabilities(dev) << std::endl; - os << " + Total amount of global GPU memory: " << std::to_string(CUDA::cuda_device_memory(dev) / (1024 * 1024)) << " MB" << std::endl; + os << " + CUDA Device Memory size: " << std::to_string(CUDA::cuda_device_memory(dev) / (1024 * 1024)) << " MB" << std::endl; } } - } #else - namespace CUDA { - bool cuda_support() { return false; } @@ -195,49 +163,74 @@ namespace Gadgetron::Server::Info { void print_cuda_information(std::ostream &os) { os << " -- CUDA Support : NO" << std::endl; } - } #endif + } // namespace CUDA void print_system_information(std::ostream &os) { - os << "Gadgetron Version Info" << std::endl; - os << " -- Version : " << gadgetron_version().c_str() << std::endl; - os << " -- Git SHA1 : " << gadgetron_build().c_str() << std::endl; + os << "Pingvin Version Info" << std::endl; + os << " -- Version : " << pingvin_version().c_str() << std::endl; + os << " -- Git SHA1 : " << pingvin_build().c_str() << std::endl; os << " -- System Memory size : " << std::to_string(system_memory() / (1024 * 1024)) << " MB" << std::endl; - os << " -- Python Support : " << (python_support() ? "YES" : "NO") << std::endl; - os << " -- Julia Support : " << (julia_support() ? "YES" : "NO") << std::endl; - os << " -- Matlab Support : " << (matlab_support() ? "YES" : "NO") << std::endl; CUDA::print_cuda_information(os); os << std::endl; } + namespace { - boost::asio::ip::tcp get_max_tcp_protocol(){ -#ifdef __linux__ - std::future output_stream; - - // cat /sys/module/ipv6/parameters/disable - auto error = Gadgetron::Process::system( - boost::process::search_path("cat"), - boost::process::args={"/sys/module/ipv6/parameters/disable"}, - boost::process::std_in.close(), - boost::process::std_out > output_stream, - boost::process::std_err > boost::process::null - ); - - if (!error) { - auto disabled = std::stoi(output_stream.get()); - - if (!disabled) { - return boost::asio::ip::tcp::v6(); - } + + #if defined __APPLE__ + #include + + std::string get_executable_path() { + char path[PATH_MAX]; + char resolved[PATH_MAX]; + uint32_t size = sizeof(path); + + if ((_NSGetExecutablePath(path, &size) == 0) && (realpath(path, resolved) != NULL)) { + return std::string(resolved); + } else { + throw std::runtime_error("Could not determine location of Pingvin binary."); } + } + #else + std::string get_executable_path(size_t buffer_size = 1024) { - GWARN_STREAM("IPv6 not supported by operating system; falling back to IPv4.") - return boost::asio::ip::tcp::v4(); -#endif - return boost::asio::ip::tcp::v6(); + auto buffer = std::make_unique(buffer_size); + + ssize_t len = readlink("/proc/self/exe", buffer.get(), buffer_size); + + if (len < 0) { + throw std::runtime_error("Failed to read /proc/self/exe - cannot determine Pingvin binary path."); + } + + if (size_t(len) == buffer_size) { + // Allocated buffer was probably too small. Try again with a bigger buffer. + return get_executable_path(buffer_size * 2); + } + + return {buffer.get(), size_t(len)}; } - const boost::asio::ip::tcp gadgetron_tcp_protocol = get_max_tcp_protocol(); - } + #endif + } // namespace - boost::asio::ip::tcp tcp_protocol() { return gadgetron_tcp_protocol; } + const boost::filesystem::path default_pingvin_home() { + + const char *home = std::getenv("PINGVIN_HOME"); + + if (home != nullptr) { + return boost::filesystem::path(home); + } + + boost::filesystem::path executable_path = get_executable_path(); + + GDEBUG_STREAM("Executable path: " << executable_path); + + boost::filesystem::path pingvin_home = executable_path + .parent_path() + .parent_path(); + + GDEBUG_STREAM("Default Pingvin home: " << pingvin_home); + + return pingvin_home; } + +} // namespace diff --git a/apps/gadgetron/system_info.h b/apps/pingvin/system_info.h similarity index 69% rename from apps/gadgetron/system_info.h rename to apps/pingvin/system_info.h index 008253e2c..6f58aac7f 100644 --- a/apps/gadgetron/system_info.h +++ b/apps/pingvin/system_info.h @@ -1,22 +1,21 @@ #pragma once #include -#include -namespace Gadgetron::Server::Info { - - void print_system_information(std::ostream &); +#include +namespace Gadgetron::Main::Info { - boost::asio::ip::tcp tcp_protocol(); - std::string ismrmrd_version(); + void print_system_information(std::ostream &); - std::string gadgetron_version(); - std::string gadgetron_build(); + std::string pingvin_version(); + std::string pingvin_build(); size_t system_memory(); bool python_support(); bool matlab_support(); + const boost::filesystem::path default_pingvin_home(); + namespace CUDA { bool cuda_support(); int cuda_device_count(); diff --git a/apps/standalone/CMakeLists.txt b/apps/standalone/CMakeLists.txt deleted file mode 100644 index 580a01764..000000000 --- a/apps/standalone/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -include_directories( - ${CMAKE_BINARY_DIR}/toolboxes/core -) - - -add_subdirectory(cpu) -if (CUDA_FOUND) - add_subdirectory(gpu) -endif() diff --git a/apps/standalone/cpu/CMakeLists.txt b/apps/standalone/cpu/CMakeLists.txt deleted file mode 100644 index d3716eda5..000000000 --- a/apps/standalone/cpu/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -include_directories( - ${ARMADILLO_INCLUDE_DIRS} - ${Boost_INCLUDE_DIR} - ${FFTW3_INCLUDE_DIR} - ${CMAKE_SOURCE_DIR}/toolboxes/mri/pmri/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/nfft/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/core - ${CMAKE_SOURCE_DIR}/toolboxes/core/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/image - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/hostutils - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/math - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/image - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/algorithm - ${CMAKE_SOURCE_DIR}/toolboxes/operators - ${CMAKE_SOURCE_DIR}/toolboxes/operators/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/solvers - ${CMAKE_SOURCE_DIR}/toolboxes/solvers/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/transformation - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/solver - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/warper - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/dissimilarity - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/register - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/cpu/application - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus/util - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus/workflow - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus/algorithm - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus/solver - ${CMAKE_SOURCE_DIR}/toolboxes/gtplus/matlab - ${CMAKE_SOURCE_DIR}/toolboxes/gadgettools - ${CMAKE_SOURCE_DIR}/apps/gadgetron - ${CMAKE_SOURCE_DIR}/apps/matlab - ${CMAKE_SOURCE_DIR}/gadgets/mri_core - ${CMAKE_SOURCE_DIR}/gadgets/gtPlus -) - -#add_subdirectory(MRI) -add_subdirectory(denoising) -add_subdirectory(registration) diff --git a/apps/standalone/cpu/denoising/2d/CMakeLists.txt b/apps/standalone/cpu/denoising/2d/CMakeLists.txt deleted file mode 100644 index 7fceac80c..000000000 --- a/apps/standalone/cpu/denoising/2d/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -if (WIN32) - add_definitions(-D_USE_MATH_DEFINES) -endif () - - - -add_executable(cpu_denoise_TV denoise_TV.cpp) -target_link_libraries(cpu_denoise_TV - gadgetron_toolbox_cpucore - gadgetron_toolbox_cpucore_math - gadgetron_toolbox_hostutils - GTBLAS - Boost::system - ) - - - -install(TARGETS cpu_denoise_TV DESTINATION bin COMPONENT main) diff --git a/apps/standalone/cpu/denoising/2d/denoise_TV.cpp b/apps/standalone/cpu/denoising/2d/denoise_TV.cpp deleted file mode 100644 index 967da0ee2..000000000 --- a/apps/standalone/cpu/denoising/2d/denoise_TV.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - Total variation denoising based on the paper - "The Split Bregman Method for L1-Regularized Problems" by Tom Goldstein and Stanley Osher. - Siam J. Imaging Sciences. Vol. 2, No. 2, pp. 323-343. -*/ - -// Gadgetron includes -#include "hoNDArray.h" -#include "hoNDArray_fileio.h" -#include "hoSbCgSolver.h" -#include "hoIdentityOperator.h" -#include "hoPartialDerivativeOperator.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Noisy image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "denoised_image_TV.real" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of cg iterations", true, "20" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of sb inner iterations", true, "1" ); - parms.add_parameter( 'O', COMMAND_LINE_INT, 1, "Number of sb outer iterations", true, "10" ); - parms.add_parameter( 'm', COMMAND_LINE_FLOAT, 1, "Regularization weight (mu)", true, "25.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running denoising with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_real> > data = - read_nd_array<_real>((char*)parms.get_parameter('d')->get_string_value()); - - if( !data.get() ){ - GINFO_STREAM(endl << "Input image not found. Quitting!\n" << endl); - return 1; - } - - if( data->get_number_of_dimensions() != 2 ){ - GINFO_STREAM(endl << "Input image is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - _real mu = (_real) parms.get_parameter('m')->get_float_value(); - _real lambda = (_real)2.0*mu; // This is a good alround setting according to Goldstein et al. - - if( mu <= (_real) 0.0 ) { - GINFO_STREAM(endl << "Regularization parameter mu should be strictly positive. Quitting!\n" << endl); - return 1; - } - - size_t num_cg_iterations = parms.get_parameter('i')->get_int_value(); - size_t num_inner_iterations = parms.get_parameter('I')->get_int_value(); - size_t num_outer_iterations = parms.get_parameter('O')->get_int_value(); - - // Setup regularization operators - boost::shared_ptr< hoPartialDerivativeOperator<_real,2> > Rx( new hoPartialDerivativeOperator<_real,2>(0) ); - Rx->set_weight( lambda ); - Rx->set_domain_dimensions(data->get_dimensions()); - Rx->set_codomain_dimensions(data->get_dimensions()); - - boost::shared_ptr< hoPartialDerivativeOperator<_real,2> > Ry( new hoPartialDerivativeOperator<_real,2>(1) ); - Ry->set_weight( lambda ); - Ry->set_domain_dimensions(data->get_dimensions()); - Ry->set_codomain_dimensions(data->get_dimensions()); - - // Define encoding operator (identity) - boost::shared_ptr< identityOperator > > E( new identityOperator >() ); - E->set_weight( mu ); - E->set_domain_dimensions(data->get_dimensions()); - E->set_codomain_dimensions(data->get_dimensions()); - - // Setup split-Bregman solver - hoSbCgSolver<_real> sb; - sb.set_encoding_operator( E ); - //sb.add_regularization_operator( Rx ); // Anisotropic denoising - //sb.add_regularization_operator( Ry ); // Anisotropic denoising - sb.add_regularization_group_operator( Rx ); // Isotropic denoising - sb.add_regularization_group_operator( Ry); // Isotropic denoising - sb.add_group(); - sb.set_max_outer_iterations(num_outer_iterations); - sb.set_max_inner_iterations(num_inner_iterations); - sb.set_output_mode( hoCgSolver<_real>::OUTPUT_VERBOSE ); - - // Setup inner conjugate gradient solver - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - sb.get_inner_solver()->set_tc_tolerance( 1e-4 ); - sb.get_inner_solver()->set_output_mode( hoCgSolver<_real>::OUTPUT_WARNINGS ); - - // Run split-Bregman solver - boost::shared_ptr< hoNDArray<_real> > sbresult = sb.solve(data.get()); - - // All done, write out the result - write_nd_array<_real>(sbresult.get(), (char*)parms.get_parameter('r')->get_string_value()); - - return 0; -} diff --git a/apps/standalone/cpu/denoising/CMakeLists.txt b/apps/standalone/cpu/denoising/CMakeLists.txt deleted file mode 100644 index 5c4cec952..000000000 --- a/apps/standalone/cpu/denoising/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(2d) diff --git a/apps/standalone/cpu/nfft/CMakeLists.txt b/apps/standalone/cpu/nfft/CMakeLists.txt deleted file mode 100644 index 179c6f89a..000000000 --- a/apps/standalone/cpu/nfft/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -include_directories( - ${cmake_source_dir}/toolboxes/core - ${cmake_source_dir}/toolboxes/core/cpu - ${cmake_source_dir}/toolboxes/core/cpu/math - ${cmake_source_dir}/toolboxes/core/cpu/hostutils - ${cmake_source_dir}/toolboxes/nfft/cpu - ${cmake_source_dir}/toolboxes/solvers - ${cmake_source_dir}/toolboxes/solvers/cpu -) - -add_executable(nfft nfft.cpp) - -target_link_libraries(nfft - gadgetron_toolbox_cpucore - gadgetron_toolbox_cpucore_math - gadgetron_toolbox_hostutils - gadgetron_toolbox_cpunfft -) - -install(TARGETS nfft DESTINATION bin COMPONENT main) diff --git a/apps/standalone/cpu/nfft/nfft.cpp b/apps/standalone/cpu/nfft/nfft.cpp deleted file mode 100644 index 2794696b9..000000000 --- a/apps/standalone/cpu/nfft/nfft.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/** - \brief command line tool for using the cpu hoNFFT toolbox - - Handles 2D data with the weights provided - - \param d: the kspace data points - \param k: the kspace trajectory - \param w: density compensation - \param s: oversampling factor for gridding recon - \param q: width of the kernl on oversampled grid - \param n: non-oversampled size of image - \param o: output file -*/ - -#include "hoNDArray.h" -#include "hoNDArray_fileio.h" -#include -#include "parameterparser.h" -#include "vector_td.h" -#include "hoNFFT.h" -#include "hoCgSolver.h" -#include -#include "hoLsqrSolver.h" - -using namespace std; -using namespace Gadgetron; - -int main(int argc, char** argv){ - ParameterParser parms; - parms.add_parameter('d', COMMAND_LINE_STRING, 1, "Data (.cplx)", true, "d.cplx"); - parms.add_parameter('k', COMMAND_LINE_STRING, 1, "Trajectories (.real", true, "k.real"); - parms.add_parameter('w', COMMAND_LINE_STRING, 1, "Density compensation (.real)", true, "w.real"); - parms.add_parameter('s', COMMAND_LINE_FLOAT, 1, "Oversampling factor (float)", true, "1.5"); - parms.add_parameter('q', COMMAND_LINE_FLOAT, 1, "Kernel width (float)", true, "7"); - parms.add_parameter('n', COMMAND_LINE_INT, 1, "Image size (int)", true, "128"); - parms.add_parameter('o', COMMAND_LINE_STRING, 1, "Output file (.cplx)", true, "out.cplx"); - - parms.parse_parameter_list(argc, argv); - if(parms.all_required_parameters_set()){ - GINFO_STREAM("Running nfft with the following parameter:" << endl); - parms.print_parameter_list(); - }else{ - GINFO_STREAM("Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load data from disk - boost::shared_ptr>> data = - read_nd_array>((char*) parms.get_parameter('d')->get_string_value()); - boost::shared_ptr> traj = - read_nd_array((char*) parms.get_parameter('k')->get_string_value()); - boost::shared_ptr> weights = - read_nd_array((char*) parms.get_parameter('w')->get_string_value()); - float osf = parms.get_parameter('s')->get_float_value(); - float kernelWidth = parms.get_parameter('q')->get_float_value(); - int n = parms.get_parameter('n')->get_int_value(); - - // Print data info - GINFO_STREAM("data n: " << data->get_number_of_elements() << endl); - GINFO_STREAM("traj n: " << traj->get_number_of_elements() << endl); - GINFO_STREAM("weights n: " << weights->get_number_of_elements() << endl); - GINFO_STREAM("osf: " << osf << endl); - GINFO_STREAM("Kernel width: " << kernelWidth << endl); - GINFO_STREAM("Matrix size: " << n << endl); - - // Reformat data for hoNFFT - hoNDArray::Type> k(weights->get_number_of_elements()); - for(size_t i = 0; i < traj->get_number_of_elements()/2; i++) - k[i][0] = (*traj)[i]; - for(size_t i = traj->get_number_of_elements()/2; i < traj->get_number_of_elements(); i++) - k[i-traj->get_number_of_elements()/2][1] = (*traj)[i]; - - typename uint64d<2>::Type matrixSize; matrixSize[0] = n; matrixSize[1] = n; - typename uint64d<2>::Type matrixSizeOs; matrixSizeOs[0] = n*osf; matrixSizeOs[1] = n*osf; - - hoNFFT_plan plan(matrixSize, osf, kernelWidth); - hoNDArray> result(matrixSizeOs[0], matrixSizeOs[1]); - plan.preprocess(k); - plan.compute((*data), result, (*weights), hoNFFT_plan::NFFT_BACKWARDS_NC2C); - - auto output = boost::make_shared>>(result); - write_nd_array>(output.get(), (char*) parms.get_parameter('o')->get_string_value()); -} diff --git a/apps/standalone/cpu/registration/2d/CMakeLists.txt b/apps/standalone/cpu/registration/2d/CMakeLists.txt deleted file mode 100644 index 4eface32e..000000000 --- a/apps/standalone/cpu/registration/2d/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/fft/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/klt/cpu - ${ACE_INCLUDE_DIR} - ${ISMRMRD_INCLUDE_DIR} - ) - -add_executable(register_HS_2d_cpu register_HS_2d.cpp) -add_executable(register_CK_2d_cpu register_CK_2d.cpp) - -target_link_libraries(register_HS_2d_cpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_cpureg - gadgetron_toolbox_cpucore - gadgetron_toolbox_cpucore_math - armadillo - ) - -target_link_libraries(register_CK_2d_cpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_cpureg - gadgetron_toolbox_cpucore - gadgetron_toolbox_cpucore_math - armadillo - ) - -install(TARGETS - register_HS_2d_cpu - register_CK_2d_cpu - DESTINATION bin COMPONENT main) diff --git a/apps/standalone/cpu/registration/2d/register_CK_2d.cpp b/apps/standalone/cpu/registration/2d/register_CK_2d.cpp deleted file mode 100644 index 5f70e77b0..000000000 --- a/apps/standalone/cpu/registration/2d/register_CK_2d.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - An example of how to register two 2d images using Cornelius-Kanade optical flow -*/ - -// Gadgetron includes -#include "hoCKOpticalFlowSolver.h" -#include "hoLinearResampleOperator.h" -#include "hoNDArray.h" -#include "hoNDArray_fileio.h" -#include "GadgetronTimer.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.05" ); - parms.add_parameter( 'b', COMMAND_LINE_FLOAT, 1, "Regularization weight (beta)", true, "1.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > fixed_image = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > moving_image = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !fixed_image.get() || !moving_image.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - size_t num_fixed_dims = fixed_image->get_number_of_dimensions(); - size_t num_moving_dims = moving_image->get_number_of_dimensions(); - - if( !(num_fixed_dims == 2 || num_fixed_dims == 3) ){ - GINFO_STREAM(endl << "The fixed image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 2 || num_moving_dims == 3) ){ - GINFO_STREAM(endl << "The moving image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - _real beta = (_real) parms.get_parameter('b')->get_float_value(); - - // Use bilinear interpolation for resampling - // - - boost::shared_ptr< hoLinearResampleOperator<_real,2> > R( new hoLinearResampleOperator<_real,2>() ); - - // Setup solver - // - - hoCKOpticalFlowSolver<_real,2> CK; - CK.set_interpolator( R ); - CK.set_output_mode( hoCKOpticalFlowSolver<_real,2>::OUTPUT_VERBOSE ); - CK.set_num_multires_levels( 4 ); - CK.set_max_num_iterations_per_level( 500 ); - CK.set_alpha(alpha); - CK.set_beta(beta); - CK.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< hoNDArray<_real> > result; - { - GadgetronTimer timer("Running registration"); - result = CK.solve( fixed_image.get(), moving_image.get() ); - } - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< hoNDArray<_real> > deformed_moving; - { - GadgetronTimer timer("Applying deformation"); - deformed_moving = CK.deform( moving_image.get(), result ); - } - - // All done, write out the result - // - - write_nd_array<_real>(result.get(), (char*)parms.get_parameter('r')->get_string_value()); - write_nd_array<_real>(deformed_moving.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/cpu/registration/2d/register_HS_2d.cpp b/apps/standalone/cpu/registration/2d/register_HS_2d.cpp deleted file mode 100644 index 8db878e61..000000000 --- a/apps/standalone/cpu/registration/2d/register_HS_2d.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/* - An example of how to register two 2d images using Horn-Schunk optical flow -*/ - -// Gadgetron includes -#include "hoHSOpticalFlowSolver.h" -#include "hoLinearResampleOperator.h" -#include "hoNDArray.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.1" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > fixed_image = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > moving_image = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !moving_image.get() || !fixed_image.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - size_t num_fixed_dims = fixed_image->get_number_of_dimensions(); - size_t num_moving_dims = moving_image->get_number_of_dimensions(); - - if( !(num_fixed_dims == 2 || num_fixed_dims == 3) ){ - GINFO_STREAM(endl << "The fixed image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 2 || num_moving_dims == 3) ){ - GINFO_STREAM(endl << "The moving image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - - // Use bilinear interpolation for resampling - // - - boost::shared_ptr< hoLinearResampleOperator<_real,2> > R( new hoLinearResampleOperator<_real,2>() ); - - // Setup solver - // - - hoHSOpticalFlowSolver<_real,2> HS; - HS.set_interpolator( R ); - HS.set_output_mode( hoHSOpticalFlowSolver<_real,2>::OUTPUT_VERBOSE ); - HS.set_num_multires_levels( 4 ); - HS.set_max_num_iterations_per_level( 500 ); - HS.set_alpha(alpha); - HS.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< hoNDArray<_real> > result = HS.solve( fixed_image.get(), moving_image.get() ); - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< hoNDArray<_real> > deformed_moving = HS.deform( moving_image.get(), result ); - - // All done, write out the result - // - - write_nd_array<_real>(result.get(), (char*)parms.get_parameter('r')->get_string_value()); - write_nd_array<_real>(deformed_moving.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/cpu/registration/3d/CMakeLists.txt b/apps/standalone/cpu/registration/3d/CMakeLists.txt deleted file mode 100644 index c487c0748..000000000 --- a/apps/standalone/cpu/registration/3d/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_executable(register_CK_3d_cpu register_CK_3d.cpp) - -target_link_libraries(register_CK_3d_cpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_cpureg - gadgetron_toolbox_cpucore - gadgetron_toolbox_cpucore_math - armadillo - ) - -install(TARGETS register_CK_3d_cpu DESTINATION bin COMPONENT main) diff --git a/apps/standalone/cpu/registration/3d/register_CK_3d.cpp b/apps/standalone/cpu/registration/3d/register_CK_3d.cpp deleted file mode 100644 index 592066b03..000000000 --- a/apps/standalone/cpu/registration/3d/register_CK_3d.cpp +++ /dev/null @@ -1,115 +0,0 @@ -/* - An example of how to register two 3d volumes using Cornelius-Kanade optical flow -*/ - -// Gadgetron includes -#include "hoCKOpticalFlowSolver.h" -#include "hoLinearResampleOperator.h" -#include "hoNDArray.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.05" ); - parms.add_parameter( 'b', COMMAND_LINE_FLOAT, 1, "Regularization weight (beta)", true, "1.0" ); - parms.add_parameter( 'l', COMMAND_LINE_INT, 1, "Number of multiresolution levels", true, "3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > fixed_image = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > moving_image = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !fixed_image.get() || !moving_image.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - size_t num_fixed_dims = fixed_image->get_number_of_dimensions(); - size_t num_moving_dims = moving_image->get_number_of_dimensions(); - - if( !(num_fixed_dims == 3 || num_fixed_dims == 4) ){ - GINFO_STREAM(endl << "The fixed image is not three- or four-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 3 || num_moving_dims == 4) ){ - GINFO_STREAM(endl << "The moving image is not three- or four-dimensional. Quitting!\n" << endl); - return 1; - } - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - _real beta = (_real) parms.get_parameter('b')->get_float_value(); - - unsigned int multires_levels = parms.get_parameter('l')->get_int_value(); - - // Use trilinear interpolation for resampling - // - - boost::shared_ptr< hoLinearResampleOperator<_real,3> > R( new hoLinearResampleOperator<_real,3>() ); - - // Setup solver - // - - hoCKOpticalFlowSolver<_real,3> CK; - CK.set_interpolator( R ); - CK.set_output_mode( hoCKOpticalFlowSolver<_real,3>::OUTPUT_VERBOSE ); - CK.set_max_num_iterations_per_level( 500 ); - CK.set_num_multires_levels( multires_levels ); - CK.set_alpha(alpha); - CK.set_beta(beta); - CK.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< hoNDArray<_real> > result = CK.solve( fixed_image.get(), moving_image.get() ); - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< hoNDArray<_real> > deformed_moving = CK.deform( moving_image.get(), result ); - - // All done, write out the result - // - - write_nd_array<_real>(result.get(), (char*)parms.get_parameter('r')->get_string_value()); - write_nd_array<_real>(deformed_moving.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/cpu/registration/CMakeLists.txt b/apps/standalone/cpu/registration/CMakeLists.txt deleted file mode 100644 index 7159eed36..000000000 --- a/apps/standalone/cpu/registration/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -add_subdirectory(2d) -add_subdirectory(3d) - diff --git a/apps/standalone/gpu/CMakeLists.txt b/apps/standalone/gpu/CMakeLists.txt deleted file mode 100644 index 1fb25ab4e..000000000 --- a/apps/standalone/gpu/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/core - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/image - ${CMAKE_SOURCE_DIR}/toolboxes/core/cpu/hostutils - ${CMAKE_SOURCE_DIR}/toolboxes/core/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/fft/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/nfft/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/operators - ${CMAKE_SOURCE_DIR}/toolboxes/operators/gpu - ${CMAKE_SOURCE_DIR}/toolboxes/solvers - ${CMAKE_SOURCE_DIR}/toolboxes/solvers/gpu - ${Boost_INCLUDE_DIR} - ${ISMRMRD_INCLUDE_DIR} - ) - -add_subdirectory(mri) -add_subdirectory(denoising) -add_subdirectory(deblurring) -add_subdirectory(registration) diff --git a/apps/standalone/gpu/deblurring/2d/CMakeLists.txt b/apps/standalone/gpu/deblurring/2d/CMakeLists.txt deleted file mode 100644 index bc5d13918..000000000 --- a/apps/standalone/gpu/deblurring/2d/CMakeLists.txt +++ /dev/null @@ -1,14 +0,0 @@ -if (WIN32) -add_definitions(-D_USE_MATH_DEFINES) -endif () - -add_executable(blur_2d blur_2d.cpp) -add_executable(deblur_2d_cg deblur_2d_cg.cpp) -add_executable(deblur_2d_sb deblur_2d_sb.cpp) - -target_link_libraries(deblur_2d_cg gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(deblur_2d_sb gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(blur_2d gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS blur_2d deblur_2d_cg deblur_2d_sb DESTINATION bin COMPONENT main) - diff --git a/apps/standalone/gpu/deblurring/2d/blur_2d.cpp b/apps/standalone/gpu/deblurring/2d/blur_2d.cpp deleted file mode 100644 index 61c3f286e..000000000 --- a/apps/standalone/gpu/deblurring/2d/blur_2d.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/* - Example code to blur an image and generate input data for the deblurring apps. -*/ - -#include "hoNDArray_fileio.h" -#include "cuNDArray_operators.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_blas.h" -#include "parameterparser.h" -#include "cuConvolutionOperator.h" - -#include -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output blurred image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "Output kernel image file name (.cplx)", true, "kernel_image.cplx" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load image from disk (single precision assumed) - boost::shared_ptr< hoNDArray > _host_image = - read_nd_array((char*)parms.get_parameter('d')->get_string_value()); - - if( !(_host_image->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Input image is not two-dimensional. Quitting.\n" << endl); - return 1; - } - - // Convert to _real - hoNDArray<_real> host_image; host_image.create(_host_image->dimensions()); - for( unsigned int i=0; iget_data_ptr()[i]; - - // Upload host image to device, normalize, and convert to complex type - cuNDArray<_real> _image(host_image); - normalize( &_image, _real(1) ); - boost::shared_ptr< cuNDArray<_complext> > image = real_to_complex<_complext>( &_image ); - - // Setup resulting blurred image - cuNDArray<_complext> blurred_image; - blurred_image.create(image->get_dimensions()); - - // Generate convolution kernel (just do this on the host for now) - _real sigma = 2.5; - hoNDArray<_real> host_kernel; - host_kernel.create(image->dimensions()); - for( unsigned int y=0; yget_size(1); y++ ){ - for( unsigned int x=0; xget_size(0); x++ ){ - _real biasx = (_real)(image->get_size(0)>>1); - _real biasy = (_real)(image->get_size(1)>>1); - _real cx = (_real)x-biasx; - _real cy = (_real)y-biasy; - host_kernel.get_data_ptr()[y*image->get_size(0)+x] = 1.0/(2.0*M_PI*sigma*sigma)*exp(-1.0*((cx*cx)/(2.0*sigma*sigma)+(cy*cy)/(2.0*sigma*sigma))); - } - } - - cuNDArray<_real> _kernel(host_kernel); - boost::shared_ptr< cuNDArray<_complext> > kernel = real_to_complex<_complext>( &_kernel ); - - // Normalize kernel - _real scale = asum(kernel.get()); - *kernel /= scale; - - // Create convolution operator and assign kernel - cuConvolutionOperator<_real,2> conv; - conv.set_kernel( kernel.get() ); - - // Convolve - conv.mult_M( image.get(), &blurred_image ); - - // - // Output result - // - - boost::shared_ptr< hoNDArray<_complext> > blurred_image_host = blurred_image.to_host(); - write_nd_array<_complext>( blurred_image_host.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&blurred_image)->to_host(); - write_nd_array<_real>( host_norm.get(), "blurred_image.real" ); - - boost::shared_ptr< hoNDArray<_complext> > kernel_image_host = kernel->to_host(); - write_nd_array<_complext>( kernel_image_host.get(), (char*)parms.get_parameter('k')->get_string_value()); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/2d/deblur_2d_cg.cpp b/apps/standalone/gpu/deblurring/2d/deblur_2d_cg.cpp deleted file mode 100644 index babc0bcd1..000000000 --- a/apps/standalone/gpu/deblurring/2d/deblur_2d_cg.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - Deblurring using conjugate gradient solver. -*/ - -// Gadgetron includes -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "cuCgSolver.h" -#include "cuPartialDerivativeOperator.h" -#include "cuConvolutionOperator.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Blurred image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "Kernel image file name (.cplx)", true, "kernel_image.cplx" ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "cg_deblurred_image.cplx" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "25" ); - parms.add_parameter( 'K', COMMAND_LINE_FLOAT, 1, "Regularization weight", true, "0.1" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running deblurring with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_complext> > host_data = - read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - - boost::shared_ptr< hoNDArray<_complext> > host_kernel = - read_nd_array<_complext>((char*)parms.get_parameter('k')->get_string_value()); - - if( !(host_data->get_number_of_dimensions() == 2) || !(host_kernel->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Input data (image/kernel) is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - cuNDArray<_complext> data(*host_data); - cuNDArray<_complext> kernel(*host_kernel); - - _real kappa = (_real) parms.get_parameter('K')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - - // Setup regularization operators - // - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > Rx( new cuPartialDerivativeOperator<_complext,2>(0) ); - Rx->set_weight( kappa ); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > Ry( new cuPartialDerivativeOperator<_complext,2>(1) ); - Ry->set_weight( kappa ); - - // - // Setup conjugate gradients solver - // - - // Define encoding matrix - boost::shared_ptr< cuConvolutionOperator<_real,2> > E( new cuConvolutionOperator<_real,2>() ); - E->set_kernel( &kernel ); - E->set_domain_dimensions(data.get_dimensions()); - - // Setup conjugate gradient solver - cuCgSolver< _complext> cg; - cg.set_encoding_operator( E ); // encoding matrix - if( kappa>0.0 ) cg.add_regularization_operator( Rx ); // regularization matrix - if( kappa>0.0 ) cg.add_regularization_operator( Ry ); // regularization matrix - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-12 ); - cg.set_output_mode( cuCgSolver< _complext>::OUTPUT_VERBOSE ); - - // - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult = cg.solve( &data ); - - // All done, write out the result - - boost::shared_ptr< hoNDArray<_complext> > host_result = cgresult->to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(cgresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "cg_deblurred_image.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/2d/deblur_2d_sb.cpp b/apps/standalone/gpu/deblurring/2d/deblur_2d_sb.cpp deleted file mode 100644 index d9d3856a0..000000000 --- a/apps/standalone/gpu/deblurring/2d/deblur_2d_sb.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - Deblurring using conjugate gradient solver. -*/ - -// Gadgetron includes -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "cuSbcCgSolver.h" -#include "cuCgSolver.h" -#include "cuPartialDerivativeOperator.h" -#include "cuConvolutionOperator.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Blurred image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "Kernel image file name (.cplx)", true, "kernel_image.cplx" ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "sb_deblurred_image.cplx" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of cg iterations", true, "20" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of sb inner iterations", true, "1" ); - parms.add_parameter( 'O', COMMAND_LINE_INT, 1, "Number of sb outer iterations", true, "50" ); - parms.add_parameter( 'M', COMMAND_LINE_FLOAT, 1, "Mu", true, "100.0" ); - parms.add_parameter( 'L', COMMAND_LINE_FLOAT, 1, "Lambda", true, "100.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running deblurring with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_complext> > host_data = - read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - - boost::shared_ptr< hoNDArray<_complext> > host_kernel = - read_nd_array<_complext>((char*)parms.get_parameter('k')->get_string_value()); - - if( !(host_data->get_number_of_dimensions() == 2) || !(host_kernel->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Input data (image/kernel) is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - cuNDArray<_complext> data(*host_data); - cuNDArray<_complext> kernel(*host_kernel); - - unsigned int num_cg_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int num_inner_iterations = parms.get_parameter('I')->get_int_value(); - unsigned int num_outer_iterations = parms.get_parameter('O')->get_int_value(); - - // Setup regularization operators - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > Rx( new cuPartialDerivativeOperator<_complext,2>(0) ); - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > Ry( new cuPartialDerivativeOperator<_complext,2>(1) ); - - _real mu = (_real) parms.get_parameter('M')->get_float_value(); - _real lambda = (_real) parms.get_parameter('L')->get_float_value(); - - if( mu <= (_real) 0.0 ) { - GINFO_STREAM(endl << "Regularization parameter mu should be strictly positive. Quitting!\n" << endl); - return 1; - } - - Rx->set_weight( lambda ); - Rx->set_domain_dimensions(data.get_dimensions()); - Rx->set_codomain_dimensions(data.get_dimensions()); - - Ry->set_weight( lambda ); - Ry->set_domain_dimensions(data.get_dimensions()); - Ry->set_codomain_dimensions(data.get_dimensions()); - - // - // Setup conjugate gradients solver - // - - // Define encoding matrix - boost::shared_ptr< cuConvolutionOperator<_real,2> > E( new cuConvolutionOperator<_real,2>() ); - E->set_kernel( &kernel ); - E->set_weight( mu ); - E->set_domain_dimensions(data.get_dimensions()); - E->set_codomain_dimensions(data.get_dimensions()); - - // Setup split-Bregman solver - cuSbcCgSolver<_complext> sb; - sb.set_encoding_operator( E ); - sb.add_regularization_group_operator( Rx ); - sb.add_regularization_group_operator( Ry ); - sb.add_group(); - sb.set_max_outer_iterations(num_outer_iterations); - sb.set_max_inner_iterations(num_inner_iterations); - sb.set_output_mode( cuSbcCgSolver<_complext>::OUTPUT_VERBOSE ); - - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - sb.get_inner_solver()->set_tc_tolerance( 1e-4 ); - sb.get_inner_solver()->set_output_mode( cuCgSolver<_complext>::OUTPUT_WARNINGS ); - - // Run split-Bregman solver - boost::shared_ptr< cuNDArray<_complext> > sbresult = sb.solve(&data); - - // All done, write out the result - - boost::shared_ptr< hoNDArray<_complext> > host_result = sbresult->to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(sbresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "sb_deblurred_image.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/3d/CMakeLists.txt b/apps/standalone/gpu/deblurring/3d/CMakeLists.txt deleted file mode 100644 index 544e8b944..000000000 --- a/apps/standalone/gpu/deblurring/3d/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -if (WIN32) -add_definitions(-D_USE_MATH_DEFINES) -endif () - -add_executable(blur_3d blur_3d.cpp) -add_executable(deblur_3d_cg deblur_3d_cg.cpp) -add_executable(deblur_3d_sb deblur_3d_sb.cpp) - -target_link_libraries(deblur_3d_cg gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(deblur_3d_sb gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(blur_3d gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS blur_3d deblur_3d_cg deblur_3d_sb DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/deblurring/3d/blur_3d.cpp b/apps/standalone/gpu/deblurring/3d/blur_3d.cpp deleted file mode 100644 index 8aee5ef17..000000000 --- a/apps/standalone/gpu/deblurring/3d/blur_3d.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/* - Example code to blur an image and generate input data for the deblurring apps. -*/ - -#include "hoNDArray_fileio.h" -#include "cuNDArray_blas.h" -#include "cuNDArray_elemwise.h" -#include "parameterparser.h" -#include "cuConvolutionOperator.h" -#include -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input image file name (.real)", true ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "In kernel image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'K', COMMAND_LINE_STRING, 1, "Output kernel file name (.cplx)", true, "kernel_image.cplx" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load image and kernel from disk (single precision assumed) - // - boost::shared_ptr< hoNDArray > _host_image = - read_nd_array((char*)parms.get_parameter('d')->get_string_value()); - - boost::shared_ptr< hoNDArray > _host_kernel = - read_nd_array((char*)parms.get_parameter('k')->get_string_value()); - - if( !(_host_image->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input image is not three-dimensional. Quitting.\n" << endl); - return 1; - } - - if( !(_host_kernel->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input kernel is not three-dimensional. Quitting.\n" << endl); - return 1; - } - - // Convert image and kernel to _real - // - hoNDArray<_real> host_image; host_image.create(_host_image->dimensions()); - for( unsigned int i=0; iget_data_ptr()[i]; - - hoNDArray<_real> host_kernel; host_kernel.create(_host_kernel->dimensions()); - for( unsigned int i=0; iget_data_ptr()[i]; - - // Upload host image/kernel and convert to complex type - // - cuNDArray<_real> _image(host_image); - boost::shared_ptr< cuNDArray<_complext> > image = real_to_complex<_complext>( &_image ); - - cuNDArray<_real> _kernel(host_kernel); - boost::shared_ptr< cuNDArray<_complext> > kernel = real_to_complex<_complext>( &_kernel ); - - // Normalize kernel - _real scale = asum(kernel.get()); - *kernel /= scale; - - // Setup resulting blurred image - cuNDArray<_complext> blurred_image; - blurred_image.create(image->get_dimensions()); - - // Create convolution operator and assign kernel - cuConvolutionOperator<_real,3> conv; - conv.set_kernel( kernel.get() ); - - // Convolve - conv.mult_M( image.get(), &blurred_image ); - - // - // Output result - // - - boost::shared_ptr< hoNDArray<_complext> > blurred_image_host = blurred_image.to_host(); - write_nd_array<_complext>( blurred_image_host.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&blurred_image)->to_host(); - write_nd_array<_real>( host_norm.get(), "blurred_image.real" ); - - boost::shared_ptr< hoNDArray<_complext> > kernel_image_host = kernel->to_host(); - write_nd_array<_complext>( kernel_image_host.get(), (char*)parms.get_parameter('K')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm_kernel = abs(kernel.get())->to_host(); - write_nd_array<_real>( host_norm_kernel.get(), "kernel_image.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/3d/deblur_3d_cg.cpp b/apps/standalone/gpu/deblurring/3d/deblur_3d_cg.cpp deleted file mode 100644 index 8d0c4fcfb..000000000 --- a/apps/standalone/gpu/deblurring/3d/deblur_3d_cg.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - Deblurring using conjugate gradient solver. -*/ - -// Gadgetron includes -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "cuCgSolver.h" -#include "cuPartialDerivativeOperator.h" -#include "cuConvolutionOperator.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Blurred image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "Kernel image file name (.cplx)", true, "kernel_image.cplx" ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "cg_deblurred_image.cplx" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "25" ); - parms.add_parameter( 'K', COMMAND_LINE_FLOAT, 1, "Regularization weight", true, "0.1" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running deblurring with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_complext> > host_data = - read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - - boost::shared_ptr< hoNDArray<_complext> > host_kernel = - read_nd_array<_complext>((char*)parms.get_parameter('k')->get_string_value()); - - if( !(host_data->get_number_of_dimensions() == 3) || !(host_kernel->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data (image/kernel) is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - cuNDArray<_complext> data(*host_data); - cuNDArray<_complext> kernel(*host_kernel); - - _real kappa = (_real) parms.get_parameter('K')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - - // Setup regularization operators - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Rx( new cuPartialDerivativeOperator<_complext,3>(0) ); - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Ry( new cuPartialDerivativeOperator<_complext,3>(1) ); - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Rz( new cuPartialDerivativeOperator<_complext,3>(2) ); - - Rx->set_weight( kappa ); - Ry->set_weight( kappa ); - Rz->set_weight( kappa ); - - // - // Setup conjugate gradients solver - // - - // Define encoding matrix - boost::shared_ptr< cuConvolutionOperator<_real,3> > E( new cuConvolutionOperator<_real,3>() ); - E->set_kernel( &kernel ); - E->set_domain_dimensions(data.get_dimensions()); - - // Setup conjugate gradient solver - cuCgSolver<_complext> cg; - cg.set_encoding_operator( E ); // encoding matrix - if( kappa>0.0 ) cg.add_regularization_operator( Rx ); // regularization matrix - if( kappa>0.0 ) cg.add_regularization_operator( Ry ); // regularization matrix - if( kappa>0.0 ) cg.add_regularization_operator( Rz ); // regularization matrix - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-12 ); - cg.set_output_mode( cuCgSolver<_complext>::OUTPUT_VERBOSE ); - - // Form right hand side - cuNDArray<_complext> rhs; rhs.create(data.get_dimensions()); - E->mult_MH( &data, &rhs ); - - // - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult = cg.solve_from_rhs(&rhs); - - // All done, write out the result - - boost::shared_ptr< hoNDArray<_complext> > host_result = cgresult->to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(cgresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "cg_deblurred_image.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/3d/deblur_3d_sb.cpp b/apps/standalone/gpu/deblurring/3d/deblur_3d_sb.cpp deleted file mode 100644 index 7420a676b..000000000 --- a/apps/standalone/gpu/deblurring/3d/deblur_3d_sb.cpp +++ /dev/null @@ -1,135 +0,0 @@ -/* - Deblurring using conjugate gradient solver. -*/ - -// Gadgetron includes -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "cuSbcCgSolver.h" -#include "cuCgSolver.h" -#include "cuPartialDerivativeOperator.h" -#include "cuConvolutionOperator.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Blurred image file name (.cplx)", true, "blurred_image.cplx" ); - parms.add_parameter( 'k', COMMAND_LINE_STRING, 1, "Kernel image file name (.cplx)", true, "kernel_image.cplx" ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "sb_deblurred_image.cplx" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of cg iterations", true, "20" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of sb inner iterations", true, "1" ); - parms.add_parameter( 'O', COMMAND_LINE_INT, 1, "Number of sb outer iterations", true, "50" ); - parms.add_parameter( 'M', COMMAND_LINE_FLOAT, 1, "Mu", true, "1.0" ); - parms.add_parameter( 'L', COMMAND_LINE_FLOAT, 1, "Lambda", true, "1.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running deblurring with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_complext> > host_data = - read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - - boost::shared_ptr< hoNDArray<_complext> > host_kernel = - read_nd_array<_complext>((char*)parms.get_parameter('k')->get_string_value()); - - if( !(host_data->get_number_of_dimensions() == 3) || !(host_kernel->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data (image/kernel) is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - cuNDArray<_complext> data(*host_data); - cuNDArray<_complext> kernel(*host_kernel); - - unsigned int num_cg_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int num_inner_iterations = parms.get_parameter('I')->get_int_value(); - unsigned int num_outer_iterations = parms.get_parameter('O')->get_int_value(); - - // Setup regularization operators - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Rx( new cuPartialDerivativeOperator<_complext,3>(0) ); - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Ry( new cuPartialDerivativeOperator<_complext,3>(1) ); - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > Rz( new cuPartialDerivativeOperator<_complext,3>(2) ); - - _real mu = (_real) parms.get_parameter('M')->get_float_value(); - _real lambda = (_real) parms.get_parameter('L')->get_float_value(); - - if( mu <= (_real) 0.0 ) { - GINFO_STREAM(endl << "Regularization parameter mu should be strictly positive. Quitting!\n" << endl); - return 1; - } - - Rx->set_weight( lambda ); - Rx->set_domain_dimensions(data.get_dimensions()); - Rx->set_codomain_dimensions(data.get_dimensions()); - - Ry->set_weight( lambda ); - Ry->set_domain_dimensions(data.get_dimensions()); - Ry->set_codomain_dimensions(data.get_dimensions()); - - Rz->set_weight( lambda ); - Rz->set_domain_dimensions(data.get_dimensions()); - Rz->set_codomain_dimensions(data.get_dimensions()); - - // - // Setup conjugate gradients solver - // - - // Define encoding matrix - boost::shared_ptr< cuConvolutionOperator<_real,3> > E( new cuConvolutionOperator<_real,3>() ); - E->set_kernel( &kernel ); - E->set_weight( mu ); - E->set_domain_dimensions(data.get_dimensions()); - E->set_codomain_dimensions(data.get_dimensions()); - - // Setup split-Bregman solver - cuSbcCgSolver<_complext> sb; - sb.set_encoding_operator( E ); - sb.add_regularization_group_operator( Rx ); - sb.add_regularization_group_operator( Ry ); - sb.add_group(); - sb.add_regularization_operator( Rz ); - sb.set_max_outer_iterations(num_outer_iterations); - sb.set_max_inner_iterations(num_inner_iterations); - sb.set_output_mode( cuSbcCgSolver< _complext>::OUTPUT_VERBOSE ); - - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - sb.get_inner_solver()->set_tc_tolerance( 1e-8 ); - sb.get_inner_solver()->set_output_mode( cuCgSolver<_complext>::OUTPUT_WARNINGS ); - - // Run split-Bregman solver - boost::shared_ptr< cuNDArray<_complext> > sbresult = sb.solve(&data); - - // All done, write out the result - - boost::shared_ptr< hoNDArray<_complext> > host_result = sbresult->to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(sbresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "sb_deblurred_image.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/deblurring/CMakeLists.txt b/apps/standalone/gpu/deblurring/CMakeLists.txt deleted file mode 100644 index 5550044e7..000000000 --- a/apps/standalone/gpu/deblurring/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(2d) -add_subdirectory(3d) diff --git a/apps/standalone/gpu/denoising/2d/CMakeLists.txt b/apps/standalone/gpu/denoising/2d/CMakeLists.txt deleted file mode 100644 index 416f14d8b..000000000 --- a/apps/standalone/gpu/denoising/2d/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -if (WIN32) -add_definitions(-D_USE_MATH_DEFINES) -endif () - -include_directories(${CMAKE_SOURCE_DIR}/toolboxes/dwt/gpu) -add_executable(denoise_TV denoise_TV.cpp) - -target_link_libraries(denoise_TV - gadgetron_toolbox_gpu - gadgetron_toolbox_hostutils - ${CUDA_LIBRARIES}) - -install(TARGETS denoise_TV DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/denoising/2d/denoise_TV.cpp b/apps/standalone/gpu/denoising/2d/denoise_TV.cpp deleted file mode 100644 index 0d8c3e2ad..000000000 --- a/apps/standalone/gpu/denoising/2d/denoise_TV.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - Total variation denoising based on the paper - "The Split Bregman Method for L1-Regularized Problems" by Tom Goldstein and Stanley Osher. - Siam J. Imaging Sciences. Vol. 2, No. 2, pp. 323-343. -*/ - -// Gadgetron includes -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "cuSbCgSolver.h" -#include "cuCgSolver.h" -#include "identityOperator.h" -#include "cuPartialDerivativeOperator.h" -#include "parameterparser.h" -#include "cuNDDWT.h" -#include "cuDWTOperator.h" -#include -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Noisy image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "denoised_image_TV.real" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of cg iterations", true, "20" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of sb inner iterations", true, "1" ); - parms.add_parameter( 'O', COMMAND_LINE_INT, 1, "Number of sb outer iterations", true, "10" ); - parms.add_parameter( 'l', COMMAND_LINE_FLOAT, 1, "Total variation weight (lambda)", true, "50.0" ); - parms.add_parameter( 'm', COMMAND_LINE_FLOAT, 1, "Regularization weight (mu)", true, "25.0" ); - parms.add_parameter('w', COMMAND_LINE_FLOAT, 1, "Wavelet weight" ,true, "0"); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running denoising with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - boost::shared_ptr< hoNDArray<_real> > host_data = - read_nd_array<_real>((char*)parms.get_parameter('d')->get_string_value()); - - if( !host_data.get() ){ - GINFO_STREAM(endl << "Input image not found. Quitting!\n" << endl); - return 1; - } - - if( host_data->get_number_of_dimensions() != 2 ){ - GINFO_STREAM(endl << "Input image is not two-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - cuNDArray<_real> data(*host_data); - - _real mu = (_real) parms.get_parameter('m')->get_float_value(); - _real lambda = (_real)parms.get_parameter('l')->get_float_value(); - - if( mu <= (_real) 0.0 ) { - GINFO_STREAM(endl << "Regularization parameter mu should be strictly positive. Quitting!\n" << endl); - return 1; - } - - unsigned int num_cg_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int num_inner_iterations = parms.get_parameter('I')->get_int_value(); - unsigned int num_outer_iterations = parms.get_parameter('O')->get_int_value(); - - // Define encoding operator (identity) - boost::shared_ptr< identityOperator > > E( new identityOperator >() ); - E->set_weight( mu ); - E->set_domain_dimensions(data.get_dimensions()); - E->set_codomain_dimensions(data.get_dimensions()); - - // Setup split-Bregman solver - cuSbCgSolver<_real> sb; - sb.set_encoding_operator( E ); - sb.set_max_outer_iterations(num_outer_iterations); - sb.set_max_inner_iterations(num_inner_iterations); - sb.set_output_mode( cuCgSolver<_real>::OUTPUT_VERBOSE ); - // Setup regularization operators - - if (lambda > 0){ - boost::shared_ptr< cuPartialDerivativeOperator<_real,2> > Rx( new cuPartialDerivativeOperator<_real,2>(0) ); - Rx->set_weight( lambda ); - Rx->set_domain_dimensions(data.get_dimensions()); - Rx->set_codomain_dimensions(data.get_dimensions()); - - boost::shared_ptr< cuPartialDerivativeOperator<_real,2> > Ry( new cuPartialDerivativeOperator<_real,2>(1) ); - Ry->set_weight( lambda ); - Ry->set_domain_dimensions(data.get_dimensions()); - Ry->set_codomain_dimensions(data.get_dimensions()); - //sb.add_regularization_operator( Rx ); // Anisotropic denoising - //sb.add_regularization_operator( Ry ); // Anisotropic denoising - sb.add_regularization_group_operator( Rx ); // Isotropic denoising - sb.add_regularization_group_operator( Ry); // Isotropic denoising - sb.add_group(); - } - - _real wavelet = parms.get_parameter('w')->get_float_value(); - if (wavelet > 0){ - auto dwt = boost::make_shared>(); - dwt->set_levels(3); - dwt->set_weight(wavelet); - sb.add_regularization_operator(dwt); - dwt->set_domain_dimensions(data.get_dimensions()); - dwt->set_codomain_dimensions(data.get_dimensions()); - dwt->use_random(true); - } - - // Setup inner conjugate gradient solver - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - sb.get_inner_solver()->set_tc_tolerance( 1e-4 ); - sb.get_inner_solver()->set_output_mode( cuCgSolver<_real>::OUTPUT_WARNINGS ); - - // Run split-Bregman solver - boost::shared_ptr< cuNDArray<_real> > sbresult = sb.solve(&data); - - /* - boost::shared_ptr< cuNDArray<_real> > sbresult(new cuNDArray<_real>(data.get_dimensions())); - clear(sbresult.get()); - - vector_td daubechies4({0.6830127f,1.1830127f,0.3169873f,-0.1830127f}); - vector_td haahr(1.0f,1.0f); - vector_td daubechies6{0.47046721f,1.14111692f,0.650365f,-0.19093442f, -0.12083221f,0.0498175f}; - - cuDWTOperator dwt; - dwt.set_levels(3); - dwt.mult_M(&data,sbresult.get()); - //data = *sbresult; - shrink1(sbresult.get(),30.0f,&data); - dwt.mult_MH(&data,sbresult.get());*/ - //clear(sbresult.get()); - // All done, write out the result - boost::shared_ptr< hoNDArray<_real> > host_result = sbresult->to_host(); - write_nd_array<_real>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - return 0; -} diff --git a/apps/standalone/gpu/denoising/CMakeLists.txt b/apps/standalone/gpu/denoising/CMakeLists.txt deleted file mode 100644 index 5c4cec952..000000000 --- a/apps/standalone/gpu/denoising/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -add_subdirectory(2d) diff --git a/apps/standalone/gpu/mri/CMakeLists.txt b/apps/standalone/gpu/mri/CMakeLists.txt deleted file mode 100644 index 866ed620c..000000000 --- a/apps/standalone/gpu/mri/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(nfft) -add_subdirectory(sense) diff --git a/apps/standalone/gpu/mri/nfft/2d/CMakeLists.txt b/apps/standalone/gpu/mri/nfft/2d/CMakeLists.txt deleted file mode 100644 index c11dbc45d..000000000 --- a/apps/standalone/gpu/mri/nfft/2d/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/mri/pmri/gpu -) - -add_executable(nfft_2d_radial main_nfft.cpp) -add_executable(nffth_2d_radial main_nffth.cpp) -#add_executable(moco moco.cpp) -add_executable(nffth_cg_2d_radial main_cg.cpp) -add_executable(nffth_sb_2d_radial main_sb.cpp) - -target_link_libraries(nfft_2d_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(nffth_2d_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -#target_link_libraries(moco gpusolvers gpureg gpucore gpuparallelmri gpuoperators gpunfft hostutils ${CUDA_LIBRARIES}) -target_link_libraries(nffth_cg_2d_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(nffth_sb_2d_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - - -install(TARGETS nfft_2d_radial nffth_2d_radial nffth_cg_2d_radial nffth_sb_2d_radial DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/mri/nfft/2d/main_cg.cpp b/apps/standalone/gpu/mri/nfft/2d/main_cg.cpp deleted file mode 100644 index 53ef4892a..000000000 --- a/apps/standalone/gpu/mri/nfft/2d/main_cg.cpp +++ /dev/null @@ -1,141 +0,0 @@ -/* - - Sample application of the NFFT toolbox: using the NFFT matrix operator in a conjugate gradient solver - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray.h" -#include "vector_td_utilities.h" -#include "parameterparser.h" -#include "../../../../../../toolboxes/nfft/NFFTOperator.h" -#include "cuCgSolver.h" -#include "GPUTimer.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "10" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("Loading samples from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Samples ndarray is not two-dimensional (samples/profile x #profiles). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - - unsigned int num_profiles = host_samples->get_size(1); - unsigned int samples_per_profile = host_samples->get_size(0); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - // Upload host data to device - timer = new GPUTimer("Uploading samples to device"); - cuNDArray<_complext> samples(*host_samples); - delete timer; - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real>( samples_per_profile, num_profiles, 1 ); - delete timer; - - // Compute density compensation weights - timer = new GPUTimer("Computing density compensation weights"); - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, num_profiles, alpha, _real(1)/((_real)samples_per_profile/(_real)matrix_size.vec[0]) ); - sqrt_inplace(dcw.get()); - delete timer; - - samples *= *dcw; - - // Define and setup NFFT encoding operator - auto E = boost::make_shared>(); - - E->setup( matrix_size, matrix_size_os, kernel_width ); - - // Notify encoding operator of dcw - E->set_dcw(dcw); - - // Set image dimensions - vector image_dims = to_std_vector(matrix_size); - E->set_domain_dimensions(image_dims); - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - E->preprocess( *traj ); - delete timer; - - // Setup conjugate gradient solver - cuCgSolver< _complext> cg; - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-6 ); - cg.set_output_mode( cuCgSolver<_complext>::OUTPUT_VERBOSE ); - cg.set_encoding_operator( E); - - // Solve - boost::shared_ptr< cuNDArray<_complext> > cgresult; - { - GPUTimer timer("GPU Conjugate Gradient solve"); - cgresult = cg.solve(&samples); - } - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - - boost::shared_ptr< hoNDArray<_complext> > host_image = cgresult->to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(cgresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/2d/main_nfft.cpp b/apps/standalone/gpu/mri/nfft/2d/main_nfft.cpp deleted file mode 100644 index 629dcdf3a..000000000 --- a/apps/standalone/gpu/mri/nfft/2d/main_nfft.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/* - - Sample application of the NFFT toolbox: standalone "inverse gridding" example. - - ----------- - - The nfft is written generically and templetized to - - - transform arbitrary trajectories - - transform an "arbitrary" number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs from an single precision input image ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_impl<_real,2> plan_type; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name (.cplx)", true, "samples.cplx" ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Number of profiles", true ); - parms.add_parameter( 's', COMMAND_LINE_INT, 1, "Samples per profiles", true ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load image from disk - timer = new GPUTimer("Loading image from disk"); - boost::shared_ptr< hoNDArray<_real> > host_image = read_nd_array<_real>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_image->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Input image is not two-dimensional. Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - unsigned int num_profiles = parms.get_parameter('p')->get_int_value(); - unsigned int samples_per_profile = parms.get_parameter('s')->get_int_value(); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - - uint64d2 matrix_size = from_std_vector(host_image->get_dimensions()); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - if( matrix_size.vec[0] != matrix_size.vec[1] ){ - GINFO_STREAM( - endl << "For this samples application we only allow square input images. " << - endl << "The only reason being that only one oversampled matrix size is specified and the oversampling ratio must be consistent." << - endl); - } - - // Upload host image to device, normalize, and convert to complex type - timer = new GPUTimer("Uploading, normalizing and converting to complex"); - cuNDArray<_real> _image(*host_image); - normalize( &_image, 1.0f ); - boost::shared_ptr< cuNDArray<_complext> > image = real_to_complex<_complext>( &_image ); - delete timer; - - // Setup resulting samples array - vector samples_dims; samples_dims.push_back( samples_per_profile ); samples_dims.push_back( num_profiles ); - cuNDArray<_complext> samples(samples_dims); - - // Initialize plan - timer = new GPUTimer("Initializing plan"); - plan_type plan( matrix_size, matrix_size_os, kernel_width ); - delete timer; - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real>( samples_per_profile, num_profiles, 1 ); - delete timer; - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - plan.preprocess( *traj, NFFT_prep_mode::C2NC ); - delete timer; - - // Gridder - timer = new GPUTimer("Computing nfft"); - plan.compute( *image, samples, 0, NFFT_comp_mode::BACKWARDS_NC2C ); - delete timer; - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = samples.to_host(); - write_nd_array<_complext>( host_samples.get(), (char*)parms.get_parameter('r')->get_string_value()); - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/2d/main_nffth.cpp b/apps/standalone/gpu/mri/nfft/2d/main_nffth.cpp deleted file mode 100644 index 722ba8f3c..000000000 --- a/apps/standalone/gpu/mri/nfft/2d/main_nffth.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/* - - Sample application of the NFFT toolbox: standalone "gridding" example. - - ----------- - - The nfft is written generically and templetized to - - transform arbitrary trajectories - - transform an arbitrary number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs a gridded image from input ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_impl<_real,2> plan_type; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("Loading samples from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Samples ndarray is not two-dimensional (samples/profile x #profiles). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - - unsigned int num_profiles = host_samples->get_size(1); - unsigned int samples_per_profile = host_samples->get_size(0); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - // Upload host data to device - timer = new GPUTimer("Uploading samples to device"); - cuNDArray<_complext> samples(*host_samples); - delete timer; - - // Setup resulting image array - vector image_dims = to_std_vector(matrix_size); - cuNDArray<_complext> image(image_dims); - - // Initialize plan - timer = new GPUTimer("Initializing plan"); - plan_type plan( matrix_size, matrix_size_os, kernel_width ); - delete timer; - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real>( samples_per_profile, num_profiles, 1 ); - delete timer; - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - plan.preprocess( *traj, NFFT_prep_mode::NC2C ); - delete timer; - - // Compute density compensation weights - timer = new GPUTimer("Computing density compensation weights"); - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, num_profiles, alpha, _real(1)/((_real)samples_per_profile/(_real)matrix_size.vec[0]) ); - delete timer; - - // Gridder - timer = new GPUTimer("Computing adjoint nfft (gridding)"); - plan.compute( samples, image, dcw.get(), NFFT_comp_mode::BACKWARDS_NC2C ); - delete timer; - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - - boost::shared_ptr< hoNDArray<_complext> > host_image = image.to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value()); - - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&image)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/2d/main_sb.cpp b/apps/standalone/gpu/mri/nfft/2d/main_sb.cpp deleted file mode 100644 index 819eb4183..000000000 --- a/apps/standalone/gpu/mri/nfft/2d/main_sb.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/* - - Sample application of the NFFT toolbox: using the NFFT matrix operator in a Split Bregman solver - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray.h" -#include "parameterparser.h" -#include "../../../../../../toolboxes/nfft/NFFTOperator.h" -#include "cuSbcCgSolver.h" -#include "vector_td_utilities.h" -#include "cuPartialDerivativeOperator.h" -#include "GPUTimer.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of inner iterations", true, "10" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of outer iterations", true, "10" ); - parms.add_parameter( 'l', COMMAND_LINE_FLOAT, 1, "Regularization weight (lambda)", true, "1.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("Loading samples from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Samples ndarray is not two-dimensional (samples/profile x #profiles). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - unsigned int num_cg_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int num_sb_iterations = parms.get_parameter('I')->get_int_value(); - - unsigned int num_profiles = host_samples->get_size(1); - unsigned int samples_per_profile = host_samples->get_size(0); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - _real lambda = (_real)parms.get_parameter('l')->get_float_value(); - - // Upload host data to device - timer = new GPUTimer("Uploading samples to device"); - cuNDArray<_complext> samples(*host_samples); - delete timer; - - // Reshape the data array to a one-dimensional array (we have no batch dimension) - std::vector sample_dims; - sample_dims.push_back(samples.get_number_of_elements()); - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real>( samples_per_profile, num_profiles, 1 ); - delete timer; - - // Compute density compensation weights - timer = new GPUTimer("Computing density compensation weights"); - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, num_profiles, alpha, _real(1)/((_real)samples_per_profile/(_real)matrix_size.vec[0]) ); - sqrt_inplace(dcw.get()); - - samples *= *dcw; - - delete timer; - - - // Define and setup NFFT encoding operator - auto E = boost::make_shared>(); - E->set_weight(lambda); - - E->setup( matrix_size, matrix_size_os, kernel_width ); - - // Notify encoding operator of dcw - E->set_dcw(dcw); - - // Set image dimensions - vector image_dims = to_std_vector(matrix_size); - E->set_domain_dimensions(image_dims); - E->set_codomain_dimensions(sample_dims); - - // Setup regularization operators - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > - Rx( new cuPartialDerivativeOperator<_complext,2>(0) ); - Rx->set_weight( lambda ); - Rx->set_domain_dimensions(image_dims); - Rx->set_codomain_dimensions(image_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,2> > - Ry( new cuPartialDerivativeOperator<_complext,2>(1) ); - Ry->set_weight( lambda ); - Ry->set_domain_dimensions(image_dims); - Ry->set_codomain_dimensions(image_dims); - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - E->preprocess( *traj ); - delete timer; - - // Setup split bregman solver - cuSbcCgSolver<_complext> sb; - sb.set_max_outer_iterations( num_sb_iterations ); - sb.set_max_inner_iterations( 1 ); - sb.set_output_mode( cuCgSolver< _complext>::OUTPUT_VERBOSE ); - - sb.set_encoding_operator( E); - sb.add_regularization_group_operator( Rx ); - sb.add_regularization_group_operator( Ry ); - sb.add_group(); - - // Setup inner conjugate gradient solver - sb.get_inner_solver()->set_output_mode( cuCgSolver<_complext>::OUTPUT_WARNINGS ); - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - - // Solve - boost::shared_ptr< cuNDArray<_complext> > cgresult; - { - GPUTimer timer("GPU Conjugate Gradient solve"); - cgresult = sb.solve(&samples); - } - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - - boost::shared_ptr< hoNDArray<_complext> > host_image = cgresult->to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(cgresult.get())->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/CMakeLists.txt b/apps/standalone/gpu/mri/nfft/CMakeLists.txt deleted file mode 100644 index 68dd4c7f0..000000000 --- a/apps/standalone/gpu/mri/nfft/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(2d) -add_subdirectory(ms2d) diff --git a/apps/standalone/gpu/mri/nfft/ms2d/CMakeLists.txt b/apps/standalone/gpu/mri/nfft/ms2d/CMakeLists.txt deleted file mode 100644 index 7d7f2ed8f..000000000 --- a/apps/standalone/gpu/mri/nfft/ms2d/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_executable(nfft_2d_ms_radial nfft_main.cpp) -add_executable(nffth_2d_ms_radial nffth_main.cpp) -add_executable(nffth_2d_ms_generic nffth_generic.cpp) - -target_link_libraries(nfft_2d_ms_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(nffth_2d_ms_radial gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(nffth_2d_ms_generic gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS nfft_2d_ms_radial nffth_2d_ms_radial nffth_2d_ms_generic DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/mri/nfft/ms2d/nfft_main.cpp b/apps/standalone/gpu/mri/nfft/ms2d/nfft_main.cpp deleted file mode 100644 index d0cb171e6..000000000 --- a/apps/standalone/gpu/mri/nfft/ms2d/nfft_main.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* - Sample application of the NFFT toolbox: standalone "inverse gridding" example. - - ----------- - - The nfft is written generically and templetized to - - - transform arbitrary trajectories - - transform an arbitrary number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs from a single precision multislice input image ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_impl<_real,2> plan_type; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "samples.cplx" ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "#profiles/frame", true ); - parms.add_parameter( 's', COMMAND_LINE_INT, 1, "#samples/profile", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "#frames/reconstruction (a negative value means all)", true, "-1" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load image from disk - timer = new GPUTimer("Loading image from disk"); - boost::shared_ptr< hoNDArray<_real> > host_image = read_nd_array<_real>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_image->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input image is not three-dimensional (2d multislice). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int samples_per_profile = parms.get_parameter('s')->get_int_value(); - int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - - uint64d2 matrix_size = from_std_vector(host_image->get_dimensions()); - unsigned int num_frames = host_image->get_size(2); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - if( matrix_size.vec[0] != matrix_size.vec[1] ){ - GINFO_STREAM( - endl << "For this samples application we only allow square input images. " << - endl << "The only reason being that only one oversampled matrix size is specified and the oversampling ratio must be consistent." << - endl); - } - - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_frames; - if( (unsigned int)frames_per_reconstruction > num_frames ) frames_per_reconstruction = num_frames; - - // Upload host image to device, normalize, and convert to complex type - timer = new GPUTimer("Uploading, normalizing and converting to complex"); - cuNDArray<_real> _image(*host_image); - normalize( &_image, 1.0f ); - boost::shared_ptr< cuNDArray<_complext> > image = real_to_complex<_complext>( &_image ); - delete timer; - - // Setup resulting samples array - vector samples_dims; - samples_dims.push_back( samples_per_profile ); samples_dims.push_back( profiles_per_frame ); samples_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> samples(samples_dims); - - // Initialize plan - timer = new GPUTimer("Initializing plan"); - plan_type plan( matrix_size, matrix_size_os, kernel_width ); - delete timer; - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real>( samples_per_profile, profiles_per_frame, frames_per_reconstruction ); - delete timer; - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - plan.preprocess( *traj, NFFT_prep_mode::C2NC ); - delete timer; - - // Gridder - timer = new GPUTimer("Computing nfft"); - plan.compute( *image, samples, 0x0, NFFT_comp_mode::FORWARDS_C2NC ); - delete timer; - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = samples.to_host(); - write_nd_array<_complext>( host_samples.get(), (char*)parms.get_parameter('r')->get_string_value() ); - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/ms2d/nffth_generic.cpp b/apps/standalone/gpu/mri/nfft/ms2d/nffth_generic.cpp deleted file mode 100644 index fe291f896..000000000 --- a/apps/standalone/gpu/mri/nfft/ms2d/nffth_generic.cpp +++ /dev/null @@ -1,154 +0,0 @@ -/* - - Sample application of the NFFT toolbox: standalone "gridding" example. - - ----------- - - The nfft is written generically and templetized to - - transform arbitrary trajectories - - transform an arbitrary number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs gridded images from 2D multislice input ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_impl<_real,2> plan_type; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 't', COMMAND_LINE_STRING, 1, "Input trajectories file name (.real)", true ); - parms.add_parameter( 'w', COMMAND_LINE_STRING, 1, "Input density compensation weights file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "#frames/reconstruction (a negative value means all)", true, "-1" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load data from disk - timer = new GPUTimer("Loading data from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - boost::shared_ptr< hoNDArray<_reald2> > host_traj = read_nd_array<_reald2> ((char*)parms.get_parameter('t')->get_string_value()); - boost::shared_ptr< hoNDArray<_real> > host_dcw = read_nd_array<_real> ((char*)parms.get_parameter('w')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 2 && host_traj->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Samples/trajectory arrays must be two-dimensional: (dim 0: samples/profile x #profiles/frame; dim 1: #frames). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - unsigned int num_frames = host_traj->get_size(1); - - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_frames; - if( (unsigned int)frames_per_reconstruction > num_frames ) frames_per_reconstruction = num_frames; - - // Setup resulting image array - vector image_dims = to_std_vector(matrix_size); - image_dims.push_back((num_frames/frames_per_reconstruction)*frames_per_reconstruction); - cuNDArray<_complext> image(image_dims); - clear(&image); - - // Initialize plan - timer = new GPUTimer("Initializing plan"); - plan_type plan( matrix_size, matrix_size_os, kernel_width ); - delete timer; - - // Upload arrays to device - cuNDArray<_complext> _samples(*host_samples); - cuNDArray<_reald2> _trajectory(*host_traj); - cuNDArray<_real> dcw(*host_dcw); - - std::vector dims_recon; - dims_recon.push_back(host_samples->get_size(0)); - dims_recon.push_back(frames_per_reconstruction); - - for( unsigned int iteration = 0; iteration < num_frames/frames_per_reconstruction; iteration++ ) { - - // Set samples/trajectory for sub-frames - cuNDArray<_complext> samples( dims_recon, _samples.get_data_ptr()+iteration*dims_recon[0]*dims_recon[1] ); - cuNDArray<_reald2> trajectory( dims_recon, _trajectory.get_data_ptr()+iteration*dims_recon[0]*dims_recon[1] ); - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - plan.preprocess( trajectory, NFFT_prep_mode::NC2C ); - delete timer; - - std::vector image_dims = to_std_vector(matrix_size); - image_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> tmp_image(image_dims, image.get_data_ptr()+iteration*prod(matrix_size)*frames_per_reconstruction); - - // Gridder - timer = new GPUTimer("Computing adjoint nfft (gridding)"); - plan.compute( samples, tmp_image, &dcw, NFFT_comp_mode::BACKWARDS_NC2C ); - delete timer; - } - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - boost::shared_ptr< hoNDArray<_complext> > host_image = image.to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value() ); - write_nd_array<_real>( abs(&image)->to_host().get(), "result.real" ); - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/nfft/ms2d/nffth_main.cpp b/apps/standalone/gpu/mri/nfft/ms2d/nffth_main.cpp deleted file mode 100644 index c0dded8f7..000000000 --- a/apps/standalone/gpu/mri/nfft/ms2d/nffth_main.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/* - - Sample application of the NFFT toolbox: standalone "gridding" example. - - ----------- - - The nfft is written generically and templetized to - - transform arbitrary trajectories - - transform an arbitrary number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs gridded images from 2D multislice input ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_impl<_real,2> plan_type; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, - hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); - cuNDArray<_complext> *data = new cuNDArray<_complext>( dims ); - cudaMemcpy( data->get_data_ptr(), - host_data->get_data_ptr()+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "#frames/reconstruction (a negative value means all)", true, "-1" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("Loading samples from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Samples ndarray is not three-dimensional (samples/profile x #profiles/frame x #frames). Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - - unsigned int samples_per_profile = host_samples->get_size(0); - unsigned int profiles_per_frame = host_samples->get_size(1); - unsigned int num_frames = host_samples->get_size(2); - - unsigned int profiles_per_reconstruction = profiles_per_frame*frames_per_reconstruction; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - _real alpha = (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0]; - - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_frames; - if( (unsigned int)frames_per_reconstruction > num_frames ) frames_per_reconstruction = num_frames; - - // Setup resulting image array - vector image_dims = to_std_vector(matrix_size); - image_dims.push_back((num_frames/frames_per_reconstruction)*frames_per_reconstruction); - cuNDArray<_complext> image(image_dims); - clear(&image); - - // Initialize plan - timer = new GPUTimer("Initializing plan"); - plan_type plan( matrix_size, matrix_size_os, kernel_width ); - delete timer; - - // Compute density compensation weights - timer = new GPUTimer("Computing density compensation weights"); - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, alpha, _real(1)/((_real)samples_per_profile/(_real)matrix_size.vec[0]) ); - delete timer; - - for( unsigned int iteration = 0; iteration < num_frames/frames_per_reconstruction; iteration++ ) { - - // Compute trajectories - timer = new GPUTimer("Computing golden ratio radial trajectories"); - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, iteration*profiles_per_reconstruction ); - delete timer; - - // Preprocess - timer = new GPUTimer("NFFT preprocessing"); - plan.preprocess( *traj, NFFT_prep_mode::NC2C ); - delete timer; - - // Upload data - timer = new GPUTimer("Upload data"); - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( iteration, samples_per_reconstruction, host_samples.get() ); - - vector image_dims = to_std_vector(matrix_size); - image_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> tmp_image(image_dims, image.get_data_ptr()+iteration*prod(matrix_size)*frames_per_reconstruction); - - // Gridder - timer = new GPUTimer("Computing adjoint nfft (gridding)"); - plan.compute(*data, tmp_image, dcw.get(), NFFT_comp_mode::BACKWARDS_NC2C ); - delete timer; - } - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - boost::shared_ptr< hoNDArray<_complext> > host_image = image.to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value() ); - write_nd_array<_real>( abs(&image)->to_host().get(), "result.real" ); - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/CMakeLists.txt b/apps/standalone/gpu/mri/sense/CMakeLists.txt deleted file mode 100644 index 11e472de3..000000000 --- a/apps/standalone/gpu/mri/sense/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -#add_subdirectory(cartesian) -add_subdirectory(noncartesian) diff --git a/apps/standalone/gpu/mri/sense/noncartesian/CMakeLists.txt b/apps/standalone/gpu/mri/sense/noncartesian/CMakeLists.txt deleted file mode 100644 index ddcb91bd3..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/mri/pmri/gpu - ) - -add_executable(sense_cg_generic_2d generic_cg.cpp) - -target_link_libraries(sense_cg_generic_2d gadgetron_toolbox_gpu gadgetron_toolbox_cpucore gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS sense_cg_generic_2d DESTINATION bin COMPONENT main) - -add_subdirectory(radial) diff --git a/apps/standalone/gpu/mri/sense/noncartesian/generic_cg.cpp b/apps/standalone/gpu/mri/sense/noncartesian/generic_cg.cpp deleted file mode 100644 index 1b5ea132a..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/generic_cg.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - - Sample application of the NFFT toolbox: standalone "gridding" example. - - ----------- - - The nfft is written generically and templetized to - - transform arbitrary trajectories - - transform an arbitrary number of dimensions (currently instantiated for 1d/2d/3d/4d) - - support both single and double precision - - General principles of the implementation can be found in: - - Accelerating the Non-equispaced Fast Fourier Transform on Commodity Graphics Hardware. - T.S. Sørensen, T. Schaeffter, K.Ø. Noe, M.S. Hansen. - IEEE Transactions on Medical Imaging 2008; 27(4):538-547. - - Real-time Reconstruction of Sensitivity Encoded Radial Magnetic Resonance Imaging Using a Graphics Processing Unit. - T.S. Sørensen, D. Atkinson, T. Schaeffter, M.S. Hansen. - IEEE Transactions on Medical Imaging 2009; 28(12):1974-1985. - - This example programme of the nnft utilizes golden ratio based radial trajectories - and outputs gridded images from 2D multislice input ndarrays of the corresponding samples, trajectory, and density compensation weights. - -*/ - -#include "cuNFFT.h" -#include "radial_utilities.h" -#include "vector_td_utilities.h" -#include "hoNDArray_fileio.h" -#include "cuNDArray_operators.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_blas.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuCgPreconditioner.h" -#include "cuImageOperator.h" -#include "cuCgSolver.h" -#include "GPUTimer.h" -#include "parameterparser.h" -#include "complext.h" - -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; -typedef cuNFFT_plan<_real,2> plan_type; - -int main( int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Input samples file name (.cplx)", true ); - parms.add_parameter( 't', COMMAND_LINE_STRING, 1, "Input trajectories file name (.real)", true ); - parms.add_parameter( 'w', COMMAND_LINE_STRING, 1, "Input density compensation weights file name (.real)", true ); - parms.add_parameter( 'c', COMMAND_LINE_STRING, 1, "Input coil sensitivity maps file name (.cplx)", true ); - parms.add_parameter( 'g', COMMAND_LINE_STRING, 1, "Input regularization image file name (.cplx)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Output image file name (.cplx)", true, "result.cplx" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "10" ); - parms.add_parameter( 'l', COMMAND_LINE_FLOAT, 1, "Regularization weight", true, "0.3" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Oversampling factor", true, "2.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load data from disk - timer = new GPUTimer("Loading data from disk"); - boost::shared_ptr< hoNDArray<_complext> > host_samples = read_nd_array<_complext> ((char*)parms.get_parameter('d')->get_string_value()); - boost::shared_ptr< hoNDArray<_reald2> > host_traj = read_nd_array<_reald2> ((char*)parms.get_parameter('t')->get_string_value()); - boost::shared_ptr< hoNDArray<_real> > host_dcw = read_nd_array<_real> ((char*)parms.get_parameter('w')->get_string_value()); - boost::shared_ptr< hoNDArray<_complext> > host_csm = read_nd_array<_complext> ((char*)parms.get_parameter('c')->get_string_value()); - boost::shared_ptr< hoNDArray<_complext> > host_reg = read_nd_array<_complext> ((char*)parms.get_parameter('g')->get_string_value()); - delete timer; - - if( !(host_samples->get_number_of_dimensions() == 2 && host_traj->get_number_of_dimensions() == 2) ){ - GINFO_STREAM(endl << "Samples/trajectory arrays must be two-dimensional: (dim 0: samples/profile x #profiles/frame; dim 1: #frames). Quitting.\n" << endl); - return 1; - } - - if( !(host_csm->get_number_of_dimensions() == 3 )){ - GINFO_STREAM(endl << "Coil sensitivity maps must be three-dimensional. Quitting.\n" << endl); - return 1; - } - - if( !(host_reg->get_number_of_dimensions() == 2 )){ - GINFO_STREAM(endl << "Regularization image must be two-dimensional. Quitting.\n" << endl); - return 1; - } - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(host_csm->get_size(0), host_csm->get_size(0)); - size_t _matrix_size_os = size_t((float)matrix_size[0]*parms.get_parameter('a')->get_float_value()); - uint64d2 matrix_size_os = uint64d2(_matrix_size_os, _matrix_size_os); - int num_iterations = parms.get_parameter('i')->get_int_value(); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - _real alpha = parms.get_parameter('a')->get_float_value(); - _real kappa = parms.get_parameter('l')->get_float_value(); - - unsigned int num_frames = host_traj->get_size(1); - unsigned int num_coils = host_csm->get_size(2); - - std::vector recon_dims = to_std_vector(matrix_size); - recon_dims.push_back(num_frames); - - // Upload arrays to device - cuNDArray<_complext> samples(*host_samples); - cuNDArray<_reald2> trajectory(*host_traj); - boost::shared_ptr< cuNDArray<_complext> > csm( new cuNDArray<_complext>(*host_csm)); - boost::shared_ptr< cuNDArray<_complext> > reg_image( new cuNDArray<_complext>(*host_reg)); - boost::shared_ptr< cuNDArray<_real> > dcw( new cuNDArray<_real>(*host_dcw)); - - // Define encoding matrix for non-Cartesian SENSE - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E( new cuNonCartesianSenseOperator<_real,2>() ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - E->set_dcw(dcw) ; - E->set_csm(csm); - E->set_domain_dimensions(recon_dims); - E->set_codomain_dimensions(samples.get_dimensions()); - E->preprocess(&trajectory); - - // Define regularization operator - boost::shared_ptr< cuImageOperator<_complext> > R( new cuImageOperator<_complext>() ); - R->set_weight( kappa ); - R->compute( reg_image.get() ); - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - boost::shared_ptr< cuNDArray<_real> > R_diag = R->get(); - *R_diag *= kappa; - *_precon_weights += *R_diag; - R_diag.reset(); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - precon_weights.reset(); - csm.reset(); - - // Setup conjugate gradient solver - cuCgSolver<_complext> cg; - cg.set_preconditioner ( D ); // preconditioning matrix - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-6 ); - cg.set_output_mode( cuCgSolver< _complext>::OUTPUT_VERBOSE ); - cg.set_encoding_operator( E ); // encoding matrix - cg.add_regularization_operator( R ); // regularization matrix - - // - // Invoke conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult; - { - GPUTimer timer("GPU Conjugate Gradient solve"); - cgresult = cg.solve(&samples); - } - - // - // Output result - // - - timer = new GPUTimer("Output result to disk"); - boost::shared_ptr< hoNDArray<_complext> > host_image = cgresult->to_host(); - write_nd_array<_complext>( host_image.get(), (char*)parms.get_parameter('r')->get_string_value() ); - write_nd_array<_real>( abs(cgresult.get())->to_host().get(), "result.real" ); - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/.gitignore b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/.gitignore deleted file mode 100644 index 7e4edfd13..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/.gitignore +++ /dev/null @@ -1 +0,0 @@ -radial_sense \ No newline at end of file diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/CMakeLists.txt b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/CMakeLists.txt deleted file mode 100644 index b262d7188..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_executable(sense_cg_radial_2d main_cg.cpp) -add_executable(sense_sbc_radial_2d main_sbc.cpp) -add_executable(sense_gpbb_radial_2d main_gpbb.cpp) -add_executable(sense_nlcg_radial_2d main_nlcg.cpp) - -target_link_libraries(sense_cg_radial_2d gadgetron_toolbox_gpu gadgetron_toolbox_cpucore gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(sense_sbc_radial_2d gadgetron_toolbox_gpu gadgetron_toolbox_cpucore gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(sense_gpbb_radial_2d gadgetron_toolbox_gpu gadgetron_toolbox_cpucore gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) -target_link_libraries(sense_nlcg_radial_2d gadgetron_toolbox_gpu gadgetron_toolbox_cpucore gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS sense_cg_radial_2d sense_sbc_radial_2d sense_gpbb_radial_2d sense_nlcg_radial_2d DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_cg.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_cg.cpp deleted file mode 100644 index 8b54daef7..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_cg.cpp +++ /dev/null @@ -1,291 +0,0 @@ -// Gadgetron includes -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "hoNDArray_fileio.h" -#include "vector_td_utilities.h" -#include "cuImageOperator.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuCgPreconditioner.h" -#include "cuCgSolver.h" -#include "b1_map.h" -#include "parameterparser.h" -#include "GPUTimer.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -const bool use_atomics = false; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Sample data file name", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "Frames per reconstruction (negative meaning all)", true, "-1" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "10" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'K', COMMAND_LINE_FLOAT, 1, "Kappa", true, "0.3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("\nLoading data"); - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!\n" << endl); - return 1; - } - - // Configuration from the host data - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - _real kappa = parms.get_parameter('K')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - - // Silent correction of invalid command line parameters (clamp to valid range) - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - GINFO_STREAM(endl << "#samples/profile: " << samples_per_profile); - GINFO_STREAM(endl << "#profiles/frame: " << profiles_per_frame); - GINFO_STREAM(endl << "#profiles: " << num_profiles); - GINFO_STREAM(endl << "#coils: " << num_coils); - GINFO_STREAM(endl << "#frames/reconstruction: " << frames_per_reconstruction); - GINFO_STREAM(endl << "#profiles/reconstruction: " << profiles_per_reconstruction); - GINFO_STREAM(endl << "#samples/reconstruction: " << samples_per_reconstruction << endl << endl); - - // Set density compensation weights - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os[0]/(_real)matrix_size[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size[0],matrix_size[1])) ); - - // Define encoding matrix for non-Cartesian SENSE - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E - ( new cuNonCartesianSenseOperator<_real,2>() ); - - E->setup( matrix_size, matrix_size_os, kernel_width ); - - - - // Define rhs buffer - // - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer - ( new cuSenseBuffer<_real,2>() ); - - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, 8, 16 ); - rhs_buffer->set_dcw(dcw); - - // Fill rhs buffer - // - - timer = new GPUTimer("Filling rhs buffer"); - - // Go through all the data... - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_frame ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - delete timer; - - - // Estimate CSM - // - - timer = new GPUTimer("Estimating csm"); - - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - boost::shared_ptr< cuNDArray<_complext> > csm = boost::make_shared>(estimate_b1_map<_real,2>( *acc_images.get() )); - E->set_csm(csm); - - delete timer; - - - // Define regularization image operator - // - - timer = new GPUTimer("Computing regularization"); - - std::vector image_dims = to_std_vector(matrix_size); - cuNDArray<_complext> reg_image = cuNDArray<_complext>(image_dims); - - E->mult_csm_conj_sum( acc_images.get(), ®_image ); - acc_images.reset(); - - boost::shared_ptr< cuImageOperator<_complext> > R( new cuImageOperator<_complext>() ); - R->set_weight( kappa ); - R->compute( ®_image ); - - delete timer; - - // Define preconditioning weights - // - - timer = new GPUTimer("Computing preconditioning weights"); - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - boost::shared_ptr< cuNDArray<_real> > R_diag = R->get(); - *R_diag *= kappa; - *_precon_weights += *R_diag; - R_diag.reset(); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - precon_weights.reset(); - csm.reset(); - - delete timer; - - // - // Setup radial SENSE reconstructions - // - // Notify encoding operator of dcw - sqrt_inplace(dcw.get()); - E->set_dcw(dcw); - // Setup conjugate gradient solver - cuCgSolver<_complext> cg; - cg.set_preconditioner ( D ); // preconditioning matrix - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-6 ); - cg.set_output_mode( cuCgSolver< _complext>::OUTPUT_VERBOSE ); - cg.set_encoding_operator( E ); // encoding matrix - cg.add_regularization_operator( R ); // regularization matrix - - // Reconstruct all SENSE frames iteratively - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - - // Allocate space for result - image_dims.push_back(frames_per_reconstruction*num_reconstructions); - cuNDArray<_complext> result = cuNDArray<_complext>(image_dims); - - timer = new GPUTimer("Full SENSE reconstruction."); - - // Define image dimensions - image_dims = to_std_vector(matrix_size); - image_dims.push_back(frames_per_reconstruction); - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, reconstruction*profiles_per_reconstruction ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( reconstruction, samples_per_reconstruction, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Pass image dimensions to encoding operator - E->set_domain_dimensions(image_dims); - E->set_codomain_dimensions(data->get_dimensions()); - - // Set current trajectory and trigger NFFT preprocessing - E->preprocess(traj.get()); - - *data *= *dcw; - // - // Invoke conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult; - { - GPUTimer timer("GPU Conjugate Gradient solve"); - cgresult = cg.solve(data.get()); - } - - if( !cgresult.get() ) - return 1; - - // Copy cgresult to overall result - cuNDArray<_complext> out(image_dims, result.get_data_ptr()+reconstruction*prod(matrix_size)*frames_per_reconstruction ); - out = *(cgresult.get()); - } - - delete timer; - - // All done, write out the result - - timer = new GPUTimer("Writing out result"); - - boost::shared_ptr< hoNDArray<_complext> > host_result = result.to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&result)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_gpbb.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_gpbb.cpp deleted file mode 100644 index a89d44627..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_gpbb.cpp +++ /dev/null @@ -1,287 +0,0 @@ -// Gadgetron includes -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuCgPreconditioner.h" -#include "cuPartialDerivativeOperator.h" -#include "cuGpBbSolver.h" -#include "cuTvOperator.h" -#include "cuTvPicsOperator.h" -#include "b1_map.h" -#include "GPUTimer.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Sample data file name", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "Frames per reconstruction (negative meaning all)", true, "-1" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "10" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'L', COMMAND_LINE_FLOAT, 1, "Lambda", true, "2e-7" ); - parms.add_parameter( 'A', COMMAND_LINE_FLOAT, 1, "Alpha in [0;1] (for PICS)", true, "0.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("\nLoading data"); - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!\n" << endl); - return 1; - } - - // Configuration from the host data - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - - _real lambda = (_real) parms.get_parameter('L')->get_float_value(); - _real alpha = (_real) parms.get_parameter('A')->get_float_value(); - - if( alpha>1 ) alpha = 1; - if( alpha<0 ) alpha = 0; - - // Silent correction of invalid command line parameters (clamp to valid range) - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - GINFO_STREAM(endl << "#samples/profile: " << samples_per_profile); - GINFO_STREAM(endl << "#profiles/frame: " << profiles_per_frame); - GINFO_STREAM(endl << "#profiles: " << num_profiles); - GINFO_STREAM(endl << "#coils: " << num_coils); - GINFO_STREAM(endl << "#frames/reconstruction " << frames_per_reconstruction); - GINFO_STREAM(endl << "#profiles/reconstruction " << profiles_per_reconstruction); - GINFO_STREAM(endl << "#samples/reconstruction " << samples_per_reconstruction << endl << endl); - - // Density compensation weights are constant throughout all reconstrutions - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os[0]/(_real)matrix_size[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size[0],matrix_size[1])) ); - - // Define encoding matrix for non-Cartesian SENSE - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E( new cuNonCartesianSenseOperator<_real,2>() ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - - - // Define rhs buffer - // - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer( new cuSenseBuffer<_real,2>() ); - - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, 8, 16 ); - rhs_buffer->set_dcw(dcw); - - // - // Compute CSM using accumulation in the rhs buffer - // - - timer = new GPUTimer("CSM and regularization estimation"); - - // Go through all the data... - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_frame ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - // Estimate csm - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - *acc_images *= rhs_buffer->get_normalization_factor(); - auto csm = boost::make_shared>(estimate_b1_map<_real,2>( *acc_images.get() )); - E->set_csm(csm); - - std::vector reg_dims = to_std_vector(matrix_size); - cuNDArray<_complext> _reg_image = cuNDArray<_complext>(reg_dims); - E->mult_csm_conj_sum( acc_images.get(), &_reg_image ); - - // Duplicate the regularization image to 'frames_per_reconstruction' frames - auto reg_image = boost::make_shared>(expand( _reg_image, frames_per_reconstruction )); - - acc_images.reset(); - - // Define preconditioning weights - // - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - precon_weights.reset(); - csm.reset(); - - std::vector recon_dims; - recon_dims = to_std_vector(matrix_size); - recon_dims.push_back(frames_per_reconstruction); - - delete timer; - - // - // Setup radial SENSE reconstructions - // - - std::vector data_dims; - data_dims.push_back(samples_per_reconstruction); data_dims.push_back(num_coils); - - sqrt_inplace(dcw.get()); - E->set_dcw(dcw); - E->set_domain_dimensions(recon_dims); - E->set_codomain_dimensions(data_dims); - - // Setup split-Bregman solver - cuGpBbSolver<_complext> solver; - - // Add "TV" regularization - if( (alpha<1.0f) && (lambda>0.0f)){ - boost::shared_ptr > TV(new cuTvOperator<_complext,3>); - TV->set_weight(lambda*(1.0f-alpha)); - solver.add_nonlinear_operator(TV); - } - - // Add "PICS" regularization - boost::shared_ptr > PICS; - if( (alpha>0.0f) && (lambda>0.0f)){ - PICS = boost::shared_ptr >(new cuTvPicsOperator<_complext,3>); - PICS->set_weight(lambda*alpha); - PICS->set_prior(reg_image); - solver.add_nonlinear_operator(PICS); - } - - solver.set_encoding_operator( E ); - solver.set_preconditioner ( D ); - solver.set_max_iterations( num_iterations ); - solver.set_output_mode( cuGpBbSolver<_complext>::OUTPUT_VERBOSE ); -// solver.set_x0( reg_image ); - - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - - // Allocate space for result - std::vector res_dims = to_std_vector(matrix_size); - res_dims.push_back(frames_per_reconstruction*num_reconstructions); - cuNDArray<_complext> result = cuNDArray<_complext>(res_dims); - - timer = new GPUTimer("Full SENSE reconstruction with TV regularization."); - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, reconstruction*profiles_per_reconstruction ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( reconstruction, samples_per_reconstruction, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Set current trajectory and trigger NFFT preprocessing - E->preprocess(traj.get()); - - // - // Split-Bregman solver - // - *data *= *dcw; - boost::shared_ptr< cuNDArray<_complext> > solve_result; - { - GPUTimer timer("GPU constrained Split Bregman solve"); - solve_result = solver.solve(data.get()); - } - - vector tmp_dims = to_std_vector(matrix_size); tmp_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> tmp(tmp_dims, result.get_data_ptr()+reconstruction*prod(matrix_size)*frames_per_reconstruction ); - - // Copy sbresult to result (pointed to by tmp) - tmp = *solve_result; - } - - delete timer; - - // All done, write out the result - - timer = new GPUTimer("Writing out result"); - - boost::shared_ptr< hoNDArray<_complext> > host_result = result.to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&result)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_nlcg.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_nlcg.cpp deleted file mode 100644 index 449c1359b..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_nlcg.cpp +++ /dev/null @@ -1,342 +0,0 @@ -// Gadgetron includes -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuCgPreconditioner.h" -#include "cuPartialDerivativeOperator.h" -#include "cuNlcgSolver.h" -#include "cuTvOperator.h" -#include "cuTvPicsOperator.h" -#include "b1_map.h" -#include "GPUTimer.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Sample data file name", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "Frames per reconstruction (negative meaning all)", true, "-1" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "10" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'L', COMMAND_LINE_FLOAT, 1, "Lambda", true, "2e-7" ); - parms.add_parameter( 'A', COMMAND_LINE_FLOAT, 1, "Alpha in [0;1] (for PICS)", true, "0.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("\nLoading data"); - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!\n" << endl); - return 1; - } - - // Configuration from the host data - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - - _real lambda = (_real) parms.get_parameter('L')->get_float_value(); - _real alpha = (_real) parms.get_parameter('A')->get_float_value(); - - if( alpha>1 ) alpha = 1; - if( alpha<0 ) alpha = 0; - - // Silent correction of invalid command line parameters (clamp to valid range) - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - GINFO_STREAM(endl << "#samples/profile: " << samples_per_profile); - GINFO_STREAM(endl << "#profiles/frame: " << profiles_per_frame); - GINFO_STREAM(endl << "#profiles: " << num_profiles); - GINFO_STREAM(endl << "#coils: " << num_coils); - GINFO_STREAM(endl << "#frames/reconstruction " << frames_per_reconstruction); - GINFO_STREAM(endl << "#profiles/reconstruction " << profiles_per_reconstruction); - GINFO_STREAM(endl << "#samples/reconstruction " << samples_per_reconstruction << endl << endl); - - // Density compensation weights are constant throughout all reconstrutions - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os[0]/(_real)matrix_size[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size[0],matrix_size[1])) ); - // Define rhs buffer - // - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer( new cuSenseBuffer<_real,2>() ); - - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, 8, 16 ); - rhs_buffer->set_dcw(dcw); - - // - // Compute CSM using accumulation in the rhs buffer - // - - timer = new GPUTimer("CSM and regularization estimation"); - - // Go through all the data... - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_frame ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - // Estimate csm - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - *acc_images *= rhs_buffer->get_normalization_factor(); - auto csm = boost::make_shared>(estimate_b1_map<_real,2>( *acc_images.get() )); - - - // Define encoding matrix for non-Cartesian SENSE - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E( new cuNonCartesianSenseOperator<_real,2>() ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - - - - E->set_csm(csm); - - std::vector reg_dims = to_std_vector(matrix_size); - cuNDArray<_complext> _reg_image = cuNDArray<_complext>(reg_dims); - E->mult_csm_conj_sum( acc_images.get(), &_reg_image ); - - // Duplicate the regularization image to 'frames_per_reconstruction' frames - auto reg_image = boost::make_shared>(expand( _reg_image, frames_per_reconstruction )); - - acc_images.reset(); - - // Define preconditioning weights - // - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - //precon_weights.reset(); - csm.reset(); - - std::vector recon_dims; - recon_dims = to_std_vector(matrix_size); - recon_dims.push_back(frames_per_reconstruction); - - delete timer; - - // - // Setup radial SENSE reconstructions - // - - vector data_dims; - data_dims.push_back(samples_per_reconstruction); data_dims.push_back(num_coils); - - E->set_domain_dimensions(recon_dims); - E->set_codomain_dimensions(data_dims); - - // Setup split-Bregman solver - cuNlcgSolver<_complext> solver; - - // Define regularization operators - // We need "a pair" for PICCS - // - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rx( new cuPartialDerivativeOperator<_complext,3>(0) ); - Rx->set_weight( (1.0f-alpha)*lambda ); - Rx->set_domain_dimensions(recon_dims); - Rx->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Ry( new cuPartialDerivativeOperator<_complext,3>(1) ); - Ry->set_weight( (1.0f-alpha)*lambda ); - Ry->set_domain_dimensions(recon_dims); - Ry->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rz( new cuPartialDerivativeOperator<_complext,3>(2) ); - Rz->set_weight( (1.0f-alpha)*lambda ); - Rz->set_domain_dimensions(recon_dims); - Rz->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rx2( new cuPartialDerivativeOperator<_complext,3>(0) ); - Rx2->set_weight( alpha*lambda ); - Rx2->set_domain_dimensions(recon_dims); - Rx2->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Ry2( new cuPartialDerivativeOperator<_complext,3>(1) ); - Ry2->set_weight( alpha*lambda ); - Ry2->set_domain_dimensions(recon_dims); - Ry2->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rz2( new cuPartialDerivativeOperator<_complext,3>(2) ); - Rz2->set_weight( alpha*lambda ); - Rz2->set_domain_dimensions(recon_dims); - Rz2->set_codomain_dimensions(recon_dims); - - - // Add "TV" regularization - if( (alpha<1.0f) && (lambda>0.0f)){ - boost::shared_ptr > TV(new cuTvOperator<_complext,3>); - TV->set_weight(lambda*(1.0f-alpha)); - solver.add_nonlinear_operator(TV); - /*solver.add_regularization_group_operator(Rx); - solver.add_regularization_group_operator(Ry); - solver.add_regularization_group_operator(Rz); - solver.add_group(1);*/ - GDEBUG_STREAM("Total variation in use " << std::endl); - } - - // Add "PICS" regularization - boost::shared_ptr > PICS; - if( (alpha>0.0f) && (lambda>0.0f)){ - PICS = boost::shared_ptr >(new cuTvPicsOperator<_complext,3>); - PICS->set_weight(lambda*alpha); - PICS->set_prior(reg_image); - solver.add_nonlinear_operator(PICS); - /* - solver.add_regularization_group_operator(Rx2); - solver.add_regularization_group_operator(Ry2); - solver.add_regularization_group_operator(Rz2); - solver.add_group(reg_image,1);*/ - GDEBUG_STREAM("PICS in use " << std::endl); - } - - sqrt_inplace(dcw.get()); - E->set_dcw(dcw); - solver.set_encoding_operator( E ); - solver.set_preconditioner ( D ); - solver.set_max_iterations( num_iterations ); - solver.set_output_mode( cuNlcgSolver<_complext>::OUTPUT_VERBOSE ); - //solver.set_x0( reg_image ); - - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - - // Allocate space for result - std::vector res_dims = to_std_vector(matrix_size); - res_dims.push_back(frames_per_reconstruction*num_reconstructions); - cuNDArray<_complext> result = cuNDArray<_complext>(res_dims); - - timer = new GPUTimer("Full SENSE reconstruction with TV regularization."); - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, reconstruction*profiles_per_reconstruction ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( reconstruction, samples_per_reconstruction, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - *data *= *dcw; - // Set current trajectory and trigger NFFT preprocessing - E->preprocess(traj.get()); - - // - // Split-Bregman solver - // - - boost::shared_ptr< cuNDArray<_complext> > solve_result; - { - GPUTimer timer("GPU constrained Split Bregman solve"); - solve_result = solver.solve(data.get()); - } - - vector tmp_dims = to_std_vector(matrix_size); tmp_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> tmp(tmp_dims, result.get_data_ptr()+reconstruction*prod(matrix_size)*frames_per_reconstruction ); - - // Copy sbresult to result (pointed to by tmp) - tmp = *solve_result; - } - - delete timer; - - // All done, write out the result - - timer = new GPUTimer("Writing out result"); - - boost::shared_ptr< hoNDArray<_complext> > host_result = result.to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&result)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_sbc.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_sbc.cpp deleted file mode 100644 index 6639982f0..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio/main_sbc.cpp +++ /dev/null @@ -1,335 +0,0 @@ -// Gadgetron includes -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuCgPreconditioner.h" -#include "cuPartialDerivativeOperator.h" -#include "cuCgSolver.h" -#include "cuSbcCgSolver.h" -#include "b1_map.h" -#include "GPUTimer.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace std; -using namespace Gadgetron; -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Sample data file name", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "Frames per reconstruction (negative meaning all)", true, "-1" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of cg iterations", true, "10" ); - parms.add_parameter( 'I', COMMAND_LINE_INT, 1, "Number of sb inner iterations", true, "1" ); - parms.add_parameter( 'O', COMMAND_LINE_INT, 1, "Number of sb outer iterations", true, "10" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'M', COMMAND_LINE_FLOAT, 1, "Mu", true, "1.0" ); - parms.add_parameter( 'L', COMMAND_LINE_FLOAT, 1, "Lambda", true, "2.0" ); - parms.add_parameter( 'A', COMMAND_LINE_FLOAT, 1, "Alpha in [0;1] (for PICCS)", true, "0.5" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("\nLoading data"); - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!\n" << endl); - return 1; - } - - // Configuration from the host data - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - unsigned int num_cg_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int num_sb_inner_iterations = parms.get_parameter('I')->get_int_value(); - unsigned int num_sb_outer_iterations = parms.get_parameter('O')->get_int_value(); - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - - _real mu = (_real) parms.get_parameter('M')->get_float_value(); - _real lambda = (_real) parms.get_parameter('L')->get_float_value(); - _real alpha = (_real) parms.get_parameter('A')->get_float_value(); - - if( alpha>1 ) alpha = 1; - if( alpha<0 ) alpha = 0; - - // Silent correction of invalid command line parameters (clamp to valid range) - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - GINFO_STREAM(endl << "#samples/profile: " << samples_per_profile); - GINFO_STREAM(endl << "#profiles/frame: " << profiles_per_frame); - GINFO_STREAM(endl << "#profiles: " << num_profiles); - GINFO_STREAM(endl << "#coils: " << num_coils); - GINFO_STREAM(endl << "#frames/reconstruction " << frames_per_reconstruction); - GINFO_STREAM(endl << "#profiles/reconstruction " << profiles_per_reconstruction); - GINFO_STREAM(endl << "#samples/reconstruction " << samples_per_reconstruction << endl << endl); - - // Density compensation weights are constant throughout all reconstrutions - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os[0]/(_real)matrix_size[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size[0],matrix_size[1])) ); - - // Define encoding matrix for non-Cartesian SENSE - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E( new cuNonCartesianSenseOperator<_real,2>() ); - E->set_weight( mu ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - - - // Define rhs buffer - // - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer( new cuSenseBuffer<_real,2>() ); - - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, 8, 16 ); - rhs_buffer->set_dcw(dcw); - - // - // Compute CSM using accumulation in the rhs buffer - // - - timer = new GPUTimer("CSM and regularization estimation"); - - // Go through all the data... - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_frame ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - // Estimate csm - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - *acc_images *= rhs_buffer->get_normalization_factor(); - boost::shared_ptr< cuNDArray<_complext> > csm = boost::make_shared>(estimate_b1_map<_real,2>( *acc_images )); - E->set_csm(csm); - - std::vector reg_dims = to_std_vector(matrix_size); - cuNDArray<_complext> _reg_image = cuNDArray<_complext>(reg_dims); - E->mult_csm_conj_sum( acc_images.get(), &_reg_image ); - - // Duplicate the regularization image to 'frames_per_reconstruction' frames - auto reg_image = boost::make_shared>(expand( _reg_image, frames_per_reconstruction )); - - acc_images.reset(); - - // Define preconditioning weights - // - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - precon_weights.reset(); - csm.reset(); - - std::vector recon_dims = to_std_vector(matrix_size); - recon_dims.push_back(frames_per_reconstruction); - - // Define regularization operators - // We need "a pair" for PICCS - // - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rx( new cuPartialDerivativeOperator<_complext,3>(0) ); - Rx->set_weight( (1.0f-alpha)*lambda ); - Rx->set_domain_dimensions(recon_dims); - Rx->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Ry( new cuPartialDerivativeOperator<_complext,3>(1) ); - Ry->set_weight( (1.0f-alpha)*lambda ); - Ry->set_domain_dimensions(recon_dims); - Ry->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rz( new cuPartialDerivativeOperator<_complext,3>(2) ); - Rz->set_weight( (1.0f-alpha)*lambda ); - Rz->set_domain_dimensions(recon_dims); - Rz->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rx2( new cuPartialDerivativeOperator<_complext,3>(0) ); - Rx2->set_weight( alpha*lambda ); - Rx2->set_domain_dimensions(recon_dims); - Rx2->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Ry2( new cuPartialDerivativeOperator<_complext,3>(1) ); - Ry2->set_weight( alpha*lambda ); - Ry2->set_domain_dimensions(recon_dims); - Ry2->set_codomain_dimensions(recon_dims); - - boost::shared_ptr< cuPartialDerivativeOperator<_complext,3> > - Rz2( new cuPartialDerivativeOperator<_complext,3>(2) ); - Rz2->set_weight( alpha*lambda ); - Rz2->set_domain_dimensions(recon_dims); - Rz2->set_codomain_dimensions(recon_dims); - - delete timer; - - // - // Setup radial SENSE reconstructions - // - - vector data_dims; - data_dims.push_back(samples_per_reconstruction); data_dims.push_back(num_coils); - - E->set_domain_dimensions(recon_dims); - E->set_codomain_dimensions(data_dims); - - sqrt_inplace(dcw.get()); - E->set_dcw(dcw); - // Setup split-Bregman solver - cuSbcCgSolver<_complext> sb; - sb.set_encoding_operator( E ); - - // Add "TV" regularization - if( alpha<1.0 ){ - sb.add_regularization_group_operator( Rx ); - sb.add_regularization_group_operator( Ry ); - sb.add_regularization_group_operator( Rz ); - sb.add_group(); - } - - // Add "PICCS" regularization - if( alpha > 0.0 ){ - sb.add_regularization_group_operator( Rx2 ); - sb.add_regularization_group_operator( Ry2 ); - sb.add_regularization_group_operator( Rz2 ); - sb.add_group(reg_image); - } - - sb.set_max_outer_iterations(num_sb_outer_iterations); - sb.set_max_inner_iterations(num_sb_inner_iterations); - sb.set_output_mode( cuSbcCgSolver<_complext>::OUTPUT_VERBOSE ); - - sb.get_inner_solver()->set_preconditioner ( D ); - sb.get_inner_solver()->set_max_iterations( num_cg_iterations ); - sb.get_inner_solver()->set_tc_tolerance( 1e-4 ); - sb.get_inner_solver()->set_output_mode( cuCgSolver<_complext>::OUTPUT_WARNINGS ); - - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - - // Allocate space for result - std::vector res_dims = to_std_vector(matrix_size); - res_dims.push_back(frames_per_reconstruction*num_reconstructions); - cuNDArray<_complext> result = cuNDArray<_complext>(res_dims); - - timer = new GPUTimer("Full SENSE reconstruction with TV regularization."); - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, reconstruction*profiles_per_reconstruction ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( reconstruction, samples_per_reconstruction, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Set current trajectory and trigger NFFT preprocessing - E->preprocess(traj.get()); - - *data *= *dcw; - // - // Split-Bregman solver - // - - boost::shared_ptr< cuNDArray<_complext> > sbresult; - { - GPUTimer timer("GPU constrained Split Bregman solve"); - sbresult = sb.solve(data.get()); - } - - vector tmp_dims = to_std_vector(matrix_size); tmp_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> tmp(tmp_dims, result.get_data_ptr()+reconstruction*prod(matrix_size)*frames_per_reconstruction ); - - // Copy sbresult to result (pointed to by tmp) - tmp = *sbresult; - } - - delete timer; - - // All done, write out the result - - timer = new GPUTimer("Writing out result"); - - boost::shared_ptr< hoNDArray<_complext> > host_result = result.to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&result)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/CMakeLists.txt b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/CMakeLists.txt deleted file mode 100644 index 8b4dd5968..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/CMakeLists.txt +++ /dev/null @@ -1,30 +0,0 @@ -include( ${QT_USE_FILE} ) - -#We need binary and source dirs in this because of the header files created by the make process -include_directories( - ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_CURRENT_SOURCE_DIR} - ${OPENGL_INCLUDE_DIR} - ${GLUT_INCLUDE_DIR} - ${GLEW_INCLUDE_DIR} - ${Boost_INCLUDE_DIR} -) - -set(UI_UIFILES reconBaseWidget.ui radialSenseAppBaseMainWidget.ui) -qt4_wrap_ui( UI_HEADERS ${UI_UIFILES} ) - -set(UI_MOC_HEADERS radialSenseAppMainWidget.h reconWidget.h GLReconWidget.h) -qt4_wrap_cpp (UI_MOC_OUTFILES ${UI_MOC_HEADERS}) - -add_executable(sense_2d_golden_radial_gui main.cpp ${UI_MOC_OUTFILES} -radialSenseAppMainWidget.cpp reconWidget.cpp GLReconWidget.cpp ${UI_HEADERS} ) - -target_link_libraries(sense_2d_golden_radial_gui gadgetron_toolbox_gpu -gadgetron_toolbox_hostutils gpuoperators ${CUDA_LIBRARIES} ${QT_QTGUI_LIBRARY} ${GLEW_LIBRARY} -${QT_QTCORE_LIBRARY} ${QT_QTOPENGL_LIBRARY} ${OPENGL_gl_LIBRARY} ) - -if (WIN32) -set_target_properties( sense_2d_golden_radial_gui PROPERTIES LINK_FLAGS "/FORCE:MULTIPLE") -endif () - -install(TARGETS sense_2d_golden_radial_gui DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.cpp deleted file mode 100644 index e1957903b..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.cpp +++ /dev/null @@ -1,222 +0,0 @@ -#include - -#include "GLReconWidget.h" -#include "UIconstants.h" - -#include -#include - -#include - -//MSH: Ripped from cutil.h to remove dependency, replace -# define CUDA_SAFE_CALL_NO_SYNC( call) { \ - cudaError err = call; \ - if( cudaSuccess != err) { \ - fprintf(stderr, "Cuda error in file '%s' in line %i : %s.\n", \ - __FILE__, __LINE__, cudaGetErrorString( err) ); \ - exit(EXIT_FAILURE); \ - } } - -# define CUDA_SAFE_CALL( call) CUDA_SAFE_CALL_NO_SYNC(call); \ - - -GLReconWidget::GLReconWidget(QWidget *parent) : QGLWidget(parent) -{ - cudaWidget = new cuGLReconWidget( MATRIX_SIZE_INITIAL_VALUE, MATRIX_SIZE_INITIAL_VALUE ); -} - -void GLReconWidget::setMatrixSize( unsigned int width, unsigned int height ) -{ - cudaWidget->width = width; - cudaWidget->height = height; - - cudaWidget->initializePBO(); -} - -void GLReconWidget::initializeGL() -{ - glewInit(); - - if (!glewIsSupported("GL_VERSION_2_0 GL_VERSION_1_5 GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object")) { - fprintf(stderr, "Required OpenGL extensions missing."); - exit(1); - } - - cudaWidget->initializePBO(); -} - -void GLReconWidget::paintGL() -{ - cudaWidget->display(); -} - -void GLReconWidget::resizeGL( int w, int h ) -{ - glViewport(0, 0, w, h); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0.0, 1.0, 0.0, 1.0, 0.0, 1.0); -} - -void GLReconWidget::mapPBO() -{ - cudaWidget->mapPBO(); -} - -void GLReconWidget::unmapPBO() -{ - cudaWidget->unmapPBO(); -} - -float* GLReconWidget::getDevPtr() -{ - return cudaWidget->getDevPtr(); -} - -// shader for displaying floating-point texture -static const char *shader_code = - "!!ARBfp1.0\n" - "TEX result.color, fragment.texcoord, texture[0], 2D; \n" - "END"; - -cuGLReconWidget::cuGLReconWidget( unsigned int width, unsigned int height ) -{ - this->width = width; - this->height = height; - imageDevPtr = 0x0; - pbo = texid = shader = 0; -} - -GLuint cuGLReconWidget::compileASMShader(GLenum program_type, const char *code) -{ - GLuint program_id; - glGenProgramsARB(1, &program_id); - glBindProgramARB(program_type, program_id); - glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(code), (GLubyte *) code); - - GLint error_pos; - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); - if (error_pos != -1) { - const GLubyte *error_string; - error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB); - fprintf(stderr, "Program error at position: %d\n%s\n", (int)error_pos, error_string); - return 0; - } - return program_id; -} - -void cuGLReconWidget::initializePBO() -{ - while( glGetError() != GL_NO_ERROR ){ - printf("\nWARNING: glError detected prior to initialisePBO"); - fflush(stdout); - } - - // Create pixel buffer object (PBO) to "render Cuda memory" through a texture - glGenBuffersARB(1, &pbo); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); - - // Initialize PBO with zero image - float *tmp = (float*) calloc( width*height, sizeof(float) ); - glBufferDataARB(GL_PIXEL_UNPACK_BUFFER_ARB, width*height*sizeof(float), tmp, GL_STREAM_DRAW_ARB); - - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); - CUDA_SAFE_CALL(cudaGLRegisterBufferObject(pbo)); - - // Create texture for display - glGenTextures(1, &texid); - glBindTexture(GL_TEXTURE_2D, texid); - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE32F_ARB, width, height, 0, GL_LUMINANCE, GL_FLOAT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); - - glBindTexture(GL_TEXTURE_2D, 0); - - // Load shader program - shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB, shader_code); - - while( glGetError() != GL_NO_ERROR ){ - printf("\nWARNING: glError detected prior to initialiseOpenGL"); - fflush(stdout); - } - - free(tmp); -} - -void cuGLReconWidget::mapPBO() -{ - if( width==0 || height == 0 ){ - printf("\nWARNING: pbo buffer size is 0! Has initialiseOpenGL() been called?\n"); - } - - imageDevPtr = 0x0; - - // Map the PBO used for rendering to Cuda device memory - CUDA_SAFE_CALL(cudaGLMapBufferObject((void**)&imageDevPtr, pbo)); - - if( !imageDevPtr ){ - printf("\nWARNING: no pbo allocated for reconstruction result!\n"); - } - - // Error check - cudaError_t err = cudaGetLastError(); - if( err != cudaSuccess ){ - printf("\nCuda error detected: %s\n", cudaGetErrorString(err) ); fflush(stdout); - exit(1); - } -} - -void cuGLReconWidget::unmapPBO() -{ - // Unmap Cuda <-> PBO relation - CUDA_SAFE_CALL(cudaGLUnmapBufferObject(pbo)); - - // Error check - cudaError_t err = cudaGetLastError(); - if( err != cudaSuccess ){ - printf("\nCuda error detected: %s\n", cudaGetErrorString(err) ); fflush(stdout); - exit(1); - } -} - -float* cuGLReconWidget::getDevPtr() -{ - return imageDevPtr; -} - -void cuGLReconWidget::display() -{ - // Clear window - glClear(GL_COLOR_BUFFER_BIT); - - // Load texture from PBO - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, pbo); - glBindTexture(GL_TEXTURE_2D, texid); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_LUMINANCE, GL_FLOAT, 0); - glBindBufferARB(GL_PIXEL_UNPACK_BUFFER_ARB, 0); - - // Use simple fragment program to display the floating point texture - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader); - glEnable(GL_FRAGMENT_PROGRAM_ARB); - glDisable(GL_DEPTH_TEST); - - // Render quad - glBegin(GL_QUADS); - { - glVertex2f(0, 1); glTexCoord2f(0, 1); - glVertex2f(0, 0); glTexCoord2f(0, 0); - glVertex2f(1, 0); glTexCoord2f(1, 0); - glVertex2f(1, 1); glTexCoord2f(1, 1); - } - glEnd(); - - // Restore original state - glBindTexture(GL_TEXTURE_2D, 0); - glDisable(GL_FRAGMENT_PROGRAM_ARB); -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.h b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.h deleted file mode 100644 index 4c579d3db..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/GLReconWidget.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once - -#include "cuNDArray.h" - -#if defined (WIN32) -#include -#endif - -#ifdef __MACH__ -#import -#else -#include -#endif //__MACH__ - -#include - -class cuGLReconWidget -{ -public: - cuGLReconWidget( unsigned int width, unsigned int height ); - - void initializePBO(); - void mapPBO(); - void unmapPBO(); - float* getDevPtr(); - void display(); - - GLuint compileASMShader(GLenum program_type, const char *code); - - unsigned int width; - unsigned int height; - GLuint pbo; // OpenGL pixel buffer object (map between Cuda and OpenGL) - GLuint texid; // Texture (display pbo) - GLuint shader; // Pixel shader for rendering of texture - float *imageDevPtr; // This is the "exchange buffer" between Cuda and OpenGL -}; - -class GLReconWidget : public QGLWidget -{ - Q_OBJECT - - public: - GLReconWidget(QWidget* parent = 0); - void setMatrixSize( unsigned int width, unsigned int height ); - void mapPBO(); - void unmapPBO(); - float* getDevPtr(); - -protected: - void initializeGL(); - void paintGL(); - void resizeGL(int w, int h); - -private: - cuGLReconWidget *cudaWidget; -}; diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/UIconstants.h b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/UIconstants.h deleted file mode 100644 index e9a0c9f77..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/UIconstants.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef _UI_CONSTANTS -#define _UI_CONSTANTS - -const unsigned int MATRIX_SIZE_INITIAL_VALUE = 192; -const unsigned int MATRIX_SIZE_OS_INITIAL_VALUE = 256; -const unsigned int NUM_ITERATIONS_INITIAL_VALUE = 15; -const double REG_WEIGHT_INITIAL_VALUE = 0.01; -const double KERNEL_SIZE_INITIAL_VALUE = 5.5; -const unsigned int NUM_FRAMES_PER_CSM_RECON = 8; -#endif diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/main.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/main.cpp deleted file mode 100644 index 1cf22eb84..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/main.cpp +++ /dev/null @@ -1,19 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Program main -//////////////////////////////////////////////////////////////////////////////// - -#include "radialSenseAppMainWidget.h" - -#include - -#include - -int -main( int argc, char** argv) -{ - QApplication app(argc, argv); - radialSenseAppMainWindow window; - window.show(); - - return app.exec(); -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppBaseMainWidget.ui b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppBaseMainWidget.ui deleted file mode 100644 index 49a69e310..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppBaseMainWidget.ui +++ /dev/null @@ -1,572 +0,0 @@ - - - radialSenseAppBaseMainWindow - - - - 0 - 0 - 476 - 539 - - - - - 0 - 0 - - - - Radial Sense GPU Reconstructor - - - - - - - - - 20 - 30 - 272 - 414 - - - - - 0 - 0 - - - - - 272 - 414 - - - - - - - 340 - 10 - 81 - 16 - - - - - 75 - true - true - - - - Matrix sizes - - - - - - 310 - 30 - 51 - 16 - - - - - 12 - - - - Target - - - - - false - - - - 310 - 50 - 71 - 22 - - - - 16 - - - 512 - - - 2 - - - 16 - - - - - false - - - - 390 - 50 - 61 - 22 - - - - 16 - - - 512 - - - 0 - - - 16 - - - - - - 310 - 210 - 141 - 16 - - - - - 12 - - - - Regularization weight - - - - - true - - - - 310 - 230 - 71 - 22 - - - - 3 - - - 50.000000000000000 - - - 0.010000000000000 - - - 0.000000000000000 - - - - - - 380 - 30 - 81 - 16 - - - - - 12 - - - - Oversampled - - - - - - 310 - 80 - 81 - 16 - - - - - 12 - - - - Kernel width - - - - - true - - - - 310 - 100 - 51 - 22 - - - - 2 - - - 1.000000000000000 - - - 15.000000000000000 - - - 0.500000000000000 - - - 1.000000000000000 - - - - - - 310 - 140 - 118 - 3 - - - - Qt::Horizontal - - - - - - 310 - 150 - 131 - 16 - - - - - 12 - - - - Number of iterations - - - - - - 310 - 170 - 51 - 22 - - - - 1 - - - 99 - - - 1 - - - 1 - - - - - - 310 - 270 - 131 - 16 - - - - Window scale - - - - - true - - - - 310 - 290 - 62 - 22 - - - - 1 - - - 1.000000000000000 - - - 10.000000000000000 - - - 0.250000000000000 - - - 2.000000000000000 - - - - - - - 0 - 0 - 476 - 22 - - - - - File - - - - - - - - - - - - Help - - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - toolBar_2 - - - TopToolBarArea - - - false - - - - - toolBar_3 - - - TopToolBarArea - - - false - - - - - toolBar_4 - - - TopToolBarArea - - - false - - - - - toolBar_5 - - - TopToolBarArea - - - false - - - - - Open .cplx file - - - Ctrl+O - - - - - Quit - - - Ctrl+Q - - - - - Close - - - Ctrl+W - - - - - Save image - - - Ctrl+S - - - - - - ReconWidget - QWidget -
reconWidget.h
- 1 -
-
- - - - kernelSizeSpinBox - editingFinished() - radialSenseAppBaseMainWindow - kernelWidthChanged() - - - 330 - 260 - - - 442 - 277 - - - - - matrixSizeSpinBox - editingFinished() - radialSenseAppBaseMainWindow - matrixSizeChanged() - - - 321 - 211 - - - 441 - 249 - - - - - oversampledMatrixSizeSpinBox - editingFinished() - radialSenseAppBaseMainWindow - matrixSizeOSChanged() - - - 379 - 212 - - - 448 - 224 - - - - - numIterationsSpinBox - valueChanged(int) - radialSenseAppBaseMainWindow - numIterationsChanged() - - - 320 - 382 - - - 441 - 402 - - - - - regularizationWeightSpinBox - valueChanged(double) - radialSenseAppBaseMainWindow - regularizationWeightChanged() - - - 332 - 433 - - - 446 - 453 - - - - - windowScaleSpinBox - valueChanged(double) - radialSenseAppBaseMainWindow - windowScaleChanged(double) - - - 339 - 484 - - - 444 - 501 - - - - - - matrixSizeChanged() - matrixSizeOSChanged() - regularizationWeightChanged() - numIterationsChanged() - kernelWidthChanged() - windowScaleChanged(double) - -
diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.cpp deleted file mode 100644 index e10365595..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.cpp +++ /dev/null @@ -1,690 +0,0 @@ -#include "radialSenseAppMainWidget.h" - -#include "hoNDArray_fileio.h" -#include "cuNFFT.h" -#include "NFFT_utils.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "vector_td_operators.h" -#include "vector_td_utilities.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuCgSolver.h" -#include "b1_map.h" - -#include "UIconstants.h" -#include "GLReconWidget.h" - -#include -#include -#include -#include - -#include - -using namespace std; -using namespace Gadgetron; - -void radialSenseAppMainWindow::resetPrivateData() -{ - if( statusLabel ) delete statusLabel; - statusLabel = 0x0; - ready = false; -} - -radialSenseAppMainWindow::radialSenseAppMainWindow(QWidget *parent) : QMainWindow(parent) -{ - statusLabel = 0x0; - - setupUi(this); - retranslateUi(this); - - resetPrivateData(); - - matrixSizeSpinBox->setValue(MATRIX_SIZE_INITIAL_VALUE); - oversampledMatrixSizeSpinBox->setValue(MATRIX_SIZE_OS_INITIAL_VALUE); - numIterationsSpinBox->setValue(NUM_ITERATIONS_INITIAL_VALUE); - regularizationWeightSpinBox->setValue(REG_WEIGHT_INITIAL_VALUE); - kernelSizeSpinBox->setValue(KERNEL_SIZE_INITIAL_VALUE); - - // Menu actions - connect(actionOpen_cplx_file, SIGNAL(triggered()), this, SLOT(open())); - connect(actionSave_image, SIGNAL(triggered()), this, SLOT(saveImage())); - connect(actionClose, SIGNAL(triggered()), this, SLOT(close())); - connect(actionExit, SIGNAL(triggered()), qApp, SLOT(quit())); - - // Originally, the thought was to put multiple ReconWidgets in the app. - // This is why the SignalMapper is used rather than the basic signals below. - - // Connect to the reconWidgets' frameChanged slots - QSignalMapper *signalMapper1 = new QSignalMapper(this); - connect(reconWidget->projectionSelectionScrollBar, SIGNAL(valueChanged(int)), signalMapper1, SLOT(map())); - signalMapper1->setMapping(reconWidget->projectionSelectionScrollBar, 1 ); - connect(signalMapper1, SIGNAL(mapped(int)), this, SLOT(centralProjectionChanged(int))); - - // Connect to the reconWidgets' projectionsPerFrameChanged slots - QSignalMapper *signalMapper2 = new QSignalMapper(this); - connect(reconWidget->numProjectionsScrollBar, SIGNAL(valueChanged(int)), signalMapper2, SLOT(map())); - signalMapper2->setMapping(reconWidget->numProjectionsScrollBar, 1 ); - connect(signalMapper2, SIGNAL(mapped(int)), this, SLOT(projectionsPerFrameChanged(int))); - - // Allocate encoding operator for non-Cartesian Sense - E = boost::shared_ptr< cuNonCartesianSenseOperator >( new cuNonCartesianSenseOperator() ); - - // Allocate preconditioner - D = boost::shared_ptr< cuCgPreconditioner >( new cuCgPreconditioner() ); - - // Allocate regularization image operator - R = boost::shared_ptr< cuImageOperator >( new cuImageOperator() ); - R->set_weight( 1.0f ); - - // Setup solver - cg.set_encoding_operator( E ); // encoding matrix - cg.add_regularization_operator( R ); // regularization matrix - cg.set_preconditioner ( D ); // preconditioning matrix - cg.set_max_iterations( get_num_iterations() ); - cg.set_tc_tolerance( 1e-6 ); - cg.set_output_mode( cuCgSolver::OUTPUT_SILENT ); -} - -/* - Slots -*/ - -void radialSenseAppMainWindow::open() -{ - // Open dialog box - QString filename = QFileDialog::getOpenFileName( this, tr("Open File"), "./", tr("Raw data (*.cplx)")); - - if( filename.size() == 0 ) - return; // Cancel - - // Close current file - close(); - - // Update status bar - statusLabel = new QLabel(filename); - statusBar()->addWidget(statusLabel); - - // Read samples from disk - host_samples = read_nd_array(filename.toLatin1().constData()); - GINFO_STREAM(endl << "loaded dataset with " << host_samples->get_number_of_elements() << " samples." << endl); - - // This is to prevent the user changing the matrix sizes before any data is initially loaded - matrixSizeSpinBox->setEnabled(true); - oversampledMatrixSizeSpinBox->setEnabled(true); - - // Chose startup frame - reconWidget->projectionSelectionScrollBar->setValue(get_matrix_size().vec[0]>>2); - reconWidget->numProjectionsScrollBar->setValue(34); - - replan(); - -} - -void radialSenseAppMainWindow::saveImage() -{ /* - // Open dialog box - QString filename = QFileDialog::getSaveFileName( this, tr("Save image to file"), "./", tr("Raw float data (*.raw)")); - - if( filename.size() == 0 ) - return; // Cancel - - // This code is copied from 'reconstruct' and slightly modified... - - - - LOOP: - - // Save file - cudaMemcpy( tmp, devPtr, prod(get_matrix_size())*sizeof(float), cudaMemcpyDeviceToHost ); - fwrite( tmp, prod(get_matrix_size()), sizeof(float), fout ); - - // Report any errors not already caught... - err = cudaGetLastError(); - if( err != cudaSuccess ){ - QMessageBox::critical( this, tr("Cuda error"), tr(cudaGetErrorString(err)) ); - actionExit->trigger(); - } - - END LOOP: - - reconWidget->projectionNumberSpinBox->setValue(reconWidget->projectionNumberSpinBox->value()+20); - } - - fclose(fout); - cudaFree(devPtr); - */ -} - -void radialSenseAppMainWindow::close() -{ - resetPrivateData(); -} - -void radialSenseAppMainWindow::replan() -{ - QProgressDialog progress("Calibrating", "", 0, 4, this); - progress.setWindowModality(Qt::WindowModal); - progress.setValue(0); - progress.show(); - - // Set GUI elements before the plan is created to avoid triggering unnecessary reconstructions - unsigned int maxProjections = min(get_matrix_size().vec[0]<<2, (get_num_points_per_array_coil()/get_num_samples_per_projection())>>1); - reconWidget->numProjectionsScrollBar->setMaximum(maxProjections); - reconWidget->numProjectionsSpinBox->setMaximum(maxProjections); - unsigned int maxCentralProjection = get_maximum_central_projection(); - reconWidget->projectionSelectionScrollBar->setMaximum(maxCentralProjection); - reconWidget->projectionNumberSpinBox->setMaximum(maxCentralProjection); - unsigned int minCentralProjection = get_num_projections_per_frame()>>1; - reconWidget->projectionSelectionScrollBar->setMinimum(minCentralProjection); - reconWidget->projectionNumberSpinBox->setMinimum(minCentralProjection); - - progress.setValue(1); - - // Pass matrix size to GLReconWidget::initializeGL - // reconWidget->openglCanvas->setMatrixSize( get_matrix_size().vec[0], get_matrix_size().vec[1] ); - - progress.setValue(2); - - const unsigned int samples_per_profile = get_num_samples_per_projection(); - const unsigned int num_profiles = get_num_points_per_array_coil() / samples_per_profile; - const unsigned int profiles_per_frame = get_num_projections_per_frame(); - const unsigned int frames_per_reconstruction = NUM_FRAMES_PER_CSM_RECON; - const unsigned int profiles_per_reconstruction = get_num_projections_per_frame()*frames_per_reconstruction; - const unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - // Density compensation weights are constant throughout all reconstrutions - dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (float)get_matrix_size_os().vec[0]/(float)get_matrix_size().vec[0], - float(1)/((float)samples_per_profile/(float)max(get_matrix_size().vec[0],get_matrix_size().vec[1])) ); - - progress.setValue(3); - - // Setup plan for convolution - plan.setup( get_matrix_size(), get_matrix_size_os(), get_kernel_width() ); - - // Temporary oversampled image buffer - vector image_os_dims = uint64d_to_vector<2>(get_matrix_size_os()); - image_os_dims.push_back(frames_per_reconstruction); image_os_dims.push_back(get_num_coils()); - cuNDArray *image_os = new cuNDArray(); - image_os->create(&image_os_dims); - - // Extract coil sensitivity maps and training data using all the data - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_reconstruction; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray > traj = compute_radial_trajectory_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, iteration*profiles_per_reconstruction ); - - // Preprocess - plan.preprocess( traj.get(), cuNFFT_plan::NFFT_PREP_NC2C ); - traj.reset(); - - // Upload data - boost::shared_ptr< cuNDArray > csm_data = - upload_data( iteration*profiles_per_reconstruction, samples_per_profile, samples_per_reconstruction, - num_profiles*samples_per_profile, get_num_coils(), host_samples.get() ); - - // Accumulate k-space for CSM estimation - plan.convolve( csm_data.get(), image_os, dcw.get(), cuNFFT_plan::NFFT_CONV_NC2C, (iteration==0) ? false : true ); - csm_data.reset(); - } - - // We now have 'frames_per_reconstruction' k-space images of each coil. Add these up. - boost::shared_ptr< cuNDArray > acc_image_os = sum( image_os, 2 ); - delete image_os; image_os = 0x0; - - // Complete gridding of k-space CSM image - plan.fft( acc_image_os.get(), cuNFFT_plan::NFFT_BACKWARDS ); - plan.deapodize( acc_image_os.get() ); - - // Remove oversampling - vector image_dims = uint64d_to_vector<2>(get_matrix_size()); image_dims.push_back(get_num_coils()); - cuNDArray *image = new cuNDArray(); - image->create(&image_dims); - crop( (get_matrix_size_os()-get_matrix_size())>>1, acc_image_os.get(), image ); - acc_image_os.reset(); - - // Estimate CSM - csm = estimate_b1_map( image ); - - progress.setValue(4); - - E->setup( get_matrix_size(), get_matrix_size_os(), get_kernel_width() ); - E->set_csm(csm); - - // Setup regularization operator - image_dims = uint64d_to_vector<2>(get_matrix_size()); - cuNDArray *reg_image = new cuNDArray(); - reg_image->create( &image_dims ); - - E->mult_csm_conj_sum( image, reg_image ); - R->compute( reg_image ); - - delete image; image = 0x0; - delete reg_image; reg_image = 0x0; - - // Define preconditioning weights - update_preconditioning_weights(); - - progress.setValue(5); - - ready = true; - - // Trigger the #projections slot - reconWidget->numProjectionsScrollBar->setValue(reconWidget->numProjectionsScrollBar->value()+1); - - // Perform reconstruction - reconstruct(); -} - -void radialSenseAppMainWindow::update_preconditioning_weights() -{ - boost::shared_ptr< cuNDArray > _precon_weights = sum(abs_square(csm.get()).get(),2); - boost::shared_ptr< cuNDArray > R_diag = R->get(); - *R_diag *= get_kappa(); - *_precon_weights += *R_diag; - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray > precon_weights = real_to_complex( _precon_weights.get() ); - D->set_weights( precon_weights ); -} - -void radialSenseAppMainWindow::projectionsPerFrameChanged(int) -{ - // the integer is an 'id' not the slider value! - - unsigned int value = get_num_projections_per_frame(); - - // Enforce even values - if( value%2 ){ - value--; - reconWidget->numProjectionsScrollBar->setValue(value); - return; - } - - if(!ready) return; - - // Remove the Qt lag of the slider rendering - QApplication::processEvents(); - - // The range of the frames slider/spinbox has changed - unsigned int maxCentralProjection = get_maximum_central_projection(); - reconWidget->projectionSelectionScrollBar->setMaximum(maxCentralProjection); - reconWidget->projectionNumberSpinBox->setMaximum(maxCentralProjection); - reconWidget->projectionSelectionScrollBar->setSingleStep(value>>2); - reconWidget->projectionNumberSpinBox->setSingleStep(value>>2); - - const unsigned int samples_per_profile = get_num_samples_per_projection(); - const unsigned int profiles_per_frame = get_num_projections_per_frame(); - - // Density compensation weights are constant throughout all reconstrutions - dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (float)get_matrix_size_os().vec[0]/(float)get_matrix_size().vec[0], - float(1)/((float)samples_per_profile/(float)max(get_matrix_size().vec[0],get_matrix_size().vec[1])) ); - - // Set density compensation weights - E->set_dcw(dcw); - - // Reconstruct - reconstruct(); -} - -void radialSenseAppMainWindow::centralProjectionChanged(int id) -{ - // the integer is an 'id' not the slider value! - - // Enforce even values - unsigned int value = get_central_projection(); - if( value%2 ){ - value--; - reconWidget->projectionSelectionScrollBar->setValue(value); - return; - } - - if(!ready) return; - - // Remove the lag of the slider rendering - QApplication::processEvents(); - - // Perform reconstruction - reconstruct(); -} - -void radialSenseAppMainWindow::matrixSizeChanged() -{ - static unsigned int lastValue = MATRIX_SIZE_INITIAL_VALUE; - - unsigned int value = matrixSizeSpinBox->value(); - unsigned int value_os = oversampledMatrixSizeSpinBox->value(); - - if( value == lastValue ) - return; - else - lastValue = value; - - if(!ready) return; - - // Pass matrix size to GLReconWidget - reconWidget->openglCanvas->setMatrixSize( value, value ); - - if( value_os < value ){ - oversampledMatrixSizeSpinBox->setValue(value); - } - - // and encoding matrix - E->setup( get_matrix_size(), get_matrix_size_os(), get_kernel_width() ); - - replan(); -} - -void radialSenseAppMainWindow::matrixSizeOSChanged() -{ - static unsigned int lastValue = MATRIX_SIZE_OS_INITIAL_VALUE; - - unsigned int value = matrixSizeSpinBox->value(); - unsigned int value_os = oversampledMatrixSizeSpinBox->value(); - - if( value_os == lastValue ) - return; - else - lastValue = value_os; - - if( value_os < value ){ - oversampledMatrixSizeSpinBox->setValue(value); - return; - } - - if( value_os%2 ){ - value_os++; - oversampledMatrixSizeSpinBox->setValue(value_os); - return; - } - - if(!ready) return; - - E->setup( get_matrix_size(), get_matrix_size_os(), get_kernel_width() ); - - reconstruct(); -} - -void radialSenseAppMainWindow::kernelWidthChanged() -{ - static double lastValue = KERNEL_SIZE_INITIAL_VALUE; - - double value = kernelSizeSpinBox->value(); - - if( value == lastValue ) - return; - else - lastValue = value; - - if(!ready) return; - - E->setup( get_matrix_size(), get_matrix_size_os(), get_kernel_width() ); - - reconstruct(); -} - -void radialSenseAppMainWindow::numIterationsChanged() -{ - static unsigned int lastValue = NUM_ITERATIONS_INITIAL_VALUE; - - unsigned int value = numIterationsSpinBox->value(); - - if( value == lastValue ) - return; - else - lastValue = value; - - cg.set_max_iterations( get_num_iterations() ); - - if(!ready) return; - - reconstruct(); -} - -void radialSenseAppMainWindow::regularizationWeightChanged() -{ - static double lastValue = REG_WEIGHT_INITIAL_VALUE; - - double value = regularizationWeightSpinBox->value(); - - if( value == lastValue ) - return; - else - lastValue = value; - - // Update D - update_preconditioning_weights(); - - // Update operator R - R->set_weight( get_kappa() ); - - if(!ready) return; - - reconstruct(); -} - -void radialSenseAppMainWindow::windowScaleChanged(double) -{ - if(!ready) return; - reconstruct(); -} - -/* - Reconstruct frame -*/ - -void radialSenseAppMainWindow::reconstruct() -{ - if(!ready) return; - - // Check if any data has been loaded - if( host_samples->get_number_of_elements() == 0 ) - return; - - // See if there is any uncaught errors before starting - cudaError_t err; - err = cudaGetLastError(); - if( err != cudaSuccess ){ - QMessageBox::critical( this, tr("Cuda error"), tr(cudaGetErrorString(err)) ); - actionExit->trigger(); - } - - // Map result to OpenGL - reconWidget->openglCanvas->mapPBO(); - - // Be optimistic... - bool success = true; - - const unsigned int samples_per_profile = get_num_samples_per_projection(); - const unsigned int num_profiles = get_num_points_per_array_coil() / samples_per_profile; - const unsigned int profiles_per_frame = get_num_projections_per_frame(); - const unsigned int frames_per_reconstruction = 1; - const unsigned int profiles_per_reconstruction = get_num_projections_per_frame()*frames_per_reconstruction; - const uint64d2 matrix_size = get_matrix_size(); - const uint64d2 matrix_size_os = get_matrix_size_os(); - const unsigned int num_coils = get_num_coils(); - const unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - // Determine trajectories - boost::shared_ptr< cuNDArray > traj = compute_radial_trajectory_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, get_first_projection() ); - - // Upload data - boost::shared_ptr< cuNDArray > data = - upload_data( get_first_projection(), samples_per_profile, samples_per_reconstruction, - num_profiles*samples_per_profile, num_coils, host_samples.get() ); - - // Set current trajectory and trigger NFFT preprocessing - E->preprocess(traj.get()); - - // Form rhs (use result array to save memory) - vector rhs_dims = uint64d_to_vector<2>(matrix_size); rhs_dims.push_back(frames_per_reconstruction); - cuNDArray rhs; rhs.create(&rhs_dims); - E->mult_MH( data.get(), &rhs ); - - // - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray > cgresult = cg.solve_from_rhs(&rhs); - - // Magnitudes image for visualization - boost::shared_ptr< cuNDArray > tmp_res = abs(cgresult.get()); - normalize( tmp_res.get(), get_window_scale() ); - - // Copy to OpenGL/pbo - cudaMemcpy( reconWidget->openglCanvas->getDevPtr(), - tmp_res->get_data_ptr(), - prod(matrix_size)*sizeof(float), cudaMemcpyDeviceToDevice ); - - // Report any errors not already caught... - err = cudaGetLastError(); - if( err != cudaSuccess ){ - QMessageBox::critical( this, tr("Cuda error"), tr(cudaGetErrorString(err)) ); - actionExit->trigger(); - } - - reconWidget->openglCanvas->unmapPBO(); - - if( !success ){ - QMessageBox::critical( this, tr("Reconstruction error"), tr("Check console. Quitting.") ); - actionExit->trigger(); - exit(EXIT_FAILURE); - } - - reconWidget->openglCanvas->updateGL(); -} - -/* - "Gets..." -*/ - -uint64d2 radialSenseAppMainWindow::get_matrix_size() -{ - int value = matrixSizeSpinBox->value(); - return uint64d2( value, value ); -} - -uint64d2 radialSenseAppMainWindow::get_matrix_size_os() -{ - int value = oversampledMatrixSizeSpinBox->value(); - return uint64d2( value, value ); -} - -float radialSenseAppMainWindow::get_kernel_width() -{ - double value = kernelSizeSpinBox->value(); - return (float) value; -} - -float radialSenseAppMainWindow::get_window_scale() -{ - double value = windowScaleSpinBox->value(); - return (float) value; -} - -unsigned int radialSenseAppMainWindow::get_num_samples_per_projection() -{ - if( host_samples->get_number_of_dimensions() > 0 ) - return host_samples->get_size(0); - else return 0; -} - -unsigned int radialSenseAppMainWindow::get_first_projection() -{ - int value = reconWidget->projectionNumberSpinBox->value(); - value -= get_num_projections_per_frame()>>1; - if( value<0 ) - value = 0; - return value; -} - -unsigned int radialSenseAppMainWindow::get_central_projection() -{ - int value = reconWidget->projectionSelectionScrollBar->value(); - return value; -} - -unsigned int radialSenseAppMainWindow::get_maximum_central_projection() -{ - if( get_num_samples_per_projection() == 0 ) - return 0; - - unsigned int maxCentralProjection = get_num_points_per_array_coil()/get_num_samples_per_projection()-get_num_projections_per_frame()/2-get_num_projections_per_frame()%2; - return maxCentralProjection; -} - -unsigned int radialSenseAppMainWindow::get_num_projections_per_frame() -{ - int value = reconWidget->numProjectionsSpinBox->value(); - return value; -} - -unsigned int radialSenseAppMainWindow::get_num_coils() -{ - if( host_samples->get_number_of_dimensions() < 3 ) - return 0; - - unsigned int val; - if( host_samples->get_number_of_dimensions() == 3 ) - val = host_samples->get_size(2); - else{ - printf("\nUnknown number of dimensions in dataset. Quitting.\n"); - exit(1); - } - - return val; -} - -unsigned int radialSenseAppMainWindow::get_num_points_per_reconstruction() -{ - unsigned int val = get_num_samples_per_projection()*get_num_projections_per_frame(); - return val; -} - -hoNDArray >* radialSenseAppMainWindow::get_sample_values_array() -{ - return host_samples.get(); -} - -unsigned int radialSenseAppMainWindow::get_num_points_per_array_coil() -{ - if(host_samples->get_number_of_dimensions()<2) - return 0; - - unsigned int val = host_samples->get_size(0)*host_samples->get_size(1); - return val; -} - -unsigned int radialSenseAppMainWindow::get_num_iterations() -{ - int value = numIterationsSpinBox->value(); - return value; -} - -inline float radialSenseAppMainWindow::get_kappa() -{ - double value = regularizationWeightSpinBox->value(); - return (float)value; -} - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray > -radialSenseAppMainWindow::upload_data( unsigned int profile_offset, unsigned int samples_per_profile, unsigned int samples_per_reconstruction, - unsigned int total_samples_per_coil, unsigned int num_coils, - hoNDArray *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray *data = new cuNDArray(); - data->create( &dims ); - - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+profile_offset*samples_per_profile, - samples_per_reconstruction*sizeof(float_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray >(data); -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.h b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.h deleted file mode 100644 index cff022942..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/radialSenseAppMainWidget.h +++ /dev/null @@ -1,134 +0,0 @@ -#pragma once - -// Gadgetron includes -#include "vector_td.h" -#include "vector_td_utilities.h" -#include "hoNDArray.h" -#include "cuNDArray.h" -#include "cuNFFT.h" -#include "cuCgSolver.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuImageOperator.h" -#include "cuCgPreconditioner.h" -#include "complext.h" - -#include - -// Autogenerated header by uic -#include "ui_radialSenseAppBaseMainWidget.h" - -using namespace Gadgetron; // only because this header file is not distributed... - -class radialSenseAppMainWindow : public QMainWindow, public Ui::radialSenseAppBaseMainWindow -{ - // Macro for the Qt gui - Q_OBJECT - - public: - - // Constructor - radialSenseAppMainWindow(QWidget *parent = 0); - - // Reconstruct frame - void reconstruct(); - - // Get matrix size - inline uint64d2 get_matrix_size(); - - // Get oversampled matrix size - inline uint64d2 get_matrix_size_os(); - - // Get number of coils - inline unsigned int get_num_coils(); - - // Get kernel width - inline float get_kernel_width(); - - // Get kappa (regularization weight) - inline float get_kappa(); - - // Get first projection - inline unsigned int get_first_projection(); - - // Get central projection - inline unsigned int get_central_projection(); - - // Get maximum central projection - inline unsigned int get_maximum_central_projection(); - - // Get number of projections per frame - inline unsigned int get_num_projections_per_frame(); - - // Number of samples per projection - inline unsigned int get_num_samples_per_projection(); - - // Number of points per reconstruction - inline unsigned int get_num_points_per_reconstruction(); - - // Get host side sample data array - inline hoNDArray >* get_sample_values_array(); - - // Get number of points per coil in data array - unsigned int get_num_points_per_array_coil(); - - // Get number of iterations - unsigned int get_num_iterations(); - - // Get window scale - float get_window_scale(); - - boost::shared_ptr< cuNDArray > - upload_data( unsigned int profile_offset, unsigned int samples_per_profile, unsigned int samples_per_reconstruction, - unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray *host_data ); - -private: - void resetPrivateData(); - void replan(); - void update_preconditioning_weights(); - -private slots: - void open(); - void close(); - void saveImage(); - void matrixSizeChanged(); - void matrixSizeOSChanged(); - void regularizationWeightChanged(); - void projectionsPerFrameChanged(int); - void centralProjectionChanged(int); - void numIterationsChanged(); - void kernelWidthChanged(); - void windowScaleChanged(double); - -private: - - // Reconstruction plan - cuNFFT_plan plan; - - // Define conjugate gradient solver - cuCgSolver cg; - - // Define non-Cartesian Sense solver - boost::shared_ptr< cuNonCartesianSenseOperator > E; - - // Define preconditioner - boost::shared_ptr< cuCgPreconditioner > D; - - // Define regularization image operator - boost::shared_ptr< cuImageOperator > R; - - // CSM - boost::shared_ptr< cuNDArray > csm; - - // Density compensation weights - boost::shared_ptr< cuNDArray > dcw; - - // Host data array - boost::shared_ptr< hoNDArray > host_samples; - - // Label for the status bar - QLabel *statusLabel; - - // Are we set up for reconstruction? - bool ready; -}; - diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconBaseWidget.ui b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconBaseWidget.ui deleted file mode 100644 index ad032260d..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconBaseWidget.ui +++ /dev/null @@ -1,303 +0,0 @@ - - - ReconBaseWidget - - - - 0 - 0 - 272 - 414 - - - - - 0 - 0 - - - - - 272 - 414 - - - - ReconBaseWidget - - - - - - - - 0 - 0 - 272 - 381 - - - - QFrame::Box - - - QFrame::Plain - - - - - 8 - 8 - 256 - 256 - - - - - 0 - 0 - - - - - 256 - 256 - - - - - - - - - - 8 - 290 - 176 - 16 - - - - - 0 - 0 - - - - 100 - - - 2 - - - Qt::Horizontal - - - - - - 8 - 270 - 140 - 16 - - - - - 0 - 0 - - - - Central projection - - - - - - 8 - 320 - 160 - 16 - - - - - 0 - 0 - - - - Number of projections per frame - - - - - - 8 - 340 - 186 - 16 - - - - - 0 - 0 - - - - 4 - - - 100 - - - 2 - - - 32 - - - Qt::Horizontal - - - - - - 191 - 287 - 71 - 22 - - - - - 0 - 0 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 100 - - - 2 - - - - - - 201 - 337 - 61 - 22 - - - - - 0 - 0 - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - 4 - - - 100 - - - 2 - - - 32 - - - - - - - GLReconWidget - QWidget -
GLReconWidget.h
- 1 -
-
- - - - projectionNumberSpinBox - valueChanged(int) - projectionSelectionScrollBar - setValue(int) - - - 235 - 298 - - - 162 - 298 - - - - - numProjectionsSpinBox - valueChanged(int) - numProjectionsScrollBar - setValue(int) - - - 231 - 351 - - - 180 - 353 - - - - - projectionSelectionScrollBar - valueChanged(int) - projectionNumberSpinBox - setValue(int) - - - 124 - 297 - - - 234 - 294 - - - - - numProjectionsScrollBar - valueChanged(int) - numProjectionsSpinBox - setValue(int) - - - 102 - 340 - - - 253 - 348 - - - - - - animationSpeedChanged(int) - projectionsPerFrameChanged(int) - frameChanged(int) - -
diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.cpp deleted file mode 100644 index e6ea6cca9..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.cpp +++ /dev/null @@ -1,7 +0,0 @@ -#include "reconWidget.h" - -ReconWidget::ReconWidget(QWidget *parent) : QWidget(parent) -{ - setupUi(this); - retranslateUi(this); -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.h b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.h deleted file mode 100644 index 585c9541c..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_gui/reconWidget.h +++ /dev/null @@ -1,13 +0,0 @@ -#pragma once - -// Autogenerated header by uic -#include "ui_reconBaseWidget.h" - -class ReconWidget : public QWidget, public Ui::ReconBaseWidget -{ - Q_OBJECT - - public: - // Constructor - ReconWidget(QWidget* parent = 0); -}; diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/CMakeLists.txt b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/CMakeLists.txt deleted file mode 100644 index 596eab4a2..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/CMakeLists.txt +++ /dev/null @@ -1,5 +0,0 @@ -add_executable(ktsense_radial_2d main.cpp) - -target_link_libraries(ktsense_radial_2d gadgetron_toolbox_gpu gadgetron_toolbox_hostutils ${CUDA_LIBRARIES}) - -install(TARGETS ktsense_radial_2d DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/main.cpp b/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/main.cpp deleted file mode 100644 index 3e28bf588..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/2d_golden_ratio_kt/main.cpp +++ /dev/null @@ -1,323 +0,0 @@ -// Gadgetron includes -#include "hoNDArray_fileio.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "vector_td_utilities.h" -#include "radial_utilities.h" -#include "cuNonCartesianKtSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuImageOperator.h" -#include "cuCgPreconditioner.h" -#include "cuCgSolver.h" -#include "cuNDFFT.h" -#include "b1_map.h" -#include "parameterparser.h" -#include "GPUTimer.h" - -// Std includes -#include -#include - -using namespace std; -using namespace Gadgetron; - -// Define desired precision -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -// Upload samples for one reconstruction from host to device -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, - hoNDArray<_complext> *host_data ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "Sample data file name", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "result.cplx" ); - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true ); - parms.add_parameter( 'f', COMMAND_LINE_INT, 1, "Frames per reconstruction", true, "32" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "25" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'K', COMMAND_LINE_FLOAT, 1, "Kappa", true, "0.25" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running reconstruction with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer; - - // Load sample data from disk - timer = new GPUTimer("\nLoading data"); - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - delete timer; - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!\n" << endl); - return 1; - } - - // Configuration from the host data - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - _real kappa = parms.get_parameter('K')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = parms.get_parameter('f')->get_int_value(); - - // Silent correction of invalid command line parameters (clamp to valid range) - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - GINFO_STREAM(endl << "#samples/profile: " << samples_per_profile); - GINFO_STREAM(endl << "#profiles/frame: " << profiles_per_frame); - GINFO_STREAM(endl << "#profiles: " << num_profiles); - GINFO_STREAM(endl << "#coils: " << num_coils); - GINFO_STREAM(endl << "#frames/reconstruction " << frames_per_reconstruction); - GINFO_STREAM(endl << "#profiles/reconstruction " << profiles_per_reconstruction); - GINFO_STREAM(endl << "#samples/reconstruction " << samples_per_reconstruction << endl << endl); - - // Density compensation weights are constant throughout all reconstrutions - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os[0]/(_real)matrix_size[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size[0],matrix_size[1])) ); - - // Define encoding matrix for non-Cartesian kt-SENSE - boost::shared_ptr< cuNonCartesianKtSenseOperator<_real,2> > E( new cuNonCartesianKtSenseOperator<_real,2>() ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - - // Notify encoding operator of dcw - E->set_dcw(dcw); - - // Use a rhs buffer to estimate the csm -- from all the data - // - - unsigned int profiles_per_subcycle = matrix_size_os[0]<<1; // causes no aliasing - unsigned int num_subcycles = profiles_per_subcycle / profiles_per_frame; - unsigned int num_cycles = num_profiles / profiles_per_subcycle; - - GDEBUG_STREAM("Buffer cycles/sybcycles: " << num_cycles << " / " << num_subcycles << std::endl); - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer( new cuSenseBuffer<_real,2>() ); - - // The first acquired profiles are often undesired. Skip the first two cycles... - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, num_cycles-1, num_subcycles ); - rhs_buffer->set_dcw(dcw); - - // Fill rhs buffer - // - - timer = new GPUTimer("CSM estimation"); - - // Go through all the data... - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_reconstruction ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - auto csm = boost::make_shared>(estimate_b1_map<_real,2>( *acc_images.get())); - - E->set_csm(csm); - - acc_images.reset(); - rhs_buffer.reset(); - - delete timer; - - // - // Setup radial kt-SENSE reconstructions - // - - // Define regularization image operator - boost::shared_ptr< cuImageOperator<_complext> > R( new cuImageOperator<_complext>() ); - R->set_weight( kappa ); - - // Define preconditioning operator - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - boost::shared_ptr< cuNDArray<_real> > ___precon_weights = sum(abs_square(csm.get()).get(),2); - boost::shared_ptr< cuNDArray<_real> > __precon_weights = boost::make_shared>(expand<_real>( *___precon_weights, frames_per_reconstruction )); - ___precon_weights.reset(); - - // Setup conjugate gradient solver - cuCgSolver< _complext> cg; - cg.set_encoding_operator( E ); // encoding matrix - cg.add_regularization_operator( R ); // regularization matrix - cg.set_preconditioner ( D ); // preconditioning matrix - cg.set_max_iterations( num_iterations ); - cg.set_tc_tolerance( 1e-6 ); - cg.set_output_mode( cuCgSolver< _complext>::OUTPUT_VERBOSE ); - - // Reconstruct all SENSE frames iteratively - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - - // Allocate space for result - vector image_dims = to_std_vector(matrix_size); - image_dims.push_back(frames_per_reconstruction*num_reconstructions); - - cuNDArray<_complext> result = cuNDArray<_complext>(image_dims); - - // Define shutter for training data - _real shutter_radius = ((_real)matrix_size_os[0]/(_real)matrix_size[0])*(_real)profiles_per_frame/(_real)M_PI; - shutter_radius /= _real(2); - GDEBUG_STREAM("Shutter radius: " << shutter_radius << std::endl); - - vector image_os_dims = to_std_vector(matrix_size_os); - image_os_dims.push_back(frames_per_reconstruction); image_os_dims.push_back(num_coils); - cuNDArray<_complext> *image_os = new cuNDArray<_complext>(image_os_dims); - - timer = new GPUTimer("Full SENSE reconstruction."); - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, reconstruction*profiles_per_reconstruction ); - - // Preprocess - image_dims.pop_back(); image_dims.push_back(frames_per_reconstruction); - E->set_domain_dimensions(image_dims); - E->preprocess( traj.get() ); - - // Upload data - - boost::shared_ptr > data = upload_data - (reconstruction, samples_per_reconstruction, num_profiles * samples_per_profile, num_coils, - host_data.get()); - - E->set_codomain_dimensions(data->get_dimensions()); - - { - auto data_view = data; - // Convolve to Cartesian k-space - if (dcw) { - data_view = boost::make_shared>(*data); - *data_view *= *dcw; - } - E->get_plan()->convolve(*data_view, *image_os, NFFT_conv_mode::NC2C); - } - - // Apply shutter - fill_border<_complext,2>( shutter_radius, *image_os ); - - E->get_plan()->fft( *image_os, NFFT_fft_mode::BACKWARDS ); - E->get_plan()->deapodize( *image_os ); - - // Remove oversampling - image_dims.push_back(num_coils); - cuNDArray<_complext> *image = new cuNDArray<_complext>(image_dims); - crop<_complext,2>( (matrix_size_os-matrix_size)>>1, matrix_size, *image_os, *image ); - image_dims.pop_back(); - - // Compute regularization image - cuNDArray<_complext> *reg_image = new cuNDArray<_complext>(image_dims); - - E->mult_csm_conj_sum( image, reg_image ); - cuNDFFT<_real>::instance()->ifft( reg_image, 2, true ); - - - R->compute( reg_image ); - - delete reg_image; reg_image = 0x0; - delete image; image = 0x0; - - // Define preconditioning weights - boost::shared_ptr< cuNDArray<_real> > _precon_weights( new cuNDArray<_real>(*__precon_weights.get())); - boost::shared_ptr< cuNDArray<_real> > R_diag = R->get(); - *R_diag *= kappa; - *_precon_weights += *R_diag; - R_diag.reset(); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - D->set_weights( precon_weights ); - precon_weights.reset(); - - // - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult; - { - GPUTimer timer("GPU Conjugate Gradient solve"); - cgresult = cg.solve(data.get()); - } - - // Goto from x-f to x-t space - cuNDFFT<_real>::instance()->fft( cgresult.get(), 2 ,true); - - // Copy cgresult to result - cuNDArray<_complext> tmp(image_dims, result.get_data_ptr()+reconstruction*prod(matrix_size)*frames_per_reconstruction); - tmp = *(cgresult.get()); - } - - delete timer; - delete image_os; image_os = 0x0; - csm.reset(); - - // All done, write out the result - - timer = new GPUTimer("Writing out result"); - - boost::shared_ptr< hoNDArray<_complext> > host_result = result.to_host(); - write_nd_array<_complext>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_norm = abs(&result)->to_host(); - write_nd_array<_real>( host_norm.get(), "result.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/mri/sense/noncartesian/radial/CMakeLists.txt b/apps/standalone/gpu/mri/sense/noncartesian/radial/CMakeLists.txt deleted file mode 100644 index 5767e0a8c..000000000 --- a/apps/standalone/gpu/mri/sense/noncartesian/radial/CMakeLists.txt +++ /dev/null @@ -1,10 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/pmri/gpu -) - -add_subdirectory(2d_golden_ratio) -add_subdirectory(2d_golden_ratio_kt) - -#if (QT4_FOUND AND GLEW_FOUND AND GLUT_FOUND AND OPENGL_FOUND) -# add_subdirectory(2d_golden_ratio_gui) -#endif () diff --git a/apps/standalone/gpu/registration/2d/CMakeLists.txt b/apps/standalone/gpu/registration/2d/CMakeLists.txt deleted file mode 100644 index 98987ac08..000000000 --- a/apps/standalone/gpu/registration/2d/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -add_executable(register_HS_2d_gpu register_HS_2d.cpp) -add_executable(register_CGHS_2d_gpu register_CGHS_2d.cpp) -add_executable(register_CK_2d_gpu register_CK_2d.cpp) -#add_executable(test_reg_sense_recon test_reg_sense_recon.cpp) - -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/mri/pmri/gpu -) - -target_link_libraries(register_HS_2d_gpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_gpu - ${CUDA_LIBRARIES} - ) - -target_link_libraries(register_CK_2d_gpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_gpu - ${CUDA_LIBRARIES} - ) - -#target_link_libraries(test_reg_sense_recon -# hostutils -# gpureg -# gpucore -# gpuoperators -# gpusolvers -# gpunfft -# gpuparallelmri -# ${CUDA_LIBRARIES} -# ) - - target_link_libraries(register_CGHS_2d_gpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_gpu - ${CUDA_LIBRARIES} - ) - -install(TARGETS - register_HS_2d_gpu - register_CGHS_2d_gpu - register_CK_2d_gpu - DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/registration/2d/register_CGHS_2d.cpp b/apps/standalone/gpu/registration/2d/register_CGHS_2d.cpp deleted file mode 100644 index 881a37727..000000000 --- a/apps/standalone/gpu/registration/2d/register_CGHS_2d.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - An example of how to register two 2d images using Horn-Schunk optical flow -*/ - -// Gadgetron includes -#include "cuHSOpticalFlowSolver.h" -#include "cuLinearResampleOperator.h" -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "hoNDArray_utils.h" -#include "parameterparser.h" -#include "cuCGHSOFSolver.h" -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.1" ); - parms.add_parameter( 'l', COMMAND_LINE_INT, 1, "Number of multiresolution levels", true, "3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > host_fixed = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_moving = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !host_fixed.get() || !host_moving.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - unsigned int num_fixed_dims = host_fixed->get_number_of_dimensions(); - unsigned int num_moving_dims = host_moving->get_number_of_dimensions(); - - if( !(num_fixed_dims == 2 || num_fixed_dims == 3) ){ - GINFO_STREAM(endl << "The fixed image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 2 || num_moving_dims == 3) ){ - GINFO_STREAM(endl << "The moving image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( num_fixed_dims < num_moving_dims ){ - *host_fixed = expand( *host_fixed, host_moving->get_size(2) ); - num_fixed_dims = host_fixed->get_number_of_dimensions(); - } - - if( num_moving_dims < num_moving_dims ){ - *host_moving = expand( *host_moving, host_fixed->get_size(2) ); - num_moving_dims = host_moving->get_number_of_dimensions(); - } - - // Upload host data to device - // - - cuNDArray<_real> fixed_image(*host_fixed); - cuNDArray<_real> moving_image(*host_moving); - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - - unsigned int multires_levels = parms.get_parameter('l')->get_int_value(); - - // Use bilinear interpolation for resampling - // - - boost::shared_ptr< cuLinearResampleOperator<_real,2> > R( new cuLinearResampleOperator<_real,2>() ); - - // Setup solver - // - - cuCGHSOFSolver<_real,2> HS; - HS.set_interpolator( R ); - HS.set_output_mode( cuCGHSOFSolver<_real,2>::OUTPUT_VERBOSE ); - HS.get_solver()->set_max_iterations( 100 ); - HS.get_solver()->set_output_mode(cuCgSolver<_real>::OUTPUT_VERBOSE); - HS.set_num_multires_levels( multires_levels ); - HS.set_alpha(alpha); - - - // Run registration - // - - boost::shared_ptr< cuNDArray<_real> > result = HS.solve( &fixed_image, &moving_image ); - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< cuNDArray<_real> > deformed_moving = HS.deform( &moving_image, result ); - - // All done, write out the result - // - - boost::shared_ptr< hoNDArray<_real> > host_result = result->to_host(); - write_nd_array<_real>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - host_result = deformed_moving->to_host(); - write_nd_array<_real>(host_result.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/registration/2d/register_CK_2d.cpp b/apps/standalone/gpu/registration/2d/register_CK_2d.cpp deleted file mode 100644 index 533beaec2..000000000 --- a/apps/standalone/gpu/registration/2d/register_CK_2d.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - An example of how to register two 2d images using Cornelius-Kanade optical flow -*/ - -// Gadgetron includes -#include "cuCKOpticalFlowSolver.h" -#include "cuLinearResampleOperator.h" -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" -#include "GadgetronTimer.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.05" ); - parms.add_parameter( 'b', COMMAND_LINE_FLOAT, 1, "Regularization weight (beta)", true, "1.0" ); - parms.add_parameter( 'l', COMMAND_LINE_INT, 1, "Number of multiresolution levels", true, "3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > host_fixed = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_moving = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !host_fixed.get() || !host_moving.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - unsigned int num_fixed_dims = host_fixed->get_number_of_dimensions(); - unsigned int num_moving_dims = host_moving->get_number_of_dimensions(); - - if( !(num_fixed_dims == 2 || num_fixed_dims == 3) ){ - GINFO_STREAM(endl << "The fixed image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 2 || num_moving_dims == 3) ){ - GINFO_STREAM(endl << "The moving image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - // - - cuNDArray<_real> fixed_image(*host_fixed); - cuNDArray<_real> moving_image(*host_moving); - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - _real beta = (_real) parms.get_parameter('b')->get_float_value(); - - unsigned int multires_levels = parms.get_parameter('l')->get_int_value(); - - // Use bilinear interpolation for resampling - // - - boost::shared_ptr< cuLinearResampleOperator<_real,2> > R( new cuLinearResampleOperator<_real,2>() ); - - // Setup solver - // - - cuCKOpticalFlowSolver<_real,2> CK; - CK.set_interpolator( R ); - CK.set_output_mode( cuCKOpticalFlowSolver<_real,2>::OUTPUT_VERBOSE ); - CK.set_max_num_iterations_per_level( 500 ); - CK.set_num_multires_levels( multires_levels ); - CK.set_alpha(alpha); - CK.set_beta(beta); - CK.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< cuNDArray<_real> > result; - { - GadgetronTimer timer("Running registration"); - result = CK.solve( &fixed_image, &moving_image ); - } - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< cuNDArray<_real> > deformed_moving = CK.deform( &moving_image, result ); - - // All done, write out the result - // - - boost::shared_ptr< hoNDArray<_real> > host_result = result->to_host(); - write_nd_array<_real>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - host_result = deformed_moving->to_host(); - write_nd_array<_real>(host_result.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/registration/2d/register_HS_2d.cpp b/apps/standalone/gpu/registration/2d/register_HS_2d.cpp deleted file mode 100644 index 776661f21..000000000 --- a/apps/standalone/gpu/registration/2d/register_HS_2d.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/* - An example of how to register two 2d images using Horn-Schunk optical flow -*/ - -// Gadgetron includes -#include "cuHSOpticalFlowSolver.h" -#include "cuLinearResampleOperator.h" -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.1" ); - parms.add_parameter( 'l', COMMAND_LINE_INT, 1, "Number of multiresolution levels", true, "3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > host_fixed = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_moving = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !host_fixed.get() || !host_moving.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - unsigned int num_fixed_dims = host_fixed->get_number_of_dimensions(); - unsigned int num_moving_dims = host_moving->get_number_of_dimensions(); - - if( !(num_fixed_dims == 2 || num_fixed_dims == 3) ){ - GINFO_STREAM(endl << "The fixed image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 2 || num_moving_dims == 3) ){ - GINFO_STREAM(endl << "The moving image is not two- or three-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - // - - cuNDArray<_real> fixed_image(*host_fixed); - cuNDArray<_real> moving_image(*host_moving); - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - - unsigned int multires_levels = parms.get_parameter('l')->get_int_value(); - - // Use bilinear interpolation for resampling - // - - boost::shared_ptr< cuLinearResampleOperator<_real,2> > R( new cuLinearResampleOperator<_real,2>() ); - - // Setup solver - // - - cuHSOpticalFlowSolver<_real,2> HS; - HS.set_interpolator( R ); - HS.set_output_mode( cuHSOpticalFlowSolver<_real,2>::OUTPUT_VERBOSE ); - HS.set_max_num_iterations_per_level( 500 ); - HS.set_num_multires_levels( multires_levels ); - HS.set_alpha(alpha); - HS.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< cuNDArray<_real> > result = HS.solve( &fixed_image, &moving_image ); - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< cuNDArray<_real> > deformed_moving = HS.deform( &moving_image, result ); - - // All done, write out the result - // - - boost::shared_ptr< hoNDArray<_real> > host_result = result->to_host(); - write_nd_array<_real>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - host_result = deformed_moving->to_host(); - write_nd_array<_real>(host_result.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/registration/2d/test_reg_sense_recon.cpp b/apps/standalone/gpu/registration/2d/test_reg_sense_recon.cpp deleted file mode 100644 index 9d9e0556e..000000000 --- a/apps/standalone/gpu/registration/2d/test_reg_sense_recon.cpp +++ /dev/null @@ -1,568 +0,0 @@ -#define PAD_Z - -/* - - This is an example of how to use optical flow image registration - and the image resampling operator for image reconstruction. - - This example uses golden ratio Sense MRI for demonstration. - It was tested with a free-breathing cardiac acquisition. - - !!! Note !!! - ------------ - No cardiac phase binning is performed. - And since the registration has trouble handling large, - non-rigid deformations such as the heart contraction - it serves only for demonstration purposes. - - An actual application should bin the cardiac phases and use the - registration to correct for respiratory motion only. -*/ - -#include "cuCKOpticalFlowSolver.h" -#include "cuLinearResampleOperator.h" -#include "cuNDArray.h" -#include "cuNDArray_elemwise.h" -#include "cuNDArray_operators.h" -#include "cuNDArray_utils.h" -#include "cuNDArray_reductions.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" -#include "radial_utilities.h" -#include "cuNonCartesianSenseOperator.h" -#include "cuSenseBuffer.h" -#include "cuImageOperator.h" -#include "cuCgPreconditioner.h" -#include "cuCgSolver.h" -#include "b1_map.h" -#include "GPUTimer.h" - -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -// - -typedef float _real; -typedef complext<_real> _complext; -typedef reald<_real,2>::Type _reald2; - -// -// Define matrix operator for "registration reconstruction" using non-Cartesian Sense -// For simplicity we assume that the respective operators have been setup from outside -// - -template class registrationReconOperator - : public linearOperator< cuNDArray< complext > > -{ -public: - - registrationReconOperator() : linearOperator< cuNDArray< complext< REAL> > >() {} - virtual ~registrationReconOperator() {} - - inline void set_encoding_operator( boost::shared_ptr< cuNonCartesianSenseOperator > E ){ - E_ = E; - } - - inline void set_resampling_operator( boost::shared_ptr< cuLinearResampleOperator,D> > R ){ - R_ = R; - } - - virtual void mult_M( cuNDArray< complext > *in, cuNDArray< complext > *out, bool accumulate = false) - { - if( !in || !out || !R_->get_displacement_field() ){ - throw cuda_error("registrationReconOperator::mult_M failed (1)"); - } - - // Allocate intermediate image - std::vector tmp_dims = R_->get_displacement_field()->get_dimensions(); tmp_dims.pop_back(); - cuNDArray< complext > tmp_in_out; - - tmp_in_out.create(&tmp_dims); - - // Deform the input image into multiple frames by applying the registration vector field - R_->mult_M( in, &tmp_in_out ); - - // Apply non-Cartesian Sense encoding - E_->mult_M( &tmp_in_out, out ); - } - - virtual void mult_MH( cuNDArray< complext > *in, cuNDArray< complext > *out, bool accumulate = false ) - { - if( !in || !out || !R_->is_preprocessed() ){ - throw cuda_error("registrationReconOperator::mult_MH failed (1)"); - } - - // Allocate intermediate image - std::vector tmp_dims = R_->get_displacement_field()->get_dimensions(); tmp_dims.pop_back(); - cuNDArray< complext > tmp_in_out(&tmp_dims); - - // Apply adjoint non-Cartesian Sense encoding - E_->mult_MH( in, &tmp_in_out); - - // Apply adjoint registration - R_->mult_MH( &tmp_in_out, out ); - } - - virtual void mult_MH_M( cuNDArray< complext > *in, cuNDArray< complext > *out, bool accumulate = false ) - { - if( !in || !out || !R_->get_displacement_field() ){ - throw cuda_error("registrationReconOperator::mult_MH_M failed (1)"); - } - - // Allocate intermediate image - std::vector tmp_dims = R_->get_displacement_field()->get_dimensions(); tmp_dims.pop_back(); - cuNDArray< complext > tmp_in_out1(&tmp_dims), tmp_in_out2(&tmp_dims); - - // Deform the input image into multiple frames by applying the registration vector field - R_->mult_M( in, &tmp_in_out1 ); - - // Apply non-Cartesian Sense encoding _iteration_ - E_->mult_MH_M( &tmp_in_out1, &tmp_in_out2 ); - - // Apply adjoint registration - R_->mult_MH( &tmp_in_out2, out ); - } - - virtual boost::shared_ptr< linearOperator< cuNDArray< complext > > > clone() { - return linearOperator< cuNDArray > >::clone(this); - } - -private: - boost::shared_ptr< cuNonCartesianSenseOperator > E_; - boost::shared_ptr< cuLinearResampleOperator,D> > R_; -}; - - -// -// Utility to upload samples for one reconstruction from host to device -// - -boost::shared_ptr< cuNDArray<_complext> > -upload_data( unsigned int reconstruction, unsigned int samples_per_reconstruction, unsigned int total_samples_per_coil, unsigned int num_coils, hoNDArray<_complext> *host_data, unsigned int offset = 0 ) -{ - vector dims; dims.push_back(samples_per_reconstruction); dims.push_back(num_coils); - cuNDArray<_complext> *data = new cuNDArray<_complext>(); data->create( &dims ); - for( unsigned int i=0; iget_data_ptr()+i*samples_per_reconstruction, - host_data->get_data_ptr()+i*total_samples_per_coil+reconstruction*samples_per_reconstruction+offset, - samples_per_reconstruction*sizeof(_complext), cudaMemcpyHostToDevice ); - - return boost::shared_ptr< cuNDArray<_complext> >(data); -} - -int main(int argc, char** argv) -{ - - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'd', COMMAND_LINE_STRING, 1, "MRI sample data file name", true, "fb_data.cplx" ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Reconstruction result file name", true, "result.real" ); - - // Parameters for the initial Sense reconstruction - // - - parms.add_parameter( 'm', COMMAND_LINE_INT, 1, "Matrix size", true, "256" ); - parms.add_parameter( 'o', COMMAND_LINE_INT, 1, "Oversampled matrix size", true, "384" ); - parms.add_parameter( 'p', COMMAND_LINE_INT, 1, "Profiles per frame", true, "16" ); - parms.add_parameter( 'i', COMMAND_LINE_INT, 1, "Number of iterations", true, "15" ); - parms.add_parameter( 'k', COMMAND_LINE_FLOAT, 1, "Kernel width", true, "5.5" ); - parms.add_parameter( 'K', COMMAND_LINE_FLOAT, 1, "Kappa", true, "0.1" ); - - // Parameters for the registration - // - - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Registration regularization weight (alpha)", true, "0.05" ); - parms.add_parameter( 'b', COMMAND_LINE_FLOAT, 1, "Registration regularization weight (beta)", true, "1.0" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - GPUTimer *timer = new GPUTimer("\nPerforming Sense reconstruction"); - - // - // First perform the Sense reconstruction, - // resulting in aliased presumably... - // - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_complext> > host_data = read_nd_array<_complext>((char*)parms.get_parameter('d')->get_string_value()); - - if( !(host_data->get_number_of_dimensions() == 3) ){ - GINFO_STREAM(endl << "Input data is not three-dimensional (#samples/profile x #profiles x #coils). Quitting!" << endl); - return 1; - } - - // Configuration from the host data - // - - unsigned int samples_per_profile = host_data->get_size(0); - unsigned int num_profiles = host_data->get_size(1); - unsigned int num_coils = host_data->get_size(2); - - // Configuration from the command line - // - - uint64d2 matrix_size = uint64d2(parms.get_parameter('m')->get_int_value(), parms.get_parameter('m')->get_int_value()); - uint64d2 matrix_size_os = uint64d2(parms.get_parameter('o')->get_int_value(), parms.get_parameter('o')->get_int_value()); - _real kernel_width = parms.get_parameter('k')->get_float_value(); - _real kappa = parms.get_parameter('K')->get_float_value(); - unsigned int num_iterations = parms.get_parameter('i')->get_int_value(); - unsigned int profiles_per_frame = parms.get_parameter('p')->get_int_value(); - unsigned int frames_per_reconstruction = 1; - - // Silent correction of invalid command line parameters (clamp to valid range) - // - - if( profiles_per_frame > num_profiles ) profiles_per_frame = num_profiles; - if( frames_per_reconstruction < 0 ) frames_per_reconstruction = num_profiles / profiles_per_frame; - if( frames_per_reconstruction*profiles_per_frame > num_profiles ) frames_per_reconstruction = num_profiles / profiles_per_frame; - - unsigned int profiles_per_reconstruction = frames_per_reconstruction*profiles_per_frame; - unsigned int samples_per_frame = profiles_per_frame*samples_per_profile; - unsigned int samples_per_reconstruction = profiles_per_reconstruction*samples_per_profile; - - // Set density compensation weights - // - - boost::shared_ptr< cuNDArray<_real> > dcw = compute_radial_dcw_golden_ratio_2d - ( samples_per_profile, profiles_per_frame, (_real)matrix_size_os.vec[0]/(_real)matrix_size.vec[0], - _real(1)/((_real)samples_per_profile/(_real)max(matrix_size.vec[0],matrix_size.vec[1])) ); - - // Define encoding matrix for non-Cartesian SENSE - // - - boost::shared_ptr< cuNonCartesianSenseOperator<_real,2> > E( new cuNonCartesianSenseOperator<_real,2>() ); - E->setup( matrix_size, matrix_size_os, kernel_width ); - - std::vector tmp_vec = to_std_vector(matrix_size); - tmp_vec.push_back(frames_per_reconstruction); - E->set_domain_dimensions( &tmp_vec ); - - // Notify encoding operator of dcw - // - - E->set_dcw(dcw); - - // Define rhs buffer - // - - boost::shared_ptr< cuSenseBuffer<_real,2> > rhs_buffer( new cuSenseBuffer<_real,2>() ); - rhs_buffer->setup( matrix_size, matrix_size_os, kernel_width, num_coils, 8, 16 ); - rhs_buffer->set_dcw(dcw); - - // Fill rhs buffer (go through all the data...) - // - - for( unsigned int iteration = 0; iteration < num_profiles/profiles_per_frame; iteration++ ) { - - // Define trajectories - boost::shared_ptr< cuNDArray<_reald2> > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, 1, iteration*profiles_per_frame ); - - // Upload data - boost::shared_ptr< cuNDArray<_complext> > csm_data = upload_data - ( iteration, samples_per_frame, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Add frame to rhs buffer - rhs_buffer->add_frame_data( csm_data.get(), traj.get() ); - } - - // Estimate CSM - // - - boost::shared_ptr< cuNDArray<_complext> > acc_images = rhs_buffer->get_accumulated_coil_images(); - boost::shared_ptr< cuNDArray<_complext> > csm = estimate_b1_map<_real,2>( acc_images.get() ); - - E->set_csm(csm); - - // Define regularization image operator - // - - std::vector image_dims = to_std_vector(matrix_size); - cuNDArray<_complext> *regul_image = new cuNDArray<_complext>(&image_dims); - - E->mult_csm_conj_sum( acc_images.get(), regul_image ); - acc_images.reset(); - - boost::shared_ptr< cuImageOperator<_complext> > R( new cuImageOperator<_complext>() ); - R->set_weight( kappa ); - R->compute( regul_image ); - delete regul_image; regul_image = 0x0; - - // Define preconditioning weights - // - - boost::shared_ptr< cuNDArray<_real> > _precon_weights = sum(abs_square(csm.get()).get(),2); - boost::shared_ptr< cuNDArray<_real> > R_diag = R->get(); - *R_diag *= kappa; - *_precon_weights += *R_diag; - R_diag.reset(); - reciprocal_sqrt_inplace(_precon_weights.get()); - boost::shared_ptr< cuNDArray<_complext> > precon_weights = real_to_complex<_complext>( _precon_weights.get() ); - _precon_weights.reset(); - - // Define preconditioning matrix - // - - boost::shared_ptr< cuCgPreconditioner<_complext> > D( new cuCgPreconditioner<_complext>() ); - D->set_weights( precon_weights ); - precon_weights.reset(); - csm.reset(); - - // Setup radial SENSE reconstructions (conjugate gradient solver) - // - - cuCgSolver<_complext> *cg = new cuCgSolver<_complext>; - cg->set_encoding_operator( E ); // encoding matrix - cg->add_regularization_operator( R ); // regularization matrix - cg->set_preconditioner ( D ); // preconditioning matrix - cg->set_max_iterations( num_iterations ); - cg->set_tc_tolerance( 1e-6 ); - cg->set_output_mode( cuCgSolver<_complext>::OUTPUT_VERBOSE ); - - // To save memory we allow only a certain number of frames - unsigned int max_num_frames = 25; - unsigned int reconstruction_offset = 100; // To find some respiratory movement in the test dataset - unsigned int num_reconstructions = num_profiles / profiles_per_reconstruction; - if( num_reconstructions<(max_num_frames+reconstruction_offset) ) reconstruction_offset = 0; - if( num_reconstructions > max_num_frames ) num_reconstructions = max_num_frames; - - // Allocate space for aliased reconstruction - // - - image_dims = to_std_vector(matrix_size); - image_dims.push_back(frames_per_reconstruction*num_reconstructions); - cuNDArray<_complext> *sense_result_cplx = new cuNDArray<_complext>; - GDEBUG_STREAM(std::endl << matrix_size[0] << " " << matrix_size[1] << " " << frames_per_reconstruction << " " << num_reconstructions); - - sense_result_cplx->create(&image_dims); - - // Loop and reconstruct - // - - for( unsigned int reconstruction = 0; reconstruction > traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction, (reconstruction+reconstruction_offset)*profiles_per_reconstruction ); - - // Upload data - // - - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( reconstruction+reconstruction_offset, samples_per_reconstruction, num_profiles*samples_per_profile, num_coils, host_data.get() ); - - // Set current trajectory and trigger NFFT preprocessing - // - - E->preprocess(traj.get()); - - // Form rhs (use sense_result_cplx array to save memory) - // - - vector rhs_dims = to_std_vector(matrix_size); - rhs_dims.push_back(frames_per_reconstruction); - cuNDArray<_complext> rhs; - - rhs.create( &rhs_dims, sense_result_cplx->get_data_ptr()+ - reconstruction*prod(matrix_size)*frames_per_reconstruction ); - - E->mult_MH( data.get(), &rhs ); - - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult = cg->solve(data.get()); - rhs = *(cgresult.get()); - } - - boost::shared_ptr< cuNDArray<_real> > sense_result = abs(sense_result_cplx); - write_nd_array<_complext>(sense_result_cplx->to_host().get(), "_images_all.cplx"); - - // We need all our device memory for the registration. Clean up after Sense. - // E.reset(); D.reset(); R.reset(); -- we will reuse these below - - rhs_buffer.reset(); - delete cg; delete sense_result_cplx; - delete timer; - - // Determine fixed/moving image dimensions and create arrays - // - -#ifdef PAD_Z - std::vector _3d_dims = sense_result->get_dimensions(); - unsigned int last_dim = _3d_dims.back(); - _3d_dims.pop_back(); _3d_dims.push_back(1); _3d_dims.push_back(last_dim); - sense_result->reshape( &_3d_dims ); -#endif - - vector multi_dims = sense_result->get_dimensions(); - multi_dims.pop_back(); -#ifdef PAD_Z - multi_dims.push_back(sense_result->get_size(3)-1); -#else - multi_dims.push_back(sense_result->get_size(2)-1); -#endif - vector single_dims = sense_result->get_dimensions(); - single_dims.pop_back(); - - cuNDArray<_real> - *multi_image = new cuNDArray<_real>, - *single_image = new cuNDArray<_real>; - - single_image->create( &single_dims, sense_result->get_data_ptr()); - multi_image->create( &multi_dims, sense_result->get_data_ptr()+prod(matrix_size)); - - write_nd_array<_real>(multi_image->to_host().get(), "_images_multi.real"); - write_nd_array<_real>(single_image->to_host().get(), "_image_single.real"); - - // Setup registration solver - // -#ifdef PAD_Z - cuCKOpticalFlowSolver<_real,3> *CK = new cuCKOpticalFlowSolver<_real,3>; -#else - cuCKOpticalFlowSolver<_real,2> *CK = new cuCKOpticalFlowSolver<_real,2>; -#endif - - //CK->set_output_mode( cuCKOpticalFlowSolver<_real,2>::OUTPUT_VERBOSE ); - CK->set_num_multires_levels( 1 ); - CK->set_max_num_iterations_per_level( 500 ); - CK->set_alpha((_real) parms.get_parameter('a')->get_float_value()); - CK->set_beta((_real) parms.get_parameter('b')->get_float_value()); - CK->set_limit(0.01f); - - // - // Perform "averaging by registration" type reconstruction - // - - timer = new GPUTimer("\nReconstruction by optical flow averaging"); - - // Run registration: - // - multi_image -> single_image (many to one registration) - // - - // All to one - boost::shared_ptr< cuNDArray<_real> > reg_result = CK->solve( single_image, multi_image ); - - write_nd_array<_real>(reg_result->to_host().get(), "_reg1.real"); - - // Deform the multi_image according to the deformation field and average - // - - boost::shared_ptr< cuNDArray<_real> > regis_image = CK->deform( multi_image, reg_result ); -#ifdef PAD_Z - boost::shared_ptr< cuNDArray<_real> > regis_image_avg = sum<_real>( regis_image.get(), 3); -#else - boost::shared_ptr< cuNDArray<_real> > regis_image_avg = sum<_real>( regis_image.get(), 2); -#endif - write_nd_array<_real>(regis_image->to_host().get(), "_reg_avg.real"); - write_nd_array<_real>(regis_image_avg->to_host().get(), "_avg_recon.real"); - - regis_image.reset(); regis_image_avg.reset(); reg_result.reset(); - - delete timer; - - // - // Perform "registration in cost function" type reconstruction - // - - timer = new GPUTimer("\nRunning registration recon"); - - // One to all - reg_result = CK->solve( multi_image, single_image ); - - write_nd_array<_real>(reg_result->to_host().get(), "_reg2.real"); - - regis_image = CK->deform( single_image, reg_result ); - write_nd_array<_real>(regis_image->to_host().get(), "_multi_def.real"); - regis_image.reset(); - - // Test iteration - cuNDArray<_real> out; out.create(multi_image->get_dimensions()); - cuNDArray<_real> in; in.create(single_image->get_dimensions()); - - // Release memory - delete CK; - exit(1); - // Setup solver - // - - // The non-Cartesian Sense operator is already setup, - // but the trajectories must be recomputed and preprocessed - - boost::shared_ptr< cuNDArray<_reald2> >traj = compute_radial_trajectory_golden_ratio_2d<_real> - ( samples_per_profile, profiles_per_frame, frames_per_reconstruction*(num_reconstructions-1), - (1+reconstruction_offset)*profiles_per_reconstruction ); - - E->preprocess(traj.get()); - - // Define and preprocess resampling operator - - boost::shared_ptr< cuLinearResampleOperator<_complext,2> > resampler - ( new cuLinearResampleOperator<_complext,2> ); - - resampler->set_displacement_field(reg_result); - resampler->mult_MH_preprocess(); - - // Define registrationReconstruction encoding operator - - boost::shared_ptr< registrationReconOperator<_real,2> > - RR( new registrationReconOperator<_real,2>() ); - - std::vector rhs_dims = to_std_vector(matrix_size); - RR->set_domain_dimensions( &rhs_dims ); - - RR->set_encoding_operator( E ); - RR->set_resampling_operator( resampler ); - - cg = new cuCgSolver<_complext>; - cg->set_encoding_operator( RR ); - cg->add_regularization_operator( R ); - cg->set_preconditioner ( D ); - cg->set_max_iterations( num_iterations ); - cg->set_tc_tolerance( 1e-6 ); - cg->set_output_mode( cuCgSolver<_complext>::OUTPUT_VERBOSE ); - - // Form rhs - - boost::shared_ptr< cuNDArray<_complext> > data = upload_data - ( 0, samples_per_reconstruction*(num_reconstructions-1), - num_profiles*samples_per_profile, num_coils, host_data.get(), - (reconstruction_offset+1)*samples_per_reconstruction ); - - cuNDArray<_complext> rhs(&rhs_dims); - RR->mult_MH( data.get(), &rhs ); - - write_nd_array<_complext>(rhs.to_host().get(), "_rhs.cplx" ); - write_nd_array<_real>(abs(&rhs)->to_host().get(), "_rhs.real" ); - - // Conjugate gradient solver - // - - boost::shared_ptr< cuNDArray<_complext> > cgresult = cg->solve(data.get()); - - boost::shared_ptr< hoNDArray<_real> > host_image = abs(cgresult.get())->to_host(); - write_nd_array<_real>(host_image.get(), "_reg_frame.real" ); - - delete timer; - - return 0; -} diff --git a/apps/standalone/gpu/registration/3d/CMakeLists.txt b/apps/standalone/gpu/registration/3d/CMakeLists.txt deleted file mode 100644 index 5e6a4580d..000000000 --- a/apps/standalone/gpu/registration/3d/CMakeLists.txt +++ /dev/null @@ -1,9 +0,0 @@ -add_executable(register_CK_3d_gpu register_CK_3d.cpp) - -target_link_libraries(register_CK_3d_gpu - gadgetron_toolbox_hostutils - gadgetron_toolbox_gpu - ${CUDA_LIBRARIES} - ) - -install(TARGETS register_CK_3d_gpu DESTINATION bin COMPONENT main) diff --git a/apps/standalone/gpu/registration/3d/register_CK_3d.cpp b/apps/standalone/gpu/registration/3d/register_CK_3d.cpp deleted file mode 100644 index e2f61d310..000000000 --- a/apps/standalone/gpu/registration/3d/register_CK_3d.cpp +++ /dev/null @@ -1,124 +0,0 @@ -/* - An example of how to register two 3d volumes using Cornelius-Kanade optical flow -*/ - -// Gadgetron includes -#include "cuCKOpticalFlowSolver.h" -#include "cuLinearResampleOperator.h" -#include "cuNDArray.h" -#include "hoNDArray_fileio.h" -#include "parameterparser.h" - -// Std includes -#include - -using namespace Gadgetron; -using namespace std; - -// Define desired precision -typedef float _real; - -int main(int argc, char** argv) -{ - // - // Parse command line - // - - ParameterParser parms; - parms.add_parameter( 'f', COMMAND_LINE_STRING, 1, "Fixed image file name (.real)", true ); - parms.add_parameter( 'm', COMMAND_LINE_STRING, 1, "Moving image file name (.real)", true ); - parms.add_parameter( 'r', COMMAND_LINE_STRING, 1, "Result file name", true, "displacement_field.real" ); - parms.add_parameter( 'a', COMMAND_LINE_FLOAT, 1, "Regularization weight (alpha)", true, "0.05" ); - parms.add_parameter( 'b', COMMAND_LINE_FLOAT, 1, "Regularization weight (beta)", true, "1.0" ); - parms.add_parameter( 'l', COMMAND_LINE_INT, 1, "Number of multiresolution levels", true, "3" ); - - parms.parse_parameter_list(argc, argv); - if( parms.all_required_parameters_set() ){ - GINFO_STREAM(" Running registration with the following parameters: " << endl); - parms.print_parameter_list(); - } - else{ - GINFO_STREAM(" Some required parameters are missing: " << endl); - parms.print_parameter_list(); - parms.print_usage(); - return 1; - } - - // Load sample data from disk - // - - boost::shared_ptr< hoNDArray<_real> > host_fixed = - read_nd_array<_real>((char*)parms.get_parameter('f')->get_string_value()); - - boost::shared_ptr< hoNDArray<_real> > host_moving = - read_nd_array<_real>((char*)parms.get_parameter('m')->get_string_value()); - - if( !host_fixed.get() || !host_moving.get() ){ - GINFO_STREAM(endl << "One of the input images is not found. Quitting!\n" << endl); - return 1; - } - - unsigned int num_fixed_dims = host_fixed->get_number_of_dimensions(); - unsigned int num_moving_dims = host_moving->get_number_of_dimensions(); - - if( !(num_fixed_dims == 3 || num_fixed_dims == 4) ){ - GINFO_STREAM(endl << "The fixed image is not three- or four-dimensional. Quitting!\n" << endl); - return 1; - } - - if( !(num_moving_dims == 3 || num_moving_dims == 4) ){ - GINFO_STREAM(endl << "The moving image is not three- or four-dimensional. Quitting!\n" << endl); - return 1; - } - - // Upload host data to device - // - - cuNDArray<_real> fixed_image(*host_fixed); - cuNDArray<_real> moving_image(*host_moving); - - _real alpha = (_real) parms.get_parameter('a')->get_float_value(); - _real beta = (_real) parms.get_parameter('b')->get_float_value(); - - unsigned int multires_levels = parms.get_parameter('l')->get_int_value(); - - // Use trilinear interpolation for resampling - // - - boost::shared_ptr< cuLinearResampleOperator<_real,3> > R( new cuLinearResampleOperator<_real,3>() ); - - // Setup solver - // - - cuCKOpticalFlowSolver<_real,3> CK; - CK.set_interpolator( R ); - CK.set_output_mode( cuCKOpticalFlowSolver<_real,3>::OUTPUT_VERBOSE ); - CK.set_max_num_iterations_per_level( 500 ); - CK.set_num_multires_levels( multires_levels ); - CK.set_alpha(alpha); - CK.set_beta(beta); - CK.set_limit(0.01f); - - // Run registration - // - - boost::shared_ptr< cuNDArray<_real> > result = CK.solve( &fixed_image, &moving_image/*, true*/ ); - - if( !result.get() ){ - GINFO_STREAM(endl << "Registration solver failed. Quitting!\n" << endl); - return 1; - } - - boost::shared_ptr< cuNDArray<_real> > deformed_moving = CK.deform( &moving_image, result ); - - // All done, write out the result - // - - boost::shared_ptr< hoNDArray<_real> > host_result = result->to_host(); - write_nd_array<_real>(host_result.get(), (char*)parms.get_parameter('r')->get_string_value()); - - host_result = deformed_moving->to_host(); - write_nd_array<_real>(host_result.get(), "def_moving.real" ); - - return 0; -} diff --git a/apps/standalone/gpu/registration/CMakeLists.txt b/apps/standalone/gpu/registration/CMakeLists.txt deleted file mode 100644 index 4b458f11f..000000000 --- a/apps/standalone/gpu/registration/CMakeLists.txt +++ /dev/null @@ -1,7 +0,0 @@ -include_directories( - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow - ${CMAKE_SOURCE_DIR}/toolboxes/registration/optical_flow/gpu - ) - -add_subdirectory(2d) -add_subdirectory(3d) diff --git a/azure-pipelines.yml b/azure-pipelines.yml deleted file mode 100644 index e32d823de..000000000 --- a/azure-pipelines.yml +++ /dev/null @@ -1,146 +0,0 @@ -variables: - AzureConnection: 'BiomedicalImaging-NonProd(87d8acb3-5176-4651-b457-6ab9cefd8e3d)' - imageBaseName: 'ghcr.io/gadgetron/gadgetron/ubuntu22.04' - DOCKER_BUILDKIT: 1 - isPR: $[eq(variables['Build.Reason'], 'PullRequest')] - isCI: $[or(eq(variables['Build.Reason'], 'IndividualCI'), eq(variables['Build.Reason'], 'BatchedCI'))] - poolName: gadgetron-msft-managed-pool-westus3 - -# Trigger when merging to master -trigger: -- master - -# Trigger for PRs that merge to master -pr: -- master - -jobs: -- job: BuildAndTest - pool: - name: $(poolName) - vmImage: - timeoutInMinutes: 120 - displayName: "Build, Unit and Integration tests" - strategy: - matrix: - cuda: - flavor: cuda - requirements: python,cuda - nocuda: - flavor: nocuda - requirements: python - steps: - - task: AzureKeyVault@1 - inputs: - azureSubscription: $(AzureConnection) - keyVaultName: gadgetron-build-secrets - - script: | - set -euo pipefail - curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \ - && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list \ - && sudo apt-get update - sudo apt-get install -y nvidia-container-toolkit - sudo nvidia-ctk runtime configure --runtime=docker - sudo systemctl restart docker - docker pull ghcr.io/gadgetron/gadgetron/cuda:12.3.0-base-ubuntu22.04 - docker run --rm --gpus all ghcr.io/gadgetron/gadgetron/cuda:12.3.0-base-ubuntu22.04 nvidia-smi - displayName: 'Check GPU availability' - - script: | - set -e - # First build a dev image and run unit tests - stage_name="gadgetron_$(flavor)build" - docker build --target ${stage_name} -t ${stage_name} . - test_command=". /opt/conda/etc/profile.d/conda.sh \ - && conda activate gadgetron \ - && /opt/code/gadgetron/build/test/test_all \ - && /opt/code/gadgetron/build/apps/gadgetron/test/server_tests" - docker run --gpus=all ${stage_name} /bin/bash -c "$test_command" - displayName: "Run unit and integration tests" - - script: | - set -e - ./build-images.sh --type dev --type rt --flavor $(flavor) --base-name $(imageBaseName) --tag $(build.BuildNumber) - cd test/integration && python3 get_data.py && cd ../../ - fullImageName="$(imageBaseName)_rt_$(flavor):$(build.BuildNumber)" - ./docker/integration-test-image.sh --image ${fullImageName} --ignore-requirements $(requirements) --gpus all --cases cases/* - displayName: "Publish test results" - - task: PublishTestResults@2 - inputs: - testRunner: JUnit - testResultsFiles: 'junit.xml' - failTaskOnFailedTests: true - buildPlatform: "$(imageBaseName)_rt_$(flavor)" - - script: | - set -e - echo "$(ghcr-pat)" | docker login ghcr.io -u $(ghcr-user) --password-stdin - ./build-images.sh --type dev --type rt --flavor $(flavor) --base-name $(imageBaseName) --tag $(build.BuildNumber) --push - ./build-images.sh --type dev --type rt --flavor $(flavor) --base-name $(imageBaseName) --tag latest --push - displayName: 'Push images' - condition: and(succeeded(), eq(variables.isCI, 'true')) -- job: Package - pool: - name: $(poolName) - vmImage: - timeoutInMinutes: 120 - displayName: "Create Conda Package" - steps: - - bash: echo "##vso[task.prependpath]/anaconda/bin" - displayName: Add conda to PATH - - script: | - eval "$(conda shell.bash hook)" - conda env create -f conda/environment.yml - conda activate gadgetron-build - set -euo pipefail - cd conda && ./package.sh - - task: CopyFiles@2 - displayName: 'Copy Package' - inputs: - contents: 'conda/build_pkg/**' - targetFolder: '$(Build.ArtifactStagingDirectory)' - - publish: '$(Build.ArtifactStagingDirectory)' - displayName: 'Publish package' - artifact: drop -- job: Publish - pool: - name: $(poolName) - vmImage: - timeoutInMinutes: 120 - displayName: "Publish Conda Package" - condition: and(succeeded(), eq(variables.isCI, 'true')) - dependsOn: - - BuildAndTest - - Package - steps: - - task: AzureKeyVault@1 - inputs: - azureSubscription: $(AzureConnection) - KeyVaultName: 'gadgetron-build-secrets' - SecretsFilter: 'gadgetron-token, gadgetron-user' - RunAsPreJob: true - - bash: echo "##vso[task.prependpath]/anaconda/bin" - displayName: Add conda to PATH - - download: current - artifact: drop - - script: | - eval "$(conda shell.bash hook)" - conda create --name conda-push anaconda-client=1.8.0 -y - conda activate conda-push - set -euo pipefail - cd conda && ./publish_package.sh -u $(gadgetron-user) -t $(gadgetron-token) -p `find $(Pipeline.Workspace)/drop/ -name gadgetron*.tar.bz2` -- job: buildAndTestMacOS - pool: - name: Azure Pipelines - vmImage: macOS-latest - timeoutInMinutes: 10 - displayName: "Testing for macOS" - steps: - - task: AzureKeyVault@2 - inputs: - azureSubscription: $(AzureConnection) - keyVaultName: gadgetron-build-secrets - - script: | - set -e - uname -a - which curl - which wget - which conda - displayName: "Check for basic utilities" diff --git a/chroot/CMakeLists.txt b/chroot/CMakeLists.txt deleted file mode 100644 index fb0810d90..000000000 --- a/chroot/CMakeLists.txt +++ /dev/null @@ -1,106 +0,0 @@ -configure_file("start-gadgetron.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/start-gadgetron.sh @ONLY) -configure_file("enter-chroot-env.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/enter-chroot-env.sh @ONLY) -configure_file("gadgetron-dependency-query.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/gadgetron-dependency-query.sh @ONLY) -configure_file("siemens_to_ismrmrd.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/siemens_to_ismrmrd.sh @ONLY) -configure_file("gadgetron_ismrmrd_client.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/gadgetron_ismrmrd_client.sh @ONLY) -configure_file("gadgetron_ismrmrd_client_noise_summary.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/gadgetron_ismrmrd_client_noise_summary.sh @ONLY) -configure_file("gt_alive.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/gt_alive.sh @ONLY) -configure_file("copy-cuda-lib.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/copy-cuda-lib.sh @ONLY) -configure_file("start-env.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/start-env.sh @ONLY) -configure_file("start.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/start.sh @ONLY) -configure_file("run-gadgetron-dependency-query.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron-dependency-query.sh @ONLY) -configure_file("run-gadgetron_ismrmrd_client.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron_ismrmrd_client.sh @ONLY) -configure_file("run-gadgetron_ismrmrd_client_noise_summary.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron_ismrmrd_client_noise_summary.sh @ONLY) -configure_file("run-gt_alive.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/run-gt_alive.sh @ONLY) -configure_file("run-siemens_to_ismrmrd.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/run-siemens_to_ismrmrd.sh @ONLY) -configure_file("mount_image.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/mount_image.sh @ONLY) -configure_file("start-gadgetron-from-image.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/start-gadgetron-from-image.sh @ONLY) - -set (LIBRARY_PATHS ${ISMRMRD_LIB_DIR}) - -foreach(_lib IN LISTS MKL_LIB_DIR CUDA_LIBRARIES CUDA_CUFFT_LIBRARIES CUDA_CUBLAS_LIBRARIES) - if (_lib) - get_filename_component(_libdir ${_lib} PATH) - set (LIBRARY_PATHS ${LIBRARY_PATHS}:${_libdir}) - endif() -endforeach() -list(REMOVE_DUPLICATES LIBRARY_PATHS ) -message(STATUS "LIBRARY_PATHS for chroot: ${LIBRARY_PATHS}") - -find_library( CUDA_LIBRARY NAMES libcuda.so ) - -configure_file("copy-cuda-lib.sh.in" ${CMAKE_CURRENT_BINARY_DIR}/copy-cuda-lib.sh @ONLY) - -find_program(SIEMENS_TO_ISMRMRD_EXE siemens_to_ismrmrd) - -add_custom_target(chroot_base) -add_custom_target(chroot) - -add_custom_command( - TARGET chroot_base - POST_BUILD - VERBATIM - COMMENT "Creating chroot base tar file" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND sudo bash create_chroot_base.sh - ${CMAKE_BINARY_DIR} - ) - -if (SIEMENS_TO_ISMRMRD_EXE) - add_custom_command( - TARGET chroot - POST_BUILD - VERBATIM - COMMENT "Creating chroot tar and img file" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND sudo bash create_chroot.sh - ${CMAKE_INSTALL_PREFIX} - ${CMAKE_BINARY_DIR} - ${LIBRARY_PATHS} - ${CUDA_LIBRARY} - ${CMAKE_SOURCE_DIR} - ${SIEMENS_TO_ISMRMRD_EXE} - ) -else() - add_custom_command( - TARGET chroot - POST_BUILD - VERBATIM - COMMENT "Creating chroot tar and img file" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - COMMAND sudo bash create_chroot.sh - ${CMAKE_INSTALL_PREFIX} - ${CMAKE_BINARY_DIR} - ${LIBRARY_PATHS} - ${CUDA_LIBRARY} - ${CMAKE_SOURCE_DIR} - ) -endif() - -install(PROGRAMS - ${CMAKE_CURRENT_BINARY_DIR}/copy-cuda-lib.sh - ${CMAKE_CURRENT_BINARY_DIR}/start-gadgetron.sh - ${CMAKE_CURRENT_BINARY_DIR}/enter-chroot-env.sh - ${CMAKE_CURRENT_BINARY_DIR}/gadgetron-dependency-query.sh - ${CMAKE_CURRENT_BINARY_DIR}/siemens_to_ismrmrd.sh - ${CMAKE_CURRENT_BINARY_DIR}/gadgetron_ismrmrd_client.sh - ${CMAKE_CURRENT_BINARY_DIR}/gadgetron_ismrmrd_client_noise_summary.sh - ${CMAKE_CURRENT_BINARY_DIR}/gt_alive.sh - ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron-dependency-query.sh - ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron_ismrmrd_client.sh - ${CMAKE_CURRENT_BINARY_DIR}/run-gadgetron_ismrmrd_client_noise_summary.sh - ${CMAKE_CURRENT_BINARY_DIR}/run-gt_alive.sh - ${CMAKE_CURRENT_BINARY_DIR}/run-siemens_to_ismrmrd.sh - ${CMAKE_CURRENT_BINARY_DIR}/start-env.sh - ${CMAKE_CURRENT_BINARY_DIR}/start.sh - ${CMAKE_CURRENT_BINARY_DIR}/mount_image.sh - ${CMAKE_CURRENT_BINARY_DIR}/start-gadgetron-from-image.sh - ${CMAKE_SOURCE_DIR}/chroot/mount.sh - ${CMAKE_SOURCE_DIR}/chroot/stop.sh - ${CMAKE_SOURCE_DIR}/chroot/umount_image.sh - ${CMAKE_SOURCE_DIR}/chroot/install_chroot_image.sh - ${CMAKE_SOURCE_DIR}/chroot/clean_gadgetron_data.sh - ${CMAKE_SOURCE_DIR}/chroot/nvidia-copy.sh - DESTINATION ${GADGETRON_INSTALL_CHROOT_SCRIPTS_PATH} - COMPONENT scripts - ) diff --git a/chroot/README.rst b/chroot/README.rst deleted file mode 100644 index 205322254..000000000 --- a/chroot/README.rst +++ /dev/null @@ -1,35 +0,0 @@ -Running Gadgetron in chroot -============================ - - -Introduction ------------- - - -Creating a chroot environment ------------------------------ - -First we need to install the tools required to create chroot environments:: - - sudo apt-get install dchroot debootstrap - -Next we need to add an appropriate configuration to `/etc/schroot/schroot.conf':: - - [trusty] - description=trusty - location=/var/chroot/trusty - priority=3 - users=doko - groups=sbuild - root-groups=root - -Create the folder where we will be making the root file system:: - - sudo mkdir -p /var/chroot/trusty - - -Now generate a basic root file system:: - - sudo debootstrap --variant=buildd --arch amd64 trusty /var/chroot/trusty http://archive.ubuntu.com/ubuntu/ - - diff --git a/chroot/chroot-manual.txt b/chroot/chroot-manual.txt deleted file mode 100644 index 9e1b6110d..000000000 --- a/chroot/chroot-manual.txt +++ /dev/null @@ -1,156 +0,0 @@ ----INSTALLING GADGETRON Ubuntu 14.04--- - - - -*** Dependencies *** - -sudo apt-get install build-essential git-core cmake gcc-multilib libace-dev libarmadillo-dev libboost-all-dev libfftw3-dev libgtest-dev libxslt-dev xsltproc libhdf5-serial-dev h5utils hdf5-tools libxml2-dev python-dev python-numpy python-libxml2 python-psutil python-h5py python-scipy python-twisted python-matplotlib dcmtk git doxygen libqt4-dev libglew1.6-dev docbook5-xml docbook-xsl-doc-pdf docbook-xsl-doc-html docbook-xsl-ns fop freeglut3-dev libxi-dev liblapack-dev - - - -*** Steps to install CUDA 6.5 *** - -1. sudo apt-get install build-essential - -2. In order to be able to install nvidia driver (http://stackoverflow.com/questions/25463952/drm-ko-missing-for-cuda-6-5-ubuntu-14-04-aws-ec2-gpu-instance-g2-2xlarge) -sudo apt-get install linux-image-extra-virtual - -3. Follow the instructions from: http://docs.nvidia.com/cuda/cuda-getting-started-guide-for-linux/index.html#ubuntu-installation or apply steps 1-11 from below: - - 1. cd && wget http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1404/x86_64/cuda-repo-ubuntu1404_6.5-14_amd64.deb - 2. sudo dpkg -i cuda-repo-ubuntu1404_6.5-14_amd64.deb - 3. rm cuda-repo-ubuntu1404_6.5-14_amd64.deb - 4. sudo apt-get update - 5. sudo apt-get -y install cuda - 6. echo "" >> ~/.bashrc - 7. echo "export PATH=/usr/local/cuda-6.5/bin:$PATH" >> ~/.bashrc - 8. echo "export LD_LIBRARY_PATH=/usr/local/cuda-6.5/lib64:$LD_LIBRARY_PATH" >> ~/.bashrc - - ## You should probably restart the system here - 9. sudo shutdown -r now - - ## Lets make the deviceQuery sample. This is used to verify cuda works - 10. cd /usr/local/cuda/samples/1_Utilities/deviceQuery && sudo make - - # If you see all of your cards listed, and the last line says "Result = PASS" you're good to go! - 11. /usr/local/cuda/samples/1_Utilities/deviceQuery/deviceQuery - -4. Check driver details: nvidia-smi - - - -*** Steps to install MKL *** - -If you would like to use MKL (Intel Math Kernel Library), please download your installation file from Intel and do the installation. -Here is what we did with MKL version 11.0.5.192: - -tar -xzvf l_mkl_11.0.5.192_intel64.tgz -cd l_mkl_11.0.5.192_intel64/ -sudo ./install.sh - -Follow the instructions and add the following paths to your ~/.bashrc -echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64" >> ~/.bashrc - -You will also need to install Armadillo from source, skip the libarmadillo-dev package above. -Download latest armadillo from http://arma.sourceforge.net and unpack, build and install. -If you have MKL installed, this will pick it up and build the armadillo libs against it. - -cd armadillo-3.900.6/ -cmake -make; sudo make install - - - -*** Extras *** - -Useful links (but not 100% accurate): -http://docs.nvidia.com/cuda/cuda-getting-started-guide-for-linux/index.html#ubuntu-installation -https://gist.github.com/zcshiner/4b32980792d367222304 -http://www.r-tutor.com/gpu-computing/cuda-installation/cuda6.5-ubuntu -http://askubuntu.com/questions/451672/installing-and-testing-cuda-in-ubuntu-14-04 - -MH Useful links: -https://sourceforge.net/p/gadgetron/discussion/general/thread/d0ee5b27/ -https://sourceforge.net/p/gadgetron/home/Linux%20Installation/ - - ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------- - - ----CHROOT--- - - -1. apt-get update - -2. apt-get install debootstrap -y - -3. sudo debootstrap --variant=buildd --arch amd64 trusty /opt/chroot/trusty http://gb.archive.ubuntu.com/ubuntu/ - -4. Place this script to /opt/chroot/chrootmounter.sh ------------------------------------------------------------------------------------------- -#!/bin/bash - -if [ $# -eq 2 ]; then - - if [ "$1" == "mount" ]; then - sudo mount --bind /dev "${2}/dev" - sudo mount --bind /sys "${2}/sys" - sudo mount --bind /proc "${2}/proc" - - exit 0 - fi - - if [ "$1" == "umount" ]; then - sudo umount "${2}/dev" - sudo umount "${2}/sys" - sudo umount "${2}/proc" - - exit 0 - fi - - echo -e "\nUsage: $0 (mount or umount) (chrootdir)\n" - exit 1 - -else - echo -e "\nUsage: $0 (mount or umount) (chrootdir)\n" - exit 1 -fi ------------------------------------------------------------------------------------------- - -5. chmod +x /opt/chroots/chrootmounter.sh - -6. Run the script: ./chrootmounter.sh mount /opt/chroot/trusty (check if it worked with mount command) - -*7. Make sure that /etc/resolv.conf is the same on 'real' computer and on 'chroot' one (if not, copy the file from the real one) - -*8. Copy/Extend your /etc/apt/sources.list (make sure you are using the correct version of Ubuntu Repos): - sudo cp /etc/apt/sources.list /opt/chroot/trusty/etc/apt/sources.list - -9. Run: /home/ubuntu/perl_scripts/generate_gadgetron_root - Arg 1: Gadgetron root: /usr/local/gadgetron - Arg 2: New root: /opt/chroot/trusty - -10. Enter the new environment: sudo chroot /opt/chroot/trusty - -*11. Install additional software. For example: - apt-get update - apt-get dist-upgrade -y - apt-get install nano vim htop less dialog -y - -12. Set the PATH and LD_LIBRARY_PATH variable: - export PATH=$PATH:/usr/local/gadgetron/bin - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH/usr/local/gadgetron/lib:/usr/local/lib:/usr/local/cuda-6.5/lib64:/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64 - - -*** Extras *** - -Useful links: -https://help.ubuntu.com/community/BasicChroot -http://ocsovszki-dorian.blogspot.com/2014/06/building-chroot-environment-ubuntu-1404.html - - - - -gtplus_FetalHASTE.cfg diff --git a/chroot/clean_gadgetron_data.sh b/chroot/clean_gadgetron_data.sh deleted file mode 100644 index 9092ae637..000000000 --- a/chroot/clean_gadgetron_data.sh +++ /dev/null @@ -1,61 +0,0 @@ -#!/bin/bash - -BASEDIR=$(dirname $0) - -if [ $# -eq 0 ]; then - CHROOT_ISMRMRD_DATA_PATH=/tmp/gadgetron_data - CHROOT_ISMRMRD_DISK_USAGE=80 - CHROOT_ISMRMRD_DATA_HOURS=72 -else - if [ $# -eq 1 ]; then - CHROOT_ISMRMRD_DATA_PATH=${1} - CHROOT_ISMRMRD_DISK_USAGE=80 - CHROOT_ISMRMRD_DATA_HOURS=72 - else - if [ $# -eq 2 ]; then - CHROOT_ISMRMRD_DATA_PATH=${1} - CHROOT_ISMRMRD_DISK_USAGE=${2} - CHROOT_ISMRMRD_DATA_HOURS=72 - else - CHROOT_ISMRMRD_DATA_PATH=${1} - CHROOT_ISMRMRD_DISK_USAGE=${2} - CHROOT_ISMRMRD_DATA_HOURS=${3} - fi - fi -fi - -# check disk usage -disk_used=`df /tmp/gadgetron_data | awk '$1!="Filesystem"{print $3}'` -disk_available=`df /tmp/gadgetron_data | awk '$1!="Filesystem"{print $4}'` -disk_total=$((disk_available+disk_used)) -disk_usage_ratio=$((100*disk_used/disk_total + 1)) -echo Disk usage ratio: ${disk_usage_ratio}% -echo -------------------------------------- - -if [ $disk_usage_ratio -ge $CHROOT_ISMRMRD_DISK_USAGE ]; then - - current_moment=`date +%s` - - for file in ${CHROOT_ISMRMRD_DATA_PATH}/*.h5 - do - # check the file creation time, if this file is too old, delete it - file_moment=`stat -c %Y ${file}` - file_duration_seconds=$((current_moment-file_moment)) - file_duration_mins=$((file_duration_seconds / 60)) - file_duration_hours=$((file_duration_mins / 60)) - if [ ${file_duration_hours} -ge $CHROOT_ISMRMRD_DATA_HOURS ]; then - rm -rf ${file} - echo Delete --- ${file} - else - echo Keep --- ${file} - fi - done -else - for file in ${CHROOT_ISMRMRD_DATA_PATH}/*.h5 - do - echo Keep --- ${file} - done -fi -echo -------------------------------------- - -exit 0 diff --git a/chroot/copy-cuda-lib.sh.in b/chroot/copy-cuda-lib.sh.in deleted file mode 100644 index 0efafd44e..000000000 --- a/chroot/copy-cuda-lib.sh.in +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -if [ $(id -u) -ne 0 ]; then - echo -e "\nPlease start the script as a root or sudo!\n" - exit 1 -else - if [ $# -eq 1 ]; then - BASEDIR=$(dirname $0) - CHROOT_DIR=${1} - - # Absolute path this script is in - SCRIPTPATH=$(dirname "$SCRIPT") - - # find the lib(s) - CANDIDATES=$(ldconfig -p | grep "libcuda.so\s") - - # find the one that is 64-bit - for CANDIDATE in $CANDIDATES - do - var=$(file -L $CANDIDATE | grep '64-bit') - if [ -n "$var" ]; then - NEW_CUDA_LIB=$CANDIDATE - fi - done - - # copy it to the right location (overwrite the previous one) - yes | cp $NEW_CUDA_LIB $CHROOT_DIR@CMAKE_INSTALL_PREFIX@/lib/ - exit 0 - - else - echo -e "\nUsage: $0 (chroot_dir)\n" - exit 1 - fi -fi diff --git a/chroot/copy_file_and_dependencies b/chroot/copy_file_and_dependencies deleted file mode 100755 index 138e499cc..000000000 --- a/chroot/copy_file_and_dependencies +++ /dev/null @@ -1,25 +0,0 @@ -#!/usr/bin/perl - - -use FindBin; -use lib $FindBin::Bin; - -my $file = $ARGV[0]; - -my $new_root = $ARGV[1]; - -my $gadgetron_root = $ARGV[2]; - -my $deps = `$FindBin::Bin/get_dependencies_for_binary $file`; - -my @lines = split('\n', $deps); - -system("sudo cp -n $file $new_root/$gadgetron_root/lib/"); - -foreach my $val (@lines) { - chomp($val); - if (not -e "$new_root/$val") - { - system("$FindBin::Bin/copy_file_and_dependencies $val $new_root $gadgetron_root"); - } -} diff --git a/chroot/create_chroot.sh b/chroot/create_chroot.sh deleted file mode 100755 index 1e3a49a78..000000000 --- a/chroot/create_chroot.sh +++ /dev/null @@ -1,85 +0,0 @@ -#!/bin/bash - -if [ $(id -u) -ne 0 ]; then - echo -e "\nPlease start the script as a root or sudo!\n" - exit 1 -else - if [ $# -ge 5 ]; then - - # --ARGUMENTS-- (example) - - # CHROOT_GADGETRON_INSTALL_PREFIX: /usr/local/gadgetron - # CHROOT_GADGETRON_BINARY_DIR: /home/ubuntu/gadgetron/build - # CHROOT_LIBRARY_PATHS: /usr/local/lib:/usr/lib/x86_64-linux-gnu - # CHROOT_CUDA_LIBRARY: - # CHROOT_GADGETRON_SOURCE_DIR: /home/ubuntu/gadgetron - - CHROOT_GADGETRON_INSTALL_PREFIX=${1} - echo CHROOT_GADGETRON_INSTALL_PREFIX: ${CHROOT_GADGETRON_INSTALL_PREFIX} - CHROOT_GADGETRON_BINARY_DIR=${2} - echo CHROOT_GADGETRON_BINARY_DIR: ${CHROOT_GADGETRON_BINARY_DIR} - CHROOT_LIBRARY_PATHS=${3} - echo CHROOT_LIBRARY_PATHS: ${CHROOT_LIBRARY_PATHS} - CHROOT_CUDA_LIBRARY=${4} - echo CHROOT_CUDA_LIBRARY: ${CHROOT_CUDA_LIBRARY} - CHROOT_GADGETRON_SOURCE_DIR=${5} - echo CHROOT_GADGETRON_SOURCE_DIR: ${CHROOT_GADGETRON_SOURCE_DIR} - - CHROOT_IMAGE_SIZE=1536 - echo CHROOT_IMAGE_SIZE: ${CHROOT_IMAGE_SIZE} MB - - if [ $# -ge 6 ]; then - CHROOT_SIEMENS_TO_ISMRMRD_EXE=${6} - echo CHROOT_SIEMENS_TO_ISMRMRD_EXE: ${CHROOT_SIEMENS_TO_ISMRMRD_EXE} - else - echo "SIEMENS_TO_ISMRMRD_EXE not set" - fi - - # ---------------------------------------------------------------------------------------- - - # Add LIBRARY_PATHS to LD_LIBRARY_PATH - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${CHROOT_LIBRARY_PATHS} - export LC_ALL=C - echo "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}" - - # create folders and manifest file - rm -rf ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root - touch ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/source-manifest.txt - - # get gadgetron SHA1 key - GADGETRON_INFO=${CHROOT_GADGETRON_INSTALL_PREFIX}/bin/gadgetron_info - if [ -f ${GADGETRON_INFO} ]; then - res=$(${GADGETRON_INFO}) - re=".*-- Git SHA1 : ([0-9a-z]+).*" - if [[ $res =~ $re ]]; then - CHROOT_GIT_SHA1_HASH=${BASH_REMATCH[1]} - fi - fi - - echo "gadgetron ${CHROOT_GIT_SHA1_HASH}" > ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/source-manifest.txt - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups - - # try to find chroot base package - CHROOT_BASE=`ls -t ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/gadgetron-base*.tar.gz | head -1` - - if [[ -f "${CHROOT_BASE}" ]]; then - echo "find gadgetron chroot base package : ${CHROOT_BASE}" - else - echo "Cannot find gadgetron chroot base package" - echo "Creating chroot base package ... " - ${CHROOT_GADGETRON_SOURCE_DIR}/chroot/create_chroot_base.sh ${CHROOT_GADGETRON_BINARY_DIR} - CHROOT_BASE=`ls -t ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/gadgetron-base*.tar.gz | head -1` - fi - - # create chroot from base - echo "Creating chroot package from base " ${CHROOT_BASE} - ${CHROOT_GADGETRON_SOURCE_DIR}/chroot/create_chroot_from_base.sh ${CHROOT_GADGETRON_INSTALL_PREFIX} ${CHROOT_GADGETRON_BINARY_DIR} ${CHROOT_LIBRARY_PATHS} ${CHROOT_CUDA_LIBRARY} ${CHROOT_GADGETRON_SOURCE_DIR} ${CHROOT_BASE} ${CHROOT_IMAGE_SIZE} ${CHROOT_SIEMENS_TO_ISMRMRD_EXE} - - exit 0 - else - echo -e "\nUsage: $0 (gadgetron install prefix) (gadgetron binary dir) (LIBRARY_PATHS) (CHROOT_CUDA_LIBRARY) (gadgetron source dir) (SIEMENS_TO_ISMRMRD_EXE)\n" - exit 1 - fi -fi diff --git a/chroot/create_chroot_base.sh b/chroot/create_chroot_base.sh deleted file mode 100755 index 11d593c82..000000000 --- a/chroot/create_chroot_base.sh +++ /dev/null @@ -1,46 +0,0 @@ -#!/bin/bash - -if [ $(id -u) -ne 0 ]; then - echo -e "\nPlease start the script as a root or sudo!\n" - exit 1 -else - if [ $# -ge 1 ]; then - - # --ARGUMENTS-- (example) - - # CHROOT_GADGETRON_BINARY_DIR: /home/ubuntu/gadgetron/build - - # ----------------------------------------------------------------------------------- - # input parameters - # ----------------------------------------------------------------------------------- - - CHROOT_GADGETRON_BINARY_DIR=${1} - echo CHROOT_GADGETRON_BINARY_DIR: ${CHROOT_GADGETRON_BINARY_DIR} - - rm -rf ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups - - # install debian bootstrap - apt-get install debootstrap -y - debootstrap --variant=buildd --arch amd64 trusty ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron http://gb.archive.ubuntu.com/ubuntu/ - - # install python libraries - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron apt-get install software-properties-common python-dev python-twisted python-psutil python-numpy python-libxml2 -y - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron add-apt-repository "deb http://us.archive.ubuntu.com/ubuntu/ trusty main restricted multiverse universe" - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron apt-get update - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron apt-get install python-h5py libhdf5-serial-dev hdf5-tools python-pip libplplot-dev -y - - TAR_FILE_NAME=gadgetron-base-`date '+%Y%m%d-%H%M'` - - tar -zcf "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.tar.gz" --directory "${CHROOT_GADGETRON_BINARY_DIR}/chroot" --exclude=./chroot-root/gadgetron/var --exclude=./chroot-root/gadgetron/dev --exclude=./chroot-root/gadgetron/sys --exclude=./chroot-root/gadgetron/proc --exclude=./chroot-root/gadgetron/root ./chroot-root - - rm -rf "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root" - - chmod 666 "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.tar.gz" - exit 0 - else - echo -e "\nUsage: $0 (gadgetron binary dir)\n" - exit 1 - fi -fi diff --git a/chroot/create_chroot_from_base.sh b/chroot/create_chroot_from_base.sh deleted file mode 100755 index 76da60a93..000000000 --- a/chroot/create_chroot_from_base.sh +++ /dev/null @@ -1,117 +0,0 @@ -#!/bin/bash - -if [ $(id -u) -ne 0 ]; then - echo -e "\nPlease start the script as a root or sudo!\n" - exit 1 -else - if [ $# -ge 6 ]; then - - # --ARGUMENTS-- (example) - - # CHROOT_GADGETRON_INSTALL_PREFIX: /usr/local - # CHROOT_GADGETRON_BINARY_DIR: /home/ubuntu/gadgetron/build - # CHROOT_LIBRARY_PATHS: /usr/local/lib:/usr/lib/x86_64-linux-gnu - # CHROOT_CUDA_LIBRARY: - # CHROOT_GADGETRON_SOURCE_DIR: /home/ubuntu/gadgetron - # CHROOT_GADGETRON_SOURCE_DIR: gadgetron-base.tar.gz - # CHROOT_IMAGE_SIZE: 1536 - - CHROOT_GADGETRON_INSTALL_PREFIX=${1} - echo CHROOT_GADGETRON_INSTALL_PREFIX: ${CHROOT_GADGETRON_INSTALL_PREFIX} - - CHROOT_GADGETRON_BINARY_DIR=${2} - echo CHROOT_GADGETRON_BINARY_DIR: ${CHROOT_GADGETRON_BINARY_DIR} - - CHROOT_LIBRARY_PATHS=${3} - echo CHROOT_LIBRARY_PATHS: ${CHROOT_LIBRARY_PATHS} - - CHROOT_CUDA_LIBRARY=${4} - echo CHROOT_CUDA_LIBRARY: ${CHROOT_CUDA_LIBRARY} - - CHROOT_GADGETRON_SOURCE_DIR=${5} - echo CHROOT_GADGETRON_SOURCE_DIR: ${CHROOT_GADGETRON_SOURCE_DIR} - - CHROOT_BASE_NAME=${6} - echo CHROOT_BASE_NAME: ${CHROOT_BASE_NAME} - - if [ $# -ge 7 ]; then - CHROOT_IMAGE_SIZE=${7} - else - CHROOT_IMAGE_SIZE=1536 - fi - echo CHROOT_IMAGE_SIZE: ${CHROOT_IMAGE_SIZE} - - # -------------------------------------------------------------------------------- - - # Add LIBRARY_PATHS to LD_LIBRARY_PATH - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:${CHROOT_LIBRARY_PATHS} - export LC_ALL=C - echo "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH}" - - # untar the chroot base - rm -rf ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root - tar -xzf ${CHROOT_BASE_NAME} -C ${CHROOT_GADGETRON_BINARY_DIR}/chroot - sleep 3 - - touch ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/source-manifest.txt - - GADGETRON_INFO=${CHROOT_GADGETRON_INSTALL_PREFIX}/bin/gadgetron_info - if [ -f ${GADGETRON_INFO} ]; then - res=$(${GADGETRON_INFO}) - re=".*-- Git SHA1 : ([0-9a-z]+).*" - if [[ $res =~ $re ]]; then - CHROOT_GIT_SHA1_HASH=${BASH_REMATCH[1]} - fi - fi - - echo "gadgetron ${CHROOT_GIT_SHA1_HASH}" > ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/source-manifest.txt - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron - mkdir -p ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups - - cd ${CHROOT_GADGETRON_BINARY_DIR} - make install DESTDIR="${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron" -j8 - - #This copies the SIEMENS_TO_ISMRMRD executable if it is installed - if [ $# -ge 8 ]; then - CHROOT_SIEMENS_TO_ISMRMRD_EXE=${8} - echo CHROOT_SIEMENS_TO_ISMRMRD_EXE: ${CHROOT_SIEMENS_TO_ISMRMRD_EXE} - cp ${CHROOT_SIEMENS_TO_ISMRMRD_EXE} "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron/${CHROOT_GADGETRON_INSTALL_PREFIX}/bin/" - else - echo "SIEMENS_TO_ISMRMRD_EXE not set" - fi - - ${CHROOT_GADGETRON_SOURCE_DIR}/chroot/generate_gadgetron_root ${CHROOT_GADGETRON_INSTALL_PREFIX} ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron - - cp ${CHROOT_CUDA_LIBRARY} ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron/${CHROOT_GADGETRON_INSTALL_PREFIX}/lib - cp -n ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron${CHROOT_GADGETRON_INSTALL_PREFIX}/share/gadgetron/config/gadgetron.xml.example ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron${CHROOT_GADGETRON_INSTALL_PREFIX}/share/gadgetron/config/gadgetron.xml - - ISMRMRD_PYTHON_FOLDER=${CHROOT_GADGETRON_INSTALL_PREFIX}/share/gadgetron/python/ismrmrd - if [ -d ${ISMRMRD_PYTHON_FOLDER} ]; then - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron pip install cython h5py pyxb - chroot ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron pip install --upgrade h5py - cp -rf ${ISMRMRD_PYTHON_FOLDER} "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root/gadgetron/${CHROOT_GADGETRON_INSTALL_PREFIX}/share/gadgetron/python" - fi - - TAR_FILE_NAME=gadgetron-`date '+%Y%m%d-%H%M'`-${CHROOT_GIT_SHA1_HASH:0:8} - IMAGE_FILE_NAME=${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.img - - tar -zcf "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.tar.gz" --directory "${CHROOT_GADGETRON_BINARY_DIR}/chroot" --exclude=./chroot-root/gadgetron/var --exclude=./chroot-root/gadgetron/dev --exclude=./chroot-root/gadgetron/sys --exclude=./chroot-root/gadgetron/proc --exclude=./chroot-root/gadgetron/root ./chroot-root - - dd if=/dev/zero of=${IMAGE_FILE_NAME} bs=${CHROOT_IMAGE_SIZE}k seek=1024 count=0 - mke2fs -F -t ext3 ${IMAGE_FILE_NAME} - mkdir ${CHROOT_GADGETRON_BINARY_DIR}/chroot/gadgetron_root - mount -o loop ${IMAGE_FILE_NAME} ${CHROOT_GADGETRON_BINARY_DIR}/chroot/gadgetron_root - tar -xzf ${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.tar.gz -C ${CHROOT_GADGETRON_BINARY_DIR}/chroot/gadgetron_root/ - sleep 3 - umount ${CHROOT_GADGETRON_BINARY_DIR}/chroot/gadgetron_root - rmdir ${CHROOT_GADGETRON_BINARY_DIR}/chroot/gadgetron_root - rm -rf "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-root" - - chmod 666 "${CHROOT_GADGETRON_BINARY_DIR}/chroot/chroot-backups/${TAR_FILE_NAME}.tar.gz" - chmod 666 "${IMAGE_FILE_NAME}" - exit 0 - else - echo -e "\nUsage: $0 (gadgetron install prefix) (gadgetron binary dir) (LIBRARY_PATHS) (CHROOT_CUDA_LIBRARY) (gadgetron source dir) (chroot base name) (optional, image size) (optional, SIEMENS_TO_ISMRMRD_EXE)\n" - exit 1 - fi -fi diff --git a/chroot/enter-chroot-env.sh.in b/chroot/enter-chroot-env.sh.in deleted file mode 100644 index 5f798895d..000000000 --- a/chroot/enter-chroot-env.sh.in +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:@CMAKE_INSTALL_PREFIX@/bin LD_LIBRARY_PATH=@CMAKE_INSTALL_PREFIX@/lib:/usr/local/lib:/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64 chroot ./../ diff --git a/chroot/gadgetron-dependency-query.sh.in b/chroot/gadgetron-dependency-query.sh.in deleted file mode 100644 index 2487bf3de..000000000 --- a/chroot/gadgetron-dependency-query.sh.in +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [ $# -eq 4 ]; then - - GT_HOST=${1} - GT_PORT=${2} - QUERY_OUT=${3} - TIMEOUT=${4} - - PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:@CMAKE_INSTALL_PREFIX@/bin LD_LIBRARY_PATH=@CMAKE_INSTALL_PREFIX@/lib:/usr/local/lib:/opt/intel/mkl/lib/intel64:/opt/intel/lib/intel64 @CMAKE_INSTALL_PREFIX@/bin/gadgetron_ismrmrd_client -q -c gtquery.xml -a $GT_HOST -p $GT_PORT -t $TIMEOUT -o $QUERY_OUT - exit $? -else - echo -e "\nUsage: $0